diff --git a/app/controllers/authenticate_controller.rb b/app/controllers/authenticate_controller.rb index 12e8b73c2b..05adc30b7e 100644 --- a/app/controllers/authenticate_controller.rb +++ b/app/controllers/authenticate_controller.rb @@ -9,13 +9,14 @@ def oidc_authenticate_code_redirect # params. This will likely need to be done via the Handler. params.permit! - auth_token = Authentication::Handler::AuthenticationHandler.new( + auth_token, headers_h = Authentication::Handler::AuthenticationHandler.new( authenticator_type: params[:authenticator] ).call( parameters: params.to_hash.symbolize_keys, request_ip: request.ip ) + set_headers(headers_h) render_authn_token(auth_token) rescue => e log_backtrace(e) @@ -135,13 +136,29 @@ def authenticate_jwt handle_authentication_error(e) end - # Update the input to have the username from the token and authenticate def authenticate_oidc params[:authenticator] = "authn-oidc" - input = Authentication::AuthnOidc::UpdateInputWithUsernameFromIdToken.new.( - authenticator_input: authenticator_input - ) - # We don't audit success here as the authentication process is not done + decode_and_merge_request_body + + if params[:refresh_token] || params[:code] + params.permit! + auth_token, headers_h = Authentication::Handler::AuthenticationHandler.new( + authenticator_type: params[:authenticator] + ).call( + parameters: params.to_hash.symbolize_keys, + request_ip: request.ip + ) + + set_headers(headers_h) + render_authn_token(auth_token) + return + else + # Update the input to have the username from the token and authenticate to Conjur + input = Authentication::AuthnOidc::UpdateInputWithUsernameFromIdToken.new.( + authenticator_input: authenticator_input + ) + # We don't audit success here as the authentication process is not done + end rescue => e # At this point authenticator_input.username is always empty (e.g. cucumber:user:USERNAME_MISSING) log_audit_failure( @@ -153,6 +170,7 @@ def authenticate_oidc else authenticate(input) end + def authenticate_gcp params[:authenticator] = "authn-gcp" input = Authentication::AuthnGcp::UpdateAuthenticatorInput.new.( @@ -248,6 +266,19 @@ def render_authn_token(authn_token) render(content_type => authn_token) end + def set_headers(headers_h) + headers_h.each { |key, value| + response.set_header(key, value.to_s) unless key.blank? || value.blank? + } + end + + def decode_and_merge_request_body + request_body = URI.decode_www_form(request.raw_post) + request_body.to_h.each do |param, val| + params[param] = val + end + end + def log_audit_success( authn_params:, audit_event_class: diff --git a/app/domain/authentication/authn_oidc/v2/client.rb b/app/domain/authentication/authn_oidc/v2/client.rb index 5479152a6a..7951b06d2f 100644 --- a/app/domain/authentication/authn_oidc/v2/client.rb +++ b/app/domain/authentication/authn_oidc/v2/client.rb @@ -37,11 +37,28 @@ def oidc_client end end - def callback(code:, nonce:, code_verifier:) + def get_token_with_code(code:, nonce:, code_verifier:) oidc_client.authorization_code = code + id_token, refresh_token = get_token_pair(code_verifier) + decoded_id_token = decode_id_token(id_token) + verify_id_token(decoded_id_token, nonce) + + [decoded_id_token, refresh_token] + end + + def get_token_with_refresh_token(refresh_token:, nonce:) + oidc_client.refresh_token = refresh_token + id_token, refresh_token = get_token_pair(nil) + decoded_id_token = decode_id_token(id_token) + verify_id_token(decoded_id_token, nonce, refresh: true) + + [decoded_id_token, refresh_token] + end + + def get_token_pair(code_verifier) begin bearer_token = oidc_client.access_token!( - scope: true, + scope: @authenticator.scope, client_auth_method: :basic, code_verifier: code_verifier ) @@ -54,11 +71,19 @@ def callback(code:, nonce:, code_verifier:) when /The authorization code is invalid or has expired/ raise Errors::Authentication::AuthnOidc::TokenRetrievalFailed, 'Authorization code is invalid or has expired' + when /The refresh token is invalid or expired/ + raise Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + 'Refresh token is invalid or has expired' end raise e end + id_token = bearer_token.id_token || bearer_token.access_token + refresh_token = bearer_token.refresh_token + [id_token, refresh_token] + end + def decode_id_token(id_token) begin attempts ||= 0 decoded_id_token = @oidc_id_token.decode( @@ -76,11 +101,20 @@ def callback(code:, nonce:, code_verifier:) retry end + decoded_id_token + end + + def verify_id_token(decoded_id_token, nonce, refresh: false) + expected_nonce = nonce + if refresh && decoded_id_token.raw_attributes['nonce'].nil? + expected_nonce = nil + end + begin decoded_id_token.verify!( issuer: @authenticator.provider_uri, client_id: @authenticator.client_id, - nonce: nonce + nonce: expected_nonce ) rescue OpenIDConnect::ResponseObject::IdToken::InvalidNonce raise Errors::Authentication::AuthnOidc::TokenVerificationFailed, @@ -92,7 +126,6 @@ def callback(code:, nonce:, code_verifier:) raise Errors::Authentication::AuthnOidc::TokenVerificationFailed, e.message end - decoded_id_token end def discovery_information(invalidate: false) diff --git a/app/domain/authentication/authn_oidc/v2/strategy.rb b/app/domain/authentication/authn_oidc/v2/strategy.rb index 7cea962147..9fd1327e21 100644 --- a/app/domain/authentication/authn_oidc/v2/strategy.rb +++ b/app/domain/authentication/authn_oidc/v2/strategy.rb @@ -15,24 +15,35 @@ def initialize( # Don't love this name... def callback(args) - %i[code nonce code_verifier].each do |param| - unless args[param].present? - raise Errors::Authentication::RequestBody::MissingRequestParam, param.to_s + jwt, refresh_token = nil, nil + if args[:refresh_token] + unless args[:nonce].present? + raise Errors::Authentication::RequestBody::MissingRequestParam, 'nonce' end - end - - identity = resolve_identity( - jwt: @client.callback( + jwt, refresh_token = @client.get_token_with_refresh_token( + refresh_token: args[:refresh_token], + nonce: args[:nonce] + ) + else + %i[code nonce code_verifier].each do |param| + unless args[param].present? + raise Errors::Authentication::RequestBody::MissingRequestParam, param.to_s + end + end + jwt, refresh_token = @client.get_token_with_code( code: args[:code], nonce: args[:nonce], code_verifier: args[:code_verifier] ) - ) + end + identity = resolve_identity(jwt: jwt) unless identity.present? raise Errors::Authentication::AuthnOidc::IdTokenClaimNotFoundOrEmpty, @authenticator.claim_mapping end - identity + + return [identity, {}] if refresh_token.nil? + [identity, { 'X-OIDC-Refresh-Token' => refresh_token }] end def resolve_identity(jwt:) diff --git a/app/domain/authentication/handler/authentication_handler.rb b/app/domain/authentication/handler/authentication_handler.rb index 38202ffc8d..28fe1b7868 100644 --- a/app/domain/authentication/handler/authentication_handler.rb +++ b/app/domain/authentication/handler/authentication_handler.rb @@ -31,6 +31,7 @@ def initialize( end def call(parameters:, request_ip:) + # Load Authenticator policy and values (validates data stored as variables) authenticator = @authn_repo.find( type: @authenticator_type, @@ -45,10 +46,12 @@ def call(parameters:, request_ip:) ) end + identity, headers_h = @strategy.new( + authenticator: authenticator + ).callback(parameters) + role = @identity_resolver.new.call( - identity: @strategy.new( - authenticator: authenticator - ).callback(parameters), + identity: identity, account: parameters[:account], allowed_roles: @role.that_can( :authenticate, @@ -65,10 +68,12 @@ def call(parameters:, request_ip:) log_audit_success(authenticator, role, request_ip, @authenticator_type) - TokenFactory.new.signed_token( + token = TokenFactory.new.signed_token( account: parameters[:account], username: role.role_id.split(':').last ) + + [token, headers_h] rescue => e log_audit_failure(parameters[:account], parameters[:service_id], request_ip, @authenticator_type, e) handle_error(e) diff --git a/cucumber/_authenticators_common/features/support/authenticator_helpers.rb b/cucumber/_authenticators_common/features/support/authenticator_helpers.rb index 37619c3723..67231da352 100644 --- a/cucumber/_authenticators_common/features/support/authenticator_helpers.rb +++ b/cucumber/_authenticators_common/features/support/authenticator_helpers.rb @@ -72,6 +72,7 @@ def get(path, options = {}) ) result = RestClient::Request.execute(options) @response_body = result.body + @response_headers = result.headers @http_status = result.code result rescue RestClient::Exception => e @@ -83,6 +84,7 @@ def get(path, options = {}) def post(path, payload, options = {}) result = RestClient.post(path, payload, options) @response_body = result.body + @response_headers = result.headers @http_status = result.code rescue RestClient::Exception => e @rest_client_error = e diff --git a/cucumber/authenticators_oidc/features/authn_oidc_v2.feature b/cucumber/authenticators_oidc/features/authn_oidc_v2.feature index e2ae0722cf..b3b290a1e5 100644 --- a/cucumber/authenticators_oidc/features/authn_oidc_v2.feature +++ b/cucumber/authenticators_oidc/features/authn_oidc_v2.feature @@ -62,6 +62,25 @@ Feature: OIDC Authenticator V2 - Users can authenticate with OIDC authenticator cucumber:user:alice successfully authenticated with authenticator authn-oidc service cucumber:webservice:conjur/authn-oidc/keycloak2 """ + @smoke + Scenario: A valid code to get Conjur access token and OIDC refresh token + Given I enable OIDC V2 refresh token flows for "keycloak2" + And I fetch a code for username "alice" and password "alice" + When I authenticate via OIDC V2 with code + Then user "alice" has been authorized by Conjur + And The authentication response includes header "X-OIDC-Refresh-Token" + + @smoke + Scenario: A valid refresh token to get Conjur access token and OIDC refresh token + Given I enable OIDC V2 refresh token flows for "keycloak2" + And I fetch a code for username "alice" and password "alice" + And I authenticate via OIDC V2 with code + And The authentication response includes header "X-OIDC-Refresh-Token" + When I store the current access token + And I authenticate via OIDC V2 with refresh token + Then user "alice" has been authorized by Conjur + And a new access token was issued + @smoke Scenario: A valid code with email as claim mapping Given I extend the policy with: @@ -189,7 +208,7 @@ Feature: OIDC Authenticator V2 - Users can authenticate with OIDC authenticator Given I save my place in the log file And I fetch a code for username "alice@conjur.net" and password "alice" When I authenticate via OIDC V2 with code "bad-code" - Then it is a bad request + Then it is unauthorized And The following appears in the log after my savepoint: """ Rack::OAuth2::Client::Error diff --git a/cucumber/authenticators_oidc/features/step_definitions/authn_oidc_steps.rb b/cucumber/authenticators_oidc/features/step_definitions/authn_oidc_steps.rb index a03d12e78c..a20a3b37db 100644 --- a/cucumber/authenticators_oidc/features/step_definitions/authn_oidc_steps.rb +++ b/cucumber/authenticators_oidc/features/step_definitions/authn_oidc_steps.rb @@ -164,6 +164,24 @@ ) end +When(/^I authenticate via OIDC V2 with refresh token$/) do + authenticate_with_oidc_refresh_token( + service_id: @context.get(:service_id), + account: @context.get(:account), + refresh_token: @context.get(:x_oidc_refresh_token), + nonce: @context.get(:nonce) + ) +end + +When(/^I store the current access token$/) do + @context.set(:access_token => retrieved_access_token) +end + +When(/^a new access token was issued$/) do + previous_token = @context.get(:access_token) + expect(retrieved_access_token.token).not_to eq(@context.get(:access_token).token) +end + When(/^I authenticate via OIDC V2 with no code in the request$/) do authenticate_with_oidc_code( service_id: @context.get(:service_id), @@ -198,6 +216,10 @@ ) end +Given(/^I enable OIDC V2 refresh token flows for "([^"]*)"$/) do |service_id| + create_oidc_secret("provider-scope", "#{oidc_scope},offline_access", service_id) +end + When(/^I authenticate via OIDC V2 with code and service-id "([^"]*)"$/) do |service_id| authenticate_with_oidc_code( service_id: service_id, @@ -210,6 +232,14 @@ ) end +Then(/^The authentication response includes header "([^"]*)"$/) do |header| + header_sym = header.parameterize.underscore.to_sym + # Store header for future steps + header_val = @response_headers[header_sym] + @context.set(header_sym => header_val) + expect(header_val).not_to be_nil +end + Then(/^The Okta user has been authorized by Conjur/) do username = ENV['OKTA_USERNAME'] expect(retrieved_access_token.username).to eq(username) diff --git a/cucumber/authenticators_oidc/features/support/authn_oidc_helper.rb b/cucumber/authenticators_oidc/features/support/authn_oidc_helper.rb index a8775e14c8..9918bbb396 100644 --- a/cucumber/authenticators_oidc/features/support/authn_oidc_helper.rb +++ b/cucumber/authenticators_oidc/features/support/authn_oidc_helper.rb @@ -29,8 +29,14 @@ def authenticate_id_token_with_oidc_in_header(service_id:, account:, id_token: p end def authenticate_with_oidc_code(service_id:, account:, params: {}) - url = authn_url(type: 'oidc', account: account, service_id: service_id, params: params) - get(url) + path = authn_url(type: 'oidc', account: account, service_id: service_id) + post(path, params) + end + + def authenticate_with_oidc_refresh_token(service_id:, account:, refresh_token:, nonce:) + path = authn_url(type: 'oidc', account: account, service_id: service_id) + payload = {:refresh_token => refresh_token, :nonce => nonce} + post(path, payload) end # Generic Authenticator URL builder diff --git a/spec/app/domain/authentication/authn-oidc/v2/client_spec.rb b/spec/app/domain/authentication/authn-oidc/v2/client_spec.rb index c3f648deb9..5680820602 100644 --- a/spec/app/domain/authentication/authn-oidc/v2/client_spec.rb +++ b/spec/app/domain/authentication/authn-oidc/v2/client_spec.rb @@ -3,15 +3,21 @@ require 'spec_helper' RSpec.describe(Authentication::AuthnOidc::V2::Client) do + let(:authn_config) do + { + :provider_uri => 'https://dev-92899796.okta.com/oauth2/default', + :redirect_uri => 'http://localhost:3000/authn-oidc/okta-2/cucumber/authenticate', + :client_id => '0oa3w3xig6rHiu9yT5d7', + :client_secret => 'e349BMTTIpLO-rPuPqLLkLyH_pO-loUzhIVJCrHj', + :claim_mapping => 'foo', + :account => 'bar', + :service_id => 'baz' + } + end + let(:authenticator) do Authentication::AuthnOidc::V2::DataObjects::Authenticator.new( - provider_uri: 'https://dev-92899796.okta.com/oauth2/default', - redirect_uri: 'http://localhost:3000/authn-oidc/okta-2/cucumber/authenticate', - client_id: '0oa3w3xig6rHiu9yT5d7', - client_secret: 'e349BMTTIpLO-rPuPqLLkLyH_pO-loUzhIVJCrHj', - claim_mapping: 'foo', - account: 'bar', - service_id: 'baz' + **authn_config ) end @@ -29,21 +35,23 @@ end end - describe '.callback' do + describe '.get_token_with_code' do context 'when credentials are valid' do it 'returns a valid JWT token', vcr: 'authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials' do # Because JWT tokens have an expiration timeframe, we need to hold # time constant after caching the request. travel_to(Time.parse("2022-09-30 17:02:17 +0000")) do - token = client.callback( + id_token, refresh_token = client.get_token_with_code( code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' ) - expect(token).to be_a_kind_of(OpenIDConnect::ResponseObject::IdToken) - expect(token.raw_attributes['nonce']).to eq('7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d') - expect(token.raw_attributes['preferred_username']).to eq('test.user3@mycompany.com') - expect(token.aud).to eq('0oa3w3xig6rHiu9yT5d7') + expect(id_token).to be_a_kind_of(OpenIDConnect::ResponseObject::IdToken) + expect(id_token.raw_attributes['nonce']).to eq('7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d') + expect(id_token.raw_attributes['preferred_username']).to eq('test.user3@mycompany.com') + expect(id_token.aud).to eq('0oa3w3xig6rHiu9yT5d7') + + expect(refresh_token).to be_nil end end end @@ -52,7 +60,7 @@ it 'raises an error', vcr: 'authenticators/authn-oidc/v2/client_callback-invalid_code_verifier' do travel_to(Time.parse("2022-10-17 17:23:30 +0000")) do expect do - client.callback( + client.get_token_with_code( code: 'GV48_SF4a19ghvBhVbbSG3Lr8BuFl8PhWVPZSbokV2o', code_verifier: 'bad-code-verifier', nonce: '3e6bd5235e4692b37ca1f04cb01b6e0cb177aa20dcef19e89f' @@ -69,7 +77,7 @@ it 'raises an error', vcr: 'authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials' do travel_to(Time.parse("2022-09-30 17:02:17 +0000")) do expect do - client.callback( + client.get_token_with_code( code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', nonce: 'bad-nonce' @@ -86,7 +94,7 @@ it 'raises an error', vcr: 'authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials' do travel_to(Time.parse("2022-10-01 17:02:17 +0000")) do expect do - client.callback( + client.get_token_with_code( code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' @@ -102,7 +110,7 @@ context 'when code has previously been used' do it 'raise an exception', vcr: 'authenticators/authn-oidc/v2/client_callback-used_code-valid_oidc_credentials' do expect do - client.callback( + client.get_token_with_code( code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' @@ -117,7 +125,7 @@ context 'when code has expired', vcr: 'authenticators/authn-oidc/v2/client_callback-expired_code-valid_oidc_credentials' do it 'raise an exception' do expect do - client.callback( + client.get_token_with_code( code: 'SNSPeiQJ0-D6nUHTg-Ht9ZoDxIaaWBB80pnYuXY2VxU', code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' @@ -128,6 +136,105 @@ ) end end + + context 'when refresh token flow is enabled' do + # The 'offline_access' scope enables Okta's refresh token flow + let(:authenticator) do + Authentication::AuthnOidc::V2::DataObjects::Authenticator.new( + **authn_config.merge!({ :provider_scope => 'offline_access' }) + ) + end + + context 'when credentials are valid' do + it 'returns valid ID and refresh tokens', vcr: 'authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials_and_refresh' do + # Because JWT tokens have an expiration timeframe, we need to hold + # time constant after caching the request. + travel_to(Time.parse("2022-09-30 17:02:17 +0000")) do + id_token, refresh_token = client.get_token_with_code( + code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', + code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', + nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' + ) + expect(id_token).to be_a_kind_of(OpenIDConnect::ResponseObject::IdToken) + expect(id_token.raw_attributes['nonce']).to eq('7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d') + expect(id_token.raw_attributes['preferred_username']).to eq('test.user3@mycompany.com') + expect(id_token.aud).to eq('0oa3w3xig6rHiu9yT5d7') + + expect(refresh_token).not_to be_nil + expect(refresh_token).to be_a_kind_of(String) + expect(refresh_token).to eq('kXMJFtgtaEpOGn0Zk2x15i8umXIWp4aqY1Mh7zscfGI') + end + end + end + end + end + + describe '.get_token_with_refresh_token' do + # Use different Okta authorization server with refresh tokens enabled. + # At some point, all these test cases should point to a single Okta server, + # with PKCE and refresh tokens both enabled. + let(:authenticator) do + Authentication::AuthnOidc::V2::DataObjects::Authenticator.new( + **authn_config.merge!({ + :provider_uri => 'https://dev-56357110.okta.com/oauth2/default', + :client_id => '0oa6ccivzf3nEeiGt5d7', + :client_secret => 'YnAukUECEAtsWSWCHPzi1coiZZeOhdvQOSnri4Kz', + :provider_scope => 'offline_access' + }) + ) + end + + context 'when refresh token is valid' do + context 'with refresh token rotation disabled' do + it 'returns a valid JWT token', vcr: 'authenticators/authn-oidc/v2/client_refresh-valid_token' do + travel_to(Time.parse("2022-10-19 17:02:17 +0000")) do + id_token, refresh_token = client.get_token_with_refresh_token( + refresh_token: 'a8VLPRtcOS5-IFYXkZYzZbrIhSJq6trFXxYJyKbaUng', + nonce: 'some-nonce' + ) + expect(id_token).to be_a_kind_of(OpenIDConnect::ResponseObject::IdToken) + expect(id_token.raw_attributes['nonce']).to be_nil + expect(id_token.raw_attributes['preferred_username']).to eq('test.user3@mycompany.com') + expect(id_token.aud).to eq('0oa6ccivzf3nEeiGt5d7') + + expect(refresh_token).to be_nil + end + end + end + + context 'with refresh token rotation enabled' do + it 'returns a valid JWT token and refresh token', vcr: 'authenticators/authn-oidc/v2/client_refresh-valid_token_with_rotation' do + travel_to(Time.parse("2022-10-19 17:02:17 +0000")) do + id_token, refresh_token = client.get_token_with_refresh_token( + refresh_token: 'a8VLPRtcOS5-IFYXkZYzZbrIhSJq6trFXxYJyKbaUng', + nonce: 'some-nonce' + ) + expect(id_token).to be_a_kind_of(OpenIDConnect::ResponseObject::IdToken) + expect(id_token.raw_attributes['nonce']).to be_nil + expect(id_token.raw_attributes['preferred_username']).to eq('test.user3@mycompany.com') + expect(id_token.aud).to eq('0oa6ccivzf3nEeiGt5d7') + + expect(refresh_token).to eq('dyJXfWUg1Xjt4KP7IQ7qcHUVNtKNWmmtOu9qNScjkN8') + end + end + end + end + + context 'when refresh token is invalid or expired' do + it 'raises an error', vcr: 'authenticators/authn-oidc/v2/client_refresh-invalid_token' do + travel_to(Time.parse("2022-10-19 17:02:17 +0000")) do + expect do + client.get_token_with_refresh_token( + refresh_token: 'a8VLPRtcOS5-IFYXkZYzZbrIhSJq6trFXxYJyKbaUng', + nonce: 'some-nonce' + ) + end.to raise_error( + Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + "CONJ00133E Access Token retrieval failure: 'Refresh token is invalid or has expired'" + ) + end + end + end end describe '.oidc_client' do diff --git a/spec/app/domain/authentication/authn-oidc/v2/strategy_rspec.rb b/spec/app/domain/authentication/authn-oidc/v2/strategy_spec.rb similarity index 54% rename from spec/app/domain/authentication/authn-oidc/v2/strategy_rspec.rb rename to spec/app/domain/authentication/authn-oidc/v2/strategy_spec.rb index 08758e6379..e43cfe2e16 100644 --- a/spec/app/domain/authentication/authn-oidc/v2/strategy_rspec.rb +++ b/spec/app/domain/authentication/authn-oidc/v2/strategy_spec.rb @@ -5,6 +5,7 @@ RSpec.describe(' Authentication::AuthnOidc::V2::Strategy') do let(:jwt) { double(raw_attributes: { claim_mapping: "alice" }) } + let(:refresh_token) { 'kXMJFtgtaEpOGn0Zk2x15i8umXIWp4aqY1Mh7zscfGI' } let(:authenticator) do Authentication::AuthnOidc::V2::DataObjects::Authenticator.new( @@ -27,7 +28,7 @@ let(:current_client) do instance_double(::Authentication::AuthnOidc::V2::Client).tap do |double| - allow(double).to receive(:callback).and_return(jwt) + allow(double).to receive(:get_token_with_code).and_return([jwt, nil]) end end @@ -39,11 +40,13 @@ end describe('#callback') do - context 'when a role_id matches the identity exist' do + context 'When a role_id matches the identity exist' do let(:mapping) { "claim_mapping" } it 'returns the role' do - expect(strategy.callback(nonce: 'nonce', code: 'code', code_verifier: 'foo')) - .to eq('alice') + role, headers_h = strategy.callback(nonce: 'nonce', code: 'code', code_verifier: 'foo') + + expect(role).to eq('alice') + expect(headers_h).to be_empty end end @@ -76,5 +79,43 @@ end end end + + context 'When refresh token flow is enabled' do + let(:current_client) do + instance_double(::Authentication::AuthnOidc::V2::Client).tap do |double| + allow(double).to receive(:get_token_with_code).and_return([jwt, refresh_token]) + allow(double).to receive(:get_token_with_refresh_token).and_return([jwt, refresh_token]) + end + end + + let(:mapping) { "claim_mapping" } + + context 'when a role_id matches the identity exist' do + it 'returns the role and refresh token when passed an authz code' do + expect(current_client).to receive(:get_token_with_code) + .with(:nonce => 'nonce', :code => 'code', :code_verifier => 'foo') + role, headers_h = strategy.callback(nonce: 'nonce', code: 'code', code_verifier: 'foo') + + expect(role).to eq("alice") + expect(headers_h).to include('X-OIDC-Refresh-Token' => refresh_token) + end + + it 'returns the role and refresh token when passed a refresh token and nonce' do + expect(current_client).to receive(:get_token_with_refresh_token) + .with(:refresh_token => 'token', :nonce => 'nonce') + role, headers_h = strategy.callback(refresh_token: 'token', nonce: 'nonce') + + expect(role).to eq("alice") + expect(headers_h).to include('X-OIDC-Refresh-Token' => refresh_token) + end + + context 'when nonce is missing' do + it 'raises a `MissingRequestParam` error' do + expect { strategy.callback(refresh_token: 'token') } + .to raise_error(Errors::Authentication::RequestBody::MissingRequestParam) + end + end + end + end end end diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials_and_refresh.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials_and_refresh.yml new file mode 100644 index 0000000000..7062b29f45 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_callback-valid_oidc_credentials_and_refresh.yml @@ -0,0 +1,169 @@ +--- +http_interactions: +- request: + method: post + uri: https://dev-92899796.okta.com/oauth2/default/v1/token + body: + encoding: UTF-8 + string: grant_type=authorization_code&code=-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthn-oidc%2Fokta-2%2Fcucumber%2Fauthenticate&scope=true&nonce=7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d&code_verifier=c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d + headers: + User-Agent: + - Rack::OAuth2 (1.19.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Fri, 30 Sep 2022 17:02:17 GMT + Authorization: + - Basic MG9hM3czeGlnNnJIaXU5eVQ1ZDc6ZTM0OUJNVFRJcExPLXJQdVBxTExrTHlIX3BPLWxvVXpoSVZKQ3JIag== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 30 Sep 2022 17:14:38 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Okta-Request-Id: + - Yzcj_ieURr1wLPVErCrikAAAC84 + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy-Report-Only: + - 'default-src ''self'' dev-92899796.okta.com *.oktacdn.com; connect-src ''self'' + dev-92899796.okta.com dev-92899796-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com https://oinmanager.okta.com + data:; script-src ''unsafe-inline'' ''nonce-ZFIOD_nd7I1XFja243oXrDS25KhzLla9BnlkbWhH1OU'' + ''unsafe-eval'' ''self'' dev-92899796.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-92899796.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-92899796.okta.com + dev-92899796-admin.okta.com login.okta.com; img-src ''self'' dev-92899796.okta.com + *.oktacdn.com *.tiles.mapbox.com *.mapbox.com app.pendo.io data.pendo.io cdn.pendo.io + pendo-static-5634101834153984.storage.googleapis.com pendo-static-5391521872216064.storage.googleapis.com + data: blob:; font-src ''self'' dev-92899796.okta.com data: *.oktacdn.com fonts.gstatic.com; + frame-ancestors ''self''' + Content-Security-Policy: + - 'default-src ''self'' dev-92899796.okta.com *.oktacdn.com; connect-src ''self'' + dev-92899796.okta.com dev-92899796-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com https://oinmanager.okta.com + data:; script-src ''unsafe-inline'' ''unsafe-eval'' ''self'' dev-92899796.okta.com + *.oktacdn.com; style-src ''unsafe-inline'' ''self'' dev-92899796.okta.com + *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-92899796.okta.com + dev-92899796-admin.okta.com login.okta.com; img-src ''self'' dev-92899796.okta.com + *.oktacdn.com *.tiles.mapbox.com *.mapbox.com app.pendo.io data.pendo.io cdn.pendo.io + pendo-static-5634101834153984.storage.googleapis.com pendo-static-5391521872216064.storage.googleapis.com + data: blob:; font-src ''self'' dev-92899796.okta.com data: *.oktacdn.com fonts.gstatic.com; + frame-ancestors ''self''' + X-Rate-Limit-Limit: + - '300' + X-Rate-Limit-Remaining: + - '299' + X-Rate-Limit-Reset: + - '1664558138' + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - '0' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Robots-Tag: + - noindex,nofollow + Set-Cookie: + - JSESSIONID=392B5556071EB935B2684D3AF2D492E5; Path=/; Secure; HttpOnly + - autolaunch_triggered=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + - sid=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + body: + encoding: UTF-8 + string: '{"token_type":"Bearer","expires_in":3600,"access_token":"eyJraWQiOiI3NE5OR2R0RC1rQ2p1b2tZRFRVaG05VVQ3SXRjaUY5S1dEMVNEVktyZW80IiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULkNoVzZRVU1iYllmalZZdGhZT0MxT2FqR3gzNk52NUIteWFTcnNtdTBBM3ciLCJpc3MiOiJodHRwczovL2Rldi05Mjg5OTc5Ni5va3RhLmNvbS9vYXV0aDIvZGVmYXVsdCIsImF1ZCI6ImFwaTovL2RlZmF1bHQiLCJpYXQiOjE2NjQ1NTgwNzgsImV4cCI6MTY2NDU2MTY3OCwiY2lkIjoiMG9hM3czeGlnNnJIaXU5eVQ1ZDciLCJ1aWQiOiIwMHU1Z2tvNmRmNDRqMmZHcDVkNyIsInNjcCI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiXSwiYXV0aF90aW1lIjoxNjY0NTU3ODUzLCJzdWIiOiJ0ZXN0LnVzZXIzQG15Y29tcGFueS5jb20ifQ.hxsTC4_AO9M-KzYDmOac9KK2cqdvZVEXtB0jagLMEkfdkZ4XTm2h8UBcbdTlwKa1UWbM5y9JuwTeQ5_J3FJP-YMkzsfcrYvvYkAd0V7Dw39CjRh5SFU7y-_ReCWGUp5Ni__yLcfmRl0EUAufs-JauyPX3GiknYD4QPZsfjCl0qGfZ7QrPOFOO4IJu7DuKCNVb-fR9aTS4VGEdff62idOoTKexXAuIaWw9yicSTULGFpIxeyPiVMjRQtpuZAl15rdmdZi2fJqlMEY7fbMY5OzgRcT-KCITk6vzY8DsoJosOZbNBYSvwHBilbcxJYMz3o9xn39ADZIvGX69M-3llbKRQ","refresh_token":"kXMJFtgtaEpOGn0Zk2x15i8umXIWp4aqY1Mh7zscfGI","scope":"profile openid offline_access","id_token":"eyJraWQiOiI3NE5OR2R0RC1rQ2p1b2tZRFRVaG05VVQ3SXRjaUY5S1dEMVNEVktyZW80IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHU1Z2tvNmRmNDRqMmZHcDVkNyIsIm5hbWUiOiJSb2JlcnQgV2lsbGlhbXMgSUlJIiwiZW1haWwiOiJ0ZXN0LnVzZXIzQG15Y29tcGFueS5jb20iLCJ2ZXIiOjEsImlzcyI6Imh0dHBzOi8vZGV2LTkyODk5Nzk2Lm9rdGEuY29tL29hdXRoMi9kZWZhdWx0IiwiYXVkIjoiMG9hM3czeGlnNnJIaXU5eVQ1ZDciLCJpYXQiOjE2NjQ1NTgwNzgsImV4cCI6MTY2NDU2MTY3OCwianRpIjoiSUQuMFE0Uy1xTEpCaW5fbi1PUHQySVBzYVhOaE8yMjRrLVpqVlFpLVNodUxNNCIsImFtciI6WyJwd2QiXSwiaWRwIjoiMDBvM3cxeTh0dXVhWWNDVDc1ZDciLCJub25jZSI6IjdlZmNiYmEzNmE5Yjk2ZmRiNTI4NWExNTk2NjVjM2QzODJhYmQ4YjZiMzI4OGZjYzhkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdC51c2VyM0BteWNvbXBhbnkuY29tIiwiYXV0aF90aW1lIjoxNjY0NTU3ODUzLCJhdF9oYXNoIjoiY3d4OTNFaTJXdVYzRzZ3MFRiYmJBZyJ9.SrRuxy27rvHveLtC_2lWFpTWXTSc1I4UCDs4jd1pUKD4iBldSLXk7fWEY7VNQFqtHGidOSBD4rOUiSCpphLKHGfLgFLyRlqjU2k4nG8BGqslaEuiN2YhsVDECAjjjctDUazSaDHKsYiPCt4f9w7DeCWShDkG7QLH-CHlUkYzzeBz3bXmxYm2h1LzhMstZldvFTbcB-pKtKauavzhYK2NIb8k86EpXr7tHQ4wbgOUzX6_m8lw-9gMhGZc32vxROiaqu776DmZ7doQwLx3UN3NqRIdhlCThCy4seF_3_YanE73PAhCRNRTiEBZ5svct7XGBw8Vl5VElV7b6lAC21Ni5w"}' + recorded_at: Fri, 30 Sep 2022 17:02:17 GMT +- request: + method: get + uri: https://dev-92899796.okta.com/oauth2/default/v1/keys + body: + encoding: UTF-8 + string: '' + headers: + User-Agent: + - OpenIDConnect (1.3.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Fri, 30 Sep 2022 17:02:17 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 30 Sep 2022 17:14:39 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-92899796.okta.com *.oktacdn.com; connect-src ''self'' + dev-92899796.okta.com dev-92899796-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com https://oinmanager.okta.com + data:; script-src ''unsafe-inline'' ''unsafe-eval'' ''self'' dev-92899796.okta.com + *.oktacdn.com; style-src ''unsafe-inline'' ''self'' dev-92899796.okta.com + *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-92899796.okta.com + dev-92899796-admin.okta.com login.okta.com; img-src ''self'' dev-92899796.okta.com + *.oktacdn.com *.tiles.mapbox.com *.mapbox.com app.pendo.io data.pendo.io cdn.pendo.io + pendo-static-5634101834153984.storage.googleapis.com pendo-static-5391521872216064.storage.googleapis.com + data: blob:; font-src ''self'' dev-92899796.okta.com data: *.oktacdn.com fonts.gstatic.com; + frame-ancestors ''self''' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + Cache-Control: + - max-age=7730945, must-revalidate + Expires: + - Thu, 29 Dec 2022 04:43:44 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yzcj_2SzA_OGwA_yMGySgwAAAek + body: + encoding: UTF-8 + string: '{"keys":[{"kty":"RSA","alg":"RS256","kid":"74NNGdtD-kCjuokYDTUhm9UT7ItciF9KWD1SDVKreo4","use":"sig","e":"AQAB","n":"zhlW4oIEvu5wcGQ4ROfpumaqQWluAGi6FIV1Hi-gFuA9Z_Gxw4x3fQnZbpsXsuWlu2Ivfl-9RCiu2AGcpUiH7cX84BWTRtwdOuPXMvOx_g1EUVna1IdVbXSsvWzgi0gOHsv9ZGyoq9BPRccn4m69824SvoAsIi3m-Jr0W3RFe3dCojkGDmrDiH7h8mhR_CjG2IRaQVxc0OqhwOYGAIsivhKQB7YjxqR3fMyUYEpJg3285r5r0-05slJDcUfJ3kILUgAvBBx0fZdLdopHij7hWFaPPKWHW7gKvFlX8h2_IMFMkaGlCF0XQ9S35hiQa12Nqf9frEDa48qcBmUweW67Rw"},{"kty":"RSA","alg":"RS256","kid":"_I6KGcucpmmj1en6JMfUuFB7SDKergpmgfP5nOBucxI","use":"sig","e":"AQAB","n":"40IMCS23bTWYL04XSZ-lwwnKuxVpkULRZYFxUrsYSXt5O-Tob52kIfw_QV_I3qNTZqjbfzSmokifNGF8_O1sQVuENE0vDpxenh05eV8h497sunnhsuOLkl4Y0CqgLWcfH-4qgF8musOPsVBdQIZ7SQ4BNMupgAkgyxENynDDlM4GeAwhu7TYtmtA2eOsj4ut6GrLNk-6KjhHvllmVdH09RJox5cz5atwTNI_LkwK9AHRLCaaM27KNLX498kFDTLPfB27zGwwODLuOy0i6XHskf4fnzrL-ttXliVtt0zgfMKPBCPxkm8Ynk7FRZbKisZRwl82aSyDWfZo-gHU2-U8Bw"}]}' + recorded_at: Fri, 30 Sep 2022 17:02:17 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_load.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_load.yml index dbf9497344..5f395df3b9 100644 --- a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_load.yml +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_load.yml @@ -69,4 +69,80 @@ http_interactions: string: '{"issuer":"https://dev-92899796.okta.com/oauth2/default","authorization_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/authorize","token_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/token","userinfo_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/userinfo","registration_endpoint":"https://dev-92899796.okta.com/oauth2/v1/clients","jwks_uri":"https://dev-92899796.okta.com/oauth2/default/v1/keys","response_types_supported":["code","id_token","code id_token","code token","id_token token","code id_token token"],"response_modes_supported":["query","fragment","form_post","okta_post_message"],"grant_types_supported":["authorization_code","implicit","refresh_token","password","urn:ietf:params:oauth:grant-type:device_code"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"],"scopes_supported":["openid","profile","email","address","phone","offline_access","device_sso"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt","none"],"claims_supported":["iss","ver","sub","aud","iat","exp","jti","auth_time","amr","idp","nonce","name","nickname","preferred_username","given_name","middle_name","family_name","email","email_verified","profile","zoneinfo","locale","address","phone_number","picture","website","gender","birthdate","updated_at","at_hash","c_hash"],"code_challenge_methods_supported":["S256"],"introspection_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/introspect","introspection_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt","none"],"revocation_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/revoke","revocation_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt","none"],"end_session_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/logout","request_parameter_supported":true,"request_object_signing_alg_values_supported":["HS256","HS384","HS512","RS256","RS384","RS512","ES256","ES384","ES512"],"device_authorization_endpoint":"https://dev-92899796.okta.com/oauth2/default/v1/device/authorize"}' recorded_at: Sat, 01 Oct 2022 17:02:17 GMT +- request: + method: get + uri: https://dev-56357110.okta.com/oauth2/default/.well-known/openid-configuration + body: + encoding: UTF-8 + string: '' + headers: + User-Agent: + - SWD (1.3.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Wed, 19 Oct 2022 17:02:17 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 20 Oct 2022 03:25:31 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-56357110.okta.com *.oktacdn.com; connect-src ''self'' + dev-56357110.okta.com dev-56357110-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com dev-56357110.kerberos.okta.com + *.authenticatorlocalprod.com:8769 http://localhost:8769 http://127.0.0.1:8769 + *.authenticatorlocalprod.com:65111 http://localhost:65111 http://127.0.0.1:65111 + *.authenticatorlocalprod.com:65121 http://localhost:65121 http://127.0.0.1:65121 + *.authenticatorlocalprod.com:65131 http://localhost:65131 http://127.0.0.1:65131 + *.authenticatorlocalprod.com:65141 http://localhost:65141 http://127.0.0.1:65141 + *.authenticatorlocalprod.com:65151 http://localhost:65151 http://127.0.0.1:65151 + https://oinmanager.okta.com data:; script-src ''unsafe-inline'' ''unsafe-eval'' + ''self'' dev-56357110.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-56357110.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-56357110.okta.com + dev-56357110-admin.okta.com login.okta.com com-okta-authenticator:; img-src + ''self'' dev-56357110.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com + app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com data: blob:; font-src + ''self'' dev-56357110.okta.com data: *.oktacdn.com fonts.gstatic.com; frame-ancestors + ''self''' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + Cache-Control: + - max-age=86400, must-revalidate + Expires: + - Fri, 21 Oct 2022 03:25:31 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Y1C_q7Jrm1_VonLyjg35tgAADTA + body: + encoding: UTF-8 + string: '{"issuer":"https://dev-56357110.okta.com/oauth2/default","authorization_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/authorize","token_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/token","userinfo_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/userinfo","registration_endpoint":"https://dev-56357110.okta.com/oauth2/v1/clients","jwks_uri":"https://dev-56357110.okta.com/oauth2/default/v1/keys","response_types_supported":["code","id_token","code + id_token","code token","id_token token","code id_token token"],"response_modes_supported":["query","fragment","form_post","okta_post_message"],"grant_types_supported":["authorization_code","implicit","refresh_token","password","urn:ietf:params:oauth:grant-type:device_code"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"],"scopes_supported":["okta.myAccount.customAuthenticator.manage","okta.myAccount.customAuthenticator.read","okta.myAccount.email.manage","okta.myAccount.email.read","okta.myAccount.manage","okta.myAccount.phone.manage","okta.myAccount.phone.read","okta.myAccount.profile.manage","okta.myAccount.profile.read","okta.myAccount.read","openid","profile","email","address","phone","offline_access","device_sso"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt","none"],"claims_supported":["iss","ver","sub","aud","iat","exp","jti","auth_time","amr","idp","nonce","name","nickname","preferred_username","given_name","middle_name","family_name","email","email_verified","profile","zoneinfo","locale","address","phone_number","picture","website","gender","birthdate","updated_at","at_hash","c_hash"],"code_challenge_methods_supported":["S256"],"introspection_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/introspect","introspection_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt","none"],"revocation_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/revoke","revocation_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt","none"],"end_session_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/logout","request_parameter_supported":true,"request_object_signing_alg_values_supported":["HS256","HS384","HS512","RS256","RS384","RS512","ES256","ES384","ES512"],"device_authorization_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/device/authorize","pushed_authorization_request_endpoint":"https://dev-56357110.okta.com/oauth2/default/v1/par"}' + recorded_at: Wed, 19 Oct 2022 17:02:17 GMT recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-invalid_token.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-invalid_token.yml new file mode 100644 index 0000000000..efabc47b0c --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-invalid_token.yml @@ -0,0 +1,93 @@ +--- +http_interactions: +- request: + method: post + uri: https://dev-56357110.okta.com/oauth2/default/v1/token + body: + encoding: UTF-8 + string: grant_type=refresh_token&refresh_token=a8VLPRtcOS5-IFYXkZYzZbrIhSJq6trFXxYJyKbaUng&scope=openid+email+profile+offline_access + headers: + User-Agent: + - Rack::OAuth2 (1.19.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Wed, 19 Oct 2022 17:02:17 GMT + Authorization: + - Basic MG9hNmNjaXZ6ZjNuRWVpR3Q1ZDc6WW5BdWtVRUNFQXRzV1NXQ0hQemkxY29pWlplT2hkdlFPU25yaTRLeg== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 400 + message: Bad Request + headers: + Date: + - Thu, 20 Oct 2022 18:05:37 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Okta-Request-Id: + - Y1GN8P_4ihOwljdFvkAt8wAABGQ + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-56357110.okta.com *.oktacdn.com; connect-src ''self'' + dev-56357110.okta.com dev-56357110-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com dev-56357110.kerberos.okta.com + *.authenticatorlocalprod.com:8769 http://localhost:8769 http://127.0.0.1:8769 + *.authenticatorlocalprod.com:65111 http://localhost:65111 http://127.0.0.1:65111 + *.authenticatorlocalprod.com:65121 http://localhost:65121 http://127.0.0.1:65121 + *.authenticatorlocalprod.com:65131 http://localhost:65131 http://127.0.0.1:65131 + *.authenticatorlocalprod.com:65141 http://localhost:65141 http://127.0.0.1:65141 + *.authenticatorlocalprod.com:65151 http://localhost:65151 http://127.0.0.1:65151 + https://oinmanager.okta.com data:; script-src ''unsafe-inline'' ''unsafe-eval'' + ''self'' dev-56357110.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-56357110.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-56357110.okta.com + dev-56357110-admin.okta.com login.okta.com com-okta-authenticator:; img-src + ''self'' dev-56357110.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com + app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com data: blob:; font-src + ''self'' dev-56357110.okta.com data: *.oktacdn.com fonts.gstatic.com; frame-ancestors + ''self''' + X-Rate-Limit-Limit: + - '300' + X-Rate-Limit-Remaining: + - '299' + X-Rate-Limit-Reset: + - '1666289196' + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - '0' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + Set-Cookie: + - JSESSIONID=43E62E004A5E531ADAF3781F44BC4A07; Path=/; Secure; HttpOnly + - autolaunch_triggered=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + - sid=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + body: + encoding: UTF-8 + string: '{"error":"invalid_grant","error_description":"The refresh token is + invalid or expired."}' + recorded_at: Wed, 19 Oct 2022 17:02:17 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-valid_token.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-valid_token.yml new file mode 100644 index 0000000000..47b3e26f0b --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-valid_token.yml @@ -0,0 +1,170 @@ +--- +http_interactions: +- request: + method: post + uri: https://dev-56357110.okta.com/oauth2/default/v1/token + body: + encoding: UTF-8 + string: grant_type=refresh_token&refresh_token=a8VLPRtcOS5-IFYXkZYzZbrIhSJq6trFXxYJyKbaUng&scope=openid+email+profile+offline_access + headers: + User-Agent: + - Rack::OAuth2 (1.19.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Wed, 19 Oct 2022 17:02:17 GMT + Authorization: + - Basic MG9hNmNjaXZ6ZjNuRWVpR3Q1ZDc6WW5BdWtVRUNFQXRzV1NXQ0hQemkxY29pWlplT2hkdlFPU25yaTRLeg== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 20 Oct 2022 18:04:19 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Okta-Request-Id: + - Y1GNo06NZShkAkdklbsTGgAACtE + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-56357110.okta.com *.oktacdn.com; connect-src ''self'' + dev-56357110.okta.com dev-56357110-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com dev-56357110.kerberos.okta.com + *.authenticatorlocalprod.com:8769 http://localhost:8769 http://127.0.0.1:8769 + *.authenticatorlocalprod.com:65111 http://localhost:65111 http://127.0.0.1:65111 + *.authenticatorlocalprod.com:65121 http://localhost:65121 http://127.0.0.1:65121 + *.authenticatorlocalprod.com:65131 http://localhost:65131 http://127.0.0.1:65131 + *.authenticatorlocalprod.com:65141 http://localhost:65141 http://127.0.0.1:65141 + *.authenticatorlocalprod.com:65151 http://localhost:65151 http://127.0.0.1:65151 + https://oinmanager.okta.com data:; script-src ''unsafe-inline'' ''unsafe-eval'' + ''self'' dev-56357110.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-56357110.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-56357110.okta.com + dev-56357110-admin.okta.com login.okta.com com-okta-authenticator:; img-src + ''self'' dev-56357110.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com + app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com data: blob:; font-src + ''self'' dev-56357110.okta.com data: *.oktacdn.com fonts.gstatic.com; frame-ancestors + ''self''' + X-Rate-Limit-Limit: + - '300' + X-Rate-Limit-Remaining: + - '299' + X-Rate-Limit-Reset: + - '1666289119' + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - '0' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Robots-Tag: + - noindex,nofollow + Set-Cookie: + - JSESSIONID=FAC85361AD19513CA7366ADCB816DC69; Path=/; Secure; HttpOnly + - autolaunch_triggered=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + - sid=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + body: + encoding: UTF-8 + string: '{"token_type":"Bearer","expires_in":3600,"access_token":"eyJraWQiOiJrU0EwSGItaVBmUlAzV2xDaGZ5djNVdldfTks4YVhQMEdNeHhtWjlJdXFFIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULmotQ3pHbGkzeDRadGZtUjc4RUl2R2JPZTdHaXlXcWVIcEJkNnM1TlowdE0ub2FycGgwNnhkbkRWT2hIaTk1ZDYiLCJpc3MiOiJodHRwczovL2Rldi01NjM1NzExMC5va3RhLmNvbS9vYXV0aDIvZGVmYXVsdCIsImF1ZCI6ImFwaTovL2RlZmF1bHQiLCJpYXQiOjE2NjYyODkwNTksImV4cCI6MTY2NjI5MjY1OSwiY2lkIjoiMG9hNmNjaXZ6ZjNuRWVpR3Q1ZDciLCJ1aWQiOiIwMHU2eGhmbXBtVFZnbVFvRjVkNyIsInNjcCI6WyJvZmZsaW5lX2FjY2VzcyIsIm9wZW5pZCIsInByb2ZpbGUiLCJlbWFpbCJdLCJhdXRoX3RpbWUiOjE2NjYyODg3OTIsInN1YiI6InRlc3QudXNlcjNAbXljb21wYW55LmNvbSJ9.KD2fnGxkgBb2Mx1ENM2A1u3tXe0lfOUjjNoliXD9FaNhYQT2OI7cXG3jbhaDztJxcp6r98qFffalZTTqJyuvehv8-whVRrJFdX0Rw9rGfmmp6Y2DfYuOOkDgPX7OOJ4tOCjn62lXi8aSMjDtF_Oghl-G0UmorzebyWjliakUaRVJqZKN2n2-EWhan-2_FH_bOnuBvhe7bKEKbUa1JGTllDloCz85cw_95ZDkWCYfFHlIHtFKyVVZHnmVC0b-c55olNU8SFkZRhwYC-mrd2zUAYda5XWby5tPhRHCRJ6RbOVCJJweuSyywhbrGpuS6BfuCuEXoXPL9LNPaXSOgjVXqw","scope":"offline_access + openid profile email","id_token":"eyJraWQiOiJrU0EwSGItaVBmUlAzV2xDaGZ5djNVdldfTks4YVhQMEdNeHhtWjlJdXFFIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHU2eGhmbXBtVFZnbVFvRjVkNyIsIm5hbWUiOiJUZXN0IFBlcnNvbiIsImVtYWlsIjoidGVzdC51c2VyM0BteWNvbXBhbnkuY29tIiwidmVyIjoxLCJpc3MiOiJodHRwczovL2Rldi01NjM1NzExMC5va3RhLmNvbS9vYXV0aDIvZGVmYXVsdCIsImF1ZCI6IjBvYTZjY2l2emYzbkVlaUd0NWQ3IiwiaWF0IjoxNjY2Mjg5MDU5LCJleHAiOjE2NjYyOTI2NTksImp0aSI6IklELnRIdUl3VktqVHZIZWpJeWw1UHZaYlkzTDRNOUVwclN2VHhUYkE5Ui1PY2ciLCJhbXIiOltdLCJpZHAiOiIwMG82Y2JtYzJuZjJsclJnUDVkNyIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3QudXNlcjNAbXljb21wYW55LmNvbSIsImF1dGhfdGltZSI6MTY2NjI4ODc5MiwiYXRfaGFzaCI6IkNkVDNac0ZzVUhXLVJCLU1TZ0g5c0EifQ.JmcX1MJjWa5BsPiNaOwVVUn-EZUu2KRcSbN8oT2Iur-uf2sbQqHf80UVvkcehxx1tP1RbpuuHoKHMG6L_Q09rJGpkTCVXLtYObIGd9Cp4h7Q1MF13M2GkeiXGOrFy3D62OueRE5fSO47X1u5IMNUkSs5eiGljBdb1VFG2fCDNwd8EvxTrBokJtcpAzYd4otULmViqCoecihs6DTms4Erq02-KumkBW96fdWKA6VLDwPqqeeaa0o2JlQyRMQLMPja-4BAGT7zI0PGdBNLZpPSuLYcVpdvI3_1YAZXIcSJH5jzinl4Hffd--yPRdppf0Fnh429pbtl9jlPRah6QwxPfg"}' + recorded_at: Wed, 19 Oct 2022 17:02:17 GMT +- request: + method: get + uri: https://dev-56357110.okta.com/oauth2/default/v1/keys + body: + encoding: UTF-8 + string: '' + headers: + User-Agent: + - OpenIDConnect (1.3.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Wed, 19 Oct 2022 17:02:17 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 20 Oct 2022 18:04:20 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-56357110.okta.com *.oktacdn.com; connect-src ''self'' + dev-56357110.okta.com dev-56357110-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com dev-56357110.kerberos.okta.com + *.authenticatorlocalprod.com:8769 http://localhost:8769 http://127.0.0.1:8769 + *.authenticatorlocalprod.com:65111 http://localhost:65111 http://127.0.0.1:65111 + *.authenticatorlocalprod.com:65121 http://localhost:65121 http://127.0.0.1:65121 + *.authenticatorlocalprod.com:65131 http://localhost:65131 http://127.0.0.1:65131 + *.authenticatorlocalprod.com:65141 http://localhost:65141 http://127.0.0.1:65141 + *.authenticatorlocalprod.com:65151 http://localhost:65151 http://127.0.0.1:65151 + https://oinmanager.okta.com data:; script-src ''unsafe-inline'' ''unsafe-eval'' + ''self'' dev-56357110.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-56357110.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-56357110.okta.com + dev-56357110-admin.okta.com login.okta.com com-okta-authenticator:; img-src + ''self'' dev-56357110.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com + app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com data: blob:; font-src + ''self'' dev-56357110.okta.com data: *.oktacdn.com fonts.gstatic.com; frame-ancestors + ''self''' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + Cache-Control: + - max-age=7360675, must-revalidate + Expires: + - Fri, 13 Jan 2023 22:42:15 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Y1GNo0iq0-OU1Me3RAat7gAADZw + body: + encoding: UTF-8 + string: '{"keys":[{"kty":"RSA","alg":"RS256","kid":"kSA0Hb-iPfRP3WlChfyv3UvW_NK8aXP0GMxxmZ9IuqE","use":"sig","e":"AQAB","n":"0Zr8pwGpTyvZzaOZz0aBVc_xQ-YroSIUeuIrZpPLMPBO29SrF13bEpY2yLMO3PxT_HqVBsRVooyCqnMU84VJ38eL7oX4NE8WOOcqhjktHtAzNbZgLHhEyoH59yVOiM5eMFA00Z8XY_YZuKvlRHQOkjC1t3yIlFnooeKpZm1zfg9GTaaUUQuXWfV9tEVgLYsuX5rcTnJuojExRf_nQM211AugeEgiZTcD-wP7U1-DYAk7l9hnnFyWJYfBCF0B1cCS0TVCtwqqybUbv2mFe0Q7QGrdelOQXEsFB4qud6AJ8hYAGTiuFmAHkqBIngxM-zFEAtxRuK4nsf_RSBVYgS78dw"},{"kty":"RSA","alg":"RS256","kid":"xK6Bg6bmgAWe_CKgrm-5Sr8sGpyrpWQb8LV2xmxcvIc","use":"sig","e":"AQAB","n":"qyzixXfFY2c7CxTUI2aN4oYugrcbUhJ-DfYPcuYCSg50YeWBbVHG_ZVa1tcTBwRQoaIjKOJfPHRWGmweqdSYu39fFh2z7I7TyATf0dkmQTnx0Yx9nGnBWuazG4Gx0rqXfQmvHTCXsYNFmVTu16sI1EKkLlTWU6BQ4_yg99Y6Poczl55aoZn0x2PUoEH61xYAr2nMqhbxb8AHwAn_n35Gufe9uwL4Uwg8tIq56aygfXCLS7HA0fXqsrrgw_GTHBjz-zRUxuKgPdA-RdhPHjhExlxFrR1UrvN5cxXVIy2NEeKWdEAqrqVsQrJNIyWorBBVmAj5t9MDXSSKwXbFcrdf0w"}]}' + recorded_at: Wed, 19 Oct 2022 17:02:17 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-valid_token_with_rotation.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-valid_token_with_rotation.yml new file mode 100644 index 0000000000..659017de7e --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/v2/client_refresh-valid_token_with_rotation.yml @@ -0,0 +1,170 @@ +--- +http_interactions: +- request: + method: post + uri: https://dev-56357110.okta.com/oauth2/default/v1/token + body: + encoding: UTF-8 + string: grant_type=refresh_token&refresh_token=a8VLPRtcOS5-IFYXkZYzZbrIhSJq6trFXxYJyKbaUng&scope=openid+email+profile+offline_access + headers: + User-Agent: + - Rack::OAuth2 (1.19.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Wed, 19 Oct 2022 17:02:17 GMT + Authorization: + - Basic MG9hNmNjaXZ6ZjNuRWVpR3Q1ZDc6WW5BdWtVRUNFQXRzV1NXQ0hQemkxY29pWlplT2hkdlFPU25yaTRLeg== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 20 Oct 2022 18:04:19 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Okta-Request-Id: + - Y1GNo06NZShkAkdklbsTGgAACtE + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-56357110.okta.com *.oktacdn.com; connect-src ''self'' + dev-56357110.okta.com dev-56357110-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com dev-56357110.kerberos.okta.com + *.authenticatorlocalprod.com:8769 http://localhost:8769 http://127.0.0.1:8769 + *.authenticatorlocalprod.com:65111 http://localhost:65111 http://127.0.0.1:65111 + *.authenticatorlocalprod.com:65121 http://localhost:65121 http://127.0.0.1:65121 + *.authenticatorlocalprod.com:65131 http://localhost:65131 http://127.0.0.1:65131 + *.authenticatorlocalprod.com:65141 http://localhost:65141 http://127.0.0.1:65141 + *.authenticatorlocalprod.com:65151 http://localhost:65151 http://127.0.0.1:65151 + https://oinmanager.okta.com data:; script-src ''unsafe-inline'' ''unsafe-eval'' + ''self'' dev-56357110.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-56357110.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-56357110.okta.com + dev-56357110-admin.okta.com login.okta.com com-okta-authenticator:; img-src + ''self'' dev-56357110.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com + app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com data: blob:; font-src + ''self'' dev-56357110.okta.com data: *.oktacdn.com fonts.gstatic.com; frame-ancestors + ''self''' + X-Rate-Limit-Limit: + - '300' + X-Rate-Limit-Remaining: + - '299' + X-Rate-Limit-Reset: + - '1666289119' + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - '0' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Robots-Tag: + - noindex,nofollow + Set-Cookie: + - JSESSIONID=FAC85361AD19513CA7366ADCB816DC69; Path=/; Secure; HttpOnly + - autolaunch_triggered=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + - sid=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ + body: + encoding: UTF-8 + string: '{"token_type":"Bearer","expires_in":3600,"access_token":"eyJraWQiOiJrU0EwSGItaVBmUlAzV2xDaGZ5djNVdldfTks4YVhQMEdNeHhtWjlJdXFFIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULmotQ3pHbGkzeDRadGZtUjc4RUl2R2JPZTdHaXlXcWVIcEJkNnM1TlowdE0ub2FycGgwNnhkbkRWT2hIaTk1ZDYiLCJpc3MiOiJodHRwczovL2Rldi01NjM1NzExMC5va3RhLmNvbS9vYXV0aDIvZGVmYXVsdCIsImF1ZCI6ImFwaTovL2RlZmF1bHQiLCJpYXQiOjE2NjYyODkwNTksImV4cCI6MTY2NjI5MjY1OSwiY2lkIjoiMG9hNmNjaXZ6ZjNuRWVpR3Q1ZDciLCJ1aWQiOiIwMHU2eGhmbXBtVFZnbVFvRjVkNyIsInNjcCI6WyJvZmZsaW5lX2FjY2VzcyIsIm9wZW5pZCIsInByb2ZpbGUiLCJlbWFpbCJdLCJhdXRoX3RpbWUiOjE2NjYyODg3OTIsInN1YiI6InRlc3QudXNlcjNAbXljb21wYW55LmNvbSJ9.KD2fnGxkgBb2Mx1ENM2A1u3tXe0lfOUjjNoliXD9FaNhYQT2OI7cXG3jbhaDztJxcp6r98qFffalZTTqJyuvehv8-whVRrJFdX0Rw9rGfmmp6Y2DfYuOOkDgPX7OOJ4tOCjn62lXi8aSMjDtF_Oghl-G0UmorzebyWjliakUaRVJqZKN2n2-EWhan-2_FH_bOnuBvhe7bKEKbUa1JGTllDloCz85cw_95ZDkWCYfFHlIHtFKyVVZHnmVC0b-c55olNU8SFkZRhwYC-mrd2zUAYda5XWby5tPhRHCRJ6RbOVCJJweuSyywhbrGpuS6BfuCuEXoXPL9LNPaXSOgjVXqw","scope":"offline_access + openid profile email","refresh_token":"dyJXfWUg1Xjt4KP7IQ7qcHUVNtKNWmmtOu9qNScjkN8","id_token":"eyJraWQiOiJrU0EwSGItaVBmUlAzV2xDaGZ5djNVdldfTks4YVhQMEdNeHhtWjlJdXFFIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHU2eGhmbXBtVFZnbVFvRjVkNyIsIm5hbWUiOiJUZXN0IFBlcnNvbiIsImVtYWlsIjoidGVzdC51c2VyM0BteWNvbXBhbnkuY29tIiwidmVyIjoxLCJpc3MiOiJodHRwczovL2Rldi01NjM1NzExMC5va3RhLmNvbS9vYXV0aDIvZGVmYXVsdCIsImF1ZCI6IjBvYTZjY2l2emYzbkVlaUd0NWQ3IiwiaWF0IjoxNjY2Mjg5MDU5LCJleHAiOjE2NjYyOTI2NTksImp0aSI6IklELnRIdUl3VktqVHZIZWpJeWw1UHZaYlkzTDRNOUVwclN2VHhUYkE5Ui1PY2ciLCJhbXIiOltdLCJpZHAiOiIwMG82Y2JtYzJuZjJsclJnUDVkNyIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3QudXNlcjNAbXljb21wYW55LmNvbSIsImF1dGhfdGltZSI6MTY2NjI4ODc5MiwiYXRfaGFzaCI6IkNkVDNac0ZzVUhXLVJCLU1TZ0g5c0EifQ.JmcX1MJjWa5BsPiNaOwVVUn-EZUu2KRcSbN8oT2Iur-uf2sbQqHf80UVvkcehxx1tP1RbpuuHoKHMG6L_Q09rJGpkTCVXLtYObIGd9Cp4h7Q1MF13M2GkeiXGOrFy3D62OueRE5fSO47X1u5IMNUkSs5eiGljBdb1VFG2fCDNwd8EvxTrBokJtcpAzYd4otULmViqCoecihs6DTms4Erq02-KumkBW96fdWKA6VLDwPqqeeaa0o2JlQyRMQLMPja-4BAGT7zI0PGdBNLZpPSuLYcVpdvI3_1YAZXIcSJH5jzinl4Hffd--yPRdppf0Fnh429pbtl9jlPRah6QwxPfg"}' + recorded_at: Wed, 19 Oct 2022 17:02:17 GMT +- request: + method: get + uri: https://dev-56357110.okta.com/oauth2/default/v1/keys + body: + encoding: UTF-8 + string: '' + headers: + User-Agent: + - OpenIDConnect (1.3.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Wed, 19 Oct 2022 17:02:17 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 20 Oct 2022 18:04:20 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - nginx + Public-Key-Pins-Report-Only: + - pin-sha256="r5EfzZxQVvQpKo3AgYRaT7X2bDO/kj3ACwmxfdT2zt8="; pin-sha256="MaqlcUgk2mvY/RFSGeSwBRkI+rZ6/dxe/DuQfBT/vnQ="; + pin-sha256="72G5IEvDEWn+EThf3qjR7/bQSWaS2ZSLqolhnO6iyJI="; pin-sha256="rrV6CLCCvqnk89gWibYT0JO6fNQ8cCit7GGoiVTjCOg="; + max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly" + X-Xss-Protection: + - '0' + P3p: + - CP="HONK" + Content-Security-Policy: + - 'default-src ''self'' dev-56357110.okta.com *.oktacdn.com; connect-src ''self'' + dev-56357110.okta.com dev-56357110-admin.okta.com *.oktacdn.com *.mixpanel.com + *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com dev-56357110.kerberos.okta.com + *.authenticatorlocalprod.com:8769 http://localhost:8769 http://127.0.0.1:8769 + *.authenticatorlocalprod.com:65111 http://localhost:65111 http://127.0.0.1:65111 + *.authenticatorlocalprod.com:65121 http://localhost:65121 http://127.0.0.1:65121 + *.authenticatorlocalprod.com:65131 http://localhost:65131 http://127.0.0.1:65131 + *.authenticatorlocalprod.com:65141 http://localhost:65141 http://127.0.0.1:65141 + *.authenticatorlocalprod.com:65151 http://localhost:65151 http://127.0.0.1:65151 + https://oinmanager.okta.com data:; script-src ''unsafe-inline'' ''unsafe-eval'' + ''self'' dev-56357110.okta.com *.oktacdn.com; style-src ''unsafe-inline'' + ''self'' dev-56357110.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com; frame-src ''self'' dev-56357110.okta.com + dev-56357110-admin.okta.com login.okta.com com-okta-authenticator:; img-src + ''self'' dev-56357110.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com + app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com + pendo-static-5391521872216064.storage.googleapis.com data: blob:; font-src + ''self'' dev-56357110.okta.com data: *.oktacdn.com fonts.gstatic.com; frame-ancestors + ''self''' + Expect-Ct: + - report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0 + Cache-Control: + - max-age=7360675, must-revalidate + Expires: + - Fri, 13 Jan 2023 22:42:15 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Y1GNo0iq0-OU1Me3RAat7gAADZw + body: + encoding: UTF-8 + string: '{"keys":[{"kty":"RSA","alg":"RS256","kid":"kSA0Hb-iPfRP3WlChfyv3UvW_NK8aXP0GMxxmZ9IuqE","use":"sig","e":"AQAB","n":"0Zr8pwGpTyvZzaOZz0aBVc_xQ-YroSIUeuIrZpPLMPBO29SrF13bEpY2yLMO3PxT_HqVBsRVooyCqnMU84VJ38eL7oX4NE8WOOcqhjktHtAzNbZgLHhEyoH59yVOiM5eMFA00Z8XY_YZuKvlRHQOkjC1t3yIlFnooeKpZm1zfg9GTaaUUQuXWfV9tEVgLYsuX5rcTnJuojExRf_nQM211AugeEgiZTcD-wP7U1-DYAk7l9hnnFyWJYfBCF0B1cCS0TVCtwqqybUbv2mFe0Q7QGrdelOQXEsFB4qud6AJ8hYAGTiuFmAHkqBIngxM-zFEAtxRuK4nsf_RSBVYgS78dw"},{"kty":"RSA","alg":"RS256","kid":"xK6Bg6bmgAWe_CKgrm-5Sr8sGpyrpWQb8LV2xmxcvIc","use":"sig","e":"AQAB","n":"qyzixXfFY2c7CxTUI2aN4oYugrcbUhJ-DfYPcuYCSg50YeWBbVHG_ZVa1tcTBwRQoaIjKOJfPHRWGmweqdSYu39fFh2z7I7TyATf0dkmQTnx0Yx9nGnBWuazG4Gx0rqXfQmvHTCXsYNFmVTu16sI1EKkLlTWU6BQ4_yg99Y6Poczl55aoZn0x2PUoEH61xYAr2nMqhbxb8AHwAn_n35Gufe9uwL4Uwg8tIq56aygfXCLS7HA0fXqsrrgw_GTHBjz-zRUxuKgPdA-RdhPHjhExlxFrR1UrvN5cxXVIy2NEeKWdEAqrqVsQrJNIyWorBBVmAj5t9MDXSSKwXbFcrdf0w"}]}' + recorded_at: Wed, 19 Oct 2022 17:02:17 GMT +recorded_with: VCR 6.1.0