/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007 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
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* 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]"
*
* $Id: FSDefaultSPAdapter.java,v 1.6 2008/06/25 05:49:54 qcheng Exp $
*
*/
package com.sun.identity.federation.plugins;
import com.iplanet.sso.SSOToken;
import com.iplanet.sso.SSOException;
import com.sun.identity.authentication.util.ISAuthConstants;
import com.sun.identity.federation.accountmgmt.FSAccountFedInfoKey;
import com.sun.identity.federation.accountmgmt.FSAccountManager;
import com.sun.identity.federation.accountmgmt.FSAccountMgmtException;
import com.sun.identity.federation.common.FederationException;
import com.sun.identity.federation.common.FSUtils;
import com.sun.identity.federation.common.IFSConstants;
import com.sun.identity.federation.common.LogUtil;
import com.sun.identity.federation.jaxb.entityconfig.SPDescriptorConfigElement;
import com.sun.identity.federation.message.FSAuthenticationStatement;
import com.sun.identity.federation.message.FSAssertion;
import com.sun.identity.federation.message.FSAuthnRequest;
import com.sun.identity.federation.message.FSAuthnResponse;
import com.sun.identity.federation.message.FSFederationTerminationNotification;
import com.sun.identity.federation.message.FSLogoutNotification;
import com.sun.identity.federation.message.FSLogoutResponse;
import com.sun.identity.federation.message.FSNameRegistrationRequest;
import com.sun.identity.federation.message.FSNameRegistrationResponse;
import com.sun.identity.federation.message.FSResponse;
import com.sun.identity.federation.message.FSSubject;
import com.sun.identity.federation.meta.IDFFMetaException;
import com.sun.identity.federation.meta.IDFFMetaManager;
import com.sun.identity.federation.services.util.FSServiceUtils;
import com.sun.identity.idm.AMIdentity;
import com.sun.identity.idm.AMIdentityRepository;
import com.sun.identity.idm.IdRepoException;
import com.sun.identity.idm.IdSearchControl;
import com.sun.identity.idm.IdSearchOpModifier;
import com.sun.identity.idm.IdSearchResults;
import com.sun.identity.idm.IdType;
import com.sun.identity.idm.IdUtils;
import com.sun.identity.saml.assertion.NameIdentifier;
import com.sun.identity.saml.assertion.Statement;
import com.sun.identity.saml.protocol.Status;
import com.sun.identity.saml.protocol.StatusCode;
import com.sun.identity.security.AdminTokenAction;
import com.sun.identity.shared.Constants;
import com.sun.identity.shared.encode.URLEncDec;
import java.security.AccessController;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FSDefaultSPAdapter implements FederationSPAdapter {
private final String ROOT_REALM = "/";
private String realm = null;
/**
* Initializes the federation adapter, this method will only be executed
* once after creation of the adapter instance.
* @param hostedProviderID provider ID for the hosted SP
* @param initParams initial set of parameters configured in the service
* provider for this adapter
*/
public void initialize(String hostedProviderID, Set initParams) {
FSUtils.debug.message("In FSDefaultSPAdapter.initialize.");
if ((initParams != null) && !initParams.isEmpty()) {
Iterator iter = initParams.iterator();
while (iter.hasNext()) {
String envValue = (String) iter.next();
if ((envValue.toUpperCase()).startsWith(
FederationSPAdapter.ENV_REALM))
{
try {
realm = envValue.substring(
(FederationSPAdapter.ENV_REALM).length(),
envValue.length());
} catch (Exception e) {
if (FSUtils.debug.warningEnabled()) {
FSUtils.debug.warning(
"FSDefaultSPAdapter.init:Could not get realm:",
e);
}
}
break;
}
}
}
if ((realm == null) || (realm.length() == 0)) {
realm = ROOT_REALM;
}
}
/**
* Invokes before federation manager sends the Single-Sing-On and Federation * request to IDP.
* @param hostedProviderID provider ID for the hosted SP
* @param idpProviderID provider id for the IDP to which the request will
* be sent
* @param request servlet request
* @param response servlet response
* @param authnRequest the authentication request to be send to IDP
*/
public void preSSOFederationRequest(
String hostedProviderID,
String idpProviderID,
HttpServletRequest request,
HttpServletResponse response,
FSAuthnRequest authnRequest)
{
FSUtils.debug.message("In FSDefaultSPAdapter.preSSOFederationRequest.");
}
/**
* Invokes when the FM received the Single-Sign-On and Federation response
* from the IDP, this is called before any processing started on SP side.
* @param hostedProviderID provider ID for the hosted SP
* @param request servlet request
* @param response servlet response
* @param authnRequest the original authentication request sent from SP
* @param authnResponse response from IDP if Browser POST or LECP profile
* is used for the request, value will be null if Browser Artifact
* profile is used.
* @param samlResponse response from IDP if Browser Artifact profile is used
* for the request, value will be null if Browser POST or LECP
* profile is used.
* @exception FederationException if user want to fail the process.
*/
public void preSSOFederationProcess(
String hostedProviderID,
HttpServletRequest request,
HttpServletResponse response,
FSAuthnRequest authnRequest,
FSAuthnResponse authnResponse,
FSResponse samlResponse)
throws FederationException {
FSUtils.debug.message("In FSDefaultSPAdapter.preSSOFederationProcess.");
}
/**
* Invokes this method after the successful Single Sign-On or Federation.
* @param hostedEntityID provider ID for the hosted SP
* @param request servlet request
* @param response servlet response
* @param ssoToken user's SSO token
* @param authnRequest the original authentication request sent from SP
* @param authnResponse response from IDP if Browser POST or LECP profile
* is used for the request, value will be null if Browser Artifact
* profile is used.
* @param samlResponse response from IDP if Browser Artifact profile is used
* for the request, value will be null if Browser POST or LECP
* profile is used.
* @exception FederationException if user want to fail the process.
* @return true if browser redirection happened, false otherwise.
*/
public boolean postSSOFederationSuccess(
String hostedEntityID,
HttpServletRequest request,
HttpServletResponse response,
Object ssoToken,
FSAuthnRequest authnRequest,
FSAuthnResponse authnResponse,
FSResponse samlResponse
) throws FederationException {
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSDefaultSPAdapter.postFedSuccess, "
+ "process " + hostedEntityID);
}
// find out if this is a federation request
boolean isFederation = false;
if (authnRequest == null) {
FSUtils.debug.error("FSDefaultSPAdapter.postFedSuccess null");
} else {
String nameIDPolicy = authnRequest.getNameIDPolicy();
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSDefaultSPAdapter.postSuccess "
+ nameIDPolicy);
}
if (nameIDPolicy.equals(IFSConstants.NAME_ID_POLICY_FEDERATED)) {
isFederation = true;
}
}
SSOToken adminToken = (SSOToken)
AccessController.doPrivileged(AdminTokenAction.getInstance());
if (isFederation && adminToken != null) {
try {
// get name Identifier
String nameId = null;
List assertions = null;
String idpEntityId = null;
if (authnResponse != null) {
// POST profile
assertions = authnResponse.getAssertion();
idpEntityId = authnResponse.getProviderId();
} else {
// Artifact profile
assertions = samlResponse.getAssertion();
}
FSAssertion assertion =
(FSAssertion) assertions.iterator().next();
if (idpEntityId == null) {
idpEntityId = assertion.getIssuer();
}
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSAdapter.postSuccess: idp="
+ idpEntityId);
}
Iterator stmtIter = assertion.getStatement().iterator();
while (stmtIter.hasNext()) {
Statement statement = (Statement) stmtIter.next();
int stmtType = statement.getStatementType();
if (stmtType == Statement.AUTHENTICATION_STATEMENT) {
FSAuthenticationStatement authStatement =
(FSAuthenticationStatement) statement;
FSSubject subject =
(FSSubject) authStatement.getSubject();
NameIdentifier ni =
subject.getIDPProvidedNameIdentifier();
if (ni == null) {
ni = subject.getNameIdentifier();
}
if (ni != null) {
nameId = ni.getName();
}
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSAdapter.postSuccess: "
+ "found name id =" + nameId);
}
break;
}
}
if (nameId == null) {
FSUtils.debug.warning("FSAdapter.postSuc : null nameID");
return false;
}
Map map = new HashMap();
Set set = new HashSet();
set.add("|" + hostedEntityID + "|" + nameId + "|");
map.put("iplanet-am-user-federation-info-key", set);
AMIdentityRepository idRepo = new AMIdentityRepository(
adminToken,
((SSOToken) ssoToken).getProperty(
ISAuthConstants.ORGANIZATION));
IdSearchControl searchControl = new IdSearchControl();
searchControl.setTimeOut(0);
searchControl.setMaxResults(0);
searchControl.setAllReturnAttributes(false);
searchControl.setSearchModifiers(IdSearchOpModifier.AND, map);
IdSearchResults searchResults = idRepo.searchIdentities(
IdType.USER, "*", searchControl);
Set amIdSet = searchResults.getSearchResults();
if (amIdSet.size() > 1) {
String univId = ((SSOToken) ssoToken).getProperty(
Constants.UNIVERSAL_IDENTIFIER);
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSAdapter.postSuccess: found "
+ amIdSet.size() + " federation with same ID as "
+ univId);
}
String metaAlias = null;
try {
IDFFMetaManager metaManager =
new IDFFMetaManager(ssoToken);
if (metaManager != null) {
SPDescriptorConfigElement spConfig =
metaManager.getSPDescriptorConfig(
realm, hostedEntityID);
if (spConfig != null) {
metaAlias = spConfig.getMetaAlias();
}
}
} catch (IDFFMetaException ie) {
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSAdapter.postSuccess: "
+ "couldn't find meta alias:", ie);
}
}
FSAccountManager accManager =
FSAccountManager.getInstance(metaAlias);
FSAccountFedInfoKey fedInfoKey =
new FSAccountFedInfoKey(hostedEntityID, nameId);
// previous federation exists with different users
Iterator it = amIdSet.iterator();
while (it.hasNext()) {
AMIdentity amId = (AMIdentity) it.next();
// compare with the SSO token
String tmpUnivId = IdUtils.getUniversalId(amId);
if (univId.equalsIgnoreCase(tmpUnivId)) {
continue;
}
// remove federation information for this user
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSAdapter.postSucces, "
+ "remove fed info for user " + tmpUnivId);
}
accManager.removeAccountFedInfo(tmpUnivId, fedInfoKey,
idpEntityId);
}
}
} catch (FSAccountMgmtException f) {
FSUtils.debug.warning("FSDefaultSPAdapter.postSSOSuccess", f);
} catch (IdRepoException i) {
FSUtils.debug.warning("FSDefaultSPAdapter.postSSOSuccess", i);
} catch (SSOException e) {
FSUtils.debug.warning("FSDefaultSPAdapter.postSSOSuccess", e);
}
}
return false;
}
/**
* Invokes this method if the Single-Sign-On or Federation fails
* for some reason.
* @param request servlet request
* @param response servlet response
* @param authnRequest the original authentication request sent from SP
* @param authnResponse response from IDP if Browser POST or LECP profile
* is used for the request, value will be null if Browser Artifact
* profile is used.
* @param samlResponse response from IDP if Browser Artifact profile is used
* for the request, value will be null if Browser POST or LECP
* profile is used.
* @param failureCode an integer specifies the failure code.
* @return true if browser redirection happened, false otherwise.
*/
public boolean postSSOFederationFailure(String hostedEntityID,
HttpServletRequest request,
HttpServletResponse response,
FSAuthnRequest authnRequest,
FSAuthnResponse authnResponse,
FSResponse samlResponse,
int failureCode
) {
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSDefaultSPAdapter.postFedFailure, "
+ "process " + hostedEntityID
+ "\nfailure code=" + failureCode);
}
String baseURL = FSServiceUtils.getBaseURL(request);
String relayState = null;
if (authnRequest != null) {
relayState = authnRequest.getRelayState();
}
String framedLoginPageURL = FSServiceUtils.getCommonLoginPageURL(
FSServiceUtils.getMetaAlias(request),
relayState, null, request, baseURL);
StringBuffer sb = new StringBuffer();
sb.append(framedLoginPageURL)
.append("&").append(IFSConstants.FAILURE_CODE).append("=")
.append(failureCode);
if (failureCode == INVALID_AUTHN_RESPONSE ||
failureCode == INVALID_RESPONSE)
{
Status status = null;
if (failureCode == INVALID_AUTHN_RESPONSE) {
status = authnResponse.getStatus();
} else {
status = samlResponse.getStatus();
}
StatusCode firstLevelStatusCode = status.getStatusCode();
if (firstLevelStatusCode == null) {
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSDefaultSPAdapter.postSSO" +
"FederationFailure: Status is null");
}
return false;
}
StatusCode secondLevelStatusCode =
firstLevelStatusCode.getStatusCode();
if (secondLevelStatusCode == null) {
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSDefaultSPAdapter.postSSO" +
"FederationFailure: Second level status is empty");
}
return false;
}
String statusValue = URLEncDec.encode(
secondLevelStatusCode.getValue());
sb.append("&").append(IFSConstants.STATUS_CODE).append("=")
.append(statusValue);
}
String redirectURL = sb.toString();
if (FSUtils.debug.messageEnabled()) {
FSUtils.debug.message("FSDefaultSPAdapter.postSSOFederation" +
"Failure. URL to be redirected: " + redirectURL);
}
try {
response.setHeader("Location", redirectURL);
response.sendRedirect(redirectURL);
} catch (java.io.IOException io) {
FSUtils.debug.error("FSDefaultSPAdapter.postSSOFedFailure", io);
return false;
}
return true;
}
/**
* Invokes after Register Name Identifier processing is successful
* @param hostedProviderID provider ID for the hosted SP
* @param request servlet request
* @param response servlet response
* @param userDN DN of the user with whom name identifier registration
* performed
* @param regRequest register name identifier request, value will be
* null if the request object is not available
* @param regResponse register name identifier response, value will be
* null if the response object is not available
* @param regProfile register name identifier profile used, one of following
* IFSConstants.NAME_REGISTRATION_SP_HTTP_PROFILE
* IFSConstants.NAME_REGISTRATION_SP_SOAP_PROFILE
* IFSConstants.NAME_REGISTRATION_IDP_HTTP_PROFILE
* IFSConstants.NAME_REGISTRATION_IDP_SOAP_PROFILE
*/
public void postRegisterNameIdentifierSuccess(
String hostedProviderID,
HttpServletRequest request,
HttpServletResponse response,
String userDN,
FSNameRegistrationRequest regRequest,
FSNameRegistrationResponse regResponse,
String regProfile)
{
FSUtils.debug.message(
"In FSDefaultSPAdapter.postRegistrationNameIdentifierSuccess");
}
/**
* Invokes after the service provider successfully terminates federation
* with IDP.
* @param hostedProviderID provider ID for the hosted SP
* @param request servlet request
* @param response servlet response
* @param userDN DN of the user with whom name identifier registration
* performed
* @param notification federation termination notification message
* @param termProfile federation termination profile used, one of following
* IFSConstants.TERMINATION_SP_HTTP_PROFILE
* IFSConstants.TERMINATION_SP_SOAP_PROFILE
* IFSConstants.TERMINATION_IDP_HTTP_PROFILE
* IFSConstants.TERMINATION_IDP_SOAP_PROFILE
*/
public void postTerminationNotificationSuccess(
String hostedProviderID,
HttpServletRequest request,
HttpServletResponse response,
String userDN,
FSFederationTerminationNotification notification,
String termProfile)
{
FSUtils.debug.message(
"In FSDefaultSPAdapter.postTerminationNotificationSuccess.");
}
/**
* Invokes before single logout process started on FM side. This method
* is called before the user token is invalidated on the service provider
* side.
* @param hostedProviderID provider ID for the hosted SP
* @param request servlet request
* @param response servlet response
* @param userDN user DN
* @param logoutRequest single logout request object
* @param logoutResponse single logout response, value will be
* null if the response object is not available
* @param sloProfile single logout profile used, one of following
* IFSConstants.LOGOUT_SP_REDIRECT_PROFILE
* IFSConstants.LOGOUT_SP_SOAP_PROFILE
* IFSConstants.LOGOUT_IDP_REDIRECT_PROFILE
* IFSConstants.LOGOUT_IDP_SOAP_PROFILE
*/
public void preSingleLogoutProcess(
String hostedProviderID,
HttpServletRequest request,
HttpServletResponse response,
String userDN,
FSLogoutNotification logoutRequest,
FSLogoutResponse logoutResponse,
String sloProfile)
{
FSUtils.debug.message("In FSDefaultSPAdapter.preSingleLogoutProcess.");
}
/**
* Invokes after single logout is successful completed, i.e. user token
* has been invalidated.
*
* @param hostedProviderID provider ID for the hosted SP
* @param request servlet request
* @param response servlet response
* @param userDN user DN
* @param logoutRequest single logout request, value will be
* null if the request object is not available
* @param logoutResponse single logout response, value will be
* null if the response object is not available
* @param sloProfile single logout profile used, one of following
* IFSConstants.LOGOUT_SP_HTTP_PROFILE
* IFSConstants.LOGOUT_SP_SOAP_PROFILE
* IFSConstants.LOGOUT_IDP_HTTP_PROFILE
* IFSConstants.LOGOUT_IDP_SOAP_PROFILE
*/
public void postSingleLogoutSuccess(
String hostedProviderID,
HttpServletRequest request,
HttpServletResponse response,
String userDN,
FSLogoutNotification logoutRequest,
FSLogoutResponse logoutResponse,
String sloProfile)
{
FSUtils.debug.message("In FSDefaultSPAdapter.postSingleLogoutSuccess.");
}
}