Added ID token verification against server certificate.
This commit is contained in:
parent
d021ed5503
commit
17e540d0de
|
@ -401,6 +401,76 @@ module Google
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Verifies an ID token against a server certificate. Used to ensure that
|
||||
# an ID token supplied by an untrusted client-side mechanism is valid.
|
||||
# Raises an error if the token is invalid or missing.
|
||||
def verify_id_token!
|
||||
gem 'jwt', '~> 0.1.4'
|
||||
require 'jwt'
|
||||
require 'openssl'
|
||||
@certificates ||= {}
|
||||
if !self.authorization.respond_to?(:id_token)
|
||||
raise ArgumentError, (
|
||||
"Current authorization mechanism does not support ID tokens: " +
|
||||
"#{self.authorization.class.to_s}"
|
||||
)
|
||||
elsif !self.authorization.id_token
|
||||
raise ArgumentError, (
|
||||
"Could not verify ID token, ID token missing. " +
|
||||
"Scopes were: #{self.authorization.scope.inspect}"
|
||||
)
|
||||
else
|
||||
check_cached_certs = lambda do
|
||||
valid = false
|
||||
for key, cert in @certificates
|
||||
begin
|
||||
self.authorization.decoded_id_token(cert.public_key)
|
||||
valid = true
|
||||
rescue JWT::DecodeError, Signet::UnsafeOperationError
|
||||
# Expected exception. Ignore, ID token has not been validated.
|
||||
end
|
||||
end
|
||||
valid
|
||||
end
|
||||
if check_cached_certs.call()
|
||||
return true
|
||||
end
|
||||
request = self.generate_request(
|
||||
:http_method => :get,
|
||||
:uri => 'https://www.googleapis.com/oauth2/v1/certs',
|
||||
:authenticated => false
|
||||
)
|
||||
response = self.transmit(:request => request)
|
||||
if response.status >= 200 && response.status < 300
|
||||
@certificates.merge!(
|
||||
Hash[MultiJson.decode(response.body).map do |key, cert|
|
||||
[key, OpenSSL::X509::Certificate.new(cert)]
|
||||
end]
|
||||
)
|
||||
elsif response.status >= 400
|
||||
case response.status
|
||||
when 400...500
|
||||
exception_type = ClientError
|
||||
when 500...600
|
||||
exception_type = ServerError
|
||||
else
|
||||
exception_type = TransmissionError
|
||||
end
|
||||
url = request.to_env(Faraday.default_connection)[:url]
|
||||
raise exception_type,
|
||||
"Could not retrieve certificates from: #{url}"
|
||||
end
|
||||
if check_cached_certs.call()
|
||||
return true
|
||||
else
|
||||
raise InvalidIDTokenError,
|
||||
"Could not verify ID token against any available certificate."
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
##
|
||||
# Generates a request.
|
||||
#
|
||||
|
|
|
@ -36,5 +36,10 @@ module Google
|
|||
# A 5xx class HTTP error occurred.
|
||||
class ServerError < TransmissionError
|
||||
end
|
||||
|
||||
##
|
||||
# An exception that is raised if an ID token could not be validated.
|
||||
class InvalidIDTokenError < StandardError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue