Class: OmniAuth::Strategies::Himari

Inherits:
OAuth2
  • Object
show all
Defined in:
lib/omniauth/strategies/himari.rb

Defined Under Namespace

Classes: AccessToken, ConfigurationError, IdToken, IdTokenMissing, VerificationError

Instance Method Summary collapse

Instance Method Details

#authorize_paramsObject



128
129
130
131
132
133
134
# File 'lib/omniauth/strategies/himari.rb', line 128

def authorize_params
  super.tap do |params|
    # super reads options.scope; default to 'openid' if the caller cleared it.
    params[:scope] ||= options.scope || 'openid'
    params[:prompt] = request.GET['prompt'] if request.GET['prompt']
  end
end

#callback_urlObject



120
121
122
# File 'lib/omniauth/strategies/himari.rb', line 120

def callback_url
  options[:redirect_uri] || (full_host + callback_path) # https://github.com/omniauth/omniauth-oauth2/pull/142
end

#clientObject

Raises:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/omniauth/strategies/himari.rb', line 36

def client
  options.client_options.site ||= options.site
  options.client_options.authorize_url ||= '/oidc/authorize'
  options.client_options.token_url ||= '/public/oidc/token'
  options.client_options.userinfo_url ||= '/public/oidc/userinfo'
  options.client_options.access_token_class ||= AccessToken # https://gitlab.com/oauth-xx/oauth2/-/issues/628

  options.client_options.connection_opts ||= {}
  options.client_options.connection_opts[:headers] ||= {}
  options.client_options.connection_opts[:headers] = {
    'User-Agent' => user_agent,
  }.merge(options.client_options.connection_opts[:headers])

  raise ConfigurationError, "client_id and client_secret is required" unless options.client_id && options.client_secret
  raise ConfigurationError, "site is required" unless options.client_options.site

  super
end

#faradayObject



113
114
115
116
117
118
# File 'lib/omniauth/strategies/himari.rb', line 113

def faraday
  @faraday ||= Faraday.new(options.site, headers: {'User-Agent' => user_agent}) do |b|
    b.response :json
    b.response :raise_error
  end
end

#id_tokenObject



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/omniauth/strategies/himari.rb', line 138

def id_token
  @id_token ||= begin
    jwt = access_token.params['id_token'] or raise(IdTokenMissing, 'id_token is missing')
    retval = IdToken.new(*JWT.decode(
      jwt,
      nil,
      true,
      {
        algorithms: jwks.map { |k| k[:alg] }.compact.uniq,
        jwks: jwks,
        verify_aud: true,
        aud: options.client_id,
        verify_iss: true,
        iss: options.site,
        verify_expiration: true,
      }.merge(options.verify_options),
    ))
    verify_at_hash!(retval)
    retval
  end
end

#jwksObject



160
161
162
163
164
# File 'lib/omniauth/strategies/himari.rb', line 160

def jwks
  JWT::JWK::Set.new(jwks_json).tap do |set|
    set.filter! { |k| k[:use] == 'sig' }
  end
end

#jwks_jsonObject



166
167
168
169
170
# File 'lib/omniauth/strategies/himari.rb', line 166

def jwks_json
  faraday.get(options.jwks_url || 'public/jwks').body
rescue Faraday::Error => e
  raise JwksUnavailable, "failed to retrieve jwks; #{e.inspect}"
end

#raw_infoObject



109
110
111
# File 'lib/omniauth/strategies/himari.rb', line 109

def raw_info
  @raw_info ||= !skip_info? && options.use_userinfo ? access_token.get('/public/oidc/userinfo').parsed : id_token.claims
end

#user_agentObject



124
125
126
# File 'lib/omniauth/strategies/himari.rb', line 124

def user_agent
  options.user_agent || "OmniauthHimari/#{Omniauth::Himari::VERSION}"
end

#verify_at_hash!(id_token) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/omniauth/strategies/himari.rb', line 88

def verify_at_hash!(id_token)
  return unless options.verify_at_hash

  function = case id_token.header['alg'] # this is safe as we've verified
  when 'ES256', 'RS256' then Digest::SHA256
  when 'ES384' then Digest::SHA384
  when 'ES512' then Digest::SHA512
  else
    raise VerificationError, "unknown hash function to verify at_hash for #{id_token.header["alg"]}"
  end

  dgst = function.digest(access_token.token)
  expected_at_hash = Base64.urlsafe_encode64(dgst[0, dgst.size / 2], padding: false)

  given_at_hash = id_token.claims['at_hash']

  unless given_at_hash == expected_at_hash
    raise VerificationError, "at_hash mismatch #{given_at_hash.inspect}, #{expected_at_hash.inspect}"
  end
end