This chapter covers OpenAM support for the OAuth 2.0 authorization framework. The chapter begins by showing where OpenAM fits into the OAuth 2.0 authorization framework, and then shows how to configure the functionality.
RFC 6749, The OAuth 2.0 Authorization Framework, provides a standard way for resource owners to grant client applications access to the owners' web-based resources. The canonical example involves a user (resource owner) granting access to a printing service (client) to print photos that the user has stored on a photo-sharing server.
The section describes how OpenAM supports the OAuth 2.0 authorization framework in terms of the roles that OpenAM plays.[8] The following sequence diagram indicates the primary roles OpenAM can play in the OAuth 2.0 protocol flow.
OpenAM can function as an OAuth 2.0 authorization server. In this role, OpenAM authenticates resource owners and obtains their authorization in order to return access tokens to clients.
When using OpenAM as authorization server, you register clients with OpenAM by using OAuth 2.0 policy agent profiles. OpenAM supports both confidential and public clients.
OpenAM supports the four main grants for obtaining authorization described in RFC 6749: the authorization code grant, the implicit grant, the resource owner password credentials grant, and the client credentials grant. See RFC 6749 for details on the authorization grant process, and for details on how clients should make authorization requests and handle authorization responses. OpenAM also supports the SAML 2.0 Bearer Assertion Profiles for OAuth 2.0, described in the Internet-Draft.
The authorization code grant starts with the client, such as a web-based service, redirecting the resource owner's user-agent to the OpenAM authorization service. After authenticating the resource owner and obtaining the resource owner's authorization, OpenAM redirects the resource owner's user-agent back to the client with an authorization code that the client uses to request the access token. The following sequence diagram outlines a successful process from initial client redirection through to the client accessing the protected resource.
The implicit grant is designed for clients implemented to run inside the resource-owner user agent. Instead of providing an authorization code that the client must use to retrieve an access token, OpenAM returns the access token directly in the fragment portion of the redirect URI. The following sequence diagram outlines the successful process.
The resource owner password credentials grant lets the client use the resource owner's user name and password to get an access token directly. Although this grant might seem to conflict with an original OAuth goal of not having to share resource owner credentials with the client, it can makes sense in a secure context where other authorization grant types are not available, such as a client that is part of a device operating system using the resource owner credentials once and thereafter using refresh tokens to continue accessing resources. The following sequence diagram shows the successful process.
The client credentials grant uses client credentials as an authorization grant. This grant makes sense when the client is also the resource owner, for example. The following sequence diagram shows the successful process.
The Internet-Draft, SAML 2.0 Bearer Assertion Profiles for OAuth 2.0, describes a means to use SAML 2.0 assertions to request access tokens and to authenticate OAuth 2.0 clients.
At present OpenAM implements the profile to request access tokens.
In both profiles, the issuer must sign the assertion. The client communicates the assertion over a channel protected with transport layer security, by performing an HTTP POST to the OpenAM's access token endpoint. OpenAM as OAuth 2.0 authorization server uses the issuer ID to validate the signature on the assertion.
In the profile to request an access token, the OAuth 2.0 client bears a SAML 2.0 assertion that was issued to the resource owner on successful authentication. A valid assertion in this case is equivalent to an authorization grant by the resource owner to the client. OAuth 2.0 clients must make it clear to the resource owner that by authenticating to the identity provider who issues the assertion, they are granting the client permission to access the protected resources.
The HTTP POST to OpenAM to request an access token looks something like this:
POST /openam/oauth2/access_token HTTP/1.1
Host: openam.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-bearer&
assertion=PHNhbWxwOl...[base64url encoded assertion]...ZT4&
client_id=[ID registered with OpenAM]If OpenAM is already a SAML 2.0 service provider, you can configure OpenAM as OAuth 2.0 authorization server as well, and set an adapter class name in the service provider configuration that lets OpenAM POST the assertion from the service provider to the authorization server. See Section 13.6, “Configuring OpenAM as Both SAML 2.0 Service Provider & OAuth 2.0 Authorization Server” for details.
In addition to the standard authorization and token endpoints described in RFC 6749, OpenAM also exposes a token information endpoint for resource servers to get information about access tokens so they can determine how to respond to requests for protected resources. OpenAM as authorization server exposes the following endpoints for clients and resource servers.
/oauth2/authorizeAuthorization endpoint defined in RFC 6749, used to obtain an authorization grant from the resource owner
Example: https://openam.example.com:8443/openam/oauth2/authorize
/oauth2/access_tokenToken endpoint defined in RFC 6749, used to obtain an access token from the authorization server
Example: https://openam.example.com:8443/openam/oauth2/access_token
/oauth2/tokeninfoEndpoint not defined in RFC 6749, used to validate tokens, and to retrieve information such as scopes
Given an access token, a resource server can perform an HTTP GET on
/oauth2/tokeninfo?access_token=
to retrieve a JSON object indicating token-idtoken_type,
expires_in, scope, and the
access_token ID.
Example: https://openam.example.com:8443/openam/oauth2/tokeninfo
For examples, see the Developer's Guide section, OAuth 2.0 Authorization.
OpenAM can function as an OAuth 2.0 client for installations where the web resources are protected by OpenAM. To configure OpenAM as an OAuth 2.0 client, you set up an OpenAM OAuth 2.0 authentication module instance, and then integrate the authentication module into your authentication chains as necessary.
When OpenAM functions as an OAuth 2.0 client, OpenAM provides an OpenAM SSO session after successfully authenticating the resource owner and obtaining authorization. This means the client can then access resources protected by policy agents. In this respect the OpenAM OAuth 2.0 client is just like any other authentication module, one that relies on an OAuth 2.0 authorization server to authenticate the resource owner and obtain authorization. The following sequence diagram shows how the client gains access to protected resources in the scenario where OpenAM functions as both authorization server and client for example.
As the OAuth 2.0 client functionality is implemented as an OpenAM authentication module, you do not need to deploy your own resource server implementation when using OpenAM as an OAuth 2.0 client. Instead, use policy agents or OpenIG to protect resources.
To configure OpenAM as an OAuth 2.0 client, see Hints For the OAuth 2.0 Authentication Module.
OpenAM returns bearer tokens as described in RFC 6750, The OAuth 2.0 Authorization Framework: Bearer Token Usage. Notice in the following example JSON response to an access token request that OpenAM returns a refresh token with the access token. The client can use the refresh token to get a new access token as described in RFC 6749.
{
"expires_in": 599,
"token_type": "Bearer",
"refresh_token": "f6dcf133-f00b-4943-a8d4-ee939fc1bf29",
"access_token": "f9063e26-3a29-41ec-86de-1d0d68aa85e9"
}In addition to implementing your client, the resource server must also
implement the logic for handling access tokens. The resource server can use
the /oauth2/tokeninfo endpoint to determine whether the
access token is still valid, and to retrieve the scopes associated with the
access token.
The default OpenAM implementation of OAuth 2.0 scopes assumes that the space-separated (%20 when URL encoded) list of scopes in an access token request correspond to names of attributes in the resource owner's profile.
To take a concrete example, consider an access token request where
scope=mail%20cn and where the resource owner is the
default OpenAM demo user. (The demo user has no email address by default, but
you can add one, such as demo@example.com to the demo
user's profile.) When the resource server performs an HTTP GET on the token
information endpoint, /oauth2/tokeninfo?access_token=, OpenAM populates the
token-idmail and cn scopes with the email
address (demo@example.com) and common name
(demo) from the demo user's profile. The result is a
something like the following token information response.
{
"mail": "demo@example.com",
"scope": [
"mail",
"cn"
],
"cn": "demo",
"realm": "/",
"token_type": "Bearer",
"expires_in": 577,
"access_token": "f9063e26-3a29-41ec-86de-1d0d68aa85e9"
}OpenAM is designed to allow you to plug in your own scopes implementation if the default implementation does not do what your deployment requires. See Customizing OAuth 2.0 Scope Handling for an example.
You configure the OAuth 2.0 authorization service for a particular realm, starting from the Common Tasks page of the OpenAM console. This process also protects the authorization endpoint using a standard policy.
Follow these steps.
In the OpenAM console, select Common Tasks > Configure OAuth2.
On the Configure OAuth2 page, enter the Realm for the authorization service.
If necessary, adjust the lifetimes for authorization codes (10 minutes is the recommended setting in RFC 6749), access tokens, and refresh tokens.
Select Issue Refresh Tokens unless you do not want the authorization service to supply a refresh token when returning an access token.
Select Issue Refresh Tokens on Refreshing Access Tokens unless you do not want the authorization service to supply a refresh token when refreshing an access token.
If you want to use the default scope implementation, whereby scopes are taken to be resource owner profile attribute names, then keep the default setting.
If you have a custom scope implementation, put it on the OpenAM classpath, and provide the class name as Scope Implementation Class.
Click Create to complete the process.
In addition to setting up an OAuth 2.0 authorization server for the
realm, OpenAM sets up a policy to protect the authorization endpoint.
The policy appears in the list of policies for the realm. Its name is
OAuth2ProviderPolicy.
If your provider has plugins for custom response types, add the custom response types and the corresponding plugin class names to the list of Response Type Plugins.
If resource owners log in with a user name that is not their user ID, but instead their mail address or some other profile attribute, then add the profile attribute name to the list that can be used for authentication.
To make the change, browse to Access Control > Realm
Name > Services > OAuth2 Provider, add the profile
attributes to the list titled User Profile Attribute(s) the Resource Owner
is Authenticated On.
Set a multi-valued profile attribute where OpenAM can store a resource owner's decisions to authorize clients without further interaction in the Shared Consent Attribute Name field.
If no profile attribute is available for this purpose, you can add an attribute as described in Customizing Profile Attributes in the Developer's Guide.
Save your changes.
You can further adjust the authorization server configuration after you
create it in the OpenAM console under Access Control > Realm
Name > Services > OAuth2 Provider.
You can adjust global defaults in the OpenAM console under Configuration > Global > OAuth2 Provider.
You register an OAuth 2.0 client with the OpenAM OAuth 2.0 authorization service by creating and configuring an OAuth 2.0 Client agent profile.
At minimum you must have the client identifier and client password in order to register your OAuth 2.0 client.
Use either of these two facilities.
In the OpenAM console, access the client registration endpoint
at /oauth2/registerClient.jsp.
The full URL depends on where you deployed OpenAM. For example,
https://openam.example.com:8443/openam/oauth2/registerClient.jsp.
The Register a Client page lets you quickly create and configure an OAuth 2.0 client in a simple web page without inline help.
In the OpenAM console under Access Control > Realm
Name > Agents > OAuth 2.0 Client > Agent, click
New, then provide the client identifier and client password, and
finally click Create to create the profile.
This page requires that you perform additional configuration separately.
After initially registering or creating a client agent profile as necessary.
In the OpenAM console, browse to Access Control >
Realm Name > Agents > OAuth 2.0 Client
> Agent > Client Name to open the Edit
Client Name page.
Adjust the configuration as needed using the inline help for hints, and also the documentation section Configuring OAuth 2.0 & OpenID Connect 1.0 Clients.
Examine the client type option. An important decision to make at this point is whether your client is a confidential client or a public client. This depends on whether your client can keep its credentials confidential, or whether its credentials can be exposed to the resource owner or other parties. If your client is a web-based application running on a server, such as the OpenAM OAuth 2.0 client, then you can keep its credentials confidential. If your client is a user-agent based client, such as a JavaScript client running in a browser, or a native application installed on a device used by the resource owner, then yours is a public client.
When finished, Save your work.
OpenAM exposes a RESTful API that lets administrators read, list, and delete OAuth 2.0 tokens. OAuth 2.0 clients can also manage their own tokens. See the Developer's Guide section on the OAuth 2.0 Token Administration Endpoint for details.
This section takes a high-level look at how to set up OpenAM both as an OAuth 2.0 authorization server and also as a client in order to protect resources by using a policy agent. The high-level steps are as follows.
Set up a policy agent or OpenIG to protect your web resources, including the policy used to protect the resources.
Make sure you can access the resources using an authentication module that you already know before working with OAuth 2.0.
Configure OpenAM's OAuth 2.0 authorization service as described in Section 13.2, “Configuring the OAuth 2.0 Authorization Service”.
Configure an OpenAM OAuth 2.0 authentication module instance using the Hints For the OAuth 2.0 Authentication Module with the OpenAM authorization service endpoints.
Register the OAuth 2.0 authentication module as an OAuth 2.0 confidential client as described in Section 13.3, “Registering OAuth 2.0 Clients With the Authorization Service”.
Logout and access the protected resources to see the process in action.
This example pulls everything together (except security considerations), using OpenAM as an OAuth 2.0 authorization server, OAuth 2.0 client, and "resource server" by protecting web resources with a policy agent.
This example uses two hosts, oauth2.example.com
where OpenAM is deployed at
http://oauth2.example.com:8080/openam, and
www.example.com where the resources to protect are
deployed in Apache Tomcat at
http://www.example.com:8080/examples.
Set up an OpenAM policy agent and policy in the top-level realm,
/, to protect resources. So far this is standard
OpenAM, unrelated to OAuth 2.0.
See the OpenAM Web Policy
Agent Installation Guide
or OpenAM Java EE Policy
Agent Installation Guide
for instructions on installing a policy agent. This example relies on the
Apache Tomcat Java EE policy agent, configured to protect resources in
Apache Tomcat at http://www.example.com:8080/.
The policies for this example protect the Apache Tomcat examples
under http://www.example.com:8080/examples/, allowing
GET and POST operations by all authenticated users. For more information
on creating policies, see Configuring
Policies.
After setting up the policy agent and the policy, you can make sure
everything is working by attempting to access a protected resource, in this
case http://www.example.com:8080/examples/. The policy
agent should redirect you to OpenAM to authenticate with the default
authentication module, where you can login as user demo
password changeit. After successful authentication,
OpenAM redirects your browser back to the protected resource and the
policy agent lets you get the protected resource, in this case the Tomcat
examples top page.
Configure OpenAM's OAuth 2.0 authorization service as described in Section 13.2, “Configuring the OAuth 2.0 Authorization Service”.
The authorization endpoint to protect in this example is at
http://oauth2.example.com:8080/openam/oauth2/authorize.
Configure an OpenAM OAuth 2.0 authentication module instance for the top-level realm.
Under Access Control > / (Top-Level Realm) > Authentication
> Module Instances, click New. Name the module
OAuth2, and select the OAuth 2.0 type, then click
OK to save your work.
Then click Authentication > Module Instances > OAuth2 to open the OAuth 2.0 client configuration page. This page offers numerous options. The key settings for this example are the following.
This is the client identifier used to register your client with OpenAM's authorization server, and then used when your client must authenticate to OpenAM.
Set this to myClientID for this example.
This is the client password used to register your client with OpenAM's authorization server, and then used when your client must authenticate to OpenAM.
Set this to password for this example. Make
sure you use strong passwords when you actually deploy OAuth 2.0.
In this example,
http://oauth2.example.com:8080/openam/oauth2/authorize.
This OpenAM endpoint can take additional parameters. In particular you must specify the realm if the OpenAM OAuth 2.0 provider is configured for a subrealm rather than / (Top-Level Realm).
For example, if the OAuth 2.0 provider is configured for the
realm /customers, then use the following URL:
https://openam.example.com:8443/openam/oauth2/authorize?realm=/customers
The /oauth2/authorize endpoint can also take
module and service parameters. Use
either as described in Authenticating To OpenAM, where
module specifies the authentication module instance
to use or service specifies the authentication chain
to use when authenticating the resource owner.
In this example,
http://oauth2.example.com:8080/openam/oauth2/access_token.
This OpenAM endpoint can take additional parameters. In particular you must specify the realm if the OpenAM OAuth 2.0 provider is configured for a subrealm rather than / (Top-Level Realm).
For example, if the OAuth 2.0 provider is configured for the
realm /customers, then use the following URL:
https://openam.example.com:8443/openam/oauth2/access_token?realm=/customers
In this example,
http://oauth2.example.com:8080/openam/oauth2/tokeninfo.
In this example, cn.
The demo user has common name demo by default,
so by setting this to cn|Read your user name, OpenAM
can get the value of the attribute without the need to create
additional subjects, or to update existing subjects. The description,
Read your user name, is shown to the resource owner
in the consent page.
Identifies the parameter that contains the access token value, which
in this example is access_token.
The client redirect URL, which in this example is
http://oauth2.example.com:8080/openam/oauth2c/OAuthProxy.jsp.
In this example,
org.forgerock.openam.authentication.modules.oauth2.DefaultAccountMapper.
In this example, cn=cn.
In this example, disable this functionality.
OpenAM can create local accounts based on the account information returned by the authorization server. For this example, map all users to the anonymous account to keep it simple.
In this example, enable this functionality.
Register the OAuth 2.0 authentication module as an OAuth 2.0 confidential client as described in Section 13.3, “Registering OAuth 2.0 Clients With the Authorization Service”.
Under Access Control > / (Top-Level Realm) > Agents >
OAuth 2.0 Client > Agents > myClientID, adjust
the following settings.
In this example, confidential. OpenAM protects
its credentials as an OAuth 2.0 client.
In this example,
http://oauth2.example.com:8080/openam/oauth2c/OAuthProxy.jsp.
In this example, cn.
Before you try it out, you must make the following additional change to the configuration.
Your OpenAM OAuth 2.0 client authentication module is not part of the default chain, and therefore OpenAM does not call it unless you specifically request the OAuth 2.0 client authentication module.
To cause the policy agent to request your OAuth 2.0 client
authentication module explicitly, browse in OpenAM console to your
policy agent profile configuration, in this case
Access Control > / (Top-Level Realm) > Agents > J2EE >
Agents > Tomcat > OpenAM Services > OpenAM
Login URL, and add
http://oauth2.example.com:8080/openam/UI/Login?module=OAuth2,
moving it to the top of the list.
Save your work.
This ensures that the policy agent directs the resource owner
to OpenAM with the instruction to authenticate using the
OAuth2 authentication module.
Try it out.
First make sure you are logged out of OpenAM, for example by
browsing to the logout URL, in this case
http://oauth2.example.com:8080/openam/UI/Logout.
Next attempt to access the protected resource, in this case
http://www.example.com:8080/examples/.
If everything is set up properly, the policy agent redirects your
browser to the login page of OpenAM with module=OAuth2
among other query string parameters. After you authenticate, for example
as user demo, password changeit,
OpenAM presents you with an authorization decision page.
When you click Allow, the authorization service creates an SSO session, and redirects the client back to the resource, thus allowing the client to access the protected resource. If you configured an attribute on which to store the saved consent decision, and you choose to save the consent decision for this authorization, then OpenAM can use that saved decision to avoid prompting you for authorization next time the client accesses the resource, but only ensure that you have authenticated and have a valid session.
As described in Section 13.1.1.5, “SAML 2.0 Bearer Assertion Profiles”, OpenAM as OAuth 2.0 authorization server can handle the profile where a SAML 2.0 assertion borne by the client functions as an authorization grant to get an access token. This lets a client get an access token when a resource owner completes SAML 2.0 Web Single Sign-On.
You can configure OpenAM as both SAML 2.0 service provider and OAuth 2.0 authorization server, using an built-in adapter class to POST assertions returned to the service provider to the access token endpoint of the authorization server. This allows clients to send a resource owner to the identity provider for SAML 2.0 web SSO, get an assertion at the service provider, and retrieve an access token from the authorization server. In other words, once this scenario is configured, the client must only direct the resource owner to start web SSO as described in Using SAML 2.0 Single Sign-On & Single Logout, and then retrieve the access token on success or handle the error condition on failure.
For this scenario to work, the following conditions must be met.
The client must make the resource owner understand that by authenticating to the SAML 2.0 identity provider the resource owner grants the client access to the protected resources. OpenAM does not present the resource owner with an authorization decision.
The SAML 2.0 identity provider issuing the assertion must sign the assertion, and must correctly handle the name ID for the subject.
OpenAM as relying party must request that assertions are signed, must
verify the signatures on assertions, must correctly handle name IDs
from the issuer, and must use the built-in
org.forgerock.restlet.ext.oauth2.flow.OAuth2Saml2GrantSPAdapter
adapter class in the service provider configuration to POST assertions
to the OAuth 2.0 authorization service.
The OAuth 2.0 authorization service and SAML 2.0 service provider must be configured together on the same OpenAM server.
An OAuth 2.0 client configuration on OpenAM with the same name as the service provider entity ID must be set up on OpenAM.
The OAuth 2.0 client initiating the process must be able to consume the access token and to handle errors if necessary.
Follow these steps. The test configuration hints in this procedure let you prepare configuration to test with the demo user created in OpenAM by default.
Make sure the SAML 2.0 identity provider signs assertions and that name IDs are correctly configured to map resource owner accounts.
When configuring OpenAM as a hosted identity provider follow these steps.
Make sure the Signing Key is properly configured on setup.
For a test configuration, select the test
certificate shown in the Common Tasks > Create Hosted Service Provider
wizard.
Make sure name IDs are properly configured.
For a test configuration, in the OpenAM console under Federation
> Entity Providers > IDP name >
NameID Value Map, add
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified=cn
and then Save your work.
For more detail on configuring OpenAM as a SAML 2.0 identity provider, see Configuring Identity Providers.
Configure OpenAM as service provider.
Set up a hosted service provider in OpenAM console under
Common Tasks > Create Hosted Service Provider, keeping track of
the name, such as https://www.sp.example:8443/openam,
and selecting Use default attribute mapping from Identity Provider.
For details on configuring OpenAM as a SAML 2.0 service provider, see Configuring Service Providers.
Under Federation > Entity Providers > SP
name > Assertion Content > Request/Response Signing,
check Assertions Signed.
For a test configuration, in Federation > Entity Providers >
SP name > Assertion Content > NameID
Format List, remove all but
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified,
and then Save your work.
In Federation > Entity Providers > SP
name > Assertion Processing > Adapter, add
org.forgerock.restlet.ext.oauth2.flow.OAuth2Saml2GrantSPAdapter,
and then Save your work.
This is the adapter class that POSTs the SAML 2.0 assertion to the OAuth 2.0 access token endpoint.
Use the wizard under Common Tasks > Register Remote Identity Provider to import the identity provider metadata.
Make sure the identity provider imports the metadata for your service provider.
If your service provider is at
https://www.sp.example:8443/openam, then the metadata
can be accessed at
https://www.sp.example:8443/openam/saml2/jsp/exportmetadata.jsp.
On the service provider OpenAM server, set up the OAuth 2.0 authorization server as described in Section 13.2, “Configuring the OAuth 2.0 Authorization Service”.
For a test configuration, set the realm to /, and
accept the defaults.
On the service provider and authorization server OpenAM server, set
up an OAuth 2.0 client profile with the same name as the service
provider under Access Control > realm >
Agents > OAuth 2.0 Client > New...
For example, if the service provider name is
https://www.sp.example:8443/openam, then that is also
the name of the OAuth 2.0 client profile.
You can make additional changes to the client profile if necessary. See Section 13.3, “Registering OAuth 2.0 Clients With the Authorization Service” for details.
Test your configuration.
Logout of all OpenAM servers.
Initiate SAML 2.0 Web SSO.
For example, if your identity provider is at
https://www.idp.example:8443/openam with meta alias
/idp and your service provider is at
https://www.sp.example:8443/openam, then browse to the
following URL (without line breaks or spaces).
http://www.idp.example:8443/openam/saml2/jsp/idpSSOInit.jsp ?metaAlias=/idp&spEntityID=http://www.sp.example:8443/openam
For other configurations, see Using SAML 2.0 Single Sign-On & Single Logout.
Login to the identity provider.
For OpenAM, login with user name demo and
password changeit.
Login to the service provider.
For OpenAM, login with user name demo and
password changeit.
See the resulting access token on successful login.
The result looks something like this, all on one line.
{
"expires_in": 59,
"token_type": "Bearer",
"access_token": "f0f731e0-6013-47e3-9c07-da598157a85f"
}OAuth 2.0 messages involve credentials and access tokens that allow the bearer to retrieve protected resources. Therefore, do not let an attacker capture requests or responses. Protect the messages going across the network.
RFC 6749 includes a number of Security Considerations, and also requires Transport Layer Security (TLS) to protect sensitive messages. Make sure you read the section covering Security Considerations, and that you can implement them in your deployment.
Also, especially when deploying a mix of other clients and resource servers, take into account the points covered in the Internet-Draft, OAuth 2.0 Threat Model and Security Considerations, before putting your service into production.