diff --git a/CHANGELOG.md b/CHANGELOG.md index 806157bd81..c2abd2244e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Nothing should go in this section, please add to the latest unreleased version (and update the corresponding date), or add a new version. +## [1.19.1] - 2022-11-23 +### Added + +- Provides support for PKCE in the OIDC Authenticator code redirect workflow. + This is disabled by default, but is available under the + `CONJUR_FEATURE_POLICY_LOAD_EXTENSIONS` feature flag. + [cyberark/conjur#2678](https://github.com/cyberark/conjur/pull/2678) + ## [1.19.0] - 2022-10-11 ### Added diff --git a/app/db/repository/authenticator_repository.rb b/app/db/repository/authenticator_repository.rb index 6a9b7f0021..4c758e9d29 100644 --- a/app/db/repository/authenticator_repository.rb +++ b/app/db/repository/authenticator_repository.rb @@ -54,8 +54,17 @@ def load_authenticator(type:, account:, id:) args[variable.resource_id.split('/')[-1].underscore.to_sym] = variable.secret.value end end + begin - @data_object.new(**args_list) + if Rails.configuration.feature_flags.enabled?(:pkce_support) + allowed_args = %i[account service_id] + + @data_object.const_get(:REQUIRED_VARIABLES) + + @data_object.const_get(:OPTIONAL_VARIABLES) + allowed_arg_list = args_list.select{ |key, _| allowed_args.include?(key) } + @data_object.new(**allowed_arg_list) + else + @data_object.new(**args_list) + end rescue ArgumentError => e @logger.debug("DB::Repository::AuthenticatorRepository.load_authenticator - exception: #{e}") nil diff --git a/app/domain/authentication/authn_oidc/pkce_support_feature/client.rb b/app/domain/authentication/authn_oidc/pkce_support_feature/client.rb new file mode 100644 index 0000000000..1c6e3c4d97 --- /dev/null +++ b/app/domain/authentication/authn_oidc/pkce_support_feature/client.rb @@ -0,0 +1,117 @@ +module Authentication + module AuthnOidc + module PkceSupportFeature + class Client + def initialize( + authenticator:, + client: ::OpenIDConnect::Client, + oidc_id_token: ::OpenIDConnect::ResponseObject::IdToken, + discovery_configuration: ::OpenIDConnect::Discovery::Provider::Config, + cache: Rails.cache, + logger: Rails.logger + ) + @authenticator = authenticator + @client = client + @oidc_id_token = oidc_id_token + @discovery_configuration = discovery_configuration + @cache = cache + @logger = logger + end + + def oidc_client + @oidc_client ||= begin + issuer_uri = URI(@authenticator.provider_uri) + @client.new( + identifier: @authenticator.client_id, + secret: @authenticator.client_secret, + redirect_uri: @authenticator.redirect_uri, + scheme: issuer_uri.scheme, + host: issuer_uri.host, + port: issuer_uri.port, + authorization_endpoint: URI(discovery_information.authorization_endpoint).path, + token_endpoint: URI(discovery_information.token_endpoint).path, + userinfo_endpoint: URI(discovery_information.userinfo_endpoint).path, + jwks_uri: URI(discovery_information.jwks_uri).path, + end_session_endpoint: URI(discovery_information.end_session_endpoint).path + ) + end + end + + def callback(code:, nonce:, code_verifier:) + oidc_client.authorization_code = code + begin + bearer_token = oidc_client.access_token!( + scope: true, + client_auth_method: :basic, + code_verifier: code_verifier + ) + rescue Rack::OAuth2::Client::Error => e + # Only handle the expected errors related to access token retrieval. + case e.message + when /PKCE verification failed/ + raise Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + 'PKCE verification failed' + when /The authorization code is invalid or has expired/ + raise Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + 'Authorization code is invalid or has expired' + when /Code not valid/ + raise Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + 'Authorization code is invalid' + end + raise e + end + id_token = bearer_token.id_token || bearer_token.access_token + + begin + attempts ||= 0 + decoded_id_token = @oidc_id_token.decode( + id_token, + discovery_information.jwks + ) + rescue Exception => e + attempts += 1 + raise e if attempts > 1 + + # If the JWKS verification fails, blow away the existing cache and + # try again. This is intended to handle the case where the OIDC certificate + # changes, and we want to cache the new certificate without decode failing. + discovery_information(invalidate: true) + retry + end + + begin + decoded_id_token.verify!( + issuer: @authenticator.provider_uri, + client_id: @authenticator.client_id, + nonce: nonce + ) + rescue OpenIDConnect::ResponseObject::IdToken::InvalidNonce + raise Errors::Authentication::AuthnOidc::TokenVerificationFailed, + 'Provided nonce does not match the nonce in the JWT' + rescue OpenIDConnect::ResponseObject::IdToken::ExpiredToken + raise Errors::Authentication::AuthnOidc::TokenVerificationFailed, + 'JWT has expired' + rescue OpenIDConnect::ValidationFailed => e + raise Errors::Authentication::AuthnOidc::TokenVerificationFailed, + e.message + end + decoded_id_token + end + + def discovery_information(invalidate: false) + @cache.fetch( + "#{@authenticator.account}/#{@authenticator.service_id}/#{URI::Parser.new.escape(@authenticator.provider_uri)}", + force: invalidate, + skip_nil: true + ) do + @discovery_configuration.discover!(@authenticator.provider_uri) + rescue HTTPClient::ConnectTimeoutError, Errno::ETIMEDOUT => e + raise Errors::Authentication::OAuth::ProviderDiscoveryTimeout.new(@authenticator.provider_uri, e.message) + rescue => e + raise Errors::Authentication::OAuth::ProviderDiscoveryFailed.new(@authenticator.provider_uri, e.message) + end + end + end + end + end +end diff --git a/app/domain/authentication/authn_oidc/pkce_support_feature/data_objects/authenticator.rb b/app/domain/authentication/authn_oidc/pkce_support_feature/data_objects/authenticator.rb new file mode 100644 index 0000000000..a9dc928031 --- /dev/null +++ b/app/domain/authentication/authn_oidc/pkce_support_feature/data_objects/authenticator.rb @@ -0,0 +1,52 @@ +module Authentication + module AuthnOidc + module PkceSupportFeature + module DataObjects + class Authenticator + + REQUIRED_VARIABLES = %i[provider_uri client_id client_secret claim_mapping].freeze + OPTIONAL_VARIABLES = %i[redirect_uri response_type provider_scope name].freeze + + attr_reader :provider_uri, :client_id, :client_secret, :claim_mapping, :account + attr_reader :service_id, :redirect_uri, :response_type + + def initialize( + provider_uri:, + client_id:, + client_secret:, + claim_mapping:, + account:, + service_id:, + redirect_uri: nil, + name: nil, + response_type: 'code', + provider_scope: nil + ) + @account = account + @provider_uri = provider_uri + @client_id = client_id + @client_secret = client_secret + @claim_mapping = claim_mapping + @response_type = response_type + @service_id = service_id + @name = name + @provider_scope = provider_scope + @redirect_uri = redirect_uri + end + + def scope + (%w[openid email profile] + [*@provider_scope.to_s.split(' ')]).uniq.join(' ') + end + + def name + @name || @service_id.titleize + end + + def resource_id + "#{account}:webservice:conjur/authn-oidc/#{service_id}" + end + end + end + end + end +end diff --git a/app/domain/authentication/authn_oidc/pkce_support_feature/resolve_identity.rb b/app/domain/authentication/authn_oidc/pkce_support_feature/resolve_identity.rb new file mode 100644 index 0000000000..4ac21cb8b2 --- /dev/null +++ b/app/domain/authentication/authn_oidc/pkce_support_feature/resolve_identity.rb @@ -0,0 +1,19 @@ +module Authentication + module AuthnOidc + module PkceSupportFeature + class ResolveIdentity + def call(identity:, account:, allowed_roles:) + # make sure role has a resource (ex. user, host) + roles = allowed_roles.select(&:resource?) + + roles.each do |role| + role_account, _, role_id = role.id.split(':') + return role if role_account == account && identity == role_id + end + + raise(Errors::Authentication::Security::RoleNotFound, identity) + end + end + end + end +end diff --git a/app/domain/authentication/authn_oidc/pkce_support_feature/strategy.rb b/app/domain/authentication/authn_oidc/pkce_support_feature/strategy.rb new file mode 100644 index 0000000000..ef3543c4b4 --- /dev/null +++ b/app/domain/authentication/authn_oidc/pkce_support_feature/strategy.rb @@ -0,0 +1,43 @@ +module Authentication + module AuthnOidc + module PkceSupportFeature + class Strategy + def initialize( + authenticator:, + client: Authentication::AuthnOidc::PkceSupportFeature::Client, + logger: Rails.logger + ) + @authenticator = authenticator + @client = client.new(authenticator: authenticator) + @logger = logger + end + + # 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 + end + end + + identity = resolve_identity( + jwt: @client.callback( + code: args[:code], + nonce: args[:nonce], + code_verifier: args[:code_verifier] + ) + ) + unless identity.present? + raise Errors::Authentication::AuthnOidc::IdTokenClaimNotFoundOrEmpty, + @authenticator.claim_mapping + end + identity + end + + def resolve_identity(jwt:) + jwt.raw_attributes.with_indifferent_access[@authenticator.claim_mapping] + end + end + end + end +end diff --git a/app/domain/authentication/authn_oidc/pkce_support_feature/views/provider_context.rb b/app/domain/authentication/authn_oidc/pkce_support_feature/views/provider_context.rb new file mode 100644 index 0000000000..1e2c244430 --- /dev/null +++ b/app/domain/authentication/authn_oidc/pkce_support_feature/views/provider_context.rb @@ -0,0 +1,60 @@ +require 'securerandom' +require 'digest' + +module Authentication + module AuthnOidc + module PkceSupportFeature + module Views + class ProviderContext + def initialize( + client: Authentication::AuthnOidc::V2::Client, + digest: Digest::SHA256, + random: SecureRandom, + logger: Rails.logger + ) + @client = client + @logger = logger + @digest = digest + @random = random + end + + def call(authenticators:) + authenticators.map do |authenticator| + nonce = @random.hex(25) + code_verifier = @random.hex(25) + code_challenge = @digest.base64digest(code_verifier).tr("+/", "-_").tr("=", "") + { + service_id: authenticator.service_id, + type: 'authn-oidc', + name: authenticator.name, + nonce: nonce, + code_verifier: code_verifier, + redirect_uri: generate_redirect_url( + client: @client.new(authenticator: authenticator), + authenticator: authenticator, + nonce: nonce, + code_challenge: code_challenge + ) + } + end + end + + def generate_redirect_url(client:, authenticator:, nonce:, code_challenge:) + params = { + client_id: authenticator.client_id, + response_type: authenticator.response_type, + scope: ERB::Util.url_encode(authenticator.scope), + nonce: nonce, + code_challenge: code_challenge, + code_challenge_method: 'S256', + redirect_uri: ERB::Util.url_encode(authenticator.redirect_uri) + } + formatted_params = params.map { |key, value| "#{key}=#{value}" }.join("&") + + "#{client.discovery_information.authorization_endpoint}?#{formatted_params}" + end + end + end + end + end +end diff --git a/app/domain/authentication/handler/authentication_handler.rb b/app/domain/authentication/handler/authentication_handler.rb index 9731b6d1ee..af344cedac 100644 --- a/app/domain/authentication/handler/authentication_handler.rb +++ b/app/domain/authentication/handler/authentication_handler.rb @@ -31,10 +31,12 @@ def initialize( end def call(parameters:, request_ip:) - required_parameters = %i[state code] - required_parameters.each do |parameter| - if !parameters.key?(parameter) || parameters[parameter].strip.empty? - raise Errors::Authentication::RequestBody::MissingRequestParam, parameter + unless Rails.configuration.feature_flags.enabled?(:pkce_support) + required_parameters = %i[state code] + required_parameters.each do |parameter| + if !parameters.key?(parameter) || parameters[parameter].strip.empty? + raise Errors::Authentication::RequestBody::MissingRequestParam, parameter + end end end diff --git a/app/domain/authentication/util/namespace_selector.rb b/app/domain/authentication/util/namespace_selector.rb index d168505d43..1311ed4ff8 100644 --- a/app/domain/authentication/util/namespace_selector.rb +++ b/app/domain/authentication/util/namespace_selector.rb @@ -9,7 +9,11 @@ def self.select(authenticator_type:) # 'V2' is a bit of a hack to handle the fact that # the original OIDC authenticator is really a # glorified JWT authenticator. - 'Authentication::AuthnOidc::V2' + if Rails.configuration.feature_flags.enabled?(:pkce_support) + 'Authentication::AuthnOidc::PkceSupportFeature' + else + 'Authentication::AuthnOidc::V2' + end else raise "'#{authenticator_type}' is not a supported authenticator type" # TODO: make this dynamic based on authenticator type. diff --git a/app/domain/errors.rb b/app/domain/errors.rb index c77bf9ce78..f4e1145cc9 100644 --- a/app/domain/errors.rb +++ b/app/domain/errors.rb @@ -219,7 +219,6 @@ module Jwt end module AuthnOidc - IdTokenClaimNotFoundOrEmpty = ::Util::TrackableErrorClass.new( msg: "Claim '{0-claim-name}' not found or empty in ID token. " \ "This claim is defined in the id-token-user-property variable.", @@ -231,16 +230,6 @@ module AuthnOidc code: "CONJ00075E" ) - StateMismatch = ::Util::TrackableErrorClass.new( - msg: "Conjur internal state doesn't match given state", - code: "CONJ00127E" - ) - - TokenVerificationFailed = ::Util::TrackableErrorClass.new( - msg: "Conjur internal state doesn't match given state", - code: "CONJ00128E" - ) - InvalidVariableValue = ::Util::TrackableErrorClass.new( msg: "Parameter {0} with value {1} invalid", code: "CONJ00129E" @@ -251,6 +240,22 @@ module AuthnOidc code: "CONJ00130E" ) + TokenVerificationFailed = ::Util::TrackableErrorClass.new( + msg: "JWT Token validation failed: '{0-error}'", + code: "CONJ00128E" + ) + + TokenRetrievalFailed = ::Util::TrackableErrorClass.new( + msg: "Access Token retrieval failure: '{0-error}'", + code: "CONJ00133E" + ) + + # TODO - this is related to the feature flag 'pkce_support'. Once + # this feature is permanently added, this error should be removed. + StateMismatch = ::Util::TrackableErrorClass.new( + msg: "Conjur internal state doesn't match given state", + code: "CONJ00127E" + ) end module AuthnIam diff --git a/config/initializers/feature_flags.rb b/config/initializers/feature_flags.rb index 5f0f9f63c8..61e930f18e 100644 --- a/config/initializers/feature_flags.rb +++ b/config/initializers/feature_flags.rb @@ -27,7 +27,15 @@ # If enabled, the Roles API will emit callbacks to extensions for # before/after events when role memberships are added or removed # through the REST API. - roles_api_extensions: false + roles_api_extensions: false, + + # If enabled, the V2 OIDC authenticator will be updated to support PKCE by + # default. This change is backward breaking as it moves State generation to + # the client and requires Nonce and PKCE to be provided to the OIDC Authenticator. + # + # Once the change is made on the UI (which is the intended target), the behavior + # enabled by the flag should be made the default behavior. + pkce_support: false }.freeze config.feature_flags = Conjur::FeatureFlags::Features.new( diff --git a/spec/app/db/repository/authenticator_repository_spec.rb b/spec/app/db/repository/authenticator_repository_spec.rb index e1b50a9eed..4904fef655 100644 --- a/spec/app/db/repository/authenticator_repository_spec.rb +++ b/spec/app/db/repository/authenticator_repository_spec.rb @@ -3,207 +3,221 @@ require 'spec_helper' RSpec.describe('DB::Repository::AuthenticatorRepository') do - let(:resource_repository) { ::Resource } - - let(:repo) do - DB::Repository::AuthenticatorRepository.new( - resource_repository: resource_repository, - data_object: Authentication::AuthnOidc::V2::DataObjects::Authenticator - ) - end - - let(:arguments) { %i[provider_uri client_id client_secret claim_mapping nonce state] } + %w[true false].each do |enabled| + context "with flag #{enabled}" do + with_feature_enabled(:pkce_support) do + let(:data_object) do + if Rails.configuration.feature_flags.enabled?(:pkce_support) + Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator + else + Authentication::AuthnOidc::V2::DataObjects::Authenticator + end + end - describe('#find_all') do - context 'when webservice is not present' do - it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec')).to eq([]) } - end + let(:resource_repository) { ::Resource } - context 'when webservices are presents' do - let(:services) { %i[foo bar] } - before(:each) do - services.each do |service| - ::Role.create( - role_id: "rspec:policy:conjur/authn-oidc/#{service}-abc123" - ) - ::Resource.create( - resource_id: "rspec:webservice:conjur/authn-oidc/#{service}-abc123", - owner_id: "rspec:policy:conjur/authn-oidc/#{service}-abc123" + let(:repo) do + DB::Repository::AuthenticatorRepository.new( + resource_repository: resource_repository, + data_object: data_object ) end - end - context 'variables are not loaded' do - it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec')).to eq([]) } - end + let(:arguments) { %i[provider_uri client_id client_secret claim_mapping nonce state] } - context 'variables are loaded' do - before(:each) do - services.each do |service| - arguments.each do |variable| - ::Resource.create( - resource_id: "rspec:variable:conjur/authn-oidc/#{service}-abc123/#{variable}", - owner_id: "rspec:policy:conjur/authn-oidc/#{service}-abc123" - ) - end + describe('#find_all') do + context 'when webservice is not present' do + it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec')).to eq([]) } end - end - - context 'secrets are not set' do - it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec')).to eq([]) } - end - context 'secrets are set' do - before(:each) do - services.each do |service| - arguments.each do |variable| - ::Secret.create( - resource_id: "rspec:variable:conjur/authn-oidc/#{service}-abc123/#{variable}", - value: "#{variable}-abc123" + context 'when webservices are presents' do + let(:services) { %i[foo bar] } + before(:each) do + services.each do |service| + ::Role.create( + role_id: "rspec:policy:conjur/authn-oidc/#{service}-abc123" + ) + ::Resource.create( + resource_id: "rspec:webservice:conjur/authn-oidc/#{service}-abc123", + owner_id: "rspec:policy:conjur/authn-oidc/#{service}-abc123" ) end end - end - let(:authenticators) { repo.find_all(type: 'authn-oidc', account: 'rspec') } + context 'variables are not loaded' do + it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec')).to eq([]) } + end - it { expect(authenticators.length).to eq(2) } - it { expect(authenticators.first).to be_kind_of(Authentication::AuthnOidc::V2::DataObjects::Authenticator) } - it { expect(authenticators.last).to be_kind_of(Authentication::AuthnOidc::V2::DataObjects::Authenticator) } + context 'variables are loaded' do + before(:each) do + services.each do |service| + arguments.each do |variable| + ::Resource.create( + resource_id: "rspec:variable:conjur/authn-oidc/#{service}-abc123/#{variable}", + owner_id: "rspec:policy:conjur/authn-oidc/#{service}-abc123" + ) + end + end + end - context 'filters invalid authenticators' do - before(:each) do - ::Role.create( - role_id: "rspec:policy:conjur/authn-oidc/baz-abc123" - ) - ::Resource.create( - resource_id: "rspec:webservice:conjur/authn-oidc/baz-abc123", - owner_id: "rspec:policy:conjur/authn-oidc/baz-abc123" - ) - end + context 'secrets are not set' do + it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec')).to eq([]) } + end - it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec').length).to eq(2) } + context 'secrets are set' do + before(:each) do + services.each do |service| + arguments.each do |variable| + ::Secret.create( + resource_id: "rspec:variable:conjur/authn-oidc/#{service}-abc123/#{variable}", + value: "#{variable}-abc123" + ) + end + end + end + + let(:authenticators) { repo.find_all(type: 'authn-oidc', account: 'rspec') } + + it { expect(authenticators.length).to eq(2) } + it { expect(authenticators.first).to be_kind_of(data_object) } + it { expect(authenticators.last).to be_kind_of(data_object) } + + context 'filters invalid authenticators' do + before(:each) do + ::Role.create( + role_id: "rspec:policy:conjur/authn-oidc/baz-abc123" + ) + ::Resource.create( + resource_id: "rspec:webservice:conjur/authn-oidc/baz-abc123", + owner_id: "rspec:policy:conjur/authn-oidc/baz-abc123" + ) + end + + it { expect(repo.find_all(type: 'authn-oidc', account: 'rspec').length).to eq(2) } + + after(:each) do + ::Resource['rspec:webservice:conjur/authn-oidc/baz-abc123'].destroy + ::Role['rspec:policy:conjur/authn-oidc/baz-abc123'].destroy + end + end + end + + after(:each) do + services.each do |service| + arguments.each do |variable| + ::Resource["rspec:variable:conjur/authn-oidc/#{service}-abc123/#{variable}"].destroy + end + end + end + end after(:each) do - ::Resource['rspec:webservice:conjur/authn-oidc/baz-abc123'].destroy - ::Role['rspec:policy:conjur/authn-oidc/baz-abc123'].destroy + services.each do |service| + ::Resource["rspec:webservice:conjur/authn-oidc/#{service}-abc123"].destroy + ::Role["rspec:policy:conjur/authn-oidc/#{service}-abc123"].destroy + end end + end end - after(:each) do - services.each do |service| - arguments.each do |variable| - ::Resource["rspec:variable:conjur/authn-oidc/#{service}-abc123/#{variable}"].destroy - end + describe('#find') do + context 'when webservice is not present' do + it { expect(repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be(nil) } end - end - end - after(:each) do - services.each do |service| - ::Resource["rspec:webservice:conjur/authn-oidc/#{service}-abc123"].destroy - ::Role["rspec:policy:conjur/authn-oidc/#{service}-abc123"].destroy - end - end + context 'when webservice is present' do + before(:each) do + ::Role.create( + role_id: "rspec:policy:conjur/authn-oidc/abc123" + ) + ::Resource.create( + resource_id: "rspec:webservice:conjur/authn-oidc/abc123", + owner_id: "rspec:policy:conjur/authn-oidc/abc123" + ) + end - end - end + context 'when no variables are set' do + it { expect(repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be(nil) } + end - describe('#find') do - context 'when webservice is not present' do - it { expect(repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be(nil) } - end + context 'when all variables are present' do + before(:each) do + arguments.each do |variable| + ::Resource.create( + resource_id: "rspec:variable:conjur/authn-oidc/abc123/#{variable}", + owner_id: "rspec:policy:conjur/authn-oidc/abc123" + ) + end + end - context 'when webservice is present' do - before(:each) do - ::Role.create( - role_id: "rspec:policy:conjur/authn-oidc/abc123" - ) - ::Resource.create( - resource_id: "rspec:webservice:conjur/authn-oidc/abc123", - owner_id: "rspec:policy:conjur/authn-oidc/abc123" - ) - end + context 'are empty' do + it { expect(repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be(nil) } + end - context 'when no variables are set' do - it { expect(repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be(nil) } - end + context 'are set' do + before(:each) do + arguments.each do |variable| + ::Secret.create( + resource_id: "rspec:variable:conjur/authn-oidc/abc123/#{variable}", + value: "#{variable}-abc123" + ) + end + end + + let(:authenticator) { repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123') } + + it { expect(authenticator).to be_truthy } + it { expect(authenticator).to be_kind_of(data_object) } + it { expect(authenticator.account).to eq('rspec') } + it { expect(authenticator.service_id).to eq('abc123') } + end - context 'when all variables are present' do - before(:each) do - arguments.each do |variable| - ::Resource.create( - resource_id: "rspec:variable:conjur/authn-oidc/abc123/#{variable}", - owner_id: "rspec:policy:conjur/authn-oidc/abc123" - ) - end - end + after(:each) do + arguments.each do |variable| + ::Resource["rspec:variable:conjur/authn-oidc/abc123/#{variable}"].destroy + end + end + end - context 'are empty' do - it { expect(repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be(nil) } + after(:each) do + ::Resource['rspec:webservice:conjur/authn-oidc/abc123'].destroy + ::Role['rspec:policy:conjur/authn-oidc/abc123'].destroy + end + end end - context 'are set' do - before(:each) do - arguments.each do |variable| - ::Secret.create( - resource_id: "rspec:variable:conjur/authn-oidc/abc123/#{variable}", - value: "#{variable}-abc123" + describe('#exists?') do + context 'when webservice is present' do + before(:context) do + ::Role.create( + role_id: "rspec:policy:conjur/authn-oidc/abc123" + ) + ::Resource.create( + resource_id: "rspec:webservice:conjur/authn-oidc/abc123", + owner_id: "rspec:policy:conjur/authn-oidc/abc123" ) end - end - let(:authenticator) { repo.find(type: 'authn-oidc', account: 'rspec', service_id: 'abc123') } + it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be_truthy } + it { expect(repo.exists?(type: nil, account: 'rspec', service_id: 'abc123')).to be_falsey } + it { expect(repo.exists?(type: 'authn-oidc', account: nil, service_id: 'abc123')).to be_falsey } + it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: nil)).to be_falsey } - it { expect(authenticator).to be_truthy } - it { expect(authenticator).to be_kind_of(Authentication::AuthnOidc::V2::DataObjects::Authenticator) } - it { expect(authenticator.account).to eq('rspec') } - it { expect(authenticator.service_id).to eq('abc123') } - end + after(:context) do + ::Resource['rspec:webservice:conjur/authn-oidc/abc123'].destroy + ::Role['rspec:policy:conjur/authn-oidc/abc123'].destroy + end + end - after(:each) do - arguments.each do |variable| - ::Resource["rspec:variable:conjur/authn-oidc/abc123/#{variable}"].destroy + context 'when webservice is not present' do + it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be_falsey } + it { expect(repo.exists?(type: nil, account: 'rspec', service_id: 'abc123')).to be_falsey } + it { expect(repo.exists?(type: 'authn-oidc', account: nil, service_id: 'abc123')).to be_falsey } + it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: nil)).to be_falsey } end end end - - after(:each) do - ::Resource['rspec:webservice:conjur/authn-oidc/abc123'].destroy - ::Role['rspec:policy:conjur/authn-oidc/abc123'].destroy - end - end - end - - describe('#exists?') do - context 'when webservice is present' do - before(:context) do - ::Role.create( - role_id: "rspec:policy:conjur/authn-oidc/abc123" - ) - ::Resource.create( - resource_id: "rspec:webservice:conjur/authn-oidc/abc123", - owner_id: "rspec:policy:conjur/authn-oidc/abc123" - ) - end - - it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be_truthy } - it { expect(repo.exists?(type: nil, account: 'rspec', service_id: 'abc123')).to be_falsey } - it { expect(repo.exists?(type: 'authn-oidc', account: nil, service_id: 'abc123')).to be_falsey } - it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: nil)).to be_falsey } - - after(:context) do - ::Resource['rspec:webservice:conjur/authn-oidc/abc123'].destroy - ::Role['rspec:policy:conjur/authn-oidc/abc123'].destroy - end - end - - context 'when webservice is not present' do - it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: 'abc123')).to be_falsey } - it { expect(repo.exists?(type: nil, account: 'rspec', service_id: 'abc123')).to be_falsey } - it { expect(repo.exists?(type: 'authn-oidc', account: nil, service_id: 'abc123')).to be_falsey } - it { expect(repo.exists?(type: 'authn-oidc', account: 'rspec', service_id: nil)).to be_falsey } end end end diff --git a/spec/app/domain/authentication/authn-oidc/pkce_support_feature/client_spec.rb b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/client_spec.rb new file mode 100644 index 0000000000..4b3d528cfb --- /dev/null +++ b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/client_spec.rb @@ -0,0 +1,195 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe(Authentication::AuthnOidc::PkceSupportFeature::Client) do + let(:authenticator) do + Authentication::AuthnOidc::PkceSupportFeature::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' + ) + end + + let(:client) do + VCR.use_cassette("authenticators/authn-oidc/pkce_support_feature/client_load") do + client = Authentication::AuthnOidc::PkceSupportFeature::Client.new( + authenticator: authenticator + ) + # The call `oidc_client` queries the OIDC endpoint. As such, + # we need to wrap this in a VCR call. Calling this before + # returning the client to allow this call to be more effectively + # mocked. + client.oidc_client + client + end + end + + describe '.callback' do + context 'when credentials are valid' do + it 'returns a valid JWT token', vcr: 'authenticators/authn-oidc/pkce_support_feature/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( + 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') + end + end + end + + context 'when code verifier does not match' do + it 'raises an error', vcr: 'authenticators/authn-oidc/pkce_support_feature/client_callback-invalid_code_verifier' do + travel_to(Time.parse("2022-10-17 17:23:30 +0000")) do + expect do + client.callback( + code: 'GV48_SF4a19ghvBhVbbSG3Lr8BuFl8PhWVPZSbokV2o', + code_verifier: 'bad-code-verifier', + nonce: '3e6bd5235e4692b37ca1f04cb01b6e0cb177aa20dcef19e89f' + ) + end.to raise_error( + Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + "CONJ00133E Access Token retrieval failure: 'PKCE verification failed'" + ) + end + end + end + + context 'when nonce does not match' do + it 'raises an error', vcr: 'authenticators/authn-oidc/pkce_support_feature/client_callback-valid_oidc_credentials' do + travel_to(Time.parse("2022-09-30 17:02:17 +0000")) do + expect do + client.callback( + code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', + code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', + nonce: 'bad-nonce' + ) + end.to raise_error( + Errors::Authentication::AuthnOidc::TokenVerificationFailed, + "CONJ00128E JWT Token validation failed: 'Provided nonce does not match the nonce in the JWT'" + ) + end + end + end + + context 'when JWT has expired' do + it 'raises an error', vcr: 'authenticators/authn-oidc/pkce_support_feature/client_callback-valid_oidc_credentials' do + travel_to(Time.parse("2022-10-01 17:02:17 +0000")) do + expect do + client.callback( + code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', + code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', + nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' + ) + end.to raise_error( + Errors::Authentication::AuthnOidc::TokenVerificationFailed, + "CONJ00128E JWT Token validation failed: 'JWT has expired'" + ) + end + end + end + + context 'when code has previously been used' do + it 'raise an exception', vcr: 'authenticators/authn-oidc/pkce_support_feature/client_callback-used_code-valid_oidc_credentials' do + expect do + client.callback( + code: '-QGREc_SONbbJIKdbpyYudA13c9PZlgqdxowkf45LOw', + code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', + nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' + ) + end.to raise_error( + Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + "CONJ00133E Access Token retrieval failure: 'Authorization code is invalid or has expired'" + ) + end + end + + context 'when code has expired', vcr: 'authenticators/authn-oidc/pkce_support_feature/client_callback-expired_code-valid_oidc_credentials' do + it 'raise an exception' do + expect do + client.callback( + code: 'SNSPeiQJ0-D6nUHTg-Ht9ZoDxIaaWBB80pnYuXY2VxU', + code_verifier: 'c1de7f1251849accd99d4839d79a637561b1181b909ed7dc1d', + nonce: '7efcbba36a9b96fdb5285a159665c3d382abd8b6b3288fcc8d' + ) + end.to raise_error( + Errors::Authentication::AuthnOidc::TokenRetrievalFailed, + "CONJ00133E Access Token retrieval failure: 'Authorization code is invalid or has expired'" + ) + end + end + end + + describe '.oidc_client' do + context 'when credentials are valid' do + it 'returns a valid oidc client', vcr: 'authenticators/authn-oidc/pkce_support_feature/client_initialization' do + oidc_client = client.oidc_client + + expect(oidc_client).to be_a_kind_of(OpenIDConnect::Client) + expect(oidc_client.identifier).to eq('0oa3w3xig6rHiu9yT5d7') + expect(oidc_client.secret).to eq('e349BMTTIpLO-rPuPqLLkLyH_pO-loUzhIVJCrHj') + expect(oidc_client.redirect_uri).to eq('http://localhost:3000/authn-oidc/okta-2/cucumber/authenticate') + expect(oidc_client.scheme).to eq('https') + expect(oidc_client.host).to eq('dev-92899796.okta.com') + expect(oidc_client.port).to eq(443) + expect(oidc_client.authorization_endpoint).to eq('/oauth2/default/v1/authorize') + expect(oidc_client.token_endpoint).to eq('/oauth2/default/v1/token') + expect(oidc_client.userinfo_endpoint).to eq('/oauth2/default/v1/userinfo') + end + end + end + + describe '.discovery_information', vcr: 'authenticators/authn-oidc/pkce_support_feature/discovery_endpoint-valid_oidc_credentials' do + context 'when credentials are valid' do + it 'endpoint returns valid data' do + discovery_information = client.discovery_information(invalidate: true) + + expect(discovery_information.authorization_endpoint).to eq( + 'https://dev-92899796.okta.com/oauth2/default/v1/authorize' + ) + expect(discovery_information.token_endpoint).to eq( + 'https://dev-92899796.okta.com/oauth2/default/v1/token' + ) + expect(discovery_information.userinfo_endpoint).to eq( + 'https://dev-92899796.okta.com/oauth2/default/v1/userinfo' + ) + expect(discovery_information.jwks_uri).to eq( + 'https://dev-92899796.okta.com/oauth2/default/v1/keys' + ) + expect(discovery_information.end_session_endpoint).to eq( + 'https://dev-92899796.okta.com/oauth2/default/v1/logout' + ) + end + end + + context 'when provider URI is invalid', vcr: 'authenticators/authn-oidc/pkce_support_feature/discovery_endpoint-invalid_oidc_provider' do + it 'returns an timeout error' do + client = Authentication::AuthnOidc::PkceSupportFeature::Client.new( + authenticator: Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator.new( + provider_uri: 'https://foo.bar1234321.com', + 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' + ) + ) + + expect{client.discovery_information(invalidate: true)}.to raise_error( + Errors::Authentication::OAuth::ProviderDiscoveryFailed + ) + end + end + end +end diff --git a/spec/app/domain/authentication/authn-oidc/pkce_support_feature/data_objects/authenticator.rb b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/data_objects/authenticator.rb new file mode 100644 index 0000000000..f499c588c3 --- /dev/null +++ b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/data_objects/authenticator.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe('Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator') do + let(:default_args) do + { + provider_uri: 'https://foo.bar.com/baz', + client_id: 'client-id-123', + client_secret: 'client-secret-123', + claim_mapping: 'email', + account: 'default', + service_id: 'my-authenticator' + } + end + let(:args) { default_args } + + let(:authenticator) { Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator.new(**args) } + + describe '.scope' do + context 'with default initializer' do + it { expect(authenticator.scope).to eq('openid email profile') } + end + + context 'when initialized with a string argument' do + let(:args) { default_args.merge({ provider_scope: 'foo' }) } + it { expect(authenticator.scope).to eq('openid email profile foo') } + end + + context 'when initialized with a non-string argument' do + let(:args) { default_args.merge({ provider_scope: 1 }) } + it { expect(authenticator.scope).to eq('openid email profile 1') } + end + + context 'when initialized with a duplicated argument' do + let(:args) { default_args.merge({ provider_scope: 'profile' }) } + it { expect(authenticator.scope).to eq('openid email profile') } + end + + context 'when initialized with an array argument' do + context 'single value array' do + let(:args) { default_args.merge({ provider_scope: 'foo' }) } + it { expect(authenticator.scope).to eq('openid email profile foo') } + end + + context 'multi-value array' do + let(:args) { default_args.merge({ provider_scope: 'foo bar' }) } + it { expect(authenticator.scope).to eq('openid email profile foo bar') } + end + end + end + + describe '.name' do + context 'when name is missing' do + it { expect(authenticator.name).to eq('My Authenticator') } + end + context 'when name is present' do + let(:args) { default_args.merge(name: 'foo') } + it { expect(authenticator.name).to eq('foo') } + end + end + + describe '.resource_id' do + context 'correctly renders' do + it { expect(authenticator.resource_id).to eq('default:webservice:conjur/authn-oidc/my-authenticator') } + end + end + + describe '.response_type' do + context 'with default initializer' do + it { expect(authenticator.response_type).to eq('code') } + end + end +end diff --git a/spec/app/domain/authentication/authn-oidc/pkce_support_feature/resolve_identity_spec.rb b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/resolve_identity_spec.rb new file mode 100644 index 0000000000..83943542fb --- /dev/null +++ b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/resolve_identity_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe(' Authentication::AuthnOidc::PkceSupportFeature::ResolveIdentity') do + let(:resolve_identity) do + Authentication::AuthnOidc::PkceSupportFeature::ResolveIdentity.new + end + + describe('#call') do + let(:valid_role) do + instance_double(::Role).tap do |double| + allow(double).to receive(:id).and_return('rspec:user:alice') + allow(double).to receive(:resource?).and_return(true) + end + end + + context 'when identity matches a role ID' do + it 'returns the matching role' do + expect( + resolve_identity.call( + account: 'rspec', + identity: 'alice', + allowed_roles: [ valid_role ] + ).id + ).to eq('rspec:user:alice') + end + + context 'when it includes roles without resources' do + it 'returns the matching role' do + expect( + resolve_identity.call( + account: 'rspec', + identity: 'alice', + allowed_roles: [ + instance_double(::Role).tap do |double| + allow(double).to receive(:id).and_return('rspec:user:alice') + allow(double).to receive(:resource?).and_return(false) + end, + valid_role + ] + ).id + ).to eq('rspec:user:alice') + end + end + + context 'when the accounts are different' do + it 'returns the matching role' do + expect( + resolve_identity.call( + account: 'rspec', + identity: 'alice', + allowed_roles: [ + instance_double(::Role).tap do |double| + allow(double).to receive(:id).and_return('foo:user:alice') + allow(double).to receive(:resource?).and_return(true) + end, + valid_role + ] + ).id + ).to eq('rspec:user:alice') + end + end + end + + context 'when the provided identity does not match a role or annotation' do + it 'raises the error RoleNotFound' do + expect { + resolve_identity.call( + account: 'rspec', + identity: 'alice', + allowed_roles: [ + instance_double(::Role).tap do |double| + allow(double).to receive(:id).and_return('rspec:user:bob') + allow(double).to receive(:resource?).and_return(true) + end, + instance_double(::Role).tap do |double| + allow(double).to receive(:id).and_return('rspec:user:chad') + allow(double).to receive(:resource?).and_return(true) + allow(double).to receive(:resource).and_return( + instance_double(::Resource).tap do |resource| + allow(resource).to receive(:annotation).with('authn-oidc/identity').and_return('chad.example') + end + ) + end + ] + ) + }.to raise_error( + Errors::Authentication::Security::RoleNotFound, + /CONJ00007E 'alice' not found/ + ) + end + end + + end +end diff --git a/spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_rspec.rb b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_rspec.rb new file mode 100644 index 0000000000..62040a41bf --- /dev/null +++ b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_rspec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe(' Authentication::AuthnOidc::PkceSupportFeature::Strategy') do + + let(:jwt) { double(raw_attributes: { claim_mapping: "alice" }) } + + let(:authenticator) do + Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator.new( + account: "cucumber", + service_id: "foo", + redirect_uri: "http://conjur/authn-oidc/cucumber/authenticate", + provider_uri: "http://test", + name: "foo", + client_id: "ConjurClient", + client_secret: 'client_secret', + claim_mapping: mapping + ) + end + + let(:client) do + class_double(::Authentication::AuthnOidc::PkceSupportFeature::Client).tap do |double| + allow(double).to receive(:new).and_return(current_client) + end + end + + let(:current_client) do + instance_double(::Authentication::AuthnOidc::PkceSupportFeature::Client).tap do |double| + allow(double).to receive(:callback).and_return(jwt) + end + end + + let(:strategy) do + Authentication::AuthnOidc::PkceSupportFeature::Strategy.new( + authenticator: authenticator, + client: client + ) + end + + describe('#callback') 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') + end + end + + context "when the claiming matching in the token doesn't match the jwt" do + let(:mapping) { 'wrong_mapping' } + it 'raises a `IdTokenClaimNotFoundOrEmpty` error' do + expect { strategy.callback(code: 'code', nonce: 'nonce', code_verifier: 'foo') } + .to raise_error(Errors::Authentication::AuthnOidc::IdTokenClaimNotFoundOrEmpty) + end + end + + context 'when required parameters are missing' do + let(:mapping) { '' } + context 'when code is missing' do + it 'raises a `MissingRequestParam` error' do + expect { strategy.callback(nonce: 'nonce', code_verifier: 'foo') } + .to raise_error(Errors::Authentication::RequestBody::MissingRequestParam) + end + end + context 'when nonce is missing' do + it 'raises a `MissingRequestParam` error' do + expect { strategy.callback(code: 'code', code_verifier: 'foo') } + .to raise_error(Errors::Authentication::RequestBody::MissingRequestParam) + end + end + context 'when code_verifier is missing' do + it 'raises a `MissingRequestParam` error' do + expect { strategy.callback(nonce: 'nonce', code: 'code') } + .to raise_error(Errors::Authentication::RequestBody::MissingRequestParam) + end + end + end + end +end diff --git a/spec/app/domain/authentication/authn-oidc/pkce_support_feature/views/providor_context_spec.rb b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/views/providor_context_spec.rb new file mode 100644 index 0000000000..f499c588c3 --- /dev/null +++ b/spec/app/domain/authentication/authn-oidc/pkce_support_feature/views/providor_context_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe('Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator') do + let(:default_args) do + { + provider_uri: 'https://foo.bar.com/baz', + client_id: 'client-id-123', + client_secret: 'client-secret-123', + claim_mapping: 'email', + account: 'default', + service_id: 'my-authenticator' + } + end + let(:args) { default_args } + + let(:authenticator) { Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator.new(**args) } + + describe '.scope' do + context 'with default initializer' do + it { expect(authenticator.scope).to eq('openid email profile') } + end + + context 'when initialized with a string argument' do + let(:args) { default_args.merge({ provider_scope: 'foo' }) } + it { expect(authenticator.scope).to eq('openid email profile foo') } + end + + context 'when initialized with a non-string argument' do + let(:args) { default_args.merge({ provider_scope: 1 }) } + it { expect(authenticator.scope).to eq('openid email profile 1') } + end + + context 'when initialized with a duplicated argument' do + let(:args) { default_args.merge({ provider_scope: 'profile' }) } + it { expect(authenticator.scope).to eq('openid email profile') } + end + + context 'when initialized with an array argument' do + context 'single value array' do + let(:args) { default_args.merge({ provider_scope: 'foo' }) } + it { expect(authenticator.scope).to eq('openid email profile foo') } + end + + context 'multi-value array' do + let(:args) { default_args.merge({ provider_scope: 'foo bar' }) } + it { expect(authenticator.scope).to eq('openid email profile foo bar') } + end + end + end + + describe '.name' do + context 'when name is missing' do + it { expect(authenticator.name).to eq('My Authenticator') } + end + context 'when name is present' do + let(:args) { default_args.merge(name: 'foo') } + it { expect(authenticator.name).to eq('foo') } + end + end + + describe '.resource_id' do + context 'correctly renders' do + it { expect(authenticator.resource_id).to eq('default:webservice:conjur/authn-oidc/my-authenticator') } + end + end + + describe '.response_type' do + context 'with default initializer' do + it { expect(authenticator.response_type).to eq('code') } + end + end +end diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-expired_code-valid_oidc_credentials.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-expired_code-valid_oidc_credentials.yml new file mode 100644 index 0000000000..68c08d72ab --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-expired_code-valid_oidc_credentials.yml @@ -0,0 +1,100 @@ +--- +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=SNSPeiQJ0-D6nUHTg-Ht9ZoDxIaaWBB80pnYuXY2VxU&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:19:21 GMT + Authorization: + - Basic MG9hM3czeGlnNnJIaXU5eVQ1ZDc6ZTM0OUJNVFRJcExPLXJQdVBxTExrTHlIX3BPLWxvVXpoSVZKQ3JIag== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 400 + message: Bad Request + headers: + Date: + - Fri, 30 Sep 2022 17:19:22 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: + - YzclGT9F51eImbj6lTlN0AAACl4 + 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-8XxNsgGJ7tleqCeom6XuCfv4ASDp8xU7hm86MEgqU-0'' + ''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: + - '1664558421' + 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=8B02BEDFF41B92741E6EEBB6CA0B2D80; 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 authorization code + is invalid or has expired."}' + recorded_at: Fri, 30 Sep 2022 17:19:22 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-invalid_code_verifier.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-invalid_code_verifier.yml new file mode 100644 index 0000000000..779411772a --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-invalid_code_verifier.yml @@ -0,0 +1,86 @@ +--- +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=GV48_SF4a19ghvBhVbbSG3Lr8BuFl8PhWVPZSbokV2o&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthn-oidc%2Fokta-2%2Fcucumber%2Fauthenticate&scope=true&nonce=3e6bd5235e4692b37ca1f04cb01b6e0cb177aa20dcef19e89f&code_verifier=bad-code-verifier + headers: + User-Agent: + - Rack::OAuth2 (1.19.0) (2.8.3, ruby 3.0.4 (2022-04-12)) + Accept: + - "*/*" + Date: + - Mon, 17 Oct 2022 17:23:30 GMT + Authorization: + - Basic MG9hM3czeGlnNnJIaXU5eVQ1ZDc6ZTM0OUJNVFRJcExPLXJQdVBxTExrTHlIX3BPLWxvVXpoSVZKQ3JIag== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 400 + message: Bad Request + headers: + Date: + - Mon, 17 Oct 2022 17:24: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: + - Y02Pw8hcjYzIfnEoK4T9AAAACQU + 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''; report-uri https://okta.report-uri.com/r/d/csp/enforce; + report-to csp' + X-Rate-Limit-Limit: + - '300' + X-Rate-Limit-Remaining: + - '299' + X-Rate-Limit-Reset: + - '1666027519' + 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=9ABDA66E3EA85BE59AB6233C8DC28B7F; 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":"PKCE verification failed."}' + recorded_at: Mon, 17 Oct 2022 17:23:30 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-used_code-valid_oidc_credentials.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-used_code-valid_oidc_credentials.yml new file mode 100644 index 0000000000..2a3cc5d4b2 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-used_code-valid_oidc_credentials.yml @@ -0,0 +1,100 @@ +--- +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:18:17 GMT + Authorization: + - Basic MG9hM3czeGlnNnJIaXU5eVQ1ZDc6ZTM0OUJNVFRJcExPLXJQdVBxTExrTHlIX3BPLWxvVXpoSVZKQ3JIag== + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 400 + message: Bad Request + headers: + Date: + - Fri, 30 Sep 2022 17:18:18 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: + - Yzck2nN7s2AQGePZY8c2gQAAB94 + 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-ZUSAcrGWJJO_LGxCGbys2QL4CSrTAzGBje02qK26sdc'' + ''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: + - '1664558358' + 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=69068D777A11001AB7E7539E934C9A20; 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 authorization code + is invalid or has expired."}' + recorded_at: Fri, 30 Sep 2022 17:18:18 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-valid_oidc_credentials.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-valid_oidc_credentials.yml new file mode 100644 index 0000000000..d0df4e7d8c --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_callback-valid_oidc_credentials.yml @@ -0,0 +1,170 @@ +--- +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","scope":"email + profile openid","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/pkce_support_feature/client_initialization.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_initialization.yml new file mode 100644 index 0000000000..3080a4f574 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_initialization.yml @@ -0,0 +1,348 @@ +--- +http_interactions: +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 06 Oct 2022 22:13:54 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 06 Oct 2022 22:13:55 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=86400, must-revalidate + Expires: + - Fri, 07 Oct 2022 22:13:55 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yz9TI_MTaB3_WDnGc1HzWAAADII + body: + encoding: UTF-8 + 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: Thu, 06 Oct 2022 22:13:55 GMT +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 06 Oct 2022 22:13:55 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 06 Oct 2022 22:13:56 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=86400, must-revalidate + Expires: + - Fri, 07 Oct 2022 22:13:56 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yz9TJACEb_A1PbEeXb-UlAAACpI + body: + encoding: UTF-8 + 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: Thu, 06 Oct 2022 22:13:56 GMT +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 06 Oct 2022 22:13:56 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 06 Oct 2022 22:13:56 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=86400, must-revalidate + Expires: + - Fri, 07 Oct 2022 22:13:56 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yz9TJJEklkO44lgEvnjWdwAABHI + body: + encoding: UTF-8 + 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: Thu, 06 Oct 2022 22:13:56 GMT +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 06 Oct 2022 22:13:56 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 06 Oct 2022 22:13:57 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=86400, must-revalidate + Expires: + - Fri, 07 Oct 2022 22:13:55 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yz9TJdnAqVMcaT4YlT5ioQAAADM + body: + encoding: UTF-8 + 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: Thu, 06 Oct 2022 22:13:57 GMT +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 06 Oct 2022 22:13:57 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 06 Oct 2022 22:13:57 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=86400, must-revalidate + Expires: + - Fri, 07 Oct 2022 22:13:56 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yz9TJf0JGaDLjG0YjGuzMQAADco + body: + encoding: UTF-8 + 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: Thu, 06 Oct 2022 22:13:57 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_load.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_load.yml new file mode 100644 index 0000000000..dbf9497344 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/client_load.yml @@ -0,0 +1,72 @@ +--- +http_interactions: +- request: + method: get + uri: https://dev-92899796.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: + - Sat, 01 Oct 2022 17:02:17 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 07 Oct 2022 21:10:51 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=86400, must-revalidate + Expires: + - Sat, 08 Oct 2022 21:10:51 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Y0CV2zAVa-KLmseiKVuYoQAABrc + body: + encoding: UTF-8 + 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 +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/discovery_endpoint-valid_oidc_credentials.yml b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/discovery_endpoint-valid_oidc_credentials.yml new file mode 100644 index 0000000000..638c583e19 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/authenticators/authn-oidc/pkce_support_feature/discovery_endpoint-valid_oidc_credentials.yml @@ -0,0 +1,137 @@ +--- +http_interactions: +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 30 Jun 2022 20:53:10 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Jun 2022 20:53:10 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 + 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; + 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 + 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=86400, must-revalidate + Expires: + - Tue, 12 Jul 2022 16:31:08 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - YsxQTEzo3y4Lo9fSGY_LawAABPE + body: + encoding: UTF-8 + 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: Thu, 30 Jun 2022 20:53:10 GMT +- request: + method: get + uri: https://dev-92899796.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: + - Thu, 30 Jun 2022 20:53:10 GMT + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Jun 2022 20:53:11 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 + 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; + 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 + 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=86400, must-revalidate + Expires: + - Fri, 01 Jul 2022 20:53:11 GMT + Vary: + - Origin + X-Content-Type-Options: + - nosniff + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + X-Okta-Request-Id: + - Yr4NN7wdOzHatG786KpGLQAACUY + body: + encoding: UTF-8 + 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: Thu, 30 Jun 2022 20:53:11 GMT +recorded_with: VCR 6.1.0