diff --git a/app/controllers/sign_up/completions_controller.rb b/app/controllers/sign_up/completions_controller.rb index 129c927f3d5..15d2a4f1cfd 100644 --- a/app/controllers/sign_up/completions_controller.rb +++ b/app/controllers/sign_up/completions_controller.rb @@ -117,6 +117,7 @@ def displayable_attributes email: email, verified_at: verified_at, x509_subject: current_user.piv_cac_configurations.first&.x509_dn_uuid, + x509_issuer: current_user.piv_cac_configurations.first&.x509_issuer, } end @@ -144,6 +145,7 @@ def pii_to_displayable_attributes email: email, verified_at: verified_at, x509_subject: current_user.piv_cac_configurations.first&.x509_dn_uuid, + x509_issuer: current_user.piv_cac_configurations.first&.x509_issuer, } end end diff --git a/app/controllers/two_factor_authentication/piv_cac_verification_controller.rb b/app/controllers/two_factor_authentication/piv_cac_verification_controller.rb index 83d2bb6bf37..35b9a819215 100644 --- a/app/controllers/two_factor_authentication/piv_cac_verification_controller.rb +++ b/app/controllers/two_factor_authentication/piv_cac_verification_controller.rb @@ -42,6 +42,7 @@ def handle_valid_piv_cac clear_piv_cac_nonce save_piv_cac_information( subject: piv_cac_verfication_form.x509_dn, + issuer: piv_cac_verfication_form.x509_issuer, presented: true, ) diff --git a/app/controllers/users/piv_cac_authentication_setup_controller.rb b/app/controllers/users/piv_cac_authentication_setup_controller.rb index 47b626f432d..14cdf285577 100644 --- a/app/controllers/users/piv_cac_authentication_setup_controller.rb +++ b/app/controllers/users/piv_cac_authentication_setup_controller.rb @@ -94,6 +94,7 @@ def process_valid_submission flash[:success] = t('notices.piv_cac_configured') save_piv_cac_information( subject: user_piv_cac_form.x509_dn, + issuer: user_piv_cac_form.x509_issuer, presented: true, ) create_user_event(:piv_cac_enabled) diff --git a/app/controllers/users/piv_cac_login_controller.rb b/app/controllers/users/piv_cac_login_controller.rb index 2111b66a62f..a814683db30 100644 --- a/app/controllers/users/piv_cac_login_controller.rb +++ b/app/controllers/users/piv_cac_login_controller.rb @@ -65,6 +65,7 @@ def process_valid_submission save_piv_cac_information( subject: piv_cac_login_form.x509_dn, + issuer: piv_cac_login_form.x509_issuer, presented: true, ) diff --git a/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb b/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb index 59b898568d0..f102797c13c 100644 --- a/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb +++ b/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb @@ -76,6 +76,7 @@ def process_valid_submission session.delete(:needs_to_setup_piv_cac_after_sign_in) save_piv_cac_information( subject: user_piv_cac_form.x509_dn, + issuer: user_piv_cac_form.x509_issuer, presented: true, ) create_user_event(:piv_cac_enabled) diff --git a/app/forms/concerns/piv_cac_form_helpers.rb b/app/forms/concerns/piv_cac_form_helpers.rb index 4d35277d89c..30394381c02 100644 --- a/app/forms/concerns/piv_cac_form_helpers.rb +++ b/app/forms/concerns/piv_cac_form_helpers.rb @@ -21,6 +21,7 @@ def not_error_token else self.x509_dn_uuid = @data['uuid'] self.x509_dn = @data['subject'] + self.x509_issuer = @data['issuer'] true end end diff --git a/app/forms/piv_cac_proofing_form.rb b/app/forms/piv_cac_proofing_form.rb index 09093f94015..44f9fb24090 100644 --- a/app/forms/piv_cac_proofing_form.rb +++ b/app/forms/piv_cac_proofing_form.rb @@ -2,8 +2,8 @@ class PivCacProofingForm include ActiveModel::Model include PivCacFormHelpers - attr_accessor :x509_dn_uuid, :x509_dn, :token, :error_type, :nonce, :user, :key_id, :first_name, - :last_name, :cn + attr_accessor :x509_dn_uuid, :x509_dn, :x509_issuer, :token, :error_type, :nonce, :user, :key_id, + :first_name, :last_name, :cn validates :token, presence: true validates :nonce, presence: true diff --git a/app/forms/user_piv_cac_login_form.rb b/app/forms/user_piv_cac_login_form.rb index 592fca2cb11..f6c2844ff57 100644 --- a/app/forms/user_piv_cac_login_form.rb +++ b/app/forms/user_piv_cac_login_form.rb @@ -2,7 +2,7 @@ class UserPivCacLoginForm include ActiveModel::Model include PivCacFormHelpers - attr_accessor :x509_dn_uuid, :x509_dn, :token, :error_type, :nonce, :user, :key_id + attr_accessor :x509_dn_uuid, :x509_dn, :x509_issuer, :token, :error_type, :nonce, :user, :key_id validates :token, presence: true validates :nonce, presence: true diff --git a/app/forms/user_piv_cac_setup_form.rb b/app/forms/user_piv_cac_setup_form.rb index deae70611ca..be6d59ac436 100644 --- a/app/forms/user_piv_cac_setup_form.rb +++ b/app/forms/user_piv_cac_setup_form.rb @@ -2,8 +2,8 @@ class UserPivCacSetupForm include ActiveModel::Model include PivCacFormHelpers - attr_accessor :x509_dn_uuid, :x509_dn, :token, :user, :nonce, :error_type, :name, :key_id, - :piv_cac_required + attr_accessor :x509_dn_uuid, :x509_dn, :x509_issuer, :token, :user, :nonce, :error_type, :name, + :key_id, :piv_cac_required attr_reader :name_taken validates :token, presence: true @@ -26,7 +26,7 @@ def submit private def process_valid_submission - Db::PivCacConfiguration::Create.call(user, x509_dn_uuid, @name) + Db::PivCacConfiguration::Create.call(user, x509_dn_uuid, @name, x509_issuer) true rescue PG::UniqueViolation self.error_type = 'piv_cac.already_associated' @@ -40,6 +40,7 @@ def valid_submission? def piv_cac_not_already_associated self.x509_dn_uuid = @data['uuid'] self.x509_dn = @data['subject'] + self.x509_issuer = @data['issuer'] if Db::PivCacConfiguration::FindUserByX509.call(x509_dn_uuid) self.error_type = 'piv_cac.already_associated' false diff --git a/app/forms/user_piv_cac_verification_form.rb b/app/forms/user_piv_cac_verification_form.rb index 3df1d79b2bc..9dfd26d0040 100644 --- a/app/forms/user_piv_cac_verification_form.rb +++ b/app/forms/user_piv_cac_verification_form.rb @@ -2,7 +2,7 @@ class UserPivCacVerificationForm include ActiveModel::Model include PivCacFormHelpers - attr_accessor :x509_dn_uuid, :x509_dn, :token, :error_type, :nonce, :user, :key_id, + attr_accessor :x509_dn_uuid, :x509_dn, :x509_issuer, :token, :error_type, :nonce, :user, :key_id, :piv_cac_required validates :token, presence: true diff --git a/app/presenters/openid_connect_user_info_presenter.rb b/app/presenters/openid_connect_user_info_presenter.rb index bbf080722cf..45ef8ddb8d1 100644 --- a/app/presenters/openid_connect_user_info_presenter.rb +++ b/app/presenters/openid_connect_user_info_presenter.rb @@ -48,6 +48,7 @@ def ial2_attributes def x509_attributes { x509_subject: stringify_attr(x509_data.subject), + x509_issuer: stringify_attr(x509_data.issuer), x509_presented: x509_data.presented, } end diff --git a/app/services/attribute_asserter.rb b/app/services/attribute_asserter.rb index 51be5cf9f92..d5d457f3aa2 100644 --- a/app/services/attribute_asserter.rb +++ b/app/services/attribute_asserter.rb @@ -86,6 +86,7 @@ def add_aal(attrs) def add_x509(attrs) attrs[:x509_subject] = { getter: ->(_principal) { x509_data.subject } } + attrs[:x509_issuer] = { getter: ->(_principal) { x509_data.issuer } } attrs[:x509_presented] = { getter: ->(_principal) { x509_data.presented } } end diff --git a/app/services/db/piv_cac_configuration/create.rb b/app/services/db/piv_cac_configuration/create.rb index 74abfc3643d..c3cc209d8fc 100644 --- a/app/services/db/piv_cac_configuration/create.rb +++ b/app/services/db/piv_cac_configuration/create.rb @@ -1,8 +1,10 @@ module Db module PivCacConfiguration class Create - def self.call(user, x509_dn_uuid, name = x509_dn_uuid) - user.piv_cac_configurations.create!(x509_dn_uuid: x509_dn_uuid, name: name) + def self.call(user, x509_dn_uuid, name = x509_dn_uuid, issuer = nil) + user.piv_cac_configurations.create!(x509_dn_uuid: x509_dn_uuid, + name: name, + x509_issuer: issuer) end end end diff --git a/app/services/openid_connect_attribute_scoper.rb b/app/services/openid_connect_attribute_scoper.rb index 4779f9396f3..d203e3495af 100644 --- a/app/services/openid_connect_attribute_scoper.rb +++ b/app/services/openid_connect_attribute_scoper.rb @@ -11,6 +11,7 @@ class OpenidConnectAttributeScoper social_security_number x509 x509:subject + x509:issuer x509:presented ].freeze @@ -20,6 +21,7 @@ class OpenidConnectAttributeScoper profile:verified_at x509 x509:subject + x509:issuer x509:presented ].freeze @@ -36,6 +38,7 @@ class OpenidConnectAttributeScoper social_security_number: %w[social_security_number], x509_subject: %w[x509 x509:subject], x509_presented: %w[x509 x509:presented], + x509_issuer: %w[x509 x509:issuer], }.with_indifferent_access.freeze SCOPE_ATTRIBUTE_MAP = {}.tap do |scope_attribute_map| diff --git a/app/services/x509/attributes.rb b/app/services/x509/attributes.rb index 648335fcacd..d497b41bfaa 100644 --- a/app/services/x509/attributes.rb +++ b/app/services/x509/attributes.rb @@ -1,6 +1,6 @@ module X509 Attributes = Struct.new( - :subject, :presented + :subject, :issuer, :presented ) do def self.new_from_hash(hash) attrs = new diff --git a/app/view_models/sign_up_completions_show.rb b/app/view_models/sign_up_completions_show.rb index ee2b107cab2..8dc7c207f08 100644 --- a/app/view_models/sign_up_completions_show.rb +++ b/app/view_models/sign_up_completions_show.rb @@ -21,12 +21,14 @@ def initialize(ial2_requested:, decorated_session:, current_user:, handoff:, ial [[:birthdate], :birthdate], [[:social_security_number], :social_security_number], [[:x509_subject], :x509_subject], + [[:x509_issuer], :x509_issuer], [[:verified_at], :verified_at], ].freeze SORTED_IAL1_ATTRIBUTE_MAPPING = [ [[:email], :email], [[:x509_subject], :x509_subject], + [[:x509_issuer], :x509_issuer], [[:verified_at], :verified_at], ].freeze diff --git a/config/locales/help_text/en.yml b/config/locales/help_text/en.yml index 257357c4479..25dbe962763 100644 --- a/config/locales/help_text/en.yml +++ b/config/locales/help_text/en.yml @@ -17,4 +17,5 @@ en: social_security_number: Social Security Number verified_at: Updated on verified_at_blank: Not yet verified + x509_issuer: PIV/CAC Issuer x509_subject: PIV/CAC Identity diff --git a/config/locales/help_text/es.yml b/config/locales/help_text/es.yml index e6d2d316e34..90b3575b841 100644 --- a/config/locales/help_text/es.yml +++ b/config/locales/help_text/es.yml @@ -17,4 +17,5 @@ es: social_security_number: Número de Seguro Social verified_at: Actualizado en verified_at_blank: Aún no verificado + x509_issuer: Emisor PIV/CAC x509_subject: Identidad PIV/CAC diff --git a/config/locales/help_text/fr.yml b/config/locales/help_text/fr.yml index ecb76a73878..3a10bf0cb3b 100644 --- a/config/locales/help_text/fr.yml +++ b/config/locales/help_text/fr.yml @@ -18,4 +18,5 @@ fr: social_security_number: Numéro de sécurité sociale verified_at: Mis à jour le verified_at_blank: Pas encore vérifié + x509_issuer: Émetteur PIV/CAC x509_subject: Identité associée à la carte PIV/CAC diff --git a/db/migrate/20200909135409_add_x509_issuer_to_piv_cac_configurations.rb b/db/migrate/20200909135409_add_x509_issuer_to_piv_cac_configurations.rb new file mode 100644 index 00000000000..e28bfa8c0e6 --- /dev/null +++ b/db/migrate/20200909135409_add_x509_issuer_to_piv_cac_configurations.rb @@ -0,0 +1,5 @@ +class AddX509IssuerToPivCacConfigurations < ActiveRecord::Migration[5.1] + def change + add_column :piv_cac_configurations, :x509_issuer, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index bdbc9fe2d50..686df6a5f31 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_09_01_134021) do +ActiveRecord::Schema.define(version: 2020_09_09_135409) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -337,6 +337,7 @@ t.string "name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "x509_issuer" t.index ["user_id", "created_at"], name: "index_piv_cac_configurations_on_user_id_and_created_at", unique: true t.index ["user_id", "name"], name: "index_piv_cac_configurations_on_user_id_and_name", unique: true t.index ["x509_dn_uuid"], name: "index_piv_cac_configurations_on_x509_dn_uuid", unique: true diff --git a/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb index 386e62f4b30..79392081bca 100644 --- a/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb +++ b/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb @@ -11,6 +11,9 @@ let(:nonce) { 'once' } let(:x509_subject) { 'o=US, ou=DoD, cn=John.Doe.1234' } + let(:x509_issuer) do + '/C=US/O=Entrust/OU=Certification Authorities/OU=Entrust Managed Services SSP CA' + end before(:each) do session_info = { piv_cac_nonce: nonce } @@ -18,21 +21,25 @@ allow(PivCacService).to receive(:decode_token).with('good-token').and_return( 'uuid' => user.piv_cac_configurations.first.x509_dn_uuid, 'subject' => x509_subject, + 'issuer' => x509_issuer, 'nonce' => nonce, ) allow(PivCacService).to receive(:decode_token).with('good-other-token').and_return( 'uuid' => user.piv_cac_configurations.first.x509_dn_uuid + 'X', 'subject' => x509_subject + 'X', + 'issuer' => x509_issuer, 'nonce' => nonce, ) allow(PivCacService).to receive(:decode_token).with('bad-token').and_return( 'uuid' => 'bad-uuid', 'subject' => 'bad-dn', + 'issuer' => x509_issuer, 'nonce' => nonce, ) allow(PivCacService).to receive(:decode_token).with('bad-nonce').and_return( 'uuid' => user.piv_cac_configurations.first.x509_dn_uuid, 'subject' => x509_subject, + 'issuer' => x509_issuer, 'nonce' => 'bad-' + nonce, ) cookies['_ga'] = ga_cookie @@ -64,6 +71,7 @@ expect(response).to redirect_to account_path expect(subject.user_session[:decrypted_x509]).to eq({ 'subject' => x509_subject, + 'issuer' => x509_issuer, 'presented' => true, }.to_json) end diff --git a/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb b/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb index 3a26e1600ea..65a61b05b1e 100644 --- a/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb +++ b/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb @@ -103,6 +103,7 @@ get :new, params: { token: good_token } json = { 'subject' => 'some dn', + 'issuer' => nil, 'presented' => true, }.to_json diff --git a/spec/services/attribute_asserter_spec.rb b/spec/services/attribute_asserter_spec.rb index 58c840fe471..93f79181b85 100644 --- a/spec/services/attribute_asserter_spec.rb +++ b/spec/services/attribute_asserter_spec.rb @@ -151,7 +151,7 @@ context 'x509 attributes included in the SP attribute bundle' do before do allow(service_provider.metadata).to receive(:[]).with(:attribute_bundle). - and_return(%w[email x509_subject x509_presented]) + and_return(%w[email x509_subject x509_issuer x509_presented]) subject.build end @@ -162,7 +162,7 @@ } end - it 'does not include x509_subject and x509_presented' do + it 'does not include x509_subject, x509_issuer, and x509_presented' do expect(user.asserted_attributes.keys).to eq %i[uuid email verified_at] end end @@ -177,8 +177,8 @@ } end - it 'includes x509_subject and x509_presented' do - expected = %i[uuid email verified_at x509_subject x509_presented] + it 'includes x509_subject x509_issuer x509_presented' do + expected = %i[uuid email verified_at x509_subject x509_issuer x509_presented] expect(user.asserted_attributes.keys).to eq expected end end @@ -299,7 +299,7 @@ context 'x509 attributes included in the SP attribute bundle' do before do allow(service_provider.metadata).to receive(:[]).with(:attribute_bundle). - and_return(%w[email x509_subject x509_presented]) + and_return(%w[email x509_subject x509_issuer x509_presented]) subject.build end @@ -310,7 +310,7 @@ } end - it 'does not include x509_subject and x509_presented' do + it 'does not include x509_subject x509_issuer and x509_presented' do expect(user.asserted_attributes.keys).to eq %i[uuid email] end end @@ -325,8 +325,8 @@ } end - it 'includes x509_subject and x509_presented' do - expected = %i[uuid email x509_subject x509_presented] + it 'includes x509_subject x509_issuer and x509_presented' do + expected = %i[uuid email x509_subject x509_issuer x509_presented] expect(user.asserted_attributes.keys).to eq expected end end