omniauth-oauth_oidc 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/config/rubocop_linter_action.yml +59 -0
- data/.github/stale.yml +17 -0
- data/.github/workflows/rubocop.yml +22 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +58 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +47 -0
- data/Gemfile +4 -0
- data/Guardfile +16 -0
- data/LICENSE.txt +22 -0
- data/README.md +130 -0
- data/Rakefile +10 -0
- data/lib/omniauth/openid_connect/errors.rb +9 -0
- data/lib/omniauth/openid_connect/version.rb +7 -0
- data/lib/omniauth/openid_connect.rb +5 -0
- data/lib/omniauth/strategies/openid_connect.rb +398 -0
- data/lib/omniauth_openid_connect.rb +3 -0
- data/omniauth-oauth_oidc.gemspec +35 -0
- data/omniauth_openid_connect.gemspec +35 -0
- data/test/fixtures/id_token.txt +1 -0
- data/test/fixtures/jwks.json +8 -0
- data/test/fixtures/test.crt +19 -0
- data/test/lib/omniauth/strategies/openid_connect_test.rb +657 -0
- data/test/strategy_test_case.rb +51 -0
- data/test/test_helper.rb +16 -0
- metadata +260 -0
| @@ -0,0 +1,398 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'addressable/uri'
         | 
| 4 | 
            +
            require 'timeout'
         | 
| 5 | 
            +
            require 'net/http'
         | 
| 6 | 
            +
            require 'open-uri'
         | 
| 7 | 
            +
            require 'omniauth'
         | 
| 8 | 
            +
            require 'openid_connect'
         | 
| 9 | 
            +
            require 'forwardable'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            module OmniAuth
         | 
| 12 | 
            +
              module Strategies
         | 
| 13 | 
            +
                class OpenIDConnect
         | 
| 14 | 
            +
                  include OmniAuth::Strategy
         | 
| 15 | 
            +
                  extend Forwardable
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  RESPONSE_TYPE_EXCEPTIONS = {
         | 
| 18 | 
            +
                    'id_token' => { exception_class: OmniAuth::OpenIDConnect::MissingIdTokenError, key: :missing_id_token }.freeze,
         | 
| 19 | 
            +
                    'code' => { exception_class: OmniAuth::OpenIDConnect::MissingCodeError, key: :missing_code }.freeze,
         | 
| 20 | 
            +
                  }.freeze
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def_delegator :request, :params
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  option :name, 'openid_connect'
         | 
| 25 | 
            +
                  option(:client_options, identifier: nil,
         | 
| 26 | 
            +
                                          secret: nil,
         | 
| 27 | 
            +
                                          redirect_uri: nil,
         | 
| 28 | 
            +
                                          scheme: 'https',
         | 
| 29 | 
            +
                                          host: nil,
         | 
| 30 | 
            +
                                          port: 443,
         | 
| 31 | 
            +
                                          authorization_endpoint: '/authorize',
         | 
| 32 | 
            +
                                          token_endpoint: '/token',
         | 
| 33 | 
            +
                                          userinfo_endpoint: '/userinfo',
         | 
| 34 | 
            +
                                          jwks_uri: '/jwk',
         | 
| 35 | 
            +
                                          end_session_endpoint: nil)
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  option :issuer
         | 
| 38 | 
            +
                  option :discovery, false
         | 
| 39 | 
            +
                  option :client_signing_alg
         | 
| 40 | 
            +
                  option :client_jwk_signing_key
         | 
| 41 | 
            +
                  option :client_x509_signing_key
         | 
| 42 | 
            +
                  option :scope, [:openid]
         | 
| 43 | 
            +
                  option :response_type, 'code' # ['code', 'id_token']
         | 
| 44 | 
            +
                  option :state
         | 
| 45 | 
            +
                  option :response_mode # [:query, :fragment, :form_post, :web_message]
         | 
| 46 | 
            +
                  option :display, nil # [:page, :popup, :touch, :wap]
         | 
| 47 | 
            +
                  option :prompt, nil # [:none, :login, :consent, :select_account]
         | 
| 48 | 
            +
                  option :hd, nil
         | 
| 49 | 
            +
                  option :max_age
         | 
| 50 | 
            +
                  option :ui_locales
         | 
| 51 | 
            +
                  option :id_token_hint
         | 
| 52 | 
            +
                  option :acr_values
         | 
| 53 | 
            +
                  option :send_nonce, true
         | 
| 54 | 
            +
                  option :send_scope_to_token_endpoint, true
         | 
| 55 | 
            +
                  option :client_auth_method
         | 
| 56 | 
            +
                  option :post_logout_redirect_uri
         | 
| 57 | 
            +
                  option :extra_authorize_params, {}
         | 
| 58 | 
            +
                  option :uid_field, 'sub'
         | 
| 59 | 
            +
                  option :pkce, false
         | 
| 60 | 
            +
                  option :pkce_verifier, nil
         | 
| 61 | 
            +
                  option :pkce_options, {
         | 
| 62 | 
            +
                    code_challenge: proc { |verifier|
         | 
| 63 | 
            +
                      Base64.urlsafe_encode64(
         | 
| 64 | 
            +
                        Digest::SHA2.digest(verifier),
         | 
| 65 | 
            +
                        padding: false,
         | 
| 66 | 
            +
                        )
         | 
| 67 | 
            +
                    },
         | 
| 68 | 
            +
                    code_challenge_method: "S256",
         | 
| 69 | 
            +
                  }
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def uid
         | 
| 72 | 
            +
                    user_info.raw_attributes[options.uid_field.to_sym] || user_info.sub
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  info do
         | 
| 76 | 
            +
                    {
         | 
| 77 | 
            +
                      name: user_info.name,
         | 
| 78 | 
            +
                      email: user_info.email,
         | 
| 79 | 
            +
                      nickname: user_info.preferred_username,
         | 
| 80 | 
            +
                      first_name: user_info.given_name,
         | 
| 81 | 
            +
                      last_name: user_info.family_name,
         | 
| 82 | 
            +
                      gender: user_info.gender,
         | 
| 83 | 
            +
                      image: user_info.picture,
         | 
| 84 | 
            +
                      phone: user_info.phone_number,
         | 
| 85 | 
            +
                      urls: { website: user_info.website },
         | 
| 86 | 
            +
                    }
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  extra do
         | 
| 90 | 
            +
                    { raw_info: user_info.raw_attributes }
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  credentials do
         | 
| 94 | 
            +
                    {
         | 
| 95 | 
            +
                      id_token: access_token.id_token,
         | 
| 96 | 
            +
                      token: access_token.access_token,
         | 
| 97 | 
            +
                      refresh_token: access_token.refresh_token,
         | 
| 98 | 
            +
                      expires_in: access_token.expires_in,
         | 
| 99 | 
            +
                      scope: access_token.scope,
         | 
| 100 | 
            +
                    }
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  def client
         | 
| 104 | 
            +
                    @client ||= ::OpenIDConnect::Client.new(client_options)
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  def config
         | 
| 108 | 
            +
                    @config ||= ::OpenIDConnect::Discovery::Provider::Config.discover!(options.issuer)
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  def request_phase
         | 
| 112 | 
            +
                    options.issuer = issuer if options.issuer.to_s.empty?
         | 
| 113 | 
            +
                    discover!
         | 
| 114 | 
            +
                    redirect authorize_uri
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  def callback_phase
         | 
| 118 | 
            +
                    error = params['error_reason'] || params['error']
         | 
| 119 | 
            +
                    error_description = params['error_description'] || params['error_reason']
         | 
| 120 | 
            +
                    invalid_state = params['state'].to_s.empty? || params['state'] != stored_state
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    raise CallbackError, error: params['error'], reason: error_description, uri: params['error_uri'] if error
         | 
| 123 | 
            +
                    raise CallbackError, error: :csrf_detected, reason: "Invalid 'state' parameter" if invalid_state
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                    return unless valid_response_type?
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    options.issuer = issuer if options.issuer.nil? || options.issuer.empty?
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                    verify_id_token!(params['id_token']) if configured_response_type == 'id_token'
         | 
| 130 | 
            +
                    discover!
         | 
| 131 | 
            +
                    client.redirect_uri = redirect_uri
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                    return id_token_callback_phase if configured_response_type == 'id_token'
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                    client.authorization_code = authorization_code
         | 
| 136 | 
            +
                    access_token
         | 
| 137 | 
            +
                    super
         | 
| 138 | 
            +
                  rescue CallbackError => e
         | 
| 139 | 
            +
                    fail!(e.error, e)
         | 
| 140 | 
            +
                  rescue ::Rack::OAuth2::Client::Error => e
         | 
