High Level Features of the UAA

July 24, 2012 Dave Syer

featured-cf-genericThe User Account and Authentication Service (UAA) in Cloud Foundry is responsible for securing the platform services and providing a single sign on for web applications. A previous article introduced the UAA and placed it in the context of the platform, and here we go into a bit more detail and describe the features of the UAA individually:

Centralized Identity Management

Applications that want to act on behalf of a User, for instance to view or push apps to the users Cloud Foundry account, need to authenticate the User against the platform. Since Cloud Foundry traditionally has been secured by username (email) and password, one way to do that would be to ask the User for his credentials and forward them to the Cloud Controller. This is a bad thing for two reasons:

  1. It opens up a security threat. If Users can routinely be tempted to type their passwords into any old application that says it provides a platform-related service, there is nothing to stop such applications from stealing the credentials and using them for their own purposes.
  2. It restricts the platform to always and only supporting username-password authentication. This is architecturally brittle, and also probably not what a lot of Cloud Foundry users want, especially for enterprise installations.

Centralized identity management is the way forward. There should be one place where a User knows he can authenticate safely and not risk giving away secrets to a rogue application. The authentication mechanism should be decided centrally with no dependencies on the applications that consume it. This is the role of the UAA.

Single Sign On

Because it is centralized, the UAA can provide a Single Sign On (SSO) service for applications in the Cloud Foundry platform. The cloudfoundry.com platform has several UI components and where they need to be secure they delegate to the UAA for authentication. Examples are the support site and the Micro Cloud Foundry site. (There are no other components in the core Cloud Foundry open source platform that have a UI, so it’s not really necessary to have an SSO feature until you grow the platform beyond the core use cases.)

The UI components that need SSO use the /userinfo endpoint in the UAA, which is just a regular OAuth2 protected resource (an example of the UAA acting as a Resource Server). Here is an example output from the devuaa instance, where TOKEN has been set already to a valid OAuth2 access token:

$ curl -H "Authorization: Bearer $TOKEN" http://devuaa.cloudfoundry.com/userinfo { "user_id":"fb180054-9cbb-441d-96e7-5c3d65861e9c", "user_name":"marissa", "given_name":"Marissa", "family_name":"Bloggs", "name":"Marissa Bloggs", "email":"marissa@test.org" }

The caller would only get an error response if he tried the /userinfo endpoint without a valid access token, so the caller already believes that the user is authenticated but knows nothing about his identity. What the endpoint is doing is giving the caller (e.g., a web application) enough information about the current user to identify him and to be able to customize responses. For example, when you sign into the support site you will see a link to “My unsolved tickets.”

Applications that are part of the platform can be (and have been in cloudfoundry.com) configured in the UAA to be auto-approved (i.e., not require that the user explicitly approve the access token grant). This makes the user experience a lot nicer, and gives the impression of a single logical platform, concealing the implementation as a set of separate components.

The is no reason that applications deployed on Cloud Foundry, or indeed elsewhere, could not also use the UAA as an SSO service. Another blog article is in the pipeline to show you how to take advantage of that in your own applications.

Delegating Access to Services

Single Sign On is a huge benefit to client applications, but the primary role of the UAA is as an OAuth2 Authorization Server. (As a side note, the SSO feature is implemented as a delegated access to the userinfo service, so that was just a specific case of the more general feature.)

The basic delegation model is covered in the OAuth2 specification. In a nutshell, the Authorization Server grants access tokens to Client applications, but only if the Resource Owner (User) approves the access. An example Resource Server in Cloud Foundry is the Cloud Controller, which manages users’ applications and services. The UAA supports all the core OAuth2 token grant types, but the ones that are most relevant for delegating access are authorization_code, which we visited briefly above, and implicit, which is similar, but less secure and aimed at script clients in the browser rather than webapp clients.

The access tokens are supposed to be opaque to Client applications, but they carry information that is relevant to Resource Servers. In the case of the UAA, the token carries some basic information about the user and some other details that can be used by a Resource Server to limit access. By default, the UAA issues base64 encoded JSON tokens, based on the JSON Web Token (JWT) specification. Here’s an example of a decoded token:

