diff --git a/Gemfile.lock b/Gemfile.lock index fad1fa79..dbcd617e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -255,7 +255,7 @@ GEM snaky_hash (~> 2.0) version_gem (~> 1.1) oj (3.14.2) - omniauth (2.1.1) + omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection @@ -295,7 +295,7 @@ GEM que (>= 1) sinatra racc (1.7.1) - rack (2.2.8) + rack (2.2.9) rack-protection (3.0.5) rack rack-proxy (0.7.6) diff --git a/app/assets/images/eid-sk.svg b/app/assets/images/eid-sk.svg index 842451ed..3d4bdd54 100644 --- a/app/assets/images/eid-sk.svg +++ b/app/assets/images/eid-sk.svg @@ -16,5 +16,5 @@ - Prihlásiť cez EID + Cez slovensko.sk \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index ef33e634..816e9074 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -11,6 +11,11 @@ def create end if new_eid_identity? + unless fully_represents_subject? + render :insufficient_representation, locals: { eid_token: eid_token } + return + end + render :new_eid_identity, locals: { eid_token: eid_token } return end @@ -25,7 +30,18 @@ def create notice = user.previously_new_record? ? 'first_time_login' : 'Prihlásenie úspešné. Vitajte!' if eid_identity_approval? - user.update!(eid_sub: eid_sub_from_auth) + assertion = Upvs::Assertion.assertion(eid_token) + + if assertion + user.update!( + eid_sub: eid_sub_from_auth, + subject_name: assertion.subject_name, + subject_cin: assertion.subject_cin, + subject_edesk_number: assertion.subject_edesk_number, + ) + else + user.update!(eid_sub: eid_sub_from_auth) + end end unless should_keep_eid_token_in_session?(user.eid_sub) @@ -57,7 +73,10 @@ def logout def destroy if should_perform_eid_logout? - redirect_to eid_token.generate_logout_url(expires_in: 5.minutes) + eid_logout_url = eid_token.generate_logout_url(expires_in: 5.minutes) + reset_session + + redirect_to eid_logout_url else logout end @@ -95,4 +114,9 @@ def after_login_redirect_path return session[:after_login_callback] if session[:after_login_callback]&.start_with?("/") # Only allow local redirects root_path end + + def fully_represents_subject? + assertion = Upvs::Assertion.assertion(eid_token) + assertion&.fully_represents_subject? + end end diff --git a/app/models/eid_token.rb b/app/models/eid_token.rb index af15ef7e..4840c226 100644 --- a/app/models/eid_token.rb +++ b/app/models/eid_token.rb @@ -14,7 +14,7 @@ def decoded_token end def sub - decoded_token&.first&.fetch('actor')&.fetch('sub') + decoded_token&.first&.fetch('sub') end def name diff --git a/app/models/upvs/assertion.rb b/app/models/upvs/assertion.rb new file mode 100644 index 00000000..607bd08d --- /dev/null +++ b/app/models/upvs/assertion.rb @@ -0,0 +1,73 @@ +module Upvs + class Assertion + include ActiveModel::Model + attr_accessor(:raw, :subject_name, :subject_id, :subject_cin, :subject_edesk_number, :delegation_type) + + DELEGATION_TYPES = { + legal_representation: '0', + full_representation: '1', + partial_representation: '2', + } + + def fully_represents_subject? + delegation_type&.to_s&.in?(full_representations) + end + + def self.new_from_xml(raw:) + return unless raw + + doc = Nokogiri::XML(raw) + return unless doc + + doc.remove_namespaces! + doc_attrs = doc.xpath('//Assertion/AttributeStatement/Attribute') + return unless doc_attrs + + new( + raw:, + subject_name: doc_attrs.detect{|n| n['Name'] == 'Subject.FormattedName' }&.xpath('AttributeValue')&.text, + subject_id: doc_attrs.detect{|n| n['Name'] == 'SubjectID' }&.xpath('AttributeValue')&.text, + subject_cin: doc_attrs.detect{|n| n['Name'] == 'Subject.ICO' }&.xpath('AttributeValue')&.text, + subject_edesk_number: doc_attrs.detect{|n| n['Name'] == 'Subject.eDeskNumber' }&.xpath('AttributeValue')&.text, + delegation_type: doc_attrs.detect{|n| n['Name'] == 'DelegationType' }&.xpath('AttributeValue')&.text, + ) + end + + def self.assertion(eid_token, client: Faraday, url: "#{ENV.fetch('AUTH_EID_BASE_URL')}/api/upvs/assertion?token=#{eid_token&.api_token}") + new_from_xml(raw: get_from_sk_api(client, url, eid_token)) + end + + def self.get_from_sk_api(client, url, eid_token) + headers = { + "Accept": "application/samlassertion+xml", + "AUTHORIZATION": "Bearer #{eid_token&.api_token}", + } + + response = client.get(url, {}, headers) + error = begin + JSON.parse(response.body) + rescue StandardError + nil + end + if error && error['message'] + return nil + end + response.body + rescue StandardError => _e + raise + nil + end + + private + + def full_representations + [ + DELEGATION_TYPES[:legal_representation], + DELEGATION_TYPES[:full_representation], + ] + end + + class SkApiError < StandardError + end + end +end diff --git a/app/views/components/_header.html.erb b/app/views/components/_header.html.erb index 4a0e0c49..e29a5757 100644 --- a/app/views/components/_header.html.erb +++ b/app/views/components/_header.html.erb @@ -27,9 +27,6 @@ <%= current_user.email %> - <% if eid_token&.valid? %> - EID - <% end %>