Skip to content

Commit

Permalink
CFID-76: Tidy up login and add some rdocs
Browse files Browse the repository at this point in the history
Change-Id: Ia0791ae36fc404d560183392acdf43141d37415e
  • Loading branch information
dsyer committed Feb 5, 2012
1 parent 44f0d98 commit ff93493
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 157 deletions.
28 changes: 12 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,19 @@ First run the uaa server as described above:

Then start another terminal and from the project base directory, run:

$ ./login.sh "localhost:8080/uaa"
$ ./gem/bin/uaa target localhost:8080/uaa
$ ./gem/bin/uaa login marissa koala

And hit return twice to accept the default username and password.
(or leave out the username / password to be prompted).

This authenticates and obtains an access token from the server using the OAuth2 implicit
grant, similar to the approach intended for a client like VMC. The token is
stored in the file `.access_token`.
returned in stdout, so copy paste the value into this next command:

Now kill the `uaa` server and run the `api` server (which starts the
`uaa` server as well):

$ cd samples/api
$ mvn tomcat:run

And then (from the base directory) execute:

$ ./get.sh http://localhost:8080/api/apps

which should return a JSON array of (pretend) running applications.
$ ./gem/bin --client_id=app --client_secret=appclientsecret decode <token>

and you should see your username and the client id of the original
token grant on stdout.

## Integration tests

Expand Down Expand Up @@ -112,9 +106,11 @@ There are actually several projects here, the main `uaa` server application and

1. `uaa` is the actual UAA server

2. `api` (sample) is an OAuth2 resource service which returns a mock list of deployed apps
2. `gem` is a ruby gem (`cloudfoundry-uaa`) for interacting with the UAA server

3. `api` (sample) is an OAuth2 resource service which returns a mock list of deployed apps

3. `app` (sample) is a user application that uses both of the above
4. `app` (sample) is a user application that uses both of the above

In CloudFoundry terms

Expand Down
57 changes: 39 additions & 18 deletions gem/lib/uaa/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ class Cloudfoundry::Uaa::Client

# The target (base url) of calls to the UAA server. Default is "http://uaa.vcap.me".
attr_writer :target
# The client id to use if client authorization is needed (default "app")
# The client id to use if client authorization is needed (default "vmc")
attr_writer :client_id
# The client secret to use if client authorization is needed
attr_writer :client_secret
# The oauth scope to use if needed (default "read")
attr_writer :scope
# The grant type to use when logging in
# The grant type to use when logging in (default "implicit")
attr_writer :grant_type

def initialize
Expand All @@ -37,8 +37,9 @@ def prompts
rescue
# Ignore
end
raise StandardError, "No prompts available. Is the server running at #{@target}?" unless response
@prompts = response[:prompts] unless @prompts
raise StandardError, "No response from prompts endpoint. Is the server running at #{@target}?" unless response
@prompts ||= response[:prompts]
raise StandardError, "No prompts available. Is the server running at #{@target}?" unless @prompts
@prompts
end

Expand All @@ -54,41 +55,52 @@ def default_prompts
#
# * +opts+ - parameters to send, e.g.
# * +client_id+ - the client id (defaults to the instance attribute)
# * +grant_type+ - the OAuth2 grant type (default "implicit")
# * +grant_type+ - the OAuth2 grant type (default to the instance attribute)
# * +client_secret+ - the client secret (defaults to the instance attribute)
# * +scope+ - the oauth scopes to request, array of String, or space-separated list
# * +credentials+ - a hash of credentials to be passed to the server as a JSON literal
# * +username+ - the username of the resource owner to login (with grant_type="password")
# * +password+ - the password of the resource owner to login (with grant_type="password")
# * +scope+ - the oauth scopes to request, array of String, or comma- or space-separated list (defaults to "read")
# * +credentials+ - a hash of credentials to be passed to the server as a JSON literal (with :grant_type=>"implicit")
# * +username+ - the username of the resource owner to login (with :grant_type="password")
# * +password+ - the password of the resource owner to login (with :grant_type="password")
# (defaults to the instance attribute)
#
# === Implicit Grant
#
# The default grant type is "implicit" which is used by vmc and
# other untrusted clients. The UAA server authenticates the user in
# that case using the data provided in the +credentials+ option.
#
# As a convenience the +credentials+ default to the +username+ and
# +password+ if those are provided.
#
# If +credentials+ are not provided, or if +username+ is provided
# without a +password+ then a Cloudfoundry::Uaa::PromptRequiredError
# is raised.
def login(opts={})

opts = opts.dup

opts[:client_id] = @client_id unless opts[:client_id]
opts[:client_secret] = @client_secret unless opts[:client_secret] if @client_secret
opts[:scope] = @scope unless opts[:scope]
grant_type = opts[:grant_type] ? opts[:grant_type] : @grant_type
opts[:client_id] ||= @client_id
opts[:client_secret] ||= @client_secret if @client_secret
opts[:scope] ||= @scope
grant_type = opts[:grant_type] || @grant_type
opts[:grant_type] = grant_type

username = opts[:username]
password = opts[:password]
if grant_type=="password" then
raise Cloudfoundry::Uaa::PromptRequiredError.new(default_prompts) if (username.nil? || password.nil?)
else
if prompts==default_prompts && username && password then
if prompts_require_username_and_password? && username && password then
opts[:credentials] = {:username=>username, :password=>password}
end
unless opts[:credentials] then
raise Cloudfoundry::Uaa::PromptRequiredError.new(prompts)
end
raise Cloudfoundry::Uaa::PromptRequiredError.new(prompts) unless opts[:credentials]
# make sure they don't get used as request or form params unless we want them to
opts.delete :username
opts.delete :password
end

if grant_type!="client_credentials" && grant_type!="password" then
opts[:redirect_uri] = @redirect_uri unless opts[:redirect_uri]
opts[:redirect_uri] ||= @redirect_uri
end

opts[:scope] = join_array(opts[:scope]) if opts[:scope]
Expand Down Expand Up @@ -136,6 +148,11 @@ def login(opts={})
# * +opts+ - optional: additional parameters to send, e.g.
# * +client_id+ - the client id (defaults to the instance attribute)
# * +client_secret+ - the client secret (defaults to the instance attribute)
#
# Note that the default client (vmc) is not authorized to decode
# tokens, so callers will need to change the default or provide
# explicit values in the options. Authoeized clients must be
# pre-registered with the server.
def decode_token(token, opts={})
headers = {'Accept'=>"application/json",
'Authorization'=>client_auth(opts)}
Expand All @@ -145,6 +162,10 @@ def decode_token(token, opts={})

private

def prompts_require_username_and_password?
prompts.has_key?(:username) && prompts.has_key?(:password) && prompts.length==2
end

def join_array(value)
return value.join(" ") if value.is_a?(Array)
value
Expand Down
5 changes: 5 additions & 0 deletions gem/spec/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@
@input[:headers]['Authorization'].should =~ /Basic .*/
end

it "should not send credentials hash", :integration=>false do
token = subject.login(:username=>"vcap_tester@vmware.com", :password=>"tester", :grant_type=>"password")
@input[:payload].should_not =~ /credentials:.*/
end

end

context "with implicit grant" do
Expand Down
31 changes: 0 additions & 31 deletions get.sh

This file was deleted.

71 changes: 0 additions & 71 deletions login.sh

This file was deleted.

21 changes: 0 additions & 21 deletions post.sh

This file was deleted.

0 comments on commit ff93493

Please sign in to comment.