Skip to content

Commit

Permalink
Incorporate Azure session fix according to AzureAD/omniauth-azure-act…
Browse files Browse the repository at this point in the history
…ivedirectory#22, in the interest of eliminating "Returned nonce did not match" errors
  • Loading branch information
mbkloster committed May 17, 2022
1 parent 6d291b2 commit 6d521b2
Showing 1 changed file with 49 additions and 16 deletions.
65 changes: 49 additions & 16 deletions lib/omniauth/strategies/azure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,12 @@ def fetch_openid_config
# multiple users don't share nonces. All nonces should be generated by
# this method.
#
# Updated according to https://github.com/AzureAD/omniauth-azure-activedirectory/issues/22. Take care if upgrading!
# @return String
def new_nonce
session['omniauth-azure-activedirectory.nonce'] = SecureRandom.uuid
nonce = SecureRandom.uuid
Rails.cache.write(nonce_cache_key(nonce), true, expires_in: 7.days)
nonce
end

##
Expand Down Expand Up @@ -270,6 +273,7 @@ def tenant
#
# See OpenId Connect Core 3.1.3.7 and 3.2.2.11.
#
# Modified according to https://github.com/AzureAD/omniauth-azure-activedirectory/issues/22. Take care if upgrading!
# @return Claims, Header
def validate_and_parse_id_token(id_token)
# The second parameter is the public key to verify the signature.
Expand All @@ -278,23 +282,37 @@ def validate_and_parse_id_token(id_token)
#
# If you're thinking that this looks ugly with the raw nil and boolean,
# see https://github.com/jwt/ruby-jwt/issues/59.
jwt_claims, jwt_header =
JWT.decode(id_token, nil, true, verify_options) do |header|
# There should always be one key from the discovery endpoint that
# matches the id in the JWT header.
x5c = (signing_keys.find do |key|
key['kid'] == header['kid']
end || {})['x5c']
if x5c.nil? || x5c.empty?
fail JWT::VerificationError,
'No keys from key endpoint match the id token'
jwt_claims, jwt_header = JWT.decode(id_token, nil, true, verify_options) do |header|
# There should always be one key from the discovery endpoint that
# matches the id in the JWT header.
unless key = signing_keys.find{|k|
k['kid'] == header['kid']
}
fail JWT::VerificationError, 'No keys from key endpoint match the id token'
end

# The key also contains other fields, such as n and e, that are
# redundant. x5c is sufficient to verify the id token.
if x5c = key['x5c'] and !x5c.empty?
OpenSSL::X509::Certificate.new(Base64.urlsafe_decode64(x5c.first)).public_key
# no x5c, so we resort to e and n
elsif exp = key['e'] and mod = key['n']
key = OpenSSL::PKey::RSA.new
mod = openssl_bn_for mod
exp = openssl_bn_for exp
if key.respond_to? :set_key
# Ruby 2.4 ff
key.set_key mod, exp, nil
else
# Ruby < 2.4
key.e = exp
key.n = mod
end
# The key also contains other fields, such as n and e, that are
# redundant. x5c is sufficient to verify the id token.
OpenSSL::X509::Certificate.new(JWT.base64url_decode(x5c.first)).public_key
key.public_key
else
fail JWT::VerificationError, 'Key has no info for verification'
end
return jwt_claims, jwt_header if jwt_claims['nonce'] == read_nonce
fail JWT::DecodeError, 'Returned nonce did not match.'
end
end

##
Expand Down Expand Up @@ -330,6 +348,21 @@ def verify_options
verify_aud: true,
'aud' => client_id }
end

# Introduced according to https://github.com/AzureAD/omniauth-azure-activedirectory/issues/22. Take care if upgrading!
def nonce_cache_key(nonce)
"omniauth_azure_activedirectory:nonce:#{nonce}"
end

# Introduced according to https://github.com/AzureAD/omniauth-azure-activedirectory/issues/22. Take care if upgrading!
def claim_nonce!(nonce)
if Rails.cache.read(nonce_cache_key(nonce))
Rails.cache.delete(nonce_cache_key(nonce))
true
else
false
end
end
end
end
end
Expand Down

0 comments on commit 6d521b2

Please sign in to comment.