Skip to content

Commit 85077a4

Browse files
authored
feature: support client_assertion parameter (#103)
* feature: support client_assertion parameter * Ensure that client_assertion_type to be set if client_assertion is set
1 parent fc9028d commit 85077a4

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

lib/uaa/token_issuer.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ def request_token(params)
7575
if scope = Util.arglist(params.delete(:scope))
7676
params[:scope] = Util.strlist(scope)
7777
end
78+
client_assertion = params[:client_assertion]
79+
params.delete(:client_assertion)
7880
headers = {'content-type' => FORM_UTF8, 'accept' => JSON_UTF8}
7981
if @client_auth_method == 'client_secret_basic' && @client_secret && @client_id
8082
if @basic_auth
@@ -88,6 +90,10 @@ def request_token(params)
8890
params[:client_secret] = @client_secret
8991
elsif @client_id && params[:code_verifier]
9092
params[:client_id] = @client_id
93+
elsif client_assertion && @client_id && @client_secret.nil?
94+
params[:client_id] = @client_id
95+
params[:client_assertion] = client_assertion
96+
params[:client_assertion_type] = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
9197
else
9298
headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
9399
headers['authorization'] = Http.basic_auth(CGI.escape(@client_id || ''), CGI.escape(@client_secret || ''))
@@ -129,6 +135,7 @@ def jkey(k) @key_style ? k : k.to_s end
129135
# * +:symbolize_keys+, if true, returned hash keys are symbols.
130136
def initialize(target, client_id, client_secret = nil, options = {})
131137
@target, @client_id, @client_secret = target, client_id, client_secret
138+
@client_assertion = options[:client_assertion] || nil
132139
@token_target = options[:token_target] || target
133140
@key_style = options[:symbolize_keys] ? :sym : nil
134141
@basic_auth = options[:basic_auth] == true ? true : false
@@ -310,8 +317,8 @@ def owner_password_credentials_grant(credentials)
310317
# Uses the instance client credentials to get a token with a client
311318
# credentials grant. See http://tools.ietf.org/html/rfc6749#section-4.4
312319
# @return [TokenInfo]
313-
def client_credentials_grant(scope = nil)
314-
request_token(grant_type: 'client_credentials', scope: scope)
320+
def client_credentials_grant(scope = nil, client_assertion = nil)
321+
request_token(grant_type: 'client_credentials', scope: scope, client_assertion: client_assertion)
315322
end
316323

317324
# Uses the instance client credentials and the given +refresh_token+ to get

spec/token_issuer_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,37 @@ module CF::UAA
345345
end
346346
end
347347

348+
context 'with client_assertion using client credentials grant' do
349+
let(:client_id) { 'test_client' }
350+
let(:client_secret) { nil }
351+
352+
it 'use client_secret_post in authorization code and expect client_id and secret in body' do
353+
subject.set_request_handler do |url, method, body, headers|
354+
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
355+
headers['accept'].should =~ /application\/json/
356+
headers['X-CF-ENCODED-CREDENTIALS'].should_not
357+
headers['authorization'].should_not
358+
params = Util.decode_form(body)
359+
params['grant_type'].should == 'client_credentials'
360+
params['client_id'].should == 'test_client'
361+
params['client_assertion'].should == 'any-jwt-token'
362+
params['client_assertion_type'].should == 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
363+
params['client_secret'].should_not
364+
url.should match 'http://test.uaa.target/oauth/token'
365+
method.should == :post
366+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
367+
scope: 'logs.read', expires_in: 98765}
368+
[200, Util.json(reply), {'content-type' => 'application/json'}]
369+
end
370+
token = subject.client_credentials_grant('logs.read', 'any-jwt-token')
371+
token.should be_an_instance_of TokenInfo
372+
token.info['access_token'].should == 'test_access_token'
373+
token.info['token_type'].should =~ /^bearer$/i
374+
token.info['scope'].should == 'logs.read'
375+
token.info['expires_in'].should == 98765
376+
end
377+
end
378+
348379
context 'pkce with own code verifier' do
349380
let(:options) { {basic_auth: false, code_verifier: 'umoq1e_4XMYXvfHlaO9mSlSI17OKfxnwfR5ZD-oYreFxyn8yQZ-ZHPZfUZ4n3WjY_tkOB_MAisSy4ddqsa6aoTU5ZOcX4ps3de933PczYlC8pZpKL8EQWaDZOnpOyB2W'} }
350381

0 commit comments

Comments
 (0)