Permalink
Browse files

CFID-76: Tidy up login and add some rdocs

Change-Id: Ia0791ae36fc404d560183392acdf43141d37415e
  • Loading branch information...
1 parent 44f0d98 commit ff934930bbe068e3ca42b82b3c826503541ac08b @dsyer dsyer committed Feb 5, 2012
Showing with 56 additions and 157 deletions.
  1. +12 −16 README.md
  2. +39 −18 gem/lib/uaa/client.rb
  3. +5 −0 gem/spec/client_spec.rb
  4. +0 −31 get.sh
  5. +0 −71 login.sh
  6. +0 −21 post.sh
View
28 README.md
@@ -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
@@ -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
View
57 gem/lib/uaa/client.rb
@@ -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
@@ -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
@@ -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]
@@ -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)}
@@ -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
View
5 gem/spec/client_spec.rb
@@ -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
View
31 get.sh
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-access_token=`[ -f .access_token ] && cat .access_token`;
-
-if [ "$1" = "" ]; then
- echo "First argument should be a server path, e.g. localhost:8080/api/photos"
- exit 2;
-fi
-
-# if (echo $1 | grep -q "\-.*"); then
-# echo "Options for curl come after the server path"
-# exit 3;
-# fi
-
-get() {
- location=$1
- shift
- if [ "" = "$access_token" ]; then
- # maybe there is a cookie that identifies us
- # N.B. use -d for request parameters (and curl will switch to POST)
- mkdir -p ~/tmp
- curl -b ~/tmp/cookies.txt -c ~/tmp/cookies.txt -s -L $location $* -H "Accept: application/json; */*"
- else
- # TODO: check that the json works
- curl -s -L $location -H "Accept: application/json; */*" -H "Authorization: Bearer $access_token" $*
- fi
-}
-
-get $* || echo "Could not connect to $1. Is the service operating?" && exit 1
-
-
View
71 login.sh
@@ -1,71 +0,0 @@
-#!/bin/sh
-
-if [ "$1" = "" ]; then
- echo "First argument should be an auth server path, e.g. localhost:8080/auth"
- exit 2;
-fi
-
-# if (echo $1 | grep -q "\-.*"); then
-# echo "Options come after the server path"
-# exit 3;
-# fi
-
-ROOT=$1
-
-echo "\nInvoking /login_info endpoint...\n"
-
-response=`curl -s -H "Accept: application/json" $ROOT/login_info`
-
-echo "Response $response\n"
-
-shift
-CLIENT=vmc
-REDIRECT_URI="vmc://implicit_grant"
-SCOPE=read
-
-if [ -f .access_token ]; then
- access_token=`cat .access_token`;
-fi
-
-OPTIONS=
-
-while (echo "$1" | grep -q "\-.*"); do
-
- if [ -n "$1" -a "$1" = "-client" ]; then
- shift
- CLIENT=$1
- shift
- elif [ -n "$1" -a "$1" = "-scope" ]; then
- shift
- SCOPE=$1
- shift
- fi
-done
-
-echo "Username (marissa): \c"
-read username
-echo "Password (koala):\c"
-read password
-
-if [ "$username" = "" ]; then username=marissa; fi
-if [ "$password" = "" ]; then password=koala; fi
-
-# Request token from /authorize endpoint
-# TODO: This needs to be changed to a POST
-authorizeUrl=$ROOT/oauth/authorize
-
-credentials="{\"username\":\"$username\",\"password\":\"$password\"}"
-
-echo "\nInvoking /authorize endpoint with credentals $credentials, client=$CLIENT and scope=$SCOPE\n"
-
-response=`curl --write-out "Location: %{redirect_url}" -s -S -G --data-urlencode "credentials=$credentials" -d "client_id=$CLIENT" -d "response_type=token" -d "scope=$SCOPE" --data-urlencode "redirect_uri=$REDIRECT_URI" -H "Accept: application/json" $authorizeUrl`
-
-echo "$response\n"
-
-echo $response | grep access_token | sed -e 's/.*access_token=//' -e 's/&.*//'> .access_token
-
-if [ "`cat .access_token`" != "" ]; then echo "Successfully authenticated"; exit 0; fi
-
-echo "Failed to authenticate: "$response
-exit 1
-
View
21 post.sh
@@ -1,21 +0,0 @@
-#!/bin/sh
-
-if [ ! -f .access_token ]; then
- echo "No access token available. Please login first."
- exit 1
-fi
-
-access_token=`cat .access_token`;
-
-post() {
- location=$1
- shift
- curl -X POST -s -L -H "Accept: application/json" $location -H "Authorization: Bearer $access_token" $*
-}
-
-if [ ! "$access_token" = "" ]; then
- post $* || echo "Could not connect. Is the service operating?" && exit 1
-else
- echo "No access token available. Login first."
- exit 2
-fi

0 comments on commit ff93493

Please sign in to comment.