Enabling SAML SP-Initiated web single sign-on (SSO)
By default, the WebSphere® Application Server SAML Trust Association Interceptor (TAI) supports IdP-initiated SSO. When custom code is in place, the SAML TAI can be configured to support SP-initiated SSO.
Before you begin
Ensure that your system is enabled to use the SAML web SSO feature.
About this task
This task provides an example class and the steps to configure SP-initiated SSO with HTTP POST
binding. The AuthnRequest must be Base64 encoded. This example uses the Base64
encoder that is provided in the com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory
API. You can use any Base64 encoder that you want. For more information, see the Javadoc for the com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory API.
The SAML web SSO feature supports HTTP POST bindings. It does not support HTTP Redirect binding. You might need to consider these support details when you develop your SAML authentication request provider.
Procedure
-
Develop a SAML authentication request provider that implements the
com.ibm.wsspi.security.web.saml.AuthnRequestProvider
interface.- The
com.ibm.wsspi.security.web.saml.AuthnRequestProvider
class is found in the was_public.jar file, located in the (was_home)/dev directory. - The
com.ibm.ws.wssecurity.token.UTC
class used in this sample is found in the com.ibm.wsfp.main.jar file, located in the (was_home)/plugins directory.
The getAuthnRequest(HttpServletRequest req, String errorMsg, String acsUrl, ArrayList<String> ssoUrls method must return a map that includes four entries with the following keys.- AuthnRequestProvider.SSO_URL
- The SAML identity provider's Single-Sign-On URL.
- AuthnRequestProvider.RELAY_STATE
- The
relayState
as defined by the SAML Web Browser single sign-on profile. - AuthnRequestProvider.REQUEST_ID
- The value for this key must match the ID attribute's value in the
AuthnRequest
message. - AuthnRequestProvider.AUTHN_REQUEST
- A Base64 encoded
AuthnRequest
message. Your code is responsible for generating theAuthnRequest
message that is specific to your Identity Provider (IdP) requirements.
The following example shows a sample implementation of the
AuthnRequestProvider
interface. To implement this code, replace the values in the example with details from your IdP requirements.import java.util.ArrayList; import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import com.ibm.websphere.security.NotImplementedException; import com.ibm.ws.wssecurity.token.UTC; import com.ibm.wsspi.security.web.saml.AuthnRequestProvider; import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory; public class samlSp implements com.ibm.wsspi.security.web.saml.AuthnRequestProvider { // these values are specific to your IdP and application private static String ssoUrl_default = "https://idp.acme.com/saml20/login"; private static String issuer = "https://acme.com"; private static String nameQualifier = "aNameQualifier"; public HashMap <String, String> getAuthnRequest(HttpServletRequest req, String errorMsg, String acsUrl, ArrayList<String> ssoUrls) throws NotImplementedException { // create map with following keys HashMap <String, String> map = new HashMap <String, String>(); // the next section needs to be changed to code that is more appropriate // for your configuration and the request. Do not use this code as-is. String ssoUrl = ssoUrl_default; if (ssoUrls!=null && !ssoUrls.isEmpty() && ssoUrls.size()>0) ssoUrl=ssoUrls.get(0); map.put(AuthnRequestProvider.SSO_URL, ssoUrl); String relayState = generateRandom(); map.put(AuthnRequestProvider.RELAY_STATE, relayState); String requestId = generateRandom(); map.put(AuthnRequestProvider.REQUEST_ID, requestId); //create the AuthnRequest String authnMessage = createAuthnRequest(requestId); try { // get an instance of the WSSUtilFactory WSSUtilFactory wssuf = WSSUtilFactory.getInstance(); // base64 encode the authn request string String encAuthnMsg = wssuf.encode(authnMessage.getBytes()); // put the base64-encoded authn request in the map map.put(AuthnRequestProvider.AUTHN_REQUEST, encAuthnMsg); } catch ( Exception e ) { // this is to handle the WSSException that might thrown by WSSUtilFactory // do what you want here } return map; } private String createAuthnRequest(String reqId) { //create an Authn request that is specific to your IdP's requirements here. //An example of one that does not include a signature: return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +"<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" " +"ID=\"" + reqId + "\" Version=\"2.0\" " + "IssueInstant=\"" +UTC.format(new java.util.Date())+ "\" ForceAuthn=\"false\" IsPassive=\"false\"" + "ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" " + "AssertionConsumerServiceURL=\"" + acsUrl +"\" " + "Destination=\"" + ssoUrl +"\"> " + "<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + issuer +"</saml:Issuer> <samlp:NameIDPolicy" +"Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\"" +"SPNameQualifier=\"" + nameQualifier + "\" " +"AllowCreate=\"true\" /> <samlp:RequestedAuthnContext Comparison=\"exact\"> " +"<saml:AuthnContextClassRef xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" +"urn:oasis:names:tc:SAML:2.0:ac:classes:</saml:AuthnContextClassRef></samlp:RequestedAuthnContext>" +</samlp:AuthnRequest>"; } public String getIdentityProviderOrErrorURL(HttpServletRequest arg0, String arg1, String arg2, ArrayList<String> arg3) throws NotImplementedException { // this method is required by the IdentityProviderMapping parent interface // there is nothing to do here return null; } private String generateRandom() { // TODO implement code that generates a random alpha numeric String that must be // unique each time it is invoked and cannot be easily predicted (like a counter) } }
- The
- Put a JAR file that contains your custom class in the (WAS_HOME)/lib/ext directory.
-
Configure the SAML web SSO TAI to use your
AuthnRequest
message.- Log on to the WebSphere Application Server administrative console.
- Click Security > Global security.
- Expand Web and SIP security and click Trust association.
- Click Interceptors.
- Click com.ibm.ws.security.web.saml.ACSTrustAssociationInterceptor
-
For Custom properties, click new, then complete
the following custom property information, where
id
is what you assigned to the SSO Service Provider (SP) for which you want this property to apply.- Name
sso_<id>.sp.login.error.page
- Value
- The class name of your custom
AuthnRequestProvider
implementation.