| 141 | 
            +
                    fail!(e.response[:error], e)
         | 
| 142 | 
            +
                  rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
         | 
| 143 | 
            +
                    fail!(:timeout, e)
         | 
| 144 | 
            +
                  rescue ::SocketError => e
         | 
| 145 | 
            +
                    fail!(:failed_to_connect, e)
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  def other_phase
         | 
| 149 | 
            +
                    if logout_path_pattern.match?(current_path)
         | 
| 150 | 
            +
                      options.issuer = issuer if options.issuer.to_s.empty?
         | 
| 151 | 
            +
                      discover!
         | 
| 152 | 
            +
                      return redirect(end_session_uri) if end_session_uri
         | 
| 153 | 
            +
                    end
         | 
| 154 | 
            +
                    call_app!
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                  def authorization_code
         | 
| 158 | 
            +
                    params['code']
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                  def end_session_uri
         | 
| 162 | 
            +
                    return unless end_session_endpoint_is_valid?
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                    end_session_uri = URI(client_options.end_session_endpoint)
         | 
| 165 | 
            +
                    end_session_uri.query = encoded_post_logout_redirect_uri
         | 
| 166 | 
            +
                    end_session_uri.to_s
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  def authorize_uri
         | 
| 170 | 
            +
                    client.redirect_uri = redirect_uri
         | 
| 171 | 
            +
                    opts = {
         | 
| 172 | 
            +
                      response_type: options.response_type,
         | 
| 173 | 
            +
                      response_mode: options.response_mode,
         | 
| 174 | 
            +
                      scope: options.scope,
         | 
| 175 | 
            +
                      state: new_state,
         | 
| 176 | 
            +
                      login_hint: params['login_hint'],
         | 
| 177 | 
            +
                      ui_locales: params['ui_locales'],
         | 
| 178 | 
            +
                      claims_locales: params['claims_locales'],
         | 
| 179 | 
            +
                      prompt: options.prompt,
         | 
| 180 | 
            +
                      nonce: (new_nonce if options.send_nonce),
         | 
| 181 | 
            +
                      hd: options.hd,
         | 
| 182 | 
            +
                      acr_values: options.acr_values,
         | 
| 183 | 
            +
                    }
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                    opts.merge!(options.extra_authorize_params) unless options.extra_authorize_params.empty?
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                    if options.pkce
         | 
| 188 | 
            +
                      opts.merge!(pkce_authorize_params)
         | 
| 189 | 
            +
                      session["omniauth.pkce.verifier"] = options.pkce_verifier
         | 
| 190 | 
            +
                    end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                    client.authorization_uri(opts.reject { |_k, v| v.nil? })
         | 
| 193 | 
            +
                  end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                  def public_key
         | 
| 196 | 
            +
                    return config.jwks if options.discovery
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                    key_or_secret
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                  def pkce_authorize_params
         | 
| 202 | 
            +
                    options.pkce_verifier = SecureRandom.hex(64) if options.pkce_verifier.nil?
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    # NOTE: see https://tools.ietf.org/html/rfc7636#appendix-A
         | 
| 205 | 
            +
                    {
         | 
| 206 | 
            +
                      :code_challenge => options.pkce_options[:code_challenge].call(options.pkce_verifier),
         | 
| 207 | 
            +
                      :code_challenge_method => options.pkce_options[:code_challenge_method],
         | 
| 208 | 
            +
                    }
         | 
| 209 | 
            +
                  end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                  def pkce_token_params
         | 
| 212 | 
            +
                    return {} unless options.pkce
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                    {:code_verifier => session.delete("omniauth.pkce.verifier")}
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  private
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                  def issuer
         | 
| 220 | 
            +
                    resource = "#{ client_options.scheme }://#{ client_options.host }"
         | 
| 221 | 
            +
                    resource = "#{ resource }:#{ client_options.port }" if client_options.port
         | 
| 222 | 
            +
                    ::OpenIDConnect::Discovery::Provider.discover!(resource).issuer
         | 
| 223 | 
            +
                  end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                  def discover!
         | 
| 226 | 
            +
                    return unless options.discovery
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                    client_options.authorization_endpoint = config.authorization_endpoint
         | 
| 229 | 
            +
                    client_options.token_endpoint = config.token_endpoint
         | 
| 230 | 
            +
                    client_options.userinfo_endpoint = config.userinfo_endpoint
         | 
