2018-07-24 20:21:33 +08:00
|
|
|
module Api
|
|
|
|
class AzureJwt
|
|
|
|
require 'jwt'
|
|
|
|
|
|
|
|
KEYS_CACHING_PERIOD = 7.days
|
|
|
|
|
|
|
|
LEEWAY = 30
|
|
|
|
|
|
|
|
def self.fetch_rsa_key(k_id, app_id)
|
|
|
|
cache_key = "api_azure_ad_rsa_key_#{k_id}"
|
|
|
|
Rails.cache.fetch(cache_key, expires_in: KEYS_CACHING_PERIOD) do
|
2019-11-26 22:09:40 +08:00
|
|
|
conf_url = Rails.configuration.x.azure_ad_apps[app_id][:conf_url]
|
2018-07-24 20:21:33 +08:00
|
|
|
keys_url = JSON.parse(Net::HTTP.get(URI(conf_url)))['jwks_uri']
|
|
|
|
data = JSON.parse(Net::HTTP.get(URI.parse(keys_url)))
|
|
|
|
verif_key = data['keys'].find { |key| key['kid'] == k_id }
|
|
|
|
unless verif_key
|
|
|
|
raise JWT::VerificationError,
|
|
|
|
'Azure AD: No keys from key endpoint match the key in the token'
|
|
|
|
end
|
|
|
|
JSON::JWK.new(verif_key).to_key.to_s
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.decode(token)
|
|
|
|
# First, extract key id from token header,
|
|
|
|
# [1] is position of the header.
|
|
|
|
# We will use this ID to fetch correct public key needed for
|
|
|
|
# verification of the token signature
|
|
|
|
unverified_token = JWT.decode(token, nil, false)
|
|
|
|
|
|
|
|
k_id = unverified_token[1]['kid']
|
|
|
|
unless k_id
|
|
|
|
raise JWT::VerificationError, 'Azure AD: No Key ID in token header'
|
|
|
|
end
|
|
|
|
|
|
|
|
# Now search for matching app variables in configuration
|
|
|
|
app_id = unverified_token[0]['aud']
|
2019-11-26 22:09:40 +08:00
|
|
|
app_config = Rails.configuration.x.azure_ad_apps[app_id]
|
2018-07-24 20:21:33 +08:00
|
|
|
unless app_config
|
|
|
|
raise JWT::VerificationError,
|
|
|
|
'Azure AD: No application configured with such ID'
|
|
|
|
end
|
|
|
|
|
|
|
|
# Decode token payload and verify it's signature.
|
2019-12-11 00:24:53 +08:00
|
|
|
payload, header = JWT.decode(
|
2018-07-24 20:21:33 +08:00
|
|
|
token,
|
|
|
|
OpenSSL::PKey::RSA.new(fetch_rsa_key(k_id, app_id)),
|
|
|
|
true,
|
|
|
|
algorithm: 'RS256',
|
|
|
|
verify_expiration: true,
|
|
|
|
verify_aud: true,
|
|
|
|
aud: app_id,
|
|
|
|
verify_iss: true,
|
|
|
|
iss: app_config[:iss],
|
|
|
|
nbf_leeway: LEEWAY
|
|
|
|
)
|
2019-12-11 00:24:53 +08:00
|
|
|
[HashWithIndifferentAccess.new(payload), HashWithIndifferentAccess.new(header)]
|
2018-07-24 20:21:33 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|