Set Up SAML 2.0 SSO and Federation
For examples of the federation configuration files, see "Example Fedlet Files". To set up multiple SPs, work through this section, and then SAML 2.0 and Multiple Applications.
Set up the network:
Add
sp.example.com
to your/etc/hosts
file:127.0.0.1 localhost openam.example.com openig.example.com app.example.com sp.example.com
Traffic to the application is proxied through IG, using the host name
sp.example.com
.
Configure a Java Fedlet:
Note
The SAML library component validates the SP's AssertionConsumerService Location against the incoming IDP SAML Assertion, based on the request information, including the port. In sp.xml, always specify the port in the
Location
value ofAssertionConsumerService
, even when using defaults of443
or80
, as follows:<AssertionConsumerService isDefault="true" index="0" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.example.com:443/fedletapplication"/>
For more information about Java Fedlets, see Creating and Configuring the Fedlet in AM's SAML v2.0 Guide.
Copy and unzip the fedlet zip file,
Fedlet-7.0.2.zip
, delivered with the AM installation, into a local directory.$
unzip $HOME/openam/Fedlet-7.0.2.zip
Archive: Fedlet-7.0.0-SNAPSHOT.zip creating: conf/ inflating: README inflating: conf/FederationConfig.properties inflating: conf/fedlet.cot-template inflating: conf/idp-extended.xml-template inflating: conf/sp-extended.xml-template inflating: conf/sp.xml-template inflating: fedlet.war
For AM 6.5.2 and earlier versions, add the following lines to
FederationConfig.properties
:# Specifies implementation for # org.forgerock.openam.federation.plugin.rooturl.RootUrlProvider interface. # This property defines the default base url provider. com.sun.identity.plugin.root.url.class.default=org.forgerock.openam.federation.plugin.rooturl.impl.FedletRootUrlProvider
In each file, search and replace the following properties:
IDP_ENTITY_ID
: replace withopenam
FEDLET_ENTITY_ID
: replace withsp
FEDLET_PROTOCOL://FEDLET_HOST:FEDLET_PORT/FEDLET_DEPLOY_URI
: replace withhttp://sp.example.com:8080/saml
fedletcot
andFEDLET_COT
: replace withCircle of Trust
sp.example.com:8080/saml/fedletapplication
: replace withsp.example.com:8080/saml/fedletapplication/metaAlias/sp
Save the files as .xml, without the
-template
extension.
By default, AM as an IDP uses the NameID format
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
to communicate about a user. For information about using a different NameID format, see "Using a Non-Transient NameID Format".Set up AM:
Select Identities, and add a user with the following values:
ID/username:
george
First name:
george
Last name:
C0stanza
Note that, for this example, the last name must be the same as the password.
Password:
C0stanza
Select Applications > Federation > Circles of Trust, and add a circle of trust called
Circle of Trust
, with the default settings.Set up a remote service provider:
Select Applications > Federation > Entity Providers, and add a remote entity provider.
Drag in or import
sp.xml
created in Step 2.Select Circles of Trust:
Circle of Trust
Set up a hosted identity provider:
Select Applications > Federation > Entity Providers, and add a hosted entity provider with the following values:
Entity ID:
openam
Entity Provider Base URL:
http://openam.example.com:8088/openam
Identity Provider Meta Alias:
idp
Circles of Trust:
Circle of Trust
Select Assertion Processing > Attribute Mapper, map the following SAML attribute keys and values, and then save your changes:
SAML Attribute:
cn
, Local Attribute:cn
SAML Attribute:
sn
, Local Attribute:sn
In a terminal, export the XML-based metadata for the IPD:
$
curl -v \ --output idp.xml \ "http://openam.example.com:8088/openam/saml2/jsp/exportmetadata.jsp?entityid=openam"
The
idp.xml
file is created locally.
Set up IG:
Retrieve the Fedlet configuration files:
Copy the edited fedlet files, and the exported
idp.xml
file into the IG configuration, at$HOME/.openig/SAML
.$
ls -l $HOME/.openig/SAML
FederationConfig.properties fedlet.cot idp-extended.xml idp.xml sp-extended.xml sp.xml
In
config.json
, comment out or remove thebaseURI
:{ "handler": { "_baseURI": "http://app.example.com:8081", ...
Requests to the SamlFederationHandler must not be rebased, because the request URI must match the endpoint in the SAML metadata.
Add the following route to IG, to serve .css and other static resources for the sample application:
$HOME/.openig/config/routes/static-resources.json
%appdata%\OpenIG\config\routes\static-resources.json
{ "name" : "sampleapp_resources", "baseURI" : "http://app.example.com:8081", "condition": "${matches(request.uri.path,'^/css')}", "handler": "ReverseProxyHandler" }
Add the following route to IG:
$HOME/.openig/config/routes/saml.json
%appdata%\OpenIG\config\routes\saml.json
{ "name": "saml", "condition": "${matches(request.uri.path, '^/saml')}", "session": "JwtSession", "handler": { "type": "SamlFederationHandler", "config": { "assertionMapping": { "username": "cn", "password": "sn" }, "subjectMapping": "sp-subject-name", "redirectURI": "/home/federate" } } }
Notice the following features of the route:
The route matches requests to
/saml
.After authentication, the SamlFederationHandler extracts
cn
andsn
from the SAML assertion, and maps them to the SessionContext, atsession.username
andsession.password
.The handler stores the subject name as a string in the session field
session.sp-subject-name
, which is named by thesubjectMapping
property. By default, the subject name is stored in the session fieldsession.subjectName
.The handler redirects the request to the
/federate
route.The route uses the
JwtSession
implementation, meaning it stores encrypted session information in a browser cookie. The name is a reference to theJwtSession
object defined inconfig.json
. For details, see "JwtSession".
Add the following route to IG:
$HOME/.openig/config/routes/federate.json
%appdata%\OpenIG\config\routes\federate.json
{ "name": "federate", "condition": "${matches(request.uri.path, '^/home/federate')}", "session": "JwtSession", "baseURI": "http://app.example.com:8081", "handler": { "type": "DispatchHandler", "config": { "bindings": [ { "condition": "${empty session.username}", "handler": { "type": "StaticResponseHandler", "config": { "status": 302, "reason": "Found", "headers": { "Location": [ "http://sp.example.com:8080/saml/SPInitiatedSSO?metaAlias=/sp" ] } } } }, { "handler": { "type": "Chain", "config": { "filters": [ { "type": "HeaderFilter", "config": { "messageType": "REQUEST", "add": { "x-username": ["${session.username[0]}"], "x-password": ["${session.password[0]}"] } } } ], "handler": "ReverseProxyHandler" } } } ] } } }
Notice the following features of the route:
The route matches requests to
/home/federate
.If the user is not authenticated with AM, the username is not populated in the context. The DispatchHandler then dispatches the request to the StaticResponseHandler, which redirects it to the SP-initiated SSO endpoint.
If the credentials are in the context, or after successful authentication, the DispatchHandler dispatches the request to the Chain.
The HeaderFilter adds headers for the first value for the
username
andpassword
attributes of the SAML assertion.The route uses the
JwtSession
implementation, meaning it stores encrypted session information in a browser cookie. The name is a reference to theJwtSession
object defined inconfig.json
. For details, see "JwtSession".
Tip
For more control over the URL where the user agent is redirected, use the
RelayState
query string parameter in the URL of the redirectLocation
header.RelayState
specifies where to redirect the user when the SAML 2.0 web browser SSO process is complete. It overrides theredirectURI
set in the SamlFederationHandler.The
RelayState
value must be URL-encoded. When using an expression, use a function to encode the value. For example, use${urlEncodeQueryParameterNameOrValue(contexts.router.originalUri)}
.In the following example, the user is finally redirected to the original URI from the request:
"headers": { "Location": [ "http://openig.example.com:8080/saml/SPInitiatedSSO?RelayState=${urlEncodeQueryParameterNameOrValue(contexts.router.originalUri)}" ] }
Restart IG.
Test the setup:
Log out of AM, and test the setup with the following links:
Log in to AM with username
george
and passwordC0stanza
.IG returns the response page showing that the George has logged in.