diff --git a/.circleci/config.yml b/.circleci/config.yml index 67ba0885378..699857ff848 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -159,7 +159,8 @@ jobs: cp -a keys.example keys cp -a certs.example certs cp pwned_passwords/pwned_passwords.txt.sample pwned_passwords/pwned_passwords.txt - bundle exec rake db:create db:migrate db:seed --trace + bundle exec rake db:create db:migrate --trace + bundle exec rake db:seed bundle exec rake assets:precompile - run: name: Run Tests diff --git a/app/controllers/concerns/saml_idp_auth_concern.rb b/app/controllers/concerns/saml_idp_auth_concern.rb index eada94eec94..ca5013e9517 100644 --- a/app/controllers/concerns/saml_idp_auth_concern.rb +++ b/app/controllers/concerns/saml_idp_auth_concern.rb @@ -161,12 +161,35 @@ def saml_response ) end + def matching_cert + return @matching_cert if defined?(@matching_cert) + + @matching_cert = current_service_provider.ssl_certs.find do |ssl_cert| + fingerprint = Fingerprinter.fingerprint_cert(ssl_cert) + + saml_request = SamlIdp::Request.from_deflated_request( + params[:SAMLRequest], + get_params: params, + cert: ssl_cert, + ) + if saml_request&.service_provider + # Plumb the fingerprint through to the internal service_provider representation + saml_request.service_provider.fingerprint = fingerprint + saml_request.valid_signature? + end + end + end + def encryption_opts query_params = UriService.params(request.original_url) if query_params[:skip_encryption].present? && current_service_provider.skip_encryption_allowed nil - else - current_service_provider.encryption_opts + elsif current_service_provider.encrypt_responses? + { + cert: matching_cert || current_service_provider.certs.first, + block_encryption: current_service_provider.block_encryption, + key_transport: 'rsa-oaep-mgf1p', + } end end @@ -183,7 +206,7 @@ def current_service_provider end def current_issuer - @_issuer ||= saml_request.service_provider.identifier + @_issuer ||= saml_request.service_provider&.identifier end def request_url diff --git a/app/controllers/saml_idp_controller.rb b/app/controllers/saml_idp_controller.rb index 9c519bcbcf5..bc24d75972a 100644 --- a/app/controllers/saml_idp_controller.rb +++ b/app/controllers/saml_idp_controller.rb @@ -33,6 +33,12 @@ def logout return sign_out_with_flash if raw_saml_request.nil? decode_request(raw_saml_request) + + # Plumb the fingerprint through to the internal service_provider representation + if saml_request && matching_cert + saml_request.service_provider.fingerprint = Fingerprinter.fingerprint_cert(matching_cert) + end + track_logout_event return head(:bad_request) unless valid_saml_request? diff --git a/app/forms/openid_connect_token_form.rb b/app/forms/openid_connect_token_form.rb index 352940aa5db..ad9b2770d23 100644 --- a/app/forms/openid_connect_token_form.rb +++ b/app/forms/openid_connect_token_form.rb @@ -109,14 +109,25 @@ def validate_code_verifier def validate_client_assertion return if identity.blank? - payload, _headers = JWT.decode(client_assertion, service_provider.ssl_cert.public_key, true, - algorithm: 'RS256', iss: client_id, - verify_iss: true, sub: client_id, - verify_sub: true) - validate_aud_claim(payload) - validate_iat(payload) - rescue JWT::DecodeError => err - errors.add(:client_assertion, err.message) + payload, _headers, err = nil + + matching_cert = service_provider.ssl_certs.find do |ssl_cert| + err = nil + payload, _headers = JWT.decode(client_assertion, ssl_cert.public_key, true, + algorithm: 'RS256', iss: client_id, + verify_iss: true, sub: client_id, + verify_sub: true) + rescue JWT::DecodeError => err + next + end + + if matching_cert && payload + validate_aud_claim(payload) + validate_iat(payload) + else + errors.add(:client_assertion, + err&.message || t('openid_connect.token.errors.invalid_signature')) + end end def validate_aud_claim(payload) diff --git a/app/forms/security_event_form.rb b/app/forms/security_event_form.rb index 432b9979fd7..883b42c7964 100644 --- a/app/forms/security_event_form.rb +++ b/app/forms/security_event_form.rb @@ -95,17 +95,31 @@ def check_public_key_error(public_key) end def validate_jwt - public_key = service_provider&.ssl_cert&.public_key return if check_jwt_parse_error - return if check_public_key_error(public_key) - JWT.decode(body, public_key, true, algorithm: 'RS256', leeway: Float::INFINITY) - rescue JWT::IncorrectAlgorithm - @error_code = ErrorCodes::JWT_CRYPTO - errors.add(:jwt, t('risc.security_event.errors.alg_unsupported', expected_alg: 'RS256')) - rescue JWT::VerificationError => err - @error_code = ErrorCodes::JWS - errors.add(:jwt, err.message) + error_code = nil + error_message = nil + + matching_public_key = service_provider&.ssl_certs&.find do |ssl_cert| + error_code = nil + error_message = nil + JWT.decode(body, ssl_cert.public_key, true, algorithm: 'RS256', leeway: Float::INFINITY) + rescue JWT::IncorrectAlgorithm + error_code = ErrorCodes::JWT_CRYPTO + error_message = t('risc.security_event.errors.alg_unsupported', expected_alg: 'RS256') + nil + rescue JWT::VerificationError => err + error_code = ErrorCodes::JWS + error_message = err.message + nil + end + + if error_code && error_message + @error_code = error_code + errors.add(:jwt, error_message) + else + check_public_key_error(matching_public_key) + end end def validate_jti diff --git a/app/models/null_service_provider.rb b/app/models/null_service_provider.rb index 2f96ee7eb19..a0bf24af461 100644 --- a/app/models/null_service_provider.rb +++ b/app/models/null_service_provider.rb @@ -15,6 +15,7 @@ class NullServiceProvider attribute_bundle block_encryption cert + certs created_at default_aal description @@ -40,7 +41,6 @@ class NullServiceProvider signature signed_response_message_requested sp_initiated_login_url - ssl_cert updated_at ].freeze @@ -85,8 +85,6 @@ def encrypt_responses? false end - def encryption_opts; end - def skip_encryption_allowed false end @@ -94,4 +92,8 @@ def skip_encryption_allowed def allow_prompt_login false end + + def ssl_certs + [] + end end diff --git a/app/models/service_provider.rb b/app/models/service_provider.rb index cb77b12d934..f6c684da3f4 100644 --- a/app/models/service_provider.rb +++ b/app/models/service_provider.rb @@ -2,7 +2,7 @@ require 'identity_validations' class ServiceProvider < ApplicationRecord - self.ignored_columns = %w[deal_id agency aal] + self.ignored_columns = %w[deal_id agency aal fingerprint] belongs_to :agency @@ -27,33 +27,20 @@ def self.from_issuer(issuer) end def metadata - attributes.symbolize_keys.merge(fingerprint: fingerprint) + attributes.symbolize_keys end - def ssl_cert - @ssl_cert ||= begin - return if cert.blank? + # @return [Array] + def ssl_certs + @ssl_certs ||= (certs.presence || Array(cert)).map do |cert| OpenSSL::X509::Certificate.new(load_cert(cert)) end end - def fingerprint - @_fingerprint ||= super || Fingerprinter.fingerprint_cert(ssl_cert) - end - def encrypt_responses? block_encryption != 'none' end - def encryption_opts - return nil unless encrypt_responses? - { - cert: ssl_cert, - block_encryption: block_encryption, - key_transport: 'rsa-oaep-mgf1p', - } - end - def skip_encryption_allowed config = AppConfig.env.skip_encryption_allowed_list return false if config.blank? diff --git a/app/services/service_provider_config.rb b/app/services/service_provider_config.rb deleted file mode 100644 index 497713adcaf..00000000000 --- a/app/services/service_provider_config.rb +++ /dev/null @@ -1,17 +0,0 @@ -class ServiceProviderConfig - def initialize(issuer:) - @issuer = issuer - end - - def sp_attributes - service_provider.metadata - end - - def service_provider - @_sp ||= ServiceProvider.from_issuer(issuer) - end - - private - - attr_reader :issuer -end diff --git a/certs.example/sp/saml_test_sp2.crt b/certs.example/sp/saml_test_sp2.crt new file mode 100644 index 00000000000..a391f8d1275 --- /dev/null +++ b/certs.example/sp/saml_test_sp2.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh4CCQDN39Nwta1XWzANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzEdMBsGA1UECAwURGlzdHJpY3Qgb2YgQ29sdW1iaWExEzARBgNVBAcMCldhc2hp +bmd0b24xDDAKBgNVBAoMA0dTQTEMMAoGA1UECwwDVFRTMB4XDTIxMDMyOTE2Mzk1 +M1oXDTIyMDMyOTE2Mzk1M1owXTELMAkGA1UEBhMCVVMxHTAbBgNVBAgMFERpc3Ry +aWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHDApXYXNoaW5ndG9uMQwwCgYDVQQKDANH +U0ExDDAKBgNVBAsMA1RUUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMo28K48AyMI67bTrkXTk+THgyDLTj0aUVjmig8bTAlSZW8GLdG6I2BWlC3yCVL9 +cDx8ENWxtfG/1BQwT/+pf2f23iDzTPYR33z4Q1QZmuqZt39LGP2k3Ew0euzptQzR +anKCzNo2FbO33LnXzktlVElv8YXR0rHNsAH0+sCH/sSn/dQ8cvqyIWzKAyVeZNVX +qzyrYmLde0tiefWXrCRAZ+gbn0Vgcsd6082FaFvTRLmOWGBJaYD3SZXOSIyBgv8k +FAd6ey69M5Qg2cGiiHYF+2rxv8MP5ddA2JIyxmdxajCDJZk7zJiUUWn1Lz0ravgI +eEW1fF0w9Ss1cPvUOCCWNE8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAw/T9Cm3n +lhuO3h8hsTJVIZqiwQw7m/wI2rY9c/on0gwnsnxsvWL3Lvl5ZyqTKqFgXWoV90ZK +PoY/Lv9c5RaPx90kV4ZwIJwzzgFVdR0gwsW6OpUXKZzt3LFNruWC+4KgmREsvRyK +8ATfC5I5wVMxKf93YWEX3MBiHEh2VaTbn3cSukNVqUQsNAwYPrl3Fs3lXE6GbJAI +OScEZWlLdC0/uSxrDj1WA4R/8NFMWZOlG6ImlkBqGIBIyByuucXn7ZzlUp453+LP +KasY2FT+qJtytP05bULKIZHXLftV1CXktvt4dPTHvxwqDjLNiylfHFs/O76UE8ox +tz6PXT2P0wJ0Cw== +-----END CERTIFICATE----- diff --git a/config/initializers/saml_idp.rb b/config/initializers/saml_idp.rb index 31c8d507736..a1737db03d3 100644 --- a/config/initializers/saml_idp.rb +++ b/config/initializers/saml_idp.rb @@ -36,8 +36,6 @@ # Find ServiceProvider metadata_url and fingerprint based on our settings config.service_provider.finder = lambda do |issuer_or_entity_id| - sp_config = ServiceProviderConfig.new(issuer: issuer_or_entity_id) - sp = sp_config.service_provider - sp_config.sp_attributes.merge(fingerprint: sp.fingerprint, cert: sp.ssl_cert) + ServiceProvider.from_issuer(issuer_or_entity_id).metadata end end diff --git a/config/locales/openid_connect/en.yml b/config/locales/openid_connect/en.yml index 44d1f49f9b7..cd084580563 100644 --- a/config/locales/openid_connect/en.yml +++ b/config/locales/openid_connect/en.yml @@ -30,6 +30,8 @@ en: invalid_code_verifier: code_verifier did not match code_challenge invalid_iat: iat must be an integer or floating point Unix timestamp representing a time in the past + invalid_signature: Could not validate assertion against any registered public + keys user_info: errors: malformed_authorization: Malformed Authorization header diff --git a/config/locales/openid_connect/es.yml b/config/locales/openid_connect/es.yml index 5895c1d8aea..178ecc7c2ea 100644 --- a/config/locales/openid_connect/es.yml +++ b/config/locales/openid_connect/es.yml @@ -30,6 +30,8 @@ es: invalid_code_verifier: code_verifier no coincide con code_challenge invalid_iat: iat debe ser una marca de tiempo Unix de punto flotante o entero que represente un tiempo en el pasado + invalid_signature: No se pudo validar la aserción contra ninguna clave pública + registrada user_info: errors: malformed_authorization: Título de autorización mal formado diff --git a/config/locales/openid_connect/fr.yml b/config/locales/openid_connect/fr.yml index c79fcbbe343..7179826a545 100644 --- a/config/locales/openid_connect/fr.yml +++ b/config/locales/openid_connect/fr.yml @@ -31,6 +31,8 @@ fr: invalid_code_verifier: code_verifier ne correspondait pas à code_challenge invalid_iat: iat doit être un horodatage Unix entier ou à virgule flottante représentant une heure dans le passé + invalid_signature: Impossible de valider l'assertion contre les clés publiques + enregistrées user_info: errors: malformed_authorization: Forme de l'en-tête d'autorisation non valide diff --git a/config/service_providers.localdev.yml b/config/service_providers.localdev.yml index 40d4351b4e4..ab20bb72b3e 100644 --- a/config/service_providers.localdev.yml +++ b/config/service_providers.localdev.yml @@ -4,7 +4,9 @@ test: assertion_consumer_logout_service_url: 'http://localhost:3000/test/saml/decode_slo_request' sp_initiated_login_url: 'http://localhost:3000/test/saml' block_encryption: 'none' - cert: 'saml_test_sp' + certs: + - 'saml_test_sp' + - 'saml_test_sp2' agency: 'Test Government Agency' agency_id: 1 uuid_priority: 10 diff --git a/db/migrate/20210329162528_add_multiple_certs_to_service_providers.rb b/db/migrate/20210329162528_add_multiple_certs_to_service_providers.rb new file mode 100644 index 00000000000..254102f28f4 --- /dev/null +++ b/db/migrate/20210329162528_add_multiple_certs_to_service_providers.rb @@ -0,0 +1,5 @@ +class AddMultipleCertsToServiceProviders < ActiveRecord::Migration[6.1] + def change + add_column :service_providers, :certs, :string, array: true + end +end diff --git a/db/schema.rb b/db/schema.rb index caa1f6aad3f..ac3b1b02c95 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: 2021_03_16_082419) do +ActiveRecord::Schema.define(version: 2021_03_29_162528) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -572,6 +572,7 @@ t.date "iaa_end_date" t.string "app_id" t.integer "default_aal" + t.string "certs", array: true t.index ["issuer"], name: "index_service_providers_on_issuer", unique: true end diff --git a/keys.example/saml_test_sp2.key b/keys.example/saml_test_sp2.key new file mode 100644 index 00000000000..661bb817948 --- /dev/null +++ b/keys.example/saml_test_sp2.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKNvCuPAMjCOu2 +065F05Pkx4Mgy049GlFY5ooPG0wJUmVvBi3RuiNgVpQt8glS/XA8fBDVsbXxv9QU +ME//qX9n9t4g80z2Ed98+ENUGZrqmbd/Sxj9pNxMNHrs6bUM0WpygszaNhWzt9y5 +185LZVRJb/GF0dKxzbAB9PrAh/7Ep/3UPHL6siFsygMlXmTVV6s8q2Ji3XtLYnn1 +l6wkQGfoG59FYHLHetPNhWhb00S5jlhgSWmA90mVzkiMgYL/JBQHensuvTOUINnB +ooh2Bftq8b/DD+XXQNiSMsZncWowgyWZO8yYlFFp9S89K2r4CHhFtXxdMPUrNXD7 +1DggljRPAgMBAAECggEAHLw77XaHt5XP8TYZgMC1NoCHiMR7RMGVp71zBvyJDJYR +5foJztDVsB39hp3rZ0iuh1nWBpfvVAA/gfLvm1QZz8tL+4C3ggw+JwMchjnxQr8/ +TS59yaWAzK90fHAlk0G7D7S4qZWf9d791cbuANbQaHMo7ixH9Y5WIaEPdQaeVJGN +98hDb/HnwprqUiIT6qONkECUTB5DkxfFO9YpD4GbI8lnYc7iou/T4lCCEb+OGfSt +Wqy1EDgBRZkZu122xNWRXHbjh4vtRY5DeL9kY8aNPHCqve7T/XSQT35cUScQczwX +C8Ds8qN/eXIUdoHBRlA7LHDOZOjvmRb/U6c9YUwfOQKBgQDzYN3lm/LW7p47abB7 +CUysj8+Y9QnG38BMxRkDZN/T5O1swDZbXtr9QK9gAF3ugLKae2AKL2EiZMB1scLK +M4E4XNjMJVrK4UH77Xon7Dk6r7y8N2VjhPDHjllEtYvjbopcl5JKptkFYsVO4vcA +m+OGsj2nd8QljUtwv0geD5aFLQKBgQDUs5N2IvpYI/2E6Eg7awX1eNGn7cw8gYhF +/qzCmIuUcQJnUdYMCIoZghPJ5Xz7lCBKGmcHfr+Jh1uGQkEYjNfgwEIUPLhl2qi9 +scX9/NApPhwas6xvdOfPJq/BwaMR+oAvg+c6NhxUAFPAVvSCxI8eQPnNNQzOrnkm +PDOrqHJE6wKBgHJ/b+VFqMlVGTv6TPyVM207ev8KyL63JVD4qPvfyS121fwDsY7q +4Tuj4t3XTlmWUnA6+sPP5nK305OLPYjDElfh1ly0djJcJx7Oalm92G6znqctqJVZ +Ra2cWoLophcpOg61gC1+sTrHbOvf+zReInyL/lV7EtxXzNYOJ299BeNBAoGAOfSI +LHtRXSzJSiqEa/Q4Vm9KKQiJSr88o13GMuuftJ2qOv64ZOT6xAKGY8+s41u0BJz3 +D7rAc7e2/3kUBZ1ywOGB38O/trkCm1VSDmeRTHuI6tmkFWZ0NyRiZVfel+p6fPfi +zCCsTVMdft3yl6L5IBQyPHDFAZfWmM10gsROBmsCgYEArmE3weGh7SBveHl1nmUi +klY5edpP76N+qcRSB30ydNw2i7fHf09LzMu+/m8RmQeipaURNnF6ToE4cbQC1x/1 +sgYZNiXWR4gsdH2LjE8XWV/s9Cwf+AhFEVbvujJ9sb5xMjVol8HjV3rYog+4ID0u +gVcJW1KC4o9vRNAQPMr5kfc= +-----END PRIVATE KEY----- diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb index 3e3ffd67dfb..e81e5aec60e 100644 --- a/spec/controllers/saml_idp_controller_spec.rb +++ b/spec/controllers/saml_idp_controller_spec.rb @@ -390,6 +390,43 @@ def name_id_version(format_urn) end end + context 'service provider has multiple certs' do + let(:service_provider) do + create(:service_provider, + cert: nil, # override singular cert + certs: ['saml_test_sp2', 'saml_test_sp'], + active: true) + end + + let(:first_cert_settings) do + saml_settings.tap do |settings| + settings.issuer = service_provider.issuer + end + end + + let(:second_cert_settings) do + saml_settings.tap do |settings| + settings.issuer = service_provider.issuer + settings.certificate = File.read(Rails.root.join('certs', 'sp', 'saml_test_sp2.crt')) + settings.private_key = OpenSSL::PKey::RSA.new( + File.read(Rails.root + 'keys/saml_test_sp2.key'), + ).to_pem + end + end + + it 'encrypts the response to the right key' do + user = create(:user, :signed_up) + generate_saml_response(user, second_cert_settings) + + expect(response).to_not be_redirect + + expect { xmldoc.saml_response(first_cert_settings) }.to raise_error + + response = xmldoc.saml_response(second_cert_settings) + expect(response.decrypted_document).to be + end + end + context 'POST to auth correctly stores SP in session' do before do @user = create(:user, :signed_up) diff --git a/spec/controllers/service_provider_controller_spec.rb b/spec/controllers/service_provider_controller_spec.rb index 123b55922cd..83cf2b9c842 100644 --- a/spec/controllers/service_provider_controller_spec.rb +++ b/spec/controllers/service_provider_controller_spec.rb @@ -47,7 +47,7 @@ sp = ServiceProvider.from_issuer(dashboard_sp_issuer) expect(sp.metadata[:agency]).to eq dashboard_service_providers.first[:agency] - expect(sp.ssl_cert).to be_a OpenSSL::X509::Certificate + expect(sp.ssl_certs.first).to be_a OpenSSL::X509::Certificate expect(sp.active?).to eq true end diff --git a/spec/forms/openid_connect_token_form_spec.rb b/spec/forms/openid_connect_token_form_spec.rb index 4fecc03bf40..adcef490aec 100644 --- a/spec/forms/openid_connect_token_form_spec.rb +++ b/spec/forms/openid_connect_token_form_spec.rb @@ -21,7 +21,14 @@ let(:client_assertion_type) { OpenidConnectTokenForm::CLIENT_ASSERTION_TYPE } let(:client_assertion) { JWT.encode(jwt_payload, client_private_key, 'RS256') } - let(:client_id) { 'urn:gov:gsa:openidconnect:test' } + let(:client_id) { service_provider.issuer } + + let(:service_provider) do + create(:service_provider, + cert: nil, + certs: ['saml_test_sp2', 'saml_test_sp']) + end + let(:nonce) { SecureRandom.hex } let(:code_challenge) { nil } let(:jwt_payload) do @@ -259,7 +266,30 @@ end end - context 'signed by the wrong key' do + context 'signed by a second key' do + let(:client_private_key) do + OpenSSL::PKey::RSA.new(Rails.root.join('keys', 'saml_test_sp2.key').read) + end + + it 'is still valid' do + expect(valid?).to eq(true) + end + end + + context 'service provider has no certs registered' do + before do + service_provider.certs = [] + service_provider.save! + end + + it 'is has an error' do + expect(valid?).to eq(false) + expect(form.errors[:client_assertion]). + to include(t('openid_connect.token.errors.invalid_signature')) + end + end + + context 'signed by an unknown key' do let(:client_private_key) { OpenSSL::PKey::RSA.new(2048) } it 'is invalid' do diff --git a/spec/models/null_service_provider_spec.rb b/spec/models/null_service_provider_spec.rb index 828b992df2b..aef3cf28f44 100644 --- a/spec/models/null_service_provider_spec.rb +++ b/spec/models/null_service_provider_spec.rb @@ -34,12 +34,6 @@ end end - describe '#ssl_cert' do - it 'returns nil' do - expect(subject.ssl_cert).to be_nil - end - end - describe '#logo' do it 'returns nil' do expect(subject.logo).to be_nil diff --git a/spec/models/service_provider_spec.rb b/spec/models/service_provider_spec.rb index 5274129e0d6..320578f6b0c 100644 --- a/spec/models/service_provider_spec.rb +++ b/spec/models/service_provider_spec.rb @@ -173,16 +173,12 @@ describe '#metadata' do context 'when the service provider is defined in the YAML' do - it 'returns a hash with symbolized attributes from YAML plus fingerprint' do - fingerprint = { - fingerprint: '40808e52ef80f92e697149e058af95f898cefd9a54d0dc2416bd607c8f9891fa', - } - - yaml_attributes = ServiceProviderConfig.new( + it 'returns a hash with symbolized attributes from YAML' do + yaml_attributes = { issuer: 'http://localhost:3000', - ).sp_attributes + } - expect(service_provider.metadata).to eq yaml_attributes.merge!(fingerprint) + expect(service_provider.metadata).to include(yaml_attributes) end end end diff --git a/spec/services/service_provider_config_spec.rb b/spec/services/service_provider_config_spec.rb deleted file mode 100644 index aa2e1dd44b0..00000000000 --- a/spec/services/service_provider_config_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'rails_helper' - -describe ServiceProviderConfig do - describe '#sp_attributes' do - it 'returns the issuer attributes for the Rails.env entry in the YAML file' do - config = ServiceProviderConfig.new(issuer: 'http://test.host') - - yaml_hash = { - acs_url: 'http://test.host/test/saml/decode_assertion', - block_encryption: 'aes256-cbc', - metadata_url: 'http://test.host/test/saml/metadata', - sp_initiated_login_url: 'http://test.host/test/saml', - } - - expect(config.sp_attributes).to include yaml_hash - end - end -end diff --git a/spec/services/service_provider_seeder_spec.rb b/spec/services/service_provider_seeder_spec.rb index 18a8e6ac545..102354a60f0 100644 --- a/spec/services/service_provider_seeder_spec.rb +++ b/spec/services/service_provider_seeder_spec.rb @@ -18,6 +18,13 @@ expect { run }.to change(ServiceProvider, :count) end + it 'updates the plural certs column' do + run + + sp = ServiceProvider.from_issuer('http://localhost:3000') + expect(sp.certs).to eq(['saml_test_sp', 'saml_test_sp2']) + end + context 'with other existing service providers in the database' do let!(:existing_provider) { create(:service_provider) } diff --git a/spec/services/service_provider_updater_spec.rb b/spec/services/service_provider_updater_spec.rb index 6dfd41a30ae..072dd935f61 100644 --- a/spec/services/service_provider_updater_spec.rb +++ b/spec/services/service_provider_updater_spec.rb @@ -13,7 +13,6 @@ let(:agency_2) { create(:agency) } let(:agency_3) { create(:agency) } - # rubocop:disable Style/TrailingCommaInHashLiteral let(:friendly_sp) do { id: 'big number', @@ -30,12 +29,14 @@ active: true, native: true, approved: true, - help_text: { 'sign_in': { en: 'A new different sign-in help text' }, - 'sign_up': { en: 'A new different help text' }, - 'forgot_password': { en: 'A new different forgot password help text' }, } + help_text: { + sign_in: { en: 'A new different sign-in help text' }, + sign_up: { en: 'A new different help text' }, + forgot_password: { en: 'A new different forgot password help text' }, + }, } end - # rubocop:enable Style/TrailingCommaInHashLiteral + let(:old_sp) do { id: 'small number', @@ -67,6 +68,10 @@ agency_id: agency_1.id, redirect_uris: openid_connect_redirect_uris, active: true, + certs: [ + saml_test_sp_cert, + File.read(Rails.root.join('certs', 'sp', 'saml_test_sp2.crt')), + ], } end let(:dashboard_service_providers) { [friendly_sp, old_sp, nasty_sp, openid_connect_sp] } @@ -95,7 +100,7 @@ sp = ServiceProvider.from_issuer(dashboard_sp_issuer) expect(sp.agency).to eq agency_1 - expect(sp.ssl_cert).to be_a OpenSSL::X509::Certificate + expect(sp.ssl_certs.first).to be_a OpenSSL::X509::Certificate expect(sp.active?).to eq true expect(sp.id).to_not eq 0 expect(sp.updated_at).to_not eq friendly_sp[:updated_at] @@ -119,7 +124,7 @@ sp = ServiceProvider.from_issuer(dashboard_sp_issuer) expect(sp.agency).to eq agency_1 - expect(sp.ssl_cert).to be_a OpenSSL::X509::Certificate + expect(sp.ssl_certs.first).to be_a OpenSSL::X509::Certificate expect(sp.active?).to eq true expect(sp.id).to eq old_id expect(sp.updated_at).to_not eq friendly_sp[:updated_at] @@ -160,6 +165,11 @@ expect(sp.redirect_uris).to eq(openid_connect_redirect_uris) end + + it 'updates certs (plural)' do + expect { subject.run }. + to(change { ServiceProvider.from_issuer(openid_connect_issuer).ssl_certs.size }.to(2)) + end end context 'dashboard is not available' do