Use JWT support in signet, ignore broken PKCS12 tests on jruby

This commit is contained in:
Steven Bazyl 2013-01-02 11:50:45 -08:00
parent c793138209
commit 71fbe4a825
2 changed files with 48 additions and 62 deletions

View File

@ -22,17 +22,31 @@ module Google
# Generates access tokens using the JWT assertion profile. Requires a # Generates access tokens using the JWT assertion profile. Requires a
# service account & access to the private key. # service account & access to the private key.
# #
# @example # @example Using Signet
#
# key = Google::APIClient::KeyUtils.load_from_pkcs12('client.p12', 'notasecret')
# client.authorization = Signet::OAuth2::Client.new(
# :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
# :audience => 'https://accounts.google.com/o/oauth2/token',
# :scope => https://www.googleapis.com/auth/prediction',,
# :issuer => 123456-abcdef@developer.gserviceaccount.com',
# :signing_key => key)
# client.authorization.fetch_access_token!
# client.execute(...)
#
# @example Deprecated version
# #
# client = Google::APIClient.new # client = Google::APIClient.new
# key = Google::APIClient::PKCS12.load_key('client.p12', 'notasecret') # key = Google::APIClient::PKCS12.load_key('client.p12', 'notasecret')
# service_account = Google::APIClient::JWTAsserter.new( # service_account = Google::APIClient::JWTAsserter.new(
# '123456-abcdef@developer.gserviceaccount.com', # '123456-abcdef@developer.gserviceaccount.com',
# 'https://www.googleapis.com/auth/prediction', # 'https://www.googleapis.com/auth/prediction',
# key) # key)
# client.authorization = service_account.authorize # client.authorization = service_account.authorize
# client.execute(...) # client.execute(...)
# #
# @deprecated
# Service accounts are now supported directly in Signet
# @see https://developers.google.com/accounts/docs/OAuth2ServiceAccount # @see https://developers.google.com/accounts/docs/OAuth2ServiceAccount
class JWTAsserter class JWTAsserter
# @return [String] ID/email of the issuing party # @return [String] ID/email of the issuing party
@ -43,8 +57,10 @@ module Google
attr_accessor :skew attr_accessor :skew
# @return [String] Scopes to authorize # @return [String] Scopes to authorize
attr_reader :scope attr_reader :scope
# @return [OpenSSL::PKey] key for signing assertions # @return [String,OpenSSL::PKey] key for signing assertions
attr_writer :key attr_writer :key
# @return [String] Algorithm used for signing
attr_accessor :algorithm
## ##
# Initializes the asserter for a service account. # Initializes the asserter for a service account.
@ -53,14 +69,18 @@ module Google
# Name/ID of the client issuing the assertion # Name/ID of the client issuing the assertion
# @param [String, Array] scope # @param [String, Array] scope
# Scopes to authorize. May be a space delimited string or array of strings # Scopes to authorize. May be a space delimited string or array of strings
# @param [OpenSSL::PKey] key # @param [String,OpenSSL::PKey] key
# RSA private key for signing assertions # Key for signing assertions
def initialize(issuer, scope, key) # @param [String] algorithm
# Algorithm to use, either 'RS256' for RSA with SHA-256
# or 'HS256' for HMAC with SHA-256
def initialize(issuer, scope, key, algorithm = "RS256")
self.issuer = issuer self.issuer = issuer
self.scope = scope self.scope = scope
self.expiry = 60 # 1 min default self.expiry = 60 # 1 min default
self.skew = 60 self.skew = 60
self.key = key self.key = key
self.algorithm = algorithm
end end
## ##
@ -81,25 +101,6 @@ module Google
end end
end end
##
# Builds & signs the assertion.
#
# @param [String] person
# Email address of a user, if requesting a token to act on their behalf
# @return [String] Encoded JWT
def to_jwt(person=nil)
now = Time.new
assertion = {
"iss" => @issuer,
"scope" => self.scope,
"aud" => "https://accounts.google.com/o/oauth2/token",
"exp" => (now + expiry).to_i,
"iat" => (now - skew).to_i
}
assertion['prn'] = person unless person.nil?
return JWT.encode(assertion, @key, "RS256")
end
## ##
# Request a new access token. # Request a new access token.
# #
@ -111,42 +112,25 @@ module Google
# #
# @see Signet::OAuth2::Client.fetch_access_token! # @see Signet::OAuth2::Client.fetch_access_token!
def authorize(person = nil, options={}) def authorize(person = nil, options={})
assertion = self.to_jwt(person) authorization = self.to_authorization
authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token'
)
authorization.grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
authorization.extension_parameters = { :assertion => assertion }
authorization.fetch_access_token!(options) authorization.fetch_access_token!(options)
return JWTAuthorization.new(authorization, self, person) return authorization
end end
end
##
# Proxy for authorization that allows refreshing the access token
# using assertions instead of refresh tokens.
class JWTAuthorization < DelegateClass(Signet::OAuth2::Client)
## ##
# Initialize the proxy # Builds a Signet OAuth2 client
# #
# @param [Signet::OAuth2::Client] authorization # @return [Signet::OAuth2::Client] Access token
# Original authorization instance def to_authorization(person = nil)
# @param [Google::APIClient::JWTAsserter] return Signet::OAuth2::Client.new(
# Asserter for generating new access tokens :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
# @param [String] person :audience => 'https://accounts.google.com/o/oauth2/token',
# Optional target user if impersonating. :scope => self.scope,
def initialize(authorization, asserter, person = nil) :issuer => @issuer,
@asserter = asserter :signing_key => @key,
@person = person :signing_algorithm => @algorithm,
super(authorization) :person => person
end )
##
# @see Signet::OAuth2::Client#fetch_access_token!
def fetch_access_token!(options={})
new_authorization = @asserter.authorize(@person, options)
__setobj__(new_authorization)
self
end end
end end
end end

View File

@ -20,12 +20,14 @@ fixtures_path = File.expand_path('../../../fixtures', __FILE__)
describe Google::APIClient::KeyUtils do describe Google::APIClient::KeyUtils do
it 'should read PKCS12 files from the filesystem' do it 'should read PKCS12 files from the filesystem' do
pending "Reading from PKCS12 not supported on jruby" if RUBY_PLATFORM == 'java'
path = File.expand_path('files/privatekey.p12', fixtures_path) path = File.expand_path('files/privatekey.p12', fixtures_path)
key = Google::APIClient::KeyUtils.load_from_pkcs12(path, 'notasecret') key = Google::APIClient::KeyUtils.load_from_pkcs12(path, 'notasecret')
key.should_not == nil key.should_not == nil
end end
it 'should read PKCS12 files from loaded files' do it 'should read PKCS12 files from loaded files' do
pending "Reading from PKCS12 not supported on jruby" if RUBY_PLATFORM == 'java'
path = File.expand_path('files/privatekey.p12', fixtures_path) path = File.expand_path('files/privatekey.p12', fixtures_path)
content = File.read(path) content = File.read(path)
key = Google::APIClient::KeyUtils.load_from_pkcs12(content, 'notasecret') key = Google::APIClient::KeyUtils.load_from_pkcs12(content, 'notasecret')
@ -56,7 +58,7 @@ describe Google::APIClient::JWTAsserter do
it 'should generate valid JWTs' do it 'should generate valid JWTs' do
asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key) asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
jwt = asserter.to_jwt jwt = asserter.to_authorization.to_jwt
jwt.should_not == nil jwt.should_not == nil
claim = JWT.decode(jwt, @key.public_key, true) claim = JWT.decode(jwt, @key.public_key, true)