| 231 | 
            +
                    client_options.jwks_uri = config.jwks_uri
         | 
| 232 | 
            +
                    client_options.end_session_endpoint = config.end_session_endpoint if config.respond_to?(:end_session_endpoint)
         | 
| 233 | 
            +
                  end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                  def user_info
         | 
| 236 | 
            +
                    return @user_info if @user_info
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                    if access_token.id_token
         | 
| 239 | 
            +
                      decoded = decode_id_token(access_token.id_token).raw_attributes
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                      @user_info = ::OpenIDConnect::ResponseObject::UserInfo.new access_token.userinfo!.raw_attributes.merge(decoded)
         | 
| 242 | 
            +
                    else
         | 
| 243 | 
            +
                      @user_info = access_token.userinfo!
         | 
| 244 | 
            +
                    end
         | 
| 245 | 
            +
                  end
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                  def access_token
         | 
| 248 | 
            +
                    return @access_token if @access_token
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                    @access_token = client.access_token!(
         | 
| 251 | 
            +
                      scope: (options.scope if options.send_scope_to_token_endpoint),
         | 
| 252 | 
            +
                      client_auth_method: options.client_auth_method,
         | 
| 253 | 
            +
                      code_verifier: (session.delete("omniauth.pkce.verifier") if options.pkce)
         | 
| 254 | 
            +
                    )
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                    verify_id_token!(@access_token.id_token) if configured_response_type == 'code'
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                    @access_token
         | 
| 259 | 
            +
                  end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                  def decode_id_token(id_token)
         | 
| 262 | 
            +
                    ::OpenIDConnect::ResponseObject::IdToken.decode(id_token, public_key)
         | 
| 263 | 
            +
                  end
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                  def client_options
         | 
| 266 | 
            +
                    options.client_options
         | 
| 267 | 
            +
                  end
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                  def new_state
         | 
| 270 | 
            +
                    state = if options.state.respond_to?(:call)
         | 
| 271 | 
            +
                              if options.state.arity == 1
         | 
| 272 | 
            +
                                options.state.call(env)
         | 
| 273 | 
            +
                              else
         | 
| 274 | 
            +
                                options.state.call
         | 
| 275 | 
            +
                              end
         | 
| 276 | 
            +
                            end
         | 
| 277 | 
            +
                    session['omniauth.state'] = state || SecureRandom.hex(16)
         | 
| 278 | 
            +
                  end
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                  def stored_state
         | 
| 281 | 
            +
                    session.delete('omniauth.state')
         | 
| 282 | 
            +
                  end
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                  def new_nonce
         | 
| 285 | 
            +
                    session['omniauth.nonce'] = SecureRandom.hex(16)
         | 
| 286 | 
            +
                  end
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                  def stored_nonce
         | 
| 289 | 
            +
                    session.delete('omniauth.nonce')
         | 
| 290 | 
            +
                  end
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                  def session
         | 
| 293 | 
            +
                    return {} if @env.nil?
         | 
| 294 | 
            +
             | 
| 295 | 
            +
                    super
         | 
| 296 | 
            +
                  end
         | 
| 297 | 
            +
             | 
| 298 | 
            +
                  def key_or_secret
         | 
| 299 | 
            +
                    case options.client_signing_alg
         | 
| 300 | 
            +
                    when :HS256, :HS384, :HS512
         | 
| 301 | 
            +
                      client_options.secret
         | 
| 302 | 
            +
                    when :RS256, :RS384, :RS512
         | 
| 303 | 
            +
                      if options.client_jwk_signing_key
         | 
| 304 | 
            +
                        parse_jwk_key(options.client_jwk_signing_key)
         | 
| 305 | 
            +
                      elsif options.client_x509_signing_key
         | 
| 306 | 
            +
                        parse_x509_key(options.client_x509_signing_key)
         | 
| 307 | 
            +
                      end
         | 
| 308 | 
            +
                    end
         | 
| 309 | 
            +
                  end
         | 
| 310 | 
            +
             | 
| 311 | 
            +
                  def parse_x509_key(key)
         | 
| 312 | 
            +
                    OpenSSL::X509::Certificate.new(key).public_key
         | 
| 313 | 
            +
                  end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                  def parse_jwk_key(key)
         | 
| 316 | 
            +
                    json = JSON.parse(key)
         | 
| 317 | 
            +
                    return JSON::JWK::Set.new(json['keys']) if json.key?('keys')
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                    JSON::JWK.new(json)
         | 
| 320 | 
            +
                  end
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                  def decode(str)
         | 
| 323 | 
            +
                    UrlSafeBase64.decode64(str).unpack1('B*').to_i(2).to_s
         | 
| 324 | 
            +
                  end
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                  def redirect_uri
         | 
| 327 | 
            +
                    return client_options.redirect_uri unless params['redirect_uri']
         | 
| 328 | 
            +
             | 
| 329 | 
            +
                    "#{ client_options.redirect_uri }?redirect_uri=#{ CGI.escape(params['redirect_uri']) }"
         | 
| 330 | 
            +
                  end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                  def encoded_post_logout_redirect_uri
         | 
| 333 | 
            +
                    return unless options.post_logout_redirect_uri
         | 
| 334 | 
            +
             | 
| 335 | 
            +
                    URI.encode_www_form(
         | 
| 336 | 
            +
                      post_logout_redirect_uri: options.post_logout_redirect_uri
         | 
| 337 | 
            +
                    )
         | 
| 338 | 
            +
                  end
         | 
| 339 | 
            +
             | 
| 340 | 
            +
                  def end_session_endpoint_is_valid?
         | 
| 341 | 
            +
                    client_options.end_session_endpoint &&
         | 
| 342 | 
            +
                      client_options.end_session_endpoint =~ URI::DEFAULT_PARSER.make_regexp
         | 
| 343 | 
            +
                  end
         | 
| 344 | 
            +
             | 
| 345 | 
            +
                  def logout_path_pattern
         | 
