Skip to content

Commit edb1e75

Browse files
authored
feature: support client_secret_post (#92)
client_secret_post means client_id and client_secret in body of request not in authorization header
1 parent be7a5bb commit edb1e75

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

lib/uaa/token_issuer.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ def request_token(params)
8383
headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
8484
headers['authorization'] = Http.basic_auth(CGI.escape(@client_id), CGI.escape(@client_secret))
8585
end
86+
elsif @client_auth_method == 'client_secret_post' && @client_secret && @client_id
87+
params[:client_id] = @client_id
88+
params[:client_secret] = @client_secret
8689
elsif @client_id && params[:code_verifier]
8790
params[:client_id] = @client_id
8891
else

spec/token_issuer_spec.rb

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,41 @@ module CF::UAA
310310

311311
end
312312

313+
314+
context 'with basic_auth using auth code grant' do
315+
let(:options) { {basic_auth: true} }
316+
317+
it 'basic_auth with authorization code' do
318+
subject.set_request_handler do |url, method, body, headers|
319+
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
320+
headers['accept'].should =~ /application\/json/
321+
headers['X-CF-ENCODED-CREDENTIALS'].should_not
322+
headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCFzZWNyZXQ='
323+
params = Util.decode_form(body)
324+
params['code_verifier'].should_not
325+
params['grant_type'].should == 'authorization_code'
326+
url.should match 'http://test.uaa.target/oauth/token'
327+
method.should == :post
328+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
329+
scope: 'openid', expires_in: 98765}
330+
[200, Util.json(reply), {'content-type' => 'application/json'}]
331+
end
332+
cburi = 'http://call.back/uri_path'
333+
params = Util.decode_form(cburi[1])
334+
params['code_challenge'].should_not
335+
params['code_challenge_method'].should_not
336+
redir_uri = subject.authcode_uri(cburi)
337+
state = /state=([^&]+)/.match(redir_uri)[1]
338+
reply_query = "state=#{state}&code=kz8%2F5gQZ2pc%3D"
339+
token = subject.authcode_grant(redir_uri, reply_query)
340+
token.should be_an_instance_of TokenInfo
341+
token.info['access_token'].should == 'test_access_token'
342+
token.info['token_type'].should =~ /^bearer$/i
343+
token.info['scope'].should == 'openid'
344+
token.info['expires_in'].should == 98765
345+
end
346+
end
347+
313348
context 'pkce with own code verifier' do
314349
let(:options) { {basic_auth: false, code_verifier: 'umoq1e_4XMYXvfHlaO9mSlSI17OKfxnwfR5ZD-oYreFxyn8yQZ-ZHPZfUZ4n3WjY_tkOB_MAisSy4ddqsa6aoTU5ZOcX4ps3de933PczYlC8pZpKL8EQWaDZOnpOyB2W'} }
315350

@@ -324,6 +359,38 @@ module CF::UAA
324359
code_verifier.should == options[:code_verifier]
325360
code_challenge.should == 'TAnM2AKGgiQKOC16cRpMdF_55qwmz3B333cq6T18z0s'
326361
end
362+
363+
let(:client_secret) { nil }
364+
it 'public token request with pkce without client_secret' do
365+
subject.set_request_handler do |url, method, body, headers|
366+
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
367+
headers['accept'].should =~ /application\/json/
368+
headers['X-CF-ENCODED-CREDENTIALS'].should_not
369+
headers['authorization'].should_not
370+
params = Util.decode_form(body)
371+
params['code_verifier'].should_not
372+
params['grant_type'].should == 'authorization_code'
373+
params['client_secret'].should_not
374+
url.should match 'http://test.uaa.target/oauth/token'
375+
method.should == :post
376+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
377+
scope: 'openid', expires_in: 98765}
378+
[200, Util.json(reply), {'content-type' => 'application/json'}]
379+
end
380+
cburi = 'http://call.back/uri_path'
381+
params = Util.decode_form(cburi[1])
382+
params['code_challenge'].should_not
383+
params['code_challenge_method'].should_not
384+
redir_uri = subject.authcode_uri(cburi)
385+
state = /state=([^&]+)/.match(redir_uri)[1]
386+
reply_query = "state=#{state}&code=kz8%2F5gQZ2pc%3D"
387+
token = subject.authcode_grant(redir_uri, reply_query)
388+
token.should be_an_instance_of TokenInfo
389+
token.info['access_token'].should == 'test_access_token'
390+
token.info['token_type'].should =~ /^bearer$/i
391+
token.info['scope'].should == 'openid'
392+
token.info['expires_in'].should == 98765
393+
end
327394
end
328395

329396
context 'no pkce active as this is the default' do
@@ -338,6 +405,40 @@ module CF::UAA
338405
end
339406
end
340407

408+
context 'with client_auth_method using client_secret_post' do
409+
let(:options) { {client_auth_method: 'client_secret_post'} }
410+
let(:client_secret) { 'body!secret' }
411+
412+
it 'use client_secret_post in authorization code and expect client_id and secret in body' do
413+
subject.set_request_handler do |url, method, body, headers|
414+
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
415+
headers['accept'].should =~ /application\/json/
416+
headers['X-CF-ENCODED-CREDENTIALS'].should_not
417+
headers['authorization'].should_not
418+
params = Util.decode_form(body)
419+
params['code_verifier'].should_not
420+
params['grant_type'].should == 'authorization_code'
421+
params['client_id'].should == 'test_client'
422+
params['client_secret'].should == 'body!secret'
423+
url.should match 'http://test.uaa.target/oauth/token'
424+
method.should == :post
425+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
426+
scope: 'openid', expires_in: 98765}
427+
[200, Util.json(reply), {'content-type' => 'application/json'}]
428+
end
429+
cburi = 'http://call.back/uri_path'
430+
redir_uri = subject.authcode_uri(cburi)
431+
state = /state=([^&]+)/.match(redir_uri)[1]
432+
reply_query = "state=#{state}&code=kz8%2F5gQZ2pc%3D"
433+
token = subject.authcode_grant(redir_uri, reply_query)
434+
token.should be_an_instance_of TokenInfo
435+
token.info['access_token'].should == 'test_access_token'
436+
token.info['token_type'].should =~ /^bearer$/i
437+
token.info['scope'].should == 'openid'
438+
token.info['expires_in'].should == 98765
439+
end
440+
end
441+
341442
end
342443

343444
end

0 commit comments

Comments
 (0)