{ "exp": 1341079110, "user_id": "65dddc5d-d566-42ee-88f7-9f0098ee7f45", "user_name": "vcap_tester@vmware.com", "email": "vcap_tester@vmware.com", "scope": [ "uaa.user", "cloud_controller.read", "cloud_controller.write", "password.write", "openid" ], "aud": ["openid","cloud_controller","password"], "client_id": "vmc" }

Hint: Because of the way the token is constructed, if you want to eyeball the contents of a token, a quick and dirty way to do it is to simply base64 decode the whole thing. The result is not parseable, but you can see the contents. A Resource Server that is also a registered Client can also decode a token at the /check_token endpoint (using HTTP Basic authentication). It would do this if it prefers not to use the JWT, or wants more up to data information (an access token can be long lived and the user account data might change).

The token contents are as follows:

  • ‘exp’: expires at (seconds since start of epoch)
  • ‘user_id’: an immutable unique identifier for the user
  • ‘user_name’: the user name that the user authenticated with
  • ‘email’: the primary email address of the user (for legacy Cloud Foundry accounts the email and the user name are the same)
  • ‘scope’: the level of access granted by the user to this token.
  • ‘aud’: the audience of the token. This token was intended for the Cloud Controller and two other resources managed by the UAA itself: “password” and “openid”.
  • ‘client_id’: a unique identifier for the client to whom the token was granted.

The security features of the token rely on a Resource Server denying access to a resource if any of the following conditions applies:

  • the token has expired
  • the audience does not include the Resource Server
  • the scope is insufficient

Valid scope values are determined by the Resource Servers and they are free to interpret them in any way they need. The UAA has some conventions about the scope values it uses that help Resource Servers to pull out useful information from the scopes. The Client is allowed to ask for specific scopes when it acquires the token, but the UAA limits the values that are available to individual clients. For example, the “vmc” client that was granted the token above is not allowed to acquire a token that has scope outside the values shown (e.g., it can’t create new user accounts).

Scope values in OAuth2 are arbitrary strings, but in the UAA they normally have a resource id (as in the “aud” field) and some level of access (e.g., “read”, “write” and “admin”) separated by a period. Exceptions are the scope values defined in standard specifications like the “openid” value above which is defined in the OpenID Connect specification and gives the Client application access to the user’s profile data (read only).

The scopes in a token are a combination of values from various sources; what the client asked for, what the client is allowed to ask for, and additional group assignment information appended from the User account (“uaa.user” in the example above, signifying that the user is known to the UAA but not given any special status).

User Account Management

One of the main functions of the UAA is to store user account data, and provide endpoints for provisioning and inspecting user accounts. For these purposes the UAA implements the standard Simple Cloud Identity Management (SCIM) API, exposing an endpoint to authorized clients at /Users, and authenticating them using OAuth2 access tokens. For example:

$ curl -H "Authorization: Bearer $TOKEN" https://devuaa.cloudfoundry.com/Users { [ { "id": "4df2ddcb-6314-495b-b077-e1693f54f6a4"}, { "id": "1ce62b22-ea56-4d62-b300-c7a6c1fd9106"}, { "id": "de3ca343-fe9e-4b61-90b0-0eb97810028a"}, { "id": "a41afc1c-3006-41c9-9d3b-5ebb88f37153"}, { "id": "639d9baa-aaf9-488c-a693-d45c11c39594"}, ... ] } $ curl -H "Authorization: Bearer $TOKEN" https://devuaa.cloudfoundry.com/User/4df2ddcb-6314-495b-b077-e1693f54f6a4 { { "id": "4df2ddcb-6314-495b-b077-e1693f54f6a4", "userName": "marissa", "givenName": "Marissa", "familyName": "Bloggs", "emails": [ { "value": "marissa@test.org"} ], "groups": [ { "externalId": "uaa.user"} ] } }

A Client application with sufficient permission can manage User accounts in its own right. The Cloud Controller does this, as do the new services which are in the pipeline to support future improvements to Cloud Foundry.

Client Application Registration