| 346 | 
            +
                    @logout_path_pattern ||= %r{\A#{Regexp.quote(request_path)}(/logout)}
         | 
| 347 | 
            +
                  end
         | 
| 348 | 
            +
             | 
| 349 | 
            +
                  def id_token_callback_phase
         | 
| 350 | 
            +
                    user_data = decode_id_token(params['id_token']).raw_attributes
         | 
| 351 | 
            +
                    env['omniauth.auth'] = AuthHash.new(
         | 
| 352 | 
            +
                      provider: name,
         | 
| 353 | 
            +
                      uid: user_data['sub'],
         | 
| 354 | 
            +
                      info: { name: user_data['name'], email: user_data['email'] },
         | 
| 355 | 
            +
                      extra: { raw_info: user_data }
         | 
| 356 | 
            +
                    )
         | 
| 357 | 
            +
                    call_app!
         | 
| 358 | 
            +
                  end
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                  def valid_response_type?
         | 
| 361 | 
            +
                    return true if params.key?(configured_response_type)
         | 
| 362 | 
            +
             | 
| 363 | 
            +
                    error_attrs = RESPONSE_TYPE_EXCEPTIONS[configured_response_type]
         | 
| 364 | 
            +
                    fail!(error_attrs[:key], error_attrs[:exception_class].new(params['error']))
         | 
| 365 | 
            +
             | 
| 366 | 
            +
                    false
         | 
| 367 | 
            +
                  end
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                  def configured_response_type
         | 
| 370 | 
            +
                    @configured_response_type ||= options.response_type.to_s
         | 
| 371 | 
            +
                  end
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                  def verify_id_token!(id_token)
         | 
| 374 | 
            +
                    return unless id_token
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                    decode_id_token(id_token).verify!(issuer: options.issuer,
         | 
| 377 | 
            +
                                                      client_id: client_options.identifier,
         | 
| 378 | 
            +
                                                      nonce: stored_nonce)
         | 
| 379 | 
            +
                  end
         | 
| 380 | 
            +
             | 
| 381 | 
            +
                  class CallbackError < StandardError
         | 
| 382 | 
            +
                    attr_accessor :error, :error_reason, :error_uri
         | 
| 383 | 
            +
             | 
| 384 | 
            +
                    def initialize(data)
         | 
| 385 | 
            +
                      self.error = data[:error]
         | 
| 386 | 
            +
                      self.error_reason = data[:reason]
         | 
| 387 | 
            +
                      self.error_uri = data[:uri]
         | 
| 388 | 
            +
                    end
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                    def message
         | 
| 391 | 
            +
                      [error, error_reason, error_uri].compact.join(' | ')
         | 
| 392 | 
            +
                    end
         | 
| 393 | 
            +
                  end
         | 
| 394 | 
            +
                end
         | 
| 395 | 
            +
              end
         | 
| 396 | 
            +
            end
         | 
| 397 | 
            +
             | 
| 398 | 
            +
            OmniAuth.config.add_camelization 'openid_connect', 'OpenIDConnect'
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            lib = File.expand_path('lib', __dir__)
         | 
| 4 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 5 | 
            +
            require 'omniauth/openid_connect/version'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Gem::Specification.new do |spec|
         | 
| 8 | 
            +
              spec.name          = 'omniauth-oauth_oidc'
         | 
| 9 | 
            +
              spec.version       = OmniAuth::OpenIDConnect::VERSION
         | 
| 10 | 
            +
              spec.authors       = ['John Bohn', 'Ilya Shcherbinin', 'Dan Jay']
         | 
| 11 | 
            +
              spec.email         = ['jjbohn@gmail.com', 'm0n9oose@gmail.com', 'dan@danjay.co.uk']
         | 
| 12 | 
            +
              spec.summary       = 'OpenID Connect Strategy for OmniAuth'
         | 
| 13 | 
            +
              spec.description   = 'OpenID Connect Strategy for OmniAuth.'
         | 
| 14 | 
            +
              spec.homepage      = 'https://github.com/danjay/omniauth_openid_connect'
         | 
| 15 | 
            +
              spec.license       = 'MIT'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              spec.files         = `git ls-files -z`.split("\x0")
         | 
| 18 | 
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 19 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 20 | 
            +
              spec.require_paths = ['lib']
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              spec.add_dependency 'addressable', '~> 2.5'
         | 
| 23 | 
            +
              spec.add_dependency 'omniauth', '~> 1.9'
         | 
| 24 | 
            +
              spec.add_dependency 'openid_connect', '~> 1.1'
         | 
| 25 | 
            +
              spec.add_development_dependency 'coveralls', '~> 0.8'
         | 
| 26 | 
            +
              spec.add_development_dependency 'faker', '~> 1.6'
         | 
| 27 | 
            +
              spec.add_development_dependency 'guard', '~> 2.14'
         | 
| 28 | 
            +
              spec.add_development_dependency 'guard-bundler', '~> 2.2'
         | 
| 29 | 
            +
              spec.add_development_dependency 'guard-minitest', '~> 2.4'
         | 
| 30 | 
            +
              spec.add_development_dependency 'minitest', '~> 5.1'
         | 
| 31 | 
            +
              spec.add_development_dependency 'mocha', '~> 1.7'
         | 
| 32 | 
            +
              spec.add_development_dependency 'rake', '~> 12.0'
         | 
| 33 | 
            +
              spec.add_development_dependency 'rubocop', '~> 0.63'
         | 
| 34 | 
            +
              spec.add_development_dependency 'simplecov', '~> 0.12'
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            lib = File.expand_path('lib', __dir__)
         | 
| 4 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 5 | 
            +
            require 'omniauth/openid_connect/version'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Gem::Specification.new do |spec|
         | 
| 8 | 
            +
              spec.name          = 'omniauth_openid_connect'
         | 
| 9 | 
            +
              spec.version       = OmniAuth::OpenIDConnect::VERSION
         | 
| 10 | 
            +
              spec.authors       = ['John Bohn', 'Ilya Shcherbinin']
         | 
| 11 | 
            +
              spec.email         = ['jjbohn@gmail.com', 'm0n9oose@gmail.com']
         | 
| 12 | 
            +
              spec.summary       = 'OpenID Connect Strategy for OmniAuth'
         | 
| 13 | 
            +
              spec.description   = 'OpenID Connect Strategy for OmniAuth.'
         | 
| 14 | 
            +
              spec.homepage      = 'https://github.com/m0n9oose/omniauth_openid_connect'
         | 
| 15 | 
            +
              spec.license       = 'MIT'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              spec.files         = `git ls-files -z`.split("\x0")
         | 
| 18 | 
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 19 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 20 | 
            +
              spec.require_paths = ['lib']
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              spec.add_dependency 'addressable', '~> 2.5'
         | 
| 23 | 
            +
              spec.add_dependency 'omniauth', '~> 1.9'
         | 
| 24 | 
            +
              spec.add_dependency 'openid_connect', '~> 1.1'
         | 
| 25 | 
            +
              spec.add_development_dependency 'coveralls', '~> 0.8'
         | 
| 26 | 
            +
              spec.add_development_dependency 'faker', '~> 1.6'
         | 
| 27 | 
            +
              spec.add_development_dependency 'guard', '~> 2.14'
         | 
| 28 | 
            +
              spec.add_development_dependency 'guard-bundler', '~> 2.2'
         | 
| 29 | 
            +
              spec.add_development_dependency 'guard-minitest', '~> 2.4'
         | 
| 30 | 
            +
              spec.add_development_dependency 'minitest', '~> 5.1'
         | 
| 31 | 
            +
              spec.add_development_dependency 'mocha', '~> 1.7'
         | 
| 32 | 
            +
              spec.add_development_dependency 'rake', '~> 12.0'
         | 
| 33 | 
            +
              spec.add_development_dependency 'rubocop', '~> 0.63'
         | 
| 34 | 
            +
              spec.add_development_dependency 'simplecov', '~> 0.12'
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg
         | 
| @@ -0,0 +1,8 @@ | |
| 1 | 
            +
            {"keys": [{
         | 
| 2 | 
            +
                "kty": "RSA",
         | 
| 3 | 
            +
                "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
         | 
| 4 | 
            +
                "e": "AQAB",
         | 
| 5 | 
            +
                "alg": "RS256",
         | 
| 6 | 
            +
                "kid": "1e9gdk7"
         | 
| 7 | 
            +
              }]
         | 
| 8 | 
            +
            }
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            -----BEGIN CERTIFICATE-----
         | 
| 2 | 
            +
            MIIDJDCCAgwCCQC57Ob2JfXb+DANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJK
         | 
| 3 | 
            +
            UDEOMAwGA1UECBMFVG9reW8xITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5
         | 
| 4 | 
            +
            IEx0ZDESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDgwMTA4NTAxM1oXDTE1MDgw
         | 
| 5 | 
            +
            MTA4NTAxM1owVDELMAkGA1UEBhMCSlAxDjAMBgNVBAgTBVRva3lvMSEwHwYDVQQK
         | 
| 6 | 
            +
            ExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2FsaG9zdDCC
         | 
| 7 | 
            +
            ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+7czSGHN2087T+oX2kBCY/
         | 
| 8 | 
            +
            XN6UOS/mdU2Gn//omZlyxsQXIqvgBLNWeCVt4QdlFUbgPLggfXUelECV/RUOCIIi
         | 
| 9 | 
            +
            F2Th4t3x1LviN2XkUiva0DZBnOycqEaJdkyreEuGL1CLVZgZjKmSzNqLl0Yci3D0
         | 
| 10 | 
            +
            zgVsXFZSadQebietm4CCmfJYREt9NJxXcrLxVDgat/Xm/KJBsohs3f+cbBT8EXer
         | 
| 11 | 
            +
            7+2oZjZoVUgw1hu0alaOvAfE4mxsVwjn3g2mjDqRJLbbuWqgDobjMHah+d4zwJvN
         | 
| 12 | 
            +
            ePK8E0hfaz/XBLsJ4e6bQA3M3bANEgSvsicup/qb/0th4gUdc/kj4aJGj0RP7oEC
         | 
| 13 | 
            +
            AwEAATANBgkqhkiG9w0BAQUFAAOCAQEADuVec/8u2qJiq6K2W/gSLGYCBZq64OrA
         | 
| 14 | 
            +
            s7L2+S82m9/3gAb62wGcDNZjIGFDQubXmO6RhHv7JUT5YZqv9/kRGTJcHDUrwwoN
         | 
| 15 | 
            +
            IE99CIPizp7VfnrZ6GsYeszSsw3m+mKTETm+6ELmaSDbYAsrCg4IpGwUF0L88ATv
         | 
| 16 | 
            +
            CJ8QzW4X7b9dYVc7UAYyCie2N65GXfesBbRlSwFLuVqIzZfMdNpNijTIUwUqGSME
         | 
| 17 | 
            +
            b8IjLYzvekP53CO4wEBRrAVIPNXgftorxIE30OLWua2Qw3y6Pn+Qp5fLe47025S7
         | 
| 18 | 
            +
            Lcec18/FbHG0Vbq0qO9cKQw80XyK31N6z556wr2GN2WyixkzVRddXA==
         | 
| 19 | 
            +
            -----END CERTIFICATE-----
         |