diff --git a/README.md b/README.md index e59b6c4f..64768e7e 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,30 @@ Rails.application.config.middleware.use OmniAuth::Builder do end ``` +### For development with self-signed certificates + +**WARNING**: Only use this in development/testing environments, never in production! + +```ruby +Rails.application.config.middleware.use OmniAuth::Builder do + provider :openid_connect, { + name: :my_provider, + scope: [:openid, :email, :profile, :address], + response_type: :code, + uid_field: "preferred_username", + client_options: { + port: 8443, + scheme: "https", + host: "myprovider.local", + identifier: ENV["OP_CLIENT_ID"], + secret: ENV["OP_SECRET_KEY"], + redirect_uri: "http://myapp.com/users/auth/openid_connect/callback", + ssl_verify: false # Disable SSL certificate verification for self-signed certs + }, + } +end +``` + ### with Devise ```ruby Devise.setup do |config| @@ -115,6 +139,7 @@ These are the configuration options for the client_options hash of the configura | userinfo_endpoint | The user info endpoint on the authorization server | /userinfo | yes | | jwks_uri | The jwks_uri on the authorization server | /jwk | yes | | end_session_endpoint | The url to call to log the user out at the authorization server | nil | yes | +| ssl_verify | Control SSL certificate verification (set to false for self-signed certificates) | true | | ### Additional Configuration Notes * `name` is arbitrary, I recommend using the name of your provider. The name @@ -147,6 +172,10 @@ These are the configuration options for the client_options hash of the configura this is not in the protocol specifications. In those cases, the `send_scope_to_token_endpoint` property can be used to add the attribute to the token request. Initial value is `true`, which means that the scope attribute is included by default. + * The `ssl_verify` option can be set to `false` to disable SSL certificate verification when using self-signed + certificates in development or testing environments. **WARNING**: This should **NEVER** be used in production + as it disables certificate verification and makes your application vulnerable to man-in-the-middle attacks. + Always use properly signed certificates in production environments. ## Additional notes * In some cases, you may want to go straight to the callback phase - e.g. when requested by a stateless client, like a mobile app. diff --git a/lib/omniauth/strategies/openid_connect.rb b/lib/omniauth/strategies/openid_connect.rb index 73dd0fe0..da919d4f 100644 --- a/lib/omniauth/strategies/openid_connect.rb +++ b/lib/omniauth/strategies/openid_connect.rb @@ -33,7 +33,8 @@ class OpenIDConnect # rubocop:disable Metrics/ClassLength token_endpoint: '/token', userinfo_endpoint: '/userinfo', jwks_uri: '/jwk', - end_session_endpoint: nil) + end_session_endpoint: nil, + ssl_verify: true) option :issuer option :discovery, false @@ -106,10 +107,12 @@ def uid end def client + configure_ssl_verification @client ||= ::OpenIDConnect::Client.new(client_options) end def config + configure_ssl_verification @config ||= ::OpenIDConnect::Discovery::Provider::Config.discover!(options.issuer) end @@ -234,6 +237,20 @@ def pkce_authorize_params(verifier) private + def configure_ssl_verification + return if @ssl_configured + + # Configure SSL verification for the Faraday connection used by openid_connect gem + # This affects discovery, jwks_uri fetching, and token endpoint requests + unless client_options.ssl_verify + ::OpenIDConnect.http_config do |config| + config.ssl.verify = false + end + end + + @ssl_configured = true + end + def fetch_key @fetch_key ||= parse_jwk_key(::OpenIDConnect.http_client.get(client_options.jwks_uri).body) end diff --git a/test/lib/omniauth/strategies/openid_connect_test.rb b/test/lib/omniauth/strategies/openid_connect_test.rb index dfc519ee..9136dff8 100644 --- a/test/lib/omniauth/strategies/openid_connect_test.rb +++ b/test/lib/omniauth/strategies/openid_connect_test.rb @@ -971,6 +971,23 @@ def test_option_pkce assert(strategy.authorize_uri =~ /#{Regexp.quote(strategy.options.pkce_verifier.call)}/, 'URI must contain code challenge value') end + + def test_ssl_verify_defaults_to_true + assert_equal true, strategy.options.client_options.ssl_verify + end + + def test_ssl_verify_can_be_disabled + strategy.options.client_options.ssl_verify = false + + # Mock the OpenIDConnect http_config to verify it's called with Faraday API + ::OpenIDConnect.stubs(:http_config).yields(mock_http_config = mock('http_config')) + mock_ssl = mock('ssl') + mock_http_config.stubs(:ssl).returns(mock_ssl) + mock_ssl.expects(:verify=).with(false) + + # Trigger SSL configuration by accessing client + strategy.client + end end end end