IDPSSOFederate.java revision 3c1f7d866bc76f31417889be02304bda8489f24f
/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
*/
/*
* Portions Copyrighted 2010-2013 ForgeRock AS
*/
/**
* from a service provider. It processes the <code>AuthnRequest</code>
* sent by the service provider and generates a proper
* <code>Response</code> that contains an <code>Assertion</code>.
* It sends back a <code>Response</code> containing error status if
* something is wrong during the request processing.
*/
public class IDPSSOFederate {
private static FedMonAgent agent;
private static FedMonSAML2Svc saml2Svc;
static {
}
private IDPSSOFederate() {
}
/**
* This method processes the <code>AuthnRequest</code> coming
* from a service provider via HTTP Redirect.
*
* @param request the <code>HttpServletRequest</code> object
* @param response the <code>HttpServletResponse</code> object
*
*/
String reqBinding) {
}
/**
* This method processes the <code>AuthnRequest</code> coming
* from a service provider via HTTP Redirect.
*
* @param request the <code>HttpServletRequest</code> object
* @param response the <code>HttpServletResponse</code> object
* @param isFromECP true if the request comes from ECP
*
*/
return;
}
//IDP Proxy with introduction cookie case.
//After reading the introduction cookie, it redirects to here.
try {
//get the preferred idp
if (preferredIDP != null) {
"IDP to be proxied " + preferredIDP);
}
try {
"spSSODescriptor"),
return;
} catch (SAML2Exception re) {
"Redirecting for the proxy handling error:"
+ re.getMessage());
}
"UnableToRedirectToPreferredIDP",
return;
}
}
} // end of IDP Proxy case
request.getRequestURI());
}
"unable to get IDP meta alias from request.");
}
return;
}
// retrieve IDP entity id from meta alias
try {
"Unable to get meta manager.");
return;
}
if ((idpEntityID == null) ||
"Unable to get IDP Entity ID from meta.");
return;
}
if (isFromECP) {
}
boolean profileEnabled =
if (!profileEnabled) {
return;
}
} catch (SAML2MetaException sme) {
"Unable to get IDP Entity ID from meta.");
null);
return;
}
// Get the IDP adapter
try {
} catch (SAML2Exception se2) {
}
} else {
}
// get the request id query parameter from the request. If this
// is the first visit then the request id is not set; if it is
// coming back from a successful authentication, then request
// id should be there.
}
// There is no reqID, this is the first time that we pass here.
}
return;
}
try {
} catch (SAML2Exception saml2ex) {
return;
}
if (!SAML2Utils.isSourceSiteValid(
"Issuer in Request is not valid.");
}
return;
}
// verify the signature of the query string if applicable
try {
} catch (SAML2MetaException sme) {
}
if (idpSSODescriptor == null) {
"Unable to get IDP SSO Descriptor from meta.");
return;
}
try {
} catch (SAML2MetaException sme) {
}
// need to verify the query string containing authnRequest
if ((spEntityID == null) ||
return;
}
if (spSSODescriptor == null) {
"Unable to get SP SSO Descriptor from meta.");
return;
}
try {
boolean isSignatureOK = false;
if (isFromECP) {
} else {
spCert);
} else {
}
}
if (!isSignatureOK) {
"authn request verification failed.");
return;
}
// In ECP profile, sp doesn't know idp.
if (!isFromECP) {
// verify Destination
binding);
if (!SAML2Utils.verifyDestination(
"request destination verification failed.");
return;
}
}
} catch (SAML2Exception se) {
"authn request verification failed.", se);
return;
}
"request signature verification is successful.");
}
}
"request id=" + reqID);
}
return;
}
if (isFromECP) {
try {
response);
} catch (SAML2Exception se) {
"Unable to retrieve user session.");
}
}
} else {
// get the user sso session from the request
try {
request);
} catch (SessionException se) {
"Unable to retrieve user session.");
}
}
}
// preSingleSignOn adapter hook
// NB: This method is not called in IDPSSOUtil.doSSOFederate(...) so proxy requests or idp init sso
// will not trigger this adapter call
try {
if (idpAdapter != null) {
// If the preSingleSignOnProcess returns true we end here
return;
} // else we continue with the logic. Beware of loops
}
} catch (SAML2Exception se2) {
}
// End of adapter invocation
try {
} catch (SAML2Exception sme) {
}
if (idpAuthnContextMapper == null) {
"Unable to get IDPAuthnContextMapper from meta.");
return;
}
try {
idpEntityID, realm);
} catch (SAML2Exception sme) {
}
if (idpAuthnContextInfo == null) {
"find valid AuthnContext. Sending error Response.");
}
try {
} catch (SAML2Exception sme) {
}
return;
}
// get the relay state query parameter from the request
// the user has not logged in yet, redirect to auth
// TODO: need to verify the signature of the AuthnRequest
// save the AuthnRequest in the IDPCache so that it can be
// retrieved later when the user successfully authenticates
synchronized (IDPCache.authnRequestCache) {
new CacheObject(authnReq));
}
// save the AuthnContext in the IDPCache so that it can be
// retrieved later when the user successfully authenticates
synchronized (IDPCache.idpAuthnContextCache) {
new CacheObject(matchingAuthnContext));
}
// save the relay state in the IDPCache so that it can be
// retrieved later when the user successfully authenticates
}
//IDP Proxy: Initiate proxying
try {
if (isProxy) {
response);
if (preferredIDP != null) {
// IDP Proxy with configured proxy list
"IDP to be proxied" + preferredIDP);
}
return;
} else {
// IDP proxy with introduction cookie
return;
}
}
}
//else continue for the local authentication.
} catch (SAML2Exception re) {
"Redirecting for the proxy handling error: "
+ re.getMessage());
}
}
// preAuthentication adapter hook
try {
if (idpAdapter != null) {
// If preAuthentication returns true we end here
reqID, relayState)) {
return;
} // else continue - beware of loops
}
} catch (SAML2Exception se2) {
}
// End of adapter invocation
// redirect to the authentication service
try {
false);
} else {
try {
} catch (SAML2Exception sme) {
}
}
} catch (IOException ioe) {
"Unable to redirect to authentication.", ioe);
} catch (SAML2Exception se) {
"Unable to redirect to authentication.", se);
}
return;
} else {
"There is an existing session");
}
// Let's verify that the realm is the same for the user and the IdP
boolean isValidSessionInRealm = isValidSessionInRealm(
boolean sessionUpgrade = false;
if (isValidSessionInRealm) {
session);
+ "IDP Session Upgrade is :" + sessionUpgrade);
}
}
if (sessionUpgrade || !isValidSessionInRealm ||
// If there was no previous SAML2 session, there will be no
// sessionIndex
// Save the original IDP Session
if (oldIDPSession != null) {
} else {
+ " was not found in the idp session by indices cache");
}
}
// Save the new requestId and AuthnRequest
new CacheObject(authnReq));
// Save the new requestId and AuthnContext
new CacheObject(matchingAuthnContext));
// save if the request was an Session Upgrade case.
// save the relay state in the IDPCache so that it can
// be retrieved later when the user successfully
// authenticates
if ((relayState != null) &&
}
//IDP Proxy: Initiate proxying when session upgrade is requested
// Session upgrade could be requested by asking a greater AuthnContext
if (isValidSessionInRealm) {
try {
if (isProxy) {
response);
if (preferredIDP != null) {
// IDP Proxy with configured proxy list
+ "IDP to be proxied" + preferredIDP);
}
return;
} else {
// IDP proxy with introduction cookie
return;
}
}
}
//else continue for the local authentication.
} catch (SAML2Exception re) {
+ "Redirecting for the proxy handling error: "
+ re.getMessage());
}
}
// End of IDP Proxy: Initiate proxying when session upgrade is requested
}
// Invoke the IDP Adapter before redirecting to authn
try {
if (idpAdapter != null) {
// If the preAuthentication method returns true we end here
return;
} // else continue - beware of loops
}
} catch (SAML2Exception se2) {
}
// End of block for IDP Adapter invocation
try {
spEntityID, true);
return;
} else {
try {
} catch (SAML2Exception sme) {
}
}
} catch (IOException ioe) {
"Unable to redirect to authentication.", ioe);
sessionUpgrade = false;
} catch (SAML2Exception se) {
"Unable to redirect to authentication.", se);
sessionUpgrade = false;
}
}
// comes here if either no session upgrade or error
// redirecting to authentication url.
// generate assertion response
if (!sessionUpgrade && isValidSessionInRealm) {
// IDP Adapter invocation, to be sure that we can execute the logic
// even if there is a new request with the same session
// save the AuthnRequest in the IDPCache so that it can be
// retrieved later when the user successfully authenticates
synchronized (IDPCache.authnRequestCache) {
new CacheObject(authnReq));
}
// save the AuthnContext in the IDPCache so that it can be
// retrieved later when the user successfully authenticates
synchronized (IDPCache.idpAuthnContextCache) {
new CacheObject(matchingAuthnContext));
}
// save the relay state in the IDPCache so that it can be
// retrieved later when the user successfully authenticates
}
try {
if (idpAdapter != null) {
// If the preSendResponse returns true we end here
return;
} // else continue - beware of loops
}
} catch (SAML2Exception se2) {
}
// preSendResponse IDP adapter invocation ended
// call multi-federation protocol to set the protocol
try {
} catch (SAML2Exception se) {
"Unable to do sso or federation.", se);
}
}
}
} else {
// the second visit, the user has already authenticated
// retrieve the cache authn request and relay state
// We need the session to pass it to the IDP Adapter preSendResponse
try {
} catch (SessionException se) {
}
// Get the cached Authentication Request and Relay State before
// invoking the IDP Adapter
synchronized (IDPCache.authnRequestCache) {
}
}
// Let's verify if the session belongs to the proper realm
// There should be a session on the second pass. If this is not the case then provide an error message
// If there is a session then it must belong to the proper realm
if (!isValidSessionInRealm) {
// Send an appropriate response to the passive request
try {
} catch (SAML2Exception sme) {
}
} else {
// No attempt to authenticate now, since it is assumed that that has already been tried
try {
} catch (SAML2Exception ex) {
}
} else if (!isValidSessionInRealm) {
+ " does not correspond to that of the IdP");
}
return;
}
}
// Invoke the IDP Adapter after the user has been authenticated
try {
if (idpAdapter != null) {
// Id adapter returns true we end here
return;
} // else continue - beware of loops
}
} catch (SAML2Exception se2) {
}
// End of block for IDP Adapter invocation
synchronized (IDPCache.authnRequestCache) {
cacheObj =
}
}
synchronized (IDPCache.idpAuthnContextCache) {
cacheObj = (CacheObject)
}
}
//handle the case when the authn request is no longer available in the local cache. This could
//happen for multiple reasons:
//* the SAML response has been already sent back for this request (i.e. browser back button)
//* the second visit reached a different OpenAM server, than the first and SAML SFO is disabled
//* the cache interval has passed
+ " response");
try {
try {
if (idpAdapter != null) {
"UnableToGetAuthnReq");
}
} catch (SAML2Exception se2) {
}
try {
} catch (NumberFormatException nfe) {
}
} catch (SAML2Exception sme) {
}
return;
}
reqID);
}
boolean isSessionUpgrade = false;
isSessionUpgrade = true;
}
}
if (isSessionUpgrade) {
{
}
}
}
// call multi-federation protocol to set the protocol
}
// generate assertion response
try {
} catch (SAML2Exception se) {
"Unable to do sso or federation.", se);
}
}
} catch (IOException ioe) {
} catch (SessionException sso) {
} catch (SOAPException soapex) {
}
}
// Construct the response
Response res = SAML2Utils.getErrorResponse(authnReq, SAML2Constants.RESPONDER, SAML2Constants.NOPASSIVE, null,
IDPSSOUtil.sendResponse(request, response, acsBinding, spEntityID, idpEntityID, idpMetaAlias, realm, relayState,
}
String faultCode, String rbKey, String detail, boolean isFromECP, SAML2IdentityProviderAdapter idpAdapter)
throws IOException, SOAPException {
if (isFromECP) {
// Need to call saveChanges because we're
// going to use the MimeHeaders to set HTTP
// response information. These MimeHeaders
// are generated as part of the save.
if (soapFault.saveRequired()) {
}
// Write out the message on the response stream
} else {
}
} else {
// Invoke the IDP Adapter after the user has been authenticated
try {
if (idpAdapter != null) {
}
} catch (SAML2Exception se2) {
}
// End of block for IDP Adapter invocation
}
}
/**
* Returns the <code>AuthnRequest</code> from saml request string
*/
if (outputString != null) {
try {
} catch (SAML2Exception se) {
"IDPSSOFederate.getAuthnRequest(): cannot construct "
+ "a AuthnRequest object from the SAMLRequest value:", se);
}
}
return authnReq;
}
/**
* Returns the <code>AuthnRequest</code> from HttpServletRequest
*/
if (isFromECP) {
try {
}
return null;
} else {
"saml request = " + samlRequest);
}
if (samlRequest == null) {
return null;
}
return getAuthnRequest(samlRequest);
try {
SAML2Utils.debug.message("IDPSSOFederate.getAuthnRequest: decoded SAMl2 Authn Request: " + XMLUtils.print(doc.getDocumentElement()));
}
}
ex);
return null;
} finally {
try {
"IDPSSOFederate.getAuthnRequest:", ie);
}
}
}
}
return authnRequest;
}
return null;
}
}
return result ;
}
}
/**
* Redirect to authenticate service
* If authentication service and federation code are
* is the same j2ee container do a forward instead of
* a redirection
*/
// get the authentication service url
boolean forward ;
// build newUrl to auth service and test if redirect or forward
forward = true;
toString());
// in this case continue to forward to SSORedirect after login
} else {
// cannot forward so redirect
forward = false ;
}
// Pass spEntityID to IdP Auth Module
if (spEntityID != null) {
} else {
}
}
if ((authnTypeAndValues != null)
&& (!authnTypeAndValues.isEmpty())) {
boolean isFirst = true;
if (index != -1) {
if (isFirst) {
isFirst = false;
} else {
}
}
}
} else {
}
}
}
if (isSessionUpgrade) {
} else {
}
} else {
if (isSessionUpgrade) {
}
}
// compute gotoURL differently in case of forward or in case
// of redirection, forward needs a relative URI.
if(forward){
request.getContextPath()));
} else {
} else {
}
}
//adding these extra parameters will ensure that we can send back SAML error response to the SP even when the
//originally received AuthnRequest gets lost.
gotoURL.append(SP_ENTITY_ID).append('=').append(URLEncDec.encode(authnReq.getIssuer().getValue())).append('&');
}
// do forward if we are in the same container ,
// else redirection
if (forward) {
newURL.append('&').append(SystemPropertiesManager.get(Constants.AM_AUTH_COOKIE_NAME, "AMAuthCookie"));
try {
} catch (ServletException se) {
}
} else {
}
}
/**
* Iterates through the RequestedAuthnContext from the Service Provider and
* check if user has already authenticated with a sufficient authentication
* level.
*
* If RequestAuthnContext is not found in the authenticated AuthnContext
* then session upgrade will be done .
*
* @param requestAuthnContext the <code>RequestAuthnContext</code> object.
* @param sessionIndex the Session Index of the active session.
* @return true if the requester requires to reauthenticate
*/
private static boolean isSessionUpgrade(
// Get the Authentication Context required
// Get the AuthN level associated with the Authentication Context
int sessionAuthnLevel = 0;
try {
"Current session Authentication Level: " +
} catch (SessionException sex) {
" Couldn't get the session Auth Level", sex);
}
if (authnLevel > sessionAuthnLevel) {
return true;
} else {
return false;
}
} else {
return true;
}
}
/**
* Check that the authenticated session belongs to the same realm where the
* IDP is defined.
*
*
* @param realm the realm where the IdP is defined
* @param session The Session object of the authenticated user
* @return true if the session was initiated in the same realm as realm
*/
boolean isValidSessionInRealm = false;
try {
// A user can only be authenticated in one realm
isValidSessionInRealm = true;
} else {
+ "Invalid realm for the session:" + sessionRealm +
", while the realm of the IdP is:" + realm);
}
}
}
} catch (SessionException ex) {
+ " information", ex);
}
return isValidSessionInRealm;
}
/**
* clean up the cache created for session upgrade.
*/
}
}