The UAA keeps a registry of Client applications, and what they are allowed to do, so that it can manage the process of issuing tokens (and in particular deny a token grant if the client is invalid, or if it is asking for a scope that it is not allowed). It does this by exposing service endpoints at /oauth/clients/**, and protects them using OAuth2 token authentication. For example:

$ curl -v -H "Authorization: Bearer $TOKEN" 'https://devuaa.cloudfoundry.com/oauth/clients' { "admin": { "scope": ["uaa.none"], "client_id": "admin", "authorized_grant_types": [ "client_credentials" ], "authorities": ["clients.secret", "clients.read", "clients.write"] }, "app": { "scope": ["openid","cloud_controller.read","cloud_controller.write"], "client_id": "app", "authorized_grant_types": ["authorization_code","password","refresh_token"], "redirect_uri": ["http://localhost"], "authorities": ["uaa.none"] }, ... }

The fields in a client registration are:

  • ‘client_id’: a unique identifier.
  • ‘client_secret’: only provided when the registration is first created, or the secret is being changed. Also if the authorized grant types includes “implicit” a secret is not allowed (implicit clients are untrusted).
  • ‘scope’: the valid scope values that the UAA will allow in a token issued to this client acting on behalf of a User (so not with Client Credentials grant).
  • ‘authorized_grant_types’: the grant types that this client is allowed, as listed in the OAuth2 specification.
  • ‘authorities’: the scope values that can be requested by the client if it is asking for a “client_credentials” token grant. The “app” client in the example above is not authorized to request a “client_credentials” grant, so it has a default value “uaa.none” in this field.
  • ‘redirect_uri’: a list of callback URIs that this client is allowed to ask for. Any client that needs implicit or authorization code grants must provide at least one callback URI. The UAA allows it to ask for a callback that start with the value provided in the registration, so it can redirect to multiple places in the same application but only register one callback.
  • Additional fields (primitives or JSON objects) are also stored. The UAA uses a field ‘client_name’ to provide a user-friendly name for the client on the token grant approval page.

As things stand in cloudfoundry.com, if you have an application that you would like to register as a Client application, you should contact the Product Management team via the support site. If you want to provide a Resource Server that accepts OAuth2 tokens granted by the UAA, you should also register the server as a Client application. We are working on providing some user-facing features allowing you to use some of the UAA services including client registration, and those will be announced on the cloudfoundry.com blog site when they are available.

Other UAA Resources

There are some more services provided by the UAA in addition to those described already. Here is a brief list of all the UAA endpoints (with valid scopes if it is an OAuth2 resource):

  • OAuth2 Authorization Server: oauth/authorize and /oauth/token endpoints.
  • User info endpoint (for SSO): /userinfo, scope openid.
  • Token decoding endpoint: /check_token
  • Login info endpoint (open to anyone): /login
  • SCIM user account management: /Users endpoint, scopes [scim.read, scim.write].
  • Password changes: /Users/{id}/password endpoint, scope password.write
  • Token management, e.g. cancelling an approval: /oauth/users/{id}/tokens and /oauth/clients/{id}/tokens, scopes [tokens.read, tokens.write]
  • Client registration: /oauth/clients, scopes [clients.read, clients.write, clients.secret]
  • Password strength meter: /password
  • Management endpoints, used by the Cloud Foundry platform internally: /health and /varz

More detail is available on these and the other services provided by the UAA in the API documentation.

Note: the description of UAA scope values and the precise details of the client registrations are features of the (in progress) 1.1.0 release. You can find the code for this release on the “scopes” branch in GitHub (or on master once 1.1.0 is released). At the time of writing, the devuaa.cloudfoundry.com server is up to date with these features, but uaa.cloudfoundry.com is not.

About the Author

Biography

Previous
Unicycle Butter sandwich
Unicycle Butter sandwich

Helps jasmine:ci not closing chrome windows?

Next
Cocktail: DRY up your backbone code with mixins
Cocktail: DRY up your backbone code with mixins

I've continued to enjoy using Backbone.js to build single page apps. As I've seen more and more real world...

×

Subscribe to our Newsletter

!
Thank you!
Error - something went wrong!