This topic tells you about the User Account and Authentication (UAA) Server, the identity management service for VMware Tanzu Application Service for VMs (TAS for VMs).
The primary role of UAA is as an OAuth2 provider, that issues tokens for client apps to use when they act on behalf of TAS for VMs users. In collaboration with the login server, UAA can authenticate users with their TAS for VMs credentials, and can act as an SSO service using those, or other, credentials.
UAA has endpoints for managing user accounts, registering OAuth2 clients, and various other management functions.
Different runtimes and services use separate UAA instances. TAS for VMs has two UAA instances by default: one for BOSH Director, used to bootstrap the rest of the TAS for VMs deployment; and one for the BOSH deployment, used as a shared resource by all apps that require user authentication. This is the minimum number of UAA instances TAS for VMs must have. Other runtimes and services also have UAA instances. These instances are separate from each other. If you log into one runtime or service, you are not also logged into other runtimes and services that authenticate using UAA. You must log in to each runtime or service separately.
You can deploy UAA locally or to TAS for VMs.
To deploy and run UAA locally:
In a terminal window, clone the UAA GitHub repository by running:
git clone git://github.com/cloudfoundry/uaa.git
Go to the directory where you cloned the UAA GitHub repository.
To build and run all the components that comprise UAA and the example programs uaa
, samples/api
, and samples/app
, run:
./gradlew run
If successful, the three apps run together on a single instance of Tomcat listening on port 8080, with endpoints /uaa
, /app
, and /api
. Tomcat is a library of Java code used by UAA to create its features. For more information, see the Apache Tomcat website.
To access and use a locally deployed UAA server:
Run the UAA server as described in Deploy Locally.
Open another terminal window. From the project base directory, run curl localhost:8080/uaa/info -H "Accept: application/json"
to confirm the UAA is running. You can see basic information about the system. For example:
$ curl localhost:8080/uaa/info -H "Accept: application/json" { "app": { "version": "4.19.0" }, "links": { "uaa": "http://localhost:8080/uaa", "passwd": "/forgot_password", "login": "http://localhost:8080/uaa", "register": "/create_account" }, "zone_name": "uaa", "entityID": "cloudfoundry-saml-login", "commit_id": "af93628", "idpDefinitions": {}, "prompts": { "username": [ "text", "Email" ], "password": [ "password", "Password" ] }, "timestamp": "2018-05-25T15:34:31-0700" }
To install the TAS for VMs UAA Command Line Client (UAAC) Ruby gem, run:
gem install cf-uaac
To target the local UAA server endpoint, run:
uaac target http://localhost:8080/uaa
Run uaac token client get CLIENT_NAME -s CLIENT_SECRET
to obtain an access token. Replace CLIENT_NAME
and CLIENT_SECRET
with actual values. For example, when starting up the UAA locally for development, you must have a predefined admin client to use:
uaac token client get admin -s adminsecret
If you run the command without -s CLIENT_SECRET
, UAAC shows an interactive prompt where you must create the client secret value. The uaac token client get
command requests an access token from the server using the OAuth2 client credentials grant type. For more information about the OAuth2 client credentials, see Client Credentials in the OAuth 2.0 Authorization Framework.
View your UAAC token context. When UAAC obtains a token, the token and other metadata is stored in the ~/.uaac.yml
file on your local machine. To view the token you have obtained, run uaac context
. For example:
$ uaac context [0]*[http://localhost:8080/uaa] [0]*[admin] client_id: admin access_token: eyJhbGciOiJIUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiIxOWYyNWU2Y2E5Y2M0ZWIyYTdmNTAxNmU0NDFjZThkNCIsInN1YiI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiY2xpZW50cy5yZWFkIiwiY2xpZW50cy5zZWNyZXQiLCJjbGllbnRzLndyaXRlIiwidWFhLmFkbWluIiwiY2xpZW50cy5hZG1pbiIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiXSwic2NvcGUiOlsiY2xpZW50cy5yZWFkIiwiY2xpZW50cy5zZWNyZXQiLCJjbGllbnRzLndyaXRlIiwidWFhLmFkbWluIiwiY2xpZW50cy5hZG1pbiIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiXSwiY2xpZW50X2lkIjoiYWRtaW4iLCJjaWQiOiJhZG1pbiIsImF6cCI6ImFkbWluIiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInJldl9zaWciOiIyNjcxOTlkMSIsImlhdCI6MTUyODIzMjAxNywiZXhwIjoxNTI4Mjc1MjE3LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvdWFhL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbInNjaW0iLCJjbGllbnRzIiwidWFhIiwiYWRtaW4iXX0.L2cn6HqLQAEyqTrYYkL9Al_8JyfwB330er7DshUb9wg token_type: bearer expires_in: 43199 scope: clients.read clients.secret clients.write uaa.admin clients.admin scim.write scim.read jti: 19f25e6ca9cc4eb2a7f5016e441ce8d4Copy the access token from this output for the next step.
Run uaac token decode ACCESS-TOKEN-VALUE
to view information in the token, which is encoded using the JSON Web Token (JWT) format. Replace ACCESS-TOKEN-VALUE
with your access token, copied from the uaac context
output. The UAAC displays all the claims inside the token body. For example:
$ uaac token decode eyJhbGciOiJIUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiIxOWYyNWU2Y2E5Y2M0ZWIyYTdmNTAxNmU0NDFjZThkNCIsInN1YiI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiY2xpZW50cy5yZWFkIiwiY2xpZW50cy5zZWNyZXQiLCJjbGllbnRzLndyaXRlIiwidWFhLmFkbWluIiwiY2xpZW50cy5hZG1pbiIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiXSwic2NvcGUiOlsiY2xpZW50cy5yZWFkIiwiY2xpZW50cy5zZWNyZXQiLCJjbGllbnRzLndyaXRlIiwidWFhLmFkbWluIiwiY2xpZW50cy5hZG1pbiIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiXSwiY2xpZW50X2lkIjoiYWRtaW4iLCJjaWQiOiJhZG1pbiIsImF6cCI6ImFkbWluIiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInJldl9zaWciOiIyNjcxOTlkMSIsImlhdCI6MTUyODIzMjAxNywiZXhwIjoxNTI4Mjc1MjE3LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvdWFhL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbInNjaW0iLCJjbGllbnRzIiwidWFhIiwiYWRtaW4iXX0.L2cn6HqLQAEyqTrYYkL9Al_8JyfwB330er7DshUb9wg Note: no key given to validate token signature jti: 19f25e6ca9cc4eb2a7f5016e441ce8d4 sub: admin authorities: clients.read clients.secret clients.write uaa.admin clients.admin scim.write scim.read scope: clients.read clients.secret clients.write uaa.admin clients.admin scim.write scim.read client_id: admin cid: admin azp: admin grant_type: client_credentials rev_sig: 267199d1 iat: 1528232017 exp: 1528275217 iss: http://localhost:8080/uaa/oauth/token zid: uaa aud: scim clients uaa admin
To build the UAA as an app and push it to TAS for VMs using the Cloud Foundry Command Line Interface (cf CLI):
Clone the UAA GitHub repository by running:
git clone git://github.com/cloudfoundry/uaa.git
Go to the directory where you cloned the UAA GitHub repository.
Build the UAA as a WAR file by running:
./gradlew :cloudfoundry-identity-uaa:war
Run the cf CLI cf push APP-NAME -m 512M -p PATH-TO-WAR-FILE --no-start
command to push the app to TAS for VMs. Replace APP-NAME
with a name for your UAA app, and PATH-TO-WAR-FILE
with the path to the WAR file you created in the previous step. For example:
cf push MYUAA -m 512M -p uaa/build/libs/cloudfoundry-identity-uaa-1.8.0.war --no-start
Run cf set-env APP-NAME SPRING_PROFILES_ACTIVE default
to set the SPRING_PROFILES_ACTIVE
environment variable with the value default
. Replace APP-NAME
with the name of your app that you used in the previous step. For example:
cf set-env MYUAA SPRING_PROFILES_ACTIVE default
Run cf start APP-NAME
to start your app. Replace APP-NAME
with the name of your app. For example:
cf start MYUAA
You use a UAA server that you pushed as an app to TAS for VMs in a similar way to one you run locally. You do not need app token encoding because you do not have the client secret.
To access and use a UAA server that you pushed as an app to TAS for VMs:
Follow the procedure in Deploy UAA to TAS for VMs.
From the project base directory, run curl -H "Accept: application/json" APP-FQDN/login
to query the external login endpoint about the system. Replace APP-FQDN
with the fully qualified domain name (FQDN) of your app. For example:
$ curl -H "Accept: application/json" uaa.example.org/login { "timestamp":"2014-09-15T18:25:04+0000", "app":{"version":"1.8.3"}, "commit_id":"git-metadata-not-found", "prompts":{"username":["text","Email"], "password":["password","Password"] } }
Install the UAA Command Line Client (UAAC) Ruby gem by running:
gem install cf-uaac
Target the remote UAA Server endpoint by running:
uaac target APP-FQDN
Where APP-FQDN
is the FQDN of your app.
Log in by running:
uaac token get USERNAME PASSWORD
Where:
USERNAME
is your username.PASSWORD
is your password. If you do not specify a username and password, the UAAC prompts you to supply them.The uaac token client get
command authenticates and obtains an access token from the server using the OAuth2 implicit grant, similar to the approach intended for a standalone client like the cf CLI.
When you run integration tests, it makes sure that the UAA instance is running properly.
To run integrations tests:
./gradlew integrationTest
This command starts a UAA server running in a local Apache Tomcat instance. By default, the service URL is set to http://localhost:8080/uaa
.
You can set the environment variable CLOUD_FOUNDRY_CONFIG_PATH
to a directory containing a uaa.yml
file where you change the URLs used in the tests, and where you can set the UAA server context root.
A custom YAML configuration gives integration tests access to your UAA instance by sharing credentials in YAML file.
To create a custom YAML configuration:
Create a uaa.yml
file in the following format:
uaa:
host: UAA-HOSTNAME
test:
username: USERNAME
password: PASSWORD
email: EMAIL-ADDRESS
Where:
UAA-HOSTNAME
is the FQDN of UAA app. For example, uaa.example.org
.USERNAME
is a valid username. For example, dev@example.org
.PASSWORD
is the password for the previous username.EMAIL-ADDRESS
is the email address for the previous user. Example: dev@example.org
.From the uaa/uaa
directory, run:
CLOUD_FOUNDRY_CONFIG_PATH=/tmp ./gradlew test
The web app looks for a YAML file in the following locations when it starts, with later entries overriding earlier ones:
classpath:uaa.yml
file:${CLOUD_FOUNDRY_CONFIG_PATH}/uaa.yml
file:${UAA_CONFIG_FILE}
${UAA_CONFIG_URL}
The default UAA unit tests, ./gradlew test
, use a HyperSQL database.
To use a different database management system:
Create a uaa.yml
file containing spring_profiles: default,OTHER-DBMS
in the src/main/resources/
directory. Replace OTHER-DBMS
with the name of the other database management system to use.
Run the unit tests using your specified database management system instead of a HyperSQL database:
echo "spring_profiles: default,OTHER-DBMS" > src/main/resources/uaa.yml
./gradlew test integrationTest
Where OTHER-DBMS
is the name of the database management system you specified in your uaa.yml
file.
You can find the database configuration for the common and scim modules at common/src/test/resources/(mysql|postgresql).properties
and scim/src/test/resources/(mysql|postgresql).properties
.
The following UAA projects exist:
common
: A module containing a JAR with all the business logic. common
is used in the web apps.
uaa
: The UAA server. uaa
provides an authentication service and authorized delegation for back-end services and apps by issuing OAuth2 access tokens.
api
: A sample OAuth2 resource service that returns a mock list of deployed apps. api
provides resources that other apps might want to access on behalf of the resource owner.
app
: A sample user app that uses both api
and uaa
. app
is a web app that requires single sign-on and access to the api
service on behalf of users.
scim
: The System for Cross-domain Identity Management (SCIM) user management module used by UAA. For more information about SCIM, see Managing Users & Groups with SCIM.
The authentication service, uaa
, is a Spring MVC web app. You can deploy it in Tomcat or your container of choice, or run ./gradlew run
to run it directly from the uaa
directory in the source tree. When run with Gradle, uaa
listens on port 8080 and has the URL http://localhost:8080/uaa
.
The UAA server supports the APIs defined in the UAA-APIs document which include:
The OAuth2 /authorize
and /token
endpoints.
A /login_info
endpoint to allow querying for required login prompts.
An /introspect
endpoint to allow resource servers to obtain information about an access token submitted by an OAuth2 client.
A SCIM user-provisioning endpoint.
OpenID Connect endpoints /userinfo
and /check_id
to support authentication.
Command-line clients can perform authentication by submitting credentials directly to the /authorize
endpoint.
An ImplicitAccessTokenProvider
exists in Spring Security OAuth to use if your client is Java.
By default, uaa
runs with a context root /uaa
.
A uaa.yml
file exists in the app. This file provides defaults to the placeholders in the Spring XML.
You can override any occurrences of ${placeholder.name}
in the XML by adding it to your uaa.yml
file, or by providing a System property with the same name, -D
, to your Java virtual machine.
All passwords and client secrets in the configuration files are in plain text, but are inserted into the UAA database encrypted with BCrypt.
The default uses an in-memory relational database management system (RDBMS) user store, pre-populated with a single test user marissa
with the password koala
.
To use PostgreSQL for user data, you must activate the Spring profile postgresql
.
You can configure the active profiles in your uaa.yml
file using spring_profiles: postgresql,default
.
To use PostgreSQL instead of HyperSQL, run:
echo "spring_profiles: postgresql,default" > src/main/resources/uaa.yml
./gradlew run
To bootstrap a microcloud-type environment, you need an admin client. During the bootstrapping process, the database creates a database initializer component that inserts an admin client.
If the default profile is active, the bootstrapping process creates a cf CLI client so that the Gem login works with no additional configuration required. You can override the default settings and add additional clients in the uaa.yml
file, as in the following example:
oauth:
clients:
admin:
authorized-grant-types: client_credentials
scope: read,write,password
authorities: ROLE_CLIENT,ROLE_ADIN
id: admin
secret: adminclientsecret
resource-ids: clients
You can use the admin client to create additional clients. You must have a client with read/write access to the scim
resource to create user accounts. The integration tests handle this automatically by inserting client and user accounts as necessary for the tests.
Two sample apps are included with UAA: /api
and /app
.
You can run /api
and /app
with ./gradlew run
from the uaa
root directory. All three apps, /uaa
, /api
, and /app
, are simultaneously deployed.
The api
sample app is an example resource server. It hosts a service that returns a list of mock apps under /apps
.
The app
sample app is a user interface app, primarily aimed at browsers, that uses OpenID Connect for authentication and OAuth2 for access grants. app
authenticates with the Auth service, then accesses resources in the API service. You can run app
with ./gradlew run
from the uaa
root directory.
The app can operate in multiple different profiles according to the location and presence of the UAA server and the login app. By default, the app looks for a UAA on localhost:8080/uaa
, but you can change this by setting the UAA_PROFILE
environment variable or System Property.
The app source code, samples/app/src/main/resources
, contains multiple properties files pre-configured with different likely locations for those servers. The names of these properties files follow the format app-UAA_PROFILE.properties
.
The naming convention for the UAA_PROFILE
is:
local
: a localhost deployment
vcap
: a vcap.me
deployment
staging
: a staging deployment
Profile names can be hyphenated to indicate multiple contexts. For example, local-vcap
can be used when the login server is in a different location than the UAA server.
To see all apps, run:
GET /app/apps
The browser is redirected through a series of authentication and access grant steps.
To see the currently logged-in user details and a selection of attributes from the OpenID provider, run:
GET /app
The login
app is a user interface for authentication. UAA can also authenticate user accounts, but only if it manages them itself and it only provides a basic UI. You can brand and customize the login app for non-native authentication and for more complicated UI flows, like user registration and password reset.
The log in app is itself an OAuth2 endpoint provider, but delegates those features to the UAA server. Therefore, configuration for the log in app consists of locating the UAA through its OAuth2 endpoint URLs and registering the log in app itself as a client of the UAA. The UAA locations have a login.yml
file. For example, a local vcap
instance:
uaa:
url: http://uaa.vcap.example.net
token:
url: http://uaa.vcap.example.net/oauth/token
login:
url: http://uaa.vcap.example.net/login.do
You can define the environment variable or Java System property login_secret
to use a client secret that the app uses when it authenticates itself with UAA. The login
app is registered by default in UAA only if there are no active Spring profiles. In UAA, the registration is located in the oauth-clients.xml
config file, as in the following example:
id: login
secret: loginsecret
authorized-grant-types: client_credentials
authorities: ROLE_LOGIN
resource-ids: oauth
To authenticate with the login
app, run:
GET /login
The sample app presents a form log-in interface for the back end UAA, and an OpenID widget where a user can authenticate using Google or other credentials.
To approve an OAuth2 token grant, run:
GET /oauth/authorize?client_id=app&response_type=code...
This is the standard OAuth2 authorization endpoint. UAA handles client credentials and all other features in the back end, and the login
app is used to render the UI.
To obtain the access token, run:
POST /oauth/token
This is the standard OAuth2 authorization endpoint passed through to UAA.
UAA covers multiple scopes of privilege, and has access to UAA, Cloud Controller, and to the router. For more information about UAA, see OAuth Scopes.
The following table describes the scopes of privilege in UAA.
Scope | Description |
---|---|
uaa.user |
This scope indicates that this is a user. It is required in the token if submitting a GET request to the OAuth 2 /authorize endpoint. |
uaa.none |
This scope indicates that this client will not be performing actions on behalf of a user. |
uaa.admin |
This scope indicates that this is the superuser. |
scim.write |
This scope gives admin write access to all SCIM endpoints, /Users , and /Groups . |
scim.read |
This scope gives admin read access to all SCIM endpoints, /Users , and /Groups . |
scim.create |
This scope gives the ability to create a user with a POST request to the /Users endpoint, but not to modify, read, or delete users. |
scim.userids |
This scope is required to convert a username and origin into a user ID and vice versa. |
scim.invite |
This scope is required to participate in invitations using the /invite_users endpoint. |
groups.update |
This scope gives the ability to update a group. This ability can also be provided by the broader scim.write scope. |
password.write |
This admin scope gives the ability to change a user’s password. |
openid |
This scope is required to access the /userinfo endpoint. It is intended for OpenID clients. |
idps.read |
This scope gives read access to retrieve identity providers from the /identity-providers endpoint. |
idps.write |
This scope gives the ability to create and update identity providers from the /identity-providers endpoint. |
clients.admin |
This scope gives the ability to create, modify, and delete clients. |
clients.write |
This scope is required to create and modify clients. The scopes are prefixed with the scope holder’s client ID. For example, id:testclient authorities:client.write gives the ability to create a client that has scopes with the testclient. prefix. Authorities are limited to uaa.resource . |
clients.read |
This scope gives the ability to read information about clients. |
clients.secret |
This admin scope is required to change the password of a client. |
zones.read |
This scope is required to run the /identity-zones endpoint to read identity zones. |
zones.write |
This scope is required to run the /identity-zones endpoint to create and update identity zones. |
scim.zones |
This is a limited scope that only allows adding a user to, or removing a user from, zone management groups under the path /Groups/zones . |
oauth.approval |
/approvals endpoint . This scope is required to approve or reject clients to act on a user’s behalf. This is a default scope defined in the uaa.yml file. |
oauth.login |
This scope is used to indicate a login app, such as external login servers, can perform trusted operations, such as creating users not authenticated in the UAA. |
approvals.me |
This scope is not currently used. |
uaa.resource |
This scope indicates that this is a resource server, used for the /introspect endpoint. |
zones.ZONE-ID.admin |
This scope permits operations in a designated zone, such as creating identity providers or clients in another zone, by authenticating against the default zone. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.read |
This scope permits reading the given identity zone. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.clients.admin |
This scope translates into clients.admin after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.clients.read |
This scope translates into clients.read after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.clients.write |
his scope translates into clients.write after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.clients.scim.read |
This scope translates into scim.read after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.clients.scim.create |
This scope translates into scim.create after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.clients.scim.write |
This scope translates into scim.write after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
zones.ZONE-ID.idps.read |
This scope translates into idps.read after zone switch completes. This scope is used with the X-Identity-Zone-Id header . |
The following table describes the scopes of privilege in Cloud Controller.
Scope | Description |
---|---|
cloud_controller.read |
This scope gives the ability to read from any Cloud Controller route the token has access to. |
cloud_controller.write |
This scope gives the ability to post to Cloud Controller routes the token has access to. |
cloud_controller.admin |
This admin scope gives full permissions to Cloud Controller. |
cloud_controller.admin_read_only |
This admin scope gives read permissions to Cloud Controller. |
cloud_controller.global_auditor |
This scope gives read-only access to all Cloud Controller API resources except for secrets such as environment variables. |
The following table describes the scopes of privilege in the router.
Scope | Description |
---|---|
routing.routes.read |
This scope gives the ability to read the full routing table from the router. |
routing.routes.write |
This scope gives the ability to write the full routing table from the router. |
routing.router_groups.read |
This scope gives the ability to read the full list of routing groups. |
routing.router_groups.write |
This scopes gives the ability to write the full list of routing groups. |
The following table describes the scopes of privilege in other TAS for VMs services.
Scope | Description |
---|---|
doppler.firehose |
This scope gives the ability to read logs from the How the Loggregator Firehose forwards Logs and Metrics endpoint. |
notifications.write |
This scope gives the ability to send notifications through the Getting started with the Notifications Service. |