diff --git a/app/controllers/openid_connect/authorization_controller.rb b/app/controllers/openid_connect/authorization_controller.rb index 7b2ca8d9cba..54ffb9e564f 100644 --- a/app/controllers/openid_connect/authorization_controller.rb +++ b/app/controllers/openid_connect/authorization_controller.rb @@ -87,6 +87,7 @@ def handle_successful_handoff redirect_user( @authorize_form.success_redirect_uri, + @authorize_form.service_provider.issuer, current_user.uuid, ) @@ -144,7 +145,7 @@ def pre_validate_authorize_form if redirect_uri.nil? render :error else - redirect_user(redirect_uri, current_user&.uuid) + redirect_user(redirect_uri, @authorize_form.service_provider.issuer, current_user&.uuid) end end @@ -203,11 +204,16 @@ def track_events track_billing_events end - def redirect_user(redirect_uri, user_uuid) - redirect_method = IdentityConfig.store.openid_connect_redirect_uuid_override_map.fetch( - user_uuid, - IdentityConfig.store.openid_connect_redirect, - ) + def redirect_user(redirect_uri, issuer, user_uuid) + user_redirect_method_override = + IdentityConfig.store.openid_connect_redirect_uuid_override_map[user_uuid] + + sp_redirect_method_override = + IdentityConfig.store.openid_connect_redirect_issuer_override_map[issuer] + + redirect_method = + user_redirect_method_override || sp_redirect_method_override || + IdentityConfig.store.openid_connect_redirect case redirect_method when 'client_side' diff --git a/app/controllers/openid_connect/logout_controller.rb b/app/controllers/openid_connect/logout_controller.rb index a488159319d..660b04a9467 100644 --- a/app/controllers/openid_connect/logout_controller.rb +++ b/app/controllers/openid_connect/logout_controller.rb @@ -31,7 +31,7 @@ def delete analytics.logout_initiated(**result.to_h.except(:redirect_uri)) irs_attempts_api_tracker.logout_initiated(success: result.success?) - redirect_user(redirect_uri, current_user&.uuid) + redirect_user(redirect_uri, @logout_form.service_provider&.issuer, current_user&.uuid) sign_out else render :error @@ -44,11 +44,16 @@ def set_devise_failure_redirect_for_concurrent_session_logout request.env['devise_session_limited_failure_redirect_url'] = request.url end - def redirect_user(redirect_uri, user_uuid) - redirect_method = IdentityConfig.store.openid_connect_redirect_uuid_override_map.fetch( - user_uuid, - IdentityConfig.store.openid_connect_redirect, - ) + def redirect_user(redirect_uri, issuer, user_uuid) + user_redirect_method_override = + IdentityConfig.store.openid_connect_redirect_uuid_override_map[user_uuid] + + sp_redirect_method_override = + IdentityConfig.store.openid_connect_redirect_issuer_override_map[issuer] + + redirect_method = + user_redirect_method_override || sp_redirect_method_override || + IdentityConfig.store.openid_connect_redirect case redirect_method when 'client_side' @@ -115,7 +120,7 @@ def handle_successful_logout_request(result, redirect_uri) sign_out - redirect_user(redirect_uri, current_user&.uuid) + redirect_user(redirect_uri, @logout_form.service_provider&.issuer, current_user&.uuid) end end diff --git a/config/application.yml.default b/config/application.yml.default index e599da246eb..966deeb26fb 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -214,6 +214,7 @@ mx_timeout: 3 openid_connect_redirect: client_side_js openid_connect_content_security_form_action_enabled: false openid_connect_redirect_uuid_override_map: '{}' +openid_connect_redirect_issuer_override_map: '{}' otp_delivery_blocklist_maxretry: 10 otp_valid_for: 10 otp_expiration_warning_seconds: 150 diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 894ae4ebd83..66cbe876517 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -331,6 +331,10 @@ def self.build_store(config_map) :openid_connect_redirect_uuid_override_map, type: :json, ) + config.add( + :openid_connect_redirect_issuer_override_map, + type: :json, + ) config.add(:openid_connect_content_security_form_action_enabled, type: :boolean) config.add(:otp_delivery_blocklist_findtime, type: :integer) config.add(:otp_delivery_blocklist_maxretry, type: :integer) diff --git a/spec/controllers/openid_connect/authorization_controller_spec.rb b/spec/controllers/openid_connect/authorization_controller_spec.rb index 284024ef17a..9cbf7236de1 100644 --- a/spec/controllers/openid_connect/authorization_controller_spec.rb +++ b/spec/controllers/openid_connect/authorization_controller_spec.rb @@ -232,6 +232,42 @@ expect(assigns(:oidc_redirect_uri)).to start_with(params[:redirect_uri]) end + it 'respects UUID redirect config when issuer config is also set' do + allow(IdentityConfig.store).to receive(:openid_connect_redirect). + and_return('server_side') + allow(IdentityConfig.store).to receive(:openid_connect_redirect_issuer_override_map). + and_return({ service_provider.issuer => 'client_side' }) + allow(IdentityConfig.store).to receive(:openid_connect_redirect_uuid_override_map). + and_return({ user.uuid => 'client_side_js' }) + + IdentityLinker.new(user, service_provider).link_identity(ial: 3) + user.identities.last.update!( + verified_attributes: %w[given_name family_name birthdate verified_at], + ) + allow(controller).to receive(:pii_requested_but_locked?).and_return(false) + action + + expect(controller).to render_template('openid_connect/shared/redirect_js') + expect(assigns(:oidc_redirect_uri)).to start_with(params[:redirect_uri]) + end + + it 'respects issuer redirect config if UUID config is not set' do + allow(IdentityConfig.store).to receive(:openid_connect_redirect). + and_return('server_side') + allow(IdentityConfig.store).to receive(:openid_connect_redirect_issuer_override_map). + and_return({ service_provider.issuer => 'client_side_js' }) + + IdentityLinker.new(user, service_provider).link_identity(ial: 3) + user.identities.last.update!( + verified_attributes: %w[given_name family_name birthdate verified_at], + ) + allow(controller).to receive(:pii_requested_but_locked?).and_return(false) + action + + expect(controller).to render_template('openid_connect/shared/redirect_js') + expect(assigns(:oidc_redirect_uri)).to start_with(params[:redirect_uri]) + end + it 'redirects to the password capture url when pii is locked' do IdentityLinker.new(user, service_provider).link_identity(ial: 3) user.identities.last.update!( diff --git a/spec/controllers/openid_connect/logout_controller_spec.rb b/spec/controllers/openid_connect/logout_controller_spec.rb index f76e45e7ebb..1211dd4140c 100644 --- a/spec/controllers/openid_connect/logout_controller_spec.rb +++ b/spec/controllers/openid_connect/logout_controller_spec.rb @@ -128,6 +128,30 @@ expect(assigns(:oidc_redirect_uri)).to start_with(post_logout_redirect_uri) end + it 'respects UUID redirect config when issuer config is also set' do + allow(IdentityConfig.store).to receive(:openid_connect_redirect). + and_return('server_side') + allow(IdentityConfig.store).to receive(:openid_connect_redirect_issuer_override_map). + and_return({ service_provider.issuer => 'client_side' }) + allow(IdentityConfig.store).to receive(:openid_connect_redirect_uuid_override_map). + and_return({ user.uuid => 'client_side_js' }) + action + + expect(controller).to render_template('openid_connect/shared/redirect_js') + expect(assigns(:oidc_redirect_uri)).to start_with(post_logout_redirect_uri) + end + + it 'respects issuer redirect config if UUID config is not set' do + allow(IdentityConfig.store).to receive(:openid_connect_redirect). + and_return('server_side') + allow(IdentityConfig.store).to receive(:openid_connect_redirect_issuer_override_map). + and_return({ service_provider.issuer => 'client_side_js' }) + action + + expect(controller).to render_template('openid_connect/shared/redirect_js') + expect(assigns(:oidc_redirect_uri)).to start_with(post_logout_redirect_uri) + end + it 'tracks events' do stub_analytics expect(@analytics).to receive(:track_event).