001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: SPACSUtils.java,v 1.48 2009/11/20 21:41:16 exu Exp $
026 *
027 */
028
029/*
030 * Portions Copyrighted 2010-2013 ForgeRock AS
031 */
032
033package com.sun.identity.saml2.profile;
034
035import java.io.ByteArrayInputStream;
036import java.io.IOException;
037import java.util.ArrayList;
038import java.util.Date;
039import java.util.HashSet;
040import java.util.Iterator;
041import java.util.Map;
042import java.util.HashMap;
043import java.util.List;
044import java.util.logging.Level;
045import java.util.Set;
046
047import javax.servlet.http.HttpServletResponse;
048import javax.servlet.http.HttpServletRequest;
049import javax.servlet.ServletException;
050import java.security.cert.X509Certificate;
051
052import javax.xml.soap.SOAPConnection;
053import javax.xml.soap.SOAPException;
054import javax.xml.soap.SOAPMessage;
055
056import com.iplanet.dpro.session.exceptions.StoreException;
057import com.sun.identity.saml2.common.*;
058import org.w3c.dom.Document;
059import org.w3c.dom.Element;
060import com.sun.identity.common.SystemConfigurationUtil;
061import com.sun.identity.liberty.ws.soapbinding.Message;
062import com.sun.identity.liberty.ws.soapbinding.SOAPBindingException;
063import com.sun.identity.liberty.ws.soapbinding.SOAPFaultException;
064import com.sun.identity.shared.xml.XMLUtils;
065import com.sun.identity.shared.encode.Base64;
066import com.sun.identity.shared.encode.URLEncDec;
067import com.sun.identity.saml.common.SAMLConstants;
068import com.sun.identity.saml.common.SAMLUtils;
069import com.sun.identity.saml.xmlsig.KeyProvider;
070import com.sun.identity.saml2.assertion.Advice;
071import com.sun.identity.saml2.assertion.AssertionFactory;
072import com.sun.identity.saml2.assertion.Issuer;
073import com.sun.identity.saml2.assertion.Assertion;
074import com.sun.identity.saml2.assertion.AttributeStatement;
075import com.sun.identity.saml2.assertion.NameID;
076import com.sun.identity.saml2.assertion.EncryptedID;
077import com.sun.identity.saml2.assertion.EncryptedAttribute;
078
079import com.sun.identity.saml2.common.SAML2RepositoryFactory;
080import com.sun.identity.saml2.ecp.ECPFactory;
081import com.sun.identity.saml2.ecp.ECPRelayState;
082import com.sun.identity.saml2.jaxb.entityconfig.IDPSSOConfigElement;
083import com.sun.identity.saml2.jaxb.entityconfig.SPSSOConfigElement;
084import com.sun.identity.saml2.jaxb.metadata.AffiliationDescriptorType;
085import com.sun.identity.saml2.jaxb.metadata.ArtifactResolutionServiceElement;
086import com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement;
087import com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement;
088import com.sun.identity.saml2.key.KeyUtil;
089import com.sun.identity.saml2.logging.LogUtil;
090import com.sun.identity.saml2.meta.SAML2MetaException;
091import com.sun.identity.saml2.meta.SAML2MetaManager;
092import com.sun.identity.saml2.meta.SAML2MetaUtils;
093import com.sun.identity.saml2.protocol.Artifact;
094import com.sun.identity.saml2.protocol.ArtifactResolve;
095import com.sun.identity.saml2.protocol.ArtifactResponse;
096import com.sun.identity.saml2.protocol.AuthnRequest;
097import com.sun.identity.saml2.protocol.ProtocolFactory;
098import com.sun.identity.saml2.protocol.Response;
099import com.sun.identity.saml2.protocol.Status;
100import com.sun.identity.saml2.plugins.SAML2ServiceProviderAdapter;
101import com.sun.identity.saml2.plugins.SPAccountMapper;
102import com.sun.identity.saml2.plugins.SPAttributeMapper;
103
104import com.sun.identity.plugin.monitoring.FedMonAgent;
105import com.sun.identity.plugin.monitoring.FedMonSAML2Svc;
106import com.sun.identity.plugin.monitoring.MonitorManager;
107import com.sun.identity.plugin.session.SessionException;
108import com.sun.identity.plugin.session.SessionManager;
109import com.sun.identity.plugin.session.SessionProvider;
110
111import org.forgerock.openam.utils.ClientUtils;
112
113import java.security.PrivateKey;
114
115/**
116 * This class is used by a service provider (SP) to process the response from  
117 * an identity provider for the SP's Assertion Consumer Service.
118 *
119 * @supported.api
120 */
121public class SPACSUtils {
122
123    private static FedMonAgent agent = MonitorManager.getAgent();
124    private static FedMonSAML2Svc saml2Svc = MonitorManager.getSAML2Svc();
125
126    private SPACSUtils() {}
127
128    /**
129     * Retrieves <code>SAML</code> <code>Response</code> from http request.
130     * It handles three cases:
131     * <pre>
132     * 1. using http method get using request parameter "resID".
133     *    This is the case after local login is done.
134     * 2. using http method get using request parameter "SAMLart".
135     *    This is the case for artifact profile.
136     * 3. using http method post. This is the case for post profile.
137     * </pre>
138     * 
139     * @param request http servlet request
140     * @param response http servlet response
141     * @param orgName realm or organization name the service provider resides in
142     * @param hostEntityId Entity ID of the hosted service provider
143     * @param metaManager <code>SAML2MetaManager</code> instance.
144     * @return <code>ResponseInfo</code> instance.
145     * @throws SAML2Exception,IOException if it fails in the process.
146     */
147    public static ResponseInfo getResponse(
148                                HttpServletRequest request,
149                                HttpServletResponse response,
150                                String orgName,
151                                String hostEntityId,
152                                SAML2MetaManager metaManager)
153                throws SAML2Exception,IOException
154    {
155        ResponseInfo respInfo = null;
156
157        String method = request.getMethod();
158        if (method.equals("GET")) {
159            if (!SAML2Utils.isSPProfileBindingSupported(
160                orgName, hostEntityId, SAML2Constants.ACS_SERVICE,
161                SAML2Constants.HTTP_ARTIFACT))
162            {
163                SAMLUtils.sendError(request, response, 
164                    response.SC_BAD_REQUEST,
165                    "unsupportedBinding", 
166                    SAML2Utils.bundle.getString("unsupportedBinding"));
167                throw new SAML2Exception(
168                    SAML2Utils.bundle.getString("unsupportedBinding"));
169            }
170            respInfo = getResponseFromGet(request, response, orgName,
171                                hostEntityId, metaManager);
172        } else if (method.equals("POST")) {
173            String pathInfo = request.getPathInfo();
174            if ((pathInfo != null) && (pathInfo.startsWith("/ECP"))) {
175                if (!SAML2Utils.isSPProfileBindingSupported(
176                    orgName, hostEntityId, SAML2Constants.ACS_SERVICE,
177                    SAML2Constants.PAOS))
178                {
179                SAMLUtils.sendError(request, response, 
180                    response.SC_BAD_REQUEST,
181                    "unsupportedBinding", 
182                    SAML2Utils.bundle.getString("unsupportedBinding"));
183                throw new SAML2Exception(
184                    SAML2Utils.bundle.getString("unsupportedBinding"));
185            }
186                respInfo = getResponseFromPostECP(request, response, orgName,
187                    hostEntityId, metaManager);
188            } else {
189                if (!SAML2Utils.isSPProfileBindingSupported(
190                    orgName, hostEntityId, SAML2Constants.ACS_SERVICE,
191                    SAML2Constants.HTTP_POST))
192                {
193                    SAMLUtils.sendError(request, response, 
194                        response.SC_BAD_REQUEST,
195                        "unsupportedBinding", 
196                        SAML2Utils.bundle.getString("unsupportedBinding"));
197                    throw new SAML2Exception(
198                        SAML2Utils.bundle.getString("unsupportedBinding"));
199                }
200                respInfo = getResponseFromPost(request, response, orgName,
201                    hostEntityId, metaManager);
202            }
203        } else {
204            // not supported
205            SAMLUtils.sendError(request, response, 
206                response.SC_METHOD_NOT_ALLOWED,
207                "notSupportedHTTPMethod", 
208                SAML2Utils.bundle.getString("notSupportedHTTPMethod"));
209            throw new SAML2Exception(
210                        SAML2Utils.bundle.getString("notSupportedHTTPMethod"));
211        }
212        if (SAML2Utils.debug.messageEnabled()) {
213            SAML2Utils.debug.message("SPACSUtils.getResponse: got response="
214                + respInfo.getResponse().toXMLString(true, true));
215        }
216        return respInfo;
217    }
218
219    /**
220     * Retrieves <code>SAML Response</code> from http Get. 
221     * It first uses parameter resID to retrieve <code>Response</code>. This is
222     * the case after local login;
223     * If resID is not defined, it then uses <code>SAMLart</code> http 
224     * parameter to retrieve <code>Response</code>.
225     */
226    private static ResponseInfo getResponseFromGet(
227                                HttpServletRequest request,
228                                HttpServletResponse response,
229                                String orgName,
230                                String hostEntityId,
231                                SAML2MetaManager metaManager)
232                throws SAML2Exception,IOException
233    {
234        ResponseInfo respInfo = null;
235        String resID = request.getParameter("resID");
236        if (resID != null && resID.length() != 0) {
237            if (SAML2Utils.debug.messageEnabled()) {
238                SAML2Utils.debug.message("SPACSUtils.getResponseFromGet: resID="
239                        + resID);
240            }
241            synchronized (SPCache.responseHash) {
242                respInfo = (ResponseInfo) SPCache.responseHash.remove(resID);
243            }
244            if (respInfo == null) {
245                if (SAML2Utils.debug.messageEnabled()) {
246                    SAML2Utils.debug.message("SPACSUtils.getResponseFromGet: "
247                        + "couldn't find Response from resID.");
248                }
249                String[] data = {resID};
250                LogUtil.error(Level.INFO,
251                                LogUtil.RESPONSE_NOT_FOUND_FROM_CACHE,
252                                data,
253                                null);
254                SAMLUtils.sendError(request, response, 
255                    response.SC_INTERNAL_SERVER_ERROR, "SSOFailed",
256                    SAML2Utils.bundle.getString("SSOFailed"));
257                throw new SAML2Exception(
258                        SAML2Utils.bundle.getString("SSOFailed"));
259            }
260            return respInfo;
261        }
262
263        String samlArt = request.getParameter(SAML2Constants.SAML_ART);
264        if (samlArt == null || samlArt.trim().length() == 0) {
265            SAML2Utils.debug.error("SPACSUtils.getResponseFromGet: Artifact "
266                + "string is empty.");
267            LogUtil.error(Level.INFO,
268                        LogUtil.MISSING_ARTIFACT,
269                        null,
270                        null);
271            SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST,
272                "missingArtifact",
273                SAML2Utils.bundle.getString("missingArtifact"));
274            throw new SAML2Exception(
275                        SAML2Utils.bundle.getString("missingArtifact"));
276        }
277
278        return new ResponseInfo(getResponseFromArtifact(samlArt, hostEntityId,
279            request, response, orgName, metaManager), 
280            SAML2Constants.HTTP_ARTIFACT, null);
281    }
282
283    // Retrieves response using artifact profile.
284    private static Response getResponseFromArtifact(String samlArt,
285        String hostEntityId, HttpServletRequest request,
286        HttpServletResponse response, String orgName,
287        SAML2MetaManager sm) throws SAML2Exception,IOException
288    {
289
290        // Try to get source ID and endpointIndex, and then
291        // decide which IDP and which artifact resolution service
292        if (SAML2Utils.debug.messageEnabled()) {
293            SAML2Utils.debug.message("SPACSUtils.getResponseFromArtifact: " +
294                "samlArt = " + samlArt);
295        }
296
297        Artifact art = null;
298        try {
299            art = ProtocolFactory.getInstance().createArtifact(samlArt.trim());
300            String[] data = {samlArt.trim()};
301            LogUtil.access(Level.INFO,
302                        LogUtil.RECEIVED_ARTIFACT,
303                        data,
304                        null);
305        } catch (SAML2Exception se) {
306            SAML2Utils.debug.error("SPACSUtils.getResponseFromArtifact: "
307                 + "Unable to decode and parse artifact string:" + samlArt);
308            SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST,
309                "errorObtainArtifact",
310                SAML2Utils.bundle.getString("errorObtainArtifact"));
311            throw se;
312        }
313
314        String idpEntityID = getIDPEntityID(art, request, response, orgName, sm);
315        IDPSSODescriptorElement idp = null;
316        try {
317            idp = sm.getIDPSSODescriptor(orgName, idpEntityID);
318        } catch (SAML2MetaException se) {
319            String[] data = {orgName, idpEntityID};
320            LogUtil.error(Level.INFO,
321                        LogUtil.IDP_META_NOT_FOUND,
322                        data,
323                        null);
324            SAMLUtils.sendError(request, response, 
325                response.SC_INTERNAL_SERVER_ERROR,
326                "failedToGetIDPSSODescriptor", se.getMessage());
327            throw se;
328        }
329
330        String location = getIDPArtifactResolutionServiceUrl(
331            art.getEndpointIndex(), idpEntityID, idp, request, response);
332
333        // create ArtifactResolve message
334        ArtifactResolve resolve = null;
335        SOAPMessage resMsg = null;
336        try {
337            resolve = ProtocolFactory.getInstance().createArtifactResolve();
338            resolve.setID(SAML2Utils.generateID());
339            resolve.setVersion(SAML2Constants.VERSION_2_0);
340            resolve.setIssueInstant(new Date());
341            resolve.setArtifact(art);
342            resolve.setDestination(XMLUtils.escapeSpecialCharacters(location));
343            Issuer issuer = AssertionFactory.getInstance().createIssuer();
344            issuer.setValue(hostEntityId);
345            resolve.setIssuer(issuer);
346            String needArtiResolveSigned =
347                SAML2Utils.getAttributeValueFromSSOConfig(
348                                orgName,
349                                idpEntityID,
350                                SAML2Constants.IDP_ROLE,
351                                SAML2Constants.WANT_ARTIFACT_RESOLVE_SIGNED);
352                                                        
353            if (needArtiResolveSigned != null &&
354                needArtiResolveSigned.equals("true")) {
355                // or save it somewhere?
356                String signAlias = getAttributeValueFromSPSSOConfig(
357                                orgName,
358                                hostEntityId,
359                                sm,
360                                SAML2Constants.SIGNING_CERT_ALIAS);
361                if (signAlias == null) {
362                    throw new SAML2Exception(
363                        SAML2Utils.bundle.getString("missingSigningCertAlias"));
364                }
365                KeyProvider kp = KeyUtil.getKeyProviderInstance();
366                if (kp == null) {
367                    throw new SAML2Exception(
368                        SAML2Utils.bundle.getString("nullKeyProvider"));
369                }
370                resolve.sign(kp.getPrivateKey(signAlias),
371                                kp.getX509Certificate(signAlias));
372            }
373
374            String resolveString = resolve.toXMLString(true, true);
375            if (SAML2Utils.debug.messageEnabled()) {
376                SAML2Utils.debug.message("SPACSUtils.getResponseFromArtifact: "
377                    + "ArtifactResolve=" + resolveString);
378            }
379
380            SOAPConnection con = SAML2Utils.scf.createConnection();
381            SOAPMessage msg = SAML2Utils.createSOAPMessage(resolveString, true);
382
383            IDPSSOConfigElement config = null;
384            config = sm.getIDPSSOConfig(orgName, idpEntityID);
385            location = SAML2Utils.fillInBasicAuthInfo(
386                config, location);
387            resMsg = con.call(msg, location);
388        } catch (SAML2Exception s2e) {
389            SAML2Utils.debug.error("SPACSUtils.getResponseFromArtifact: "
390                + "couldn't create ArtifactResolve:", s2e);
391            String[] data = {hostEntityId, art.getArtifactValue()};
392            LogUtil.error(Level.INFO,
393                        LogUtil.CANNOT_CREATE_ARTIFACT_RESOLVE,
394                        data,
395                        null);
396            SAMLUtils.sendError(request, response, 
397                response.SC_INTERNAL_SERVER_ERROR,
398                "errorCreateArtifactResolve",
399                SAML2Utils.bundle.getString("errorCreateArtifactResolve"));
400            throw s2e;
401        } catch (SOAPException se) {
402            SAML2Utils.debug.error("SPACSUtils.getResponseFromGet: "
403                + "couldn't get ArtifactResponse. SOAP error:",se);
404            String[] data = {hostEntityId, location};
405            LogUtil.error(Level.INFO,
406                        LogUtil.CANNOT_GET_SOAP_RESPONSE,
407                        data,
408                        null);
409            SAMLUtils.sendError(request, response, 
410                response.SC_INTERNAL_SERVER_ERROR,
411                "errorInSOAPCommunication",
412                SAML2Utils.bundle.getString("errorInSOAPCommunication"));
413            throw new SAML2Exception(se.getMessage());
414        }
415
416        Response result = getResponseFromSOAP(resMsg, resolve, request, 
417            response, idpEntityID, idp, orgName, hostEntityId, sm);
418        String[] data = {hostEntityId, idpEntityID,
419                        art.getArtifactValue(), ""};
420        if (LogUtil.isAccessLoggable(Level.FINE)) {
421            data[3] = result.toXMLString();
422        }
423        LogUtil.access(Level.INFO,
424                        LogUtil.GOT_RESPONSE_FROM_ARTIFACT,
425                        data,
426                        null);
427        return result;
428    }
429
430    // Finds the IDP who sends the artifact;
431    private static String getIDPEntityID(
432                Artifact art,
433                HttpServletRequest request,
434                HttpServletResponse response,
435                String orgName,
436                SAML2MetaManager metaManager)
437                throws SAML2Exception,IOException
438    {
439        String sourceID = art.getSourceID();
440        // find the idp
441        String idpEntityID = null;
442        try {
443            Iterator iter =
444                metaManager.getAllRemoteIdentityProviderEntities(orgName).
445                        iterator();
446            String tmpSourceID = null;
447            while (iter.hasNext()) {
448                idpEntityID = (String) iter.next();
449                tmpSourceID = SAML2Utils.generateSourceID(idpEntityID);
450                if (sourceID.equals(tmpSourceID)) {
451                    break;
452                }
453                idpEntityID = null;
454            }
455            if (idpEntityID == null) {
456                SAML2Utils.debug.error("SPACSUtils.getResponseFromGet: Unable "
457                    + "to find the IDP based on the SourceID in the artifact");
458                String[] data = {art.getArtifactValue(), orgName};
459                LogUtil.error(Level.INFO,
460                        LogUtil.IDP_NOT_FOUND,
461                        data,
462                        null);
463                throw new SAML2Exception(
464                    SAML2Utils.bundle.getString("cannotFindIDP"));
465            }
466        } catch (SAML2Exception se) {
467            String[] data = {art.getArtifactValue(), orgName};
468            LogUtil.error(Level.INFO,
469                        LogUtil.IDP_NOT_FOUND,
470                        data,
471                        null);
472            SAMLUtils.sendError(request, response, 
473                response.SC_INTERNAL_SERVER_ERROR,
474                "cannotFindIDP", se.getMessage());
475            throw se;
476        }
477        return idpEntityID;
478    }
479
480    // Retrieves the ArtifactResolutionServiceURL for an IDP.
481    private static String getIDPArtifactResolutionServiceUrl(
482                int endpointIndex,
483                String idpEntityID,
484                IDPSSODescriptorElement idp,
485                HttpServletRequest request,
486                HttpServletResponse response)
487                throws SAML2Exception,IOException
488    {
489        // find the artifact resolution service url
490        List arsList=idp.getArtifactResolutionService();
491        ArtifactResolutionServiceElement ars = null;
492        String location = null;
493        String defaultLocation = null;
494        String firstLocation = null;
495        int index;
496        boolean isDefault = false;
497        for (int i=0; i<arsList.size(); i++) {
498            ars = (ArtifactResolutionServiceElement)arsList.get(i);
499            location = ars.getLocation();
500            //String binding = ars.getBinding();
501            index = ars.getIndex();
502            isDefault = ars.isIsDefault();
503            if (index == endpointIndex) {
504                break;
505            }
506            if (isDefault) {
507                defaultLocation = location;
508            }
509            if (i==0) {
510                firstLocation = location;
511            }
512            location = null;
513        }
514        if (location == null || location.length() == 0) {
515            location = defaultLocation;
516            if (location == null || location.length() == 0) {
517                location = firstLocation;
518                if (location == null || location.length() == 0) {
519                    SAML2Utils.debug.error("SPACSUtils: Unable to get the "
520                        + "location of artifact resolution service for "
521                        + idpEntityID);
522                    String[] data = {idpEntityID};
523                    LogUtil.error(Level.INFO,
524                                LogUtil.ARTIFACT_RESOLUTION_URL_NOT_FOUND,
525                                data,
526                                null);
527                    SAMLUtils.sendError(request, response, 
528                        response.SC_INTERNAL_SERVER_ERROR,
529                        "cannotFindArtifactResolutionUrl",
530                        SAML2Utils.bundle.getString(
531                            "cannotFindArtifactResolutionUrl"));
532                    throw new SAML2Exception(
533                        SAML2Utils.bundle.getString(
534                            "cannotFindArtifactResolutionUrl"));
535                }
536            }
537        }
538        if (SAML2Utils.debug.messageEnabled()) {
539            SAML2Utils.debug.message("SPACSUtils: IDP artifact resolution "
540                + "service url =" + location);
541        }
542        return location;
543    }
544
545    /**
546     * Obtains <code>SAML Response</code> from <code>SOAPBody</code>.
547     * Used by Artifact profile.
548     */
549    private static Response getResponseFromSOAP(SOAPMessage resMsg,
550                                                ArtifactResolve resolve,
551                                                HttpServletRequest request,
552                                                HttpServletResponse response,
553                                                String idpEntityID,
554                                                IDPSSODescriptorElement idp,
555                                                String orgName,
556                                                String hostEntityId,
557                                                SAML2MetaManager sm)
558                throws SAML2Exception,IOException
559    {
560        String method = "SPACSUtils.getResponseFromSOAP:";
561        Element resElem = null;
562        try {
563            resElem = SAML2Utils.getSamlpElement(resMsg, "ArtifactResponse");
564        } catch (SAML2Exception se) {
565            String[] data = {idpEntityID};
566            LogUtil.error(Level.INFO,
567                        LogUtil.SOAP_ERROR,
568                        data,
569                        null);
570            SAMLUtils.sendError(request, response, 
571                response.SC_INTERNAL_SERVER_ERROR,
572                "soapError", se.getMessage());
573            throw se; 
574        }
575        ArtifactResponse artiResp = null;
576        try {
577            artiResp = ProtocolFactory.getInstance().
578                createArtifactResponse(resElem);
579        } catch (SAML2Exception se) {
580            if (SAML2Utils.debug.messageEnabled()) {
581                SAML2Utils.debug.message(method + "Couldn't create "
582                        + "ArtifactResponse:", se);
583            }
584            String[] data = {idpEntityID};
585            LogUtil.error(Level.INFO,
586                        LogUtil.CANNOT_INSTANTIATE_ARTIFACT_RESPONSE,
587                        data,
588                        null);
589            SAMLUtils.sendError(request, response, 
590                response.SC_INTERNAL_SERVER_ERROR,
591                "failedToCreateArtifactResponse", se.getMessage());
592            throw se;
593        }
594
595        if (artiResp == null) {
596            String[] data = {idpEntityID};
597            LogUtil.error(Level.INFO,
598                        LogUtil.MISSING_ARTIFACT_RESPONSE,
599                        data,
600                        null);
601            SAMLUtils.sendError(request, response, 
602                response.SC_INTERNAL_SERVER_ERROR,
603                "missingArtifactResponse",
604                SAML2Utils.bundle.getString("missingArtifactResponse"));
605            throw new SAML2Exception(
606                SAML2Utils.bundle.getString("missingArtifactResponse"));
607        } else {
608            if (SAML2Utils.debug.messageEnabled()) {
609                SAML2Utils.debug.message(method + "Received ArtifactResponse:"
610                        + artiResp.toXMLString(true, true));
611            }
612        }
613
614        // verify ArtifactResponse
615        String wantArtiRespSigned = getAttributeValueFromSPSSOConfig(
616                                orgName,
617                                hostEntityId,
618                                sm,
619                                SAML2Constants.WANT_ARTIFACT_RESPONSE_SIGNED);
620        if (wantArtiRespSigned != null && wantArtiRespSigned.equals("true")) {
621            X509Certificate cert = KeyUtil.getVerificationCert(
622                idp, idpEntityID, SAML2Constants.IDP_ROLE);
623            if (!artiResp.isSigned() || !artiResp.isSignatureValid(cert)) {
624                if (SAML2Utils.debug.messageEnabled()) {
625                   SAML2Utils.debug.message(method 
626                        + "ArtifactResponse's signature is invalid.");
627                }
628                String[] data = {idpEntityID};
629                LogUtil.error(Level.INFO,
630                        LogUtil.ARTIFACT_RESPONSE_INVALID_SIGNATURE,
631                        data,
632                        null);
633                SAMLUtils.sendError(request, response, 
634                    response.SC_INTERNAL_SERVER_ERROR, "invalidSignature",
635                    SAML2Utils.bundle.getString("invalidSignature"));
636                throw new SAML2Exception(
637                    SAML2Utils.bundle.getString("invalidSignature"));
638            }
639        }
640
641        String inResponseTo = artiResp.getInResponseTo();
642        if (inResponseTo == null || !inResponseTo.equals(resolve.getID())) {
643            if (SAML2Utils.debug.messageEnabled()) {
644                SAML2Utils.debug.message(method 
645                    + "ArtifactResponse's InResponseTo is invalid.");
646            }
647            String[] data = {idpEntityID};
648            LogUtil.error(Level.INFO,
649                        LogUtil.ARTIFACT_RESPONSE_INVALID_INRESPONSETO,
650                        data,
651                        null);
652            SAMLUtils.sendError(request, response, 
653                response.SC_INTERNAL_SERVER_ERROR, "invalidInResponseTo",
654                SAML2Utils.bundle.getString("invalidInResponseTo"));
655            throw new SAML2Exception(
656                SAML2Utils.bundle.getString("invalidInResponseTo"));
657        }
658
659        Issuer idpIssuer = artiResp.getIssuer();
660        if (idpIssuer == null || !idpIssuer.getValue().equals(idpEntityID)) {
661            if (SAML2Utils.debug.messageEnabled()) {
662                SAML2Utils.debug.message(method 
663                    + "ArtifactResponse's Issuer is invalid.");
664            }
665            String[] data = {idpEntityID};
666            LogUtil.error(Level.INFO,
667                        LogUtil.ARTIFACT_RESPONSE_INVALID_ISSUER,
668                        data,
669                        null);
670            SAMLUtils.sendError(request, response, 
671                response.SC_INTERNAL_SERVER_ERROR, "invalidIssuer",
672                SAML2Utils.bundle.getString("invalidIssuer"));
673            throw new SAML2Exception(
674                SAML2Utils.bundle.getString("invalidIssuer"));
675        }
676
677        // check time?
678
679        Status status = artiResp.getStatus();
680        if (status == null || !status.getStatusCode().getValue().equals(
681                                        SAML2Constants.SUCCESS))
682        {
683            String statusCode =
684                (status == null)?"":status.getStatusCode().getValue();
685            if (SAML2Utils.debug.messageEnabled()) {
686                SAML2Utils.debug.message(method 
687                    + "ArtifactResponse's status code is not success."
688                    + statusCode);
689            }
690            String[] data = {idpEntityID, ""};
691            if (LogUtil.isErrorLoggable(Level.FINE)) {
692                data[1] = statusCode;
693            }
694            LogUtil.error(Level.INFO,
695                        LogUtil.ARTIFACT_RESPONSE_INVALID_STATUS_CODE,
696                        data,
697                        null);
698            SAMLUtils.sendError(request, response, 
699                response.SC_INTERNAL_SERVER_ERROR, "invalidStatusCode",
700                SAML2Utils.bundle.getString("invalidStatusCode"));
701            throw new SAML2Exception(
702                SAML2Utils.bundle.getString("invalidStatusCode"));
703        } 
704
705        try {
706            return ProtocolFactory.getInstance().createResponse(
707                                artiResp.getAny());
708        } catch (SAML2Exception se) {
709            if (SAML2Utils.debug.messageEnabled()) {
710                SAML2Utils.debug.message(method 
711                    + "couldn't instantiate Response:", se);
712            }
713            String[] data = {idpEntityID};
714            LogUtil.error(Level.INFO,
715                        LogUtil.CANNOT_INSTANTIATE_RESPONSE_ARTIFACT,
716                        data,
717                        null);
718            SAMLUtils.sendError(request, response, 
719                response.SC_INTERNAL_SERVER_ERROR, 
720                "failedToCreateResponse", se.getMessage());
721            throw se;
722        }
723    }
724
725    /**
726     * Obtains <code>SAML Response</code> from <code>SOAPBody</code>.
727     * Used by ECP profile.
728     */
729    private static ResponseInfo getResponseFromPostECP(
730        HttpServletRequest request, HttpServletResponse response,
731        String orgName, String hostEntityId, SAML2MetaManager metaManager)
732            throws SAML2Exception,IOException
733    {
734        Message message = null;
735        try {
736            message = new Message(SAML2Utils.getSOAPMessage(request));
737        } catch (SOAPException soapex) {
738            String[] data = { hostEntityId } ;
739            LogUtil.error(Level.INFO,
740                LogUtil.CANNOT_INSTANTIATE_SOAP_MESSAGE_ECP, data, null);
741            SAMLUtils.sendError(request, response, 
742                response.SC_INTERNAL_SERVER_ERROR,
743                "failedToCreateSOAPMessage", soapex.getMessage());
744            throw new SAML2Exception(soapex.getMessage()); 
745        } catch (SOAPBindingException soapex) {
746            String[] data = { hostEntityId } ;
747            LogUtil.error(Level.INFO,
748                LogUtil.CANNOT_INSTANTIATE_SOAP_MESSAGE_ECP, data, null);
749            SAMLUtils.sendError(request, response, 
750                response.SC_INTERNAL_SERVER_ERROR,
751                "failedToCreateSOAPMessage", soapex.getMessage());
752            throw new SAML2Exception(soapex.getMessage()); 
753        } catch(SOAPFaultException sfex) {
754            String[] data = { hostEntityId } ;
755            LogUtil.error(Level.INFO, LogUtil.RECEIVE_SOAP_FAULT_ECP,
756                data, null);
757            String faultString =
758                sfex.getSOAPFaultMessage().getSOAPFault().getFaultString();
759            SAMLUtils.sendError(request, response, 
760                response.SC_INTERNAL_SERVER_ERROR, 
761                "failedToCreateSOAPMessage", faultString);
762            throw new SAML2Exception(faultString);
763        }
764
765        List soapHeaders = message.getOtherSOAPHeaders();
766        ECPRelayState ecpRelayState = null;
767        if ((soapHeaders != null) && (!soapHeaders.isEmpty())) {
768            for(Iterator iter = soapHeaders.iterator(); iter.hasNext();) {
769                Element headerEle = (Element)iter.next();
770                try {
771                    ecpRelayState =
772                        ECPFactory.getInstance().createECPRelayState(headerEle);
773                    break;
774                } catch (SAML2Exception saml2ex) {
775                    // not ECP RelayState
776                }
777            }
778        }
779        String relayState = null;
780        if (ecpRelayState != null) {
781            relayState = ecpRelayState.getValue();
782        }
783
784        List soapBodies = message.getBodies();
785        if ((soapBodies == null) || (soapBodies.isEmpty())) {
786            String[] data = { hostEntityId } ;
787            LogUtil.error(Level.INFO,
788                LogUtil.CANNOT_INSTANTIATE_SAML_RESPONSE_FROM_ECP, data, null);
789            SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST,
790                "missingSAMLResponse",
791                SAML2Utils.bundle.getString("missingSAMLResponse"));
792            throw new SAML2Exception(
793                SAML2Utils.bundle.getString("missingSAMLResponse"));
794        }
795
796        Element resElem = (Element)soapBodies.get(0);
797
798        Response resp = null;
799        try {
800            resp = ProtocolFactory.getInstance().createResponse(resElem);
801        } catch (SAML2Exception se) {
802            if (SAML2Utils.debug.messageEnabled()) {
803                SAML2Utils.debug.message("SPACSUtils.getResponseFromPostECP:" +
804                    "Couldn't create Response:", se);
805            }
806            String[] data = { hostEntityId } ;
807            LogUtil.error(Level.INFO,
808                LogUtil.CANNOT_INSTANTIATE_SAML_RESPONSE_FROM_ECP, data, null);
809            SAMLUtils.sendError(request, response, 
810                response.SC_INTERNAL_SERVER_ERROR,
811                "failedToCreateResponse", se.getMessage());
812            throw se;
813        }
814
815        String idpEntityID = resp.getIssuer().getValue();
816        IDPSSODescriptorElement idpDesc = null;
817        try {
818            idpDesc = metaManager.getIDPSSODescriptor(orgName, idpEntityID);
819        } catch (SAML2MetaException se) {
820            String[] data = { orgName, idpEntityID };
821            LogUtil.error(Level.INFO, LogUtil.IDP_META_NOT_FOUND, data, null);
822            SAMLUtils.sendError(request, response, 
823                response.SC_INTERNAL_SERVER_ERROR,
824                "failedToGetIDPSSODescriptor", se.getMessage());
825            throw se;
826        }
827
828        X509Certificate cert = KeyUtil.getVerificationCert(idpDesc,
829            idpEntityID, SAML2Constants.IDP_ROLE);
830        List assertions = resp.getAssertion();
831        if ((assertions != null) && (!assertions.isEmpty())) {
832            for(Iterator iter = assertions.iterator(); iter.hasNext(); ) {
833                Assertion assertion = (Assertion)iter.next();
834                if (!assertion.isSigned()) {
835                    if (SAML2Utils.debug.messageEnabled()) {
836                        SAML2Utils.debug.message(
837                            "SPACSUtils.getResponseFromPostECP: " + 
838                            " Assertion is not signed.");
839                    }
840                    String[] data = { idpEntityID };
841                    LogUtil.error(Level.INFO,
842                        LogUtil.ECP_ASSERTION_NOT_SIGNED, data, null);
843                    SAMLUtils.sendError(request, response, 
844                        response.SC_INTERNAL_SERVER_ERROR,
845                        "assertionNotSigned",
846                        SAML2Utils.bundle.getString("assertionNotSigned"));
847                    throw new SAML2Exception(
848                        SAML2Utils.bundle.getString("assertionNotSigned"));
849                } else if (!assertion.isSignatureValid(cert)) {
850                    if (SAML2Utils.debug.messageEnabled()) {
851                        SAML2Utils.debug.message(
852                            "SPACSUtils.getResponseFromPostECP: " + 
853                            " Assertion signature is invalid.");
854                    }
855                    String[] data = { idpEntityID };
856                    LogUtil.error(Level.INFO,
857                        LogUtil.ECP_ASSERTION_INVALID_SIGNATURE, data, null);
858                    SAMLUtils.sendError(request, response, 
859                        response.SC_INTERNAL_SERVER_ERROR,
860                        "invalidSignature",
861                        SAML2Utils.bundle.getString("invalidSignature"));
862                    throw new SAML2Exception(
863                        SAML2Utils.bundle.getString("invalidSignature"));
864                }
865            }
866        }
867
868        return new ResponseInfo(resp, SAML2Constants.PAOS, relayState);
869    }
870
871    // Obtains SAML Response from POST.
872    private static ResponseInfo getResponseFromPost(HttpServletRequest request,
873        HttpServletResponse response, String orgName, String hostEntityId,
874        SAML2MetaManager metaManager) throws SAML2Exception,IOException
875    {
876        String classMethod = "SPACSUtils:getResponseFromPost";
877        SAML2Utils.debug.message("SPACSUtils:getResponseFromPost");
878
879        String samlArt = request.getParameter(SAML2Constants.SAML_ART);
880        if ((samlArt != null) && (samlArt.trim().length() != 0)) {
881            return new ResponseInfo(getResponseFromArtifact(samlArt,
882                hostEntityId, request, response, orgName, metaManager),
883                SAML2Constants.HTTP_ARTIFACT, null);
884        }
885
886        String samlResponse = request.getParameter(
887                        SAML2Constants.SAML_RESPONSE);
888        if (samlResponse == null) {
889            LogUtil.error(Level.INFO,
890                        LogUtil.MISSING_SAML_RESPONSE_FROM_POST,
891                        null,
892                        null);
893            SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST,
894                "missingSAMLResponse",
895                SAML2Utils.bundle.getString("missingSAMLResponse"));
896            throw new SAML2Exception(
897                SAML2Utils.bundle.getString("missingSAMLResponse"));
898        }
899
900        // Get Response back
901        // decode the Response
902        Response resp = null;
903        ByteArrayInputStream bis = null;
904        try {
905            byte[] raw = Base64.decode(samlResponse);
906            if (raw != null) {
907                bis = new ByteArrayInputStream(raw);
908                Document doc = XMLUtils.toDOMDocument(bis, SAML2Utils.debug);
909                if (doc != null) {
910                    resp = ProtocolFactory.getInstance().
911                        createResponse(doc.getDocumentElement());
912                }
913            }
914        } catch (SAML2Exception se) {
915            SAML2Utils.debug.error("SPACSUtils.getResponse: Exception "
916                + "when instantiating SAMLResponse:", se);
917            LogUtil.error(Level.INFO,
918                        LogUtil.CANNOT_INSTANTIATE_RESPONSE_POST,
919                        null,
920                        null);
921            SAMLUtils.sendError(request, response, response.SC_BAD_REQUEST,
922                "errorObtainResponse",
923                SAML2Utils.bundle.getString("errorObtainResponse"));
924            throw new SAML2Exception(
925                SAML2Utils.bundle.getString("errorObtainResponse"));
926
927        } catch (Exception e) {
928            SAML2Utils.debug.error("SPACSUtils.getResponse: Exception "
929                + "when decoding SAMLResponse:", e);
930            LogUtil.error(Level.INFO,
931                        LogUtil.CANNOT_DECODE_RESPONSE,
932                        null,
933                        null);
934            SAMLUtils.sendError(request, response, 
935                response.SC_INTERNAL_SERVER_ERROR, "errorDecodeResponse",
936                SAML2Utils.bundle.getString("errorDecodeResponse"));
937            throw new SAML2Exception(
938                SAML2Utils.bundle.getString("errorDecodeResponse"));
939        } finally {
940            if (bis != null) {
941                try {
942                    bis.close();
943                } catch (Exception ie) {
944                    if (SAML2Utils.debug.messageEnabled()) {
945                        SAML2Utils.debug.message("SPACSUtils.getResponse: "
946                            + "Exception when close the input stream:", ie);
947                    }
948                }
949            }
950        }
951
952        if (resp != null) {
953            // verify signature in Response
954            boolean needPOSTResponseSigned =
955                SAML2Utils.wantPOSTResponseSigned(
956                    orgName,hostEntityId,SAML2Constants.SP_ROLE);
957            String idpEntityID = null;
958            Issuer issuer = resp.getIssuer();
959            if (issuer != null) {
960                idpEntityID = issuer.getValue();
961            } else {
962                List assertions = resp.getAssertion();
963                if ((assertions != null) && (!assertions.isEmpty())) {
964                    for (Iterator iter = assertions.iterator();
965                                  iter.hasNext(); ) {
966                        Assertion assertion = (Assertion)iter.next();
967                        idpEntityID = assertion.getIssuer().getValue();
968                        break;
969                    }
970                }
971            }
972            IDPSSODescriptorElement idp = null;
973            try {
974                idp = metaManager.getIDPSSODescriptor(orgName,idpEntityID);
975            } catch (SAML2MetaException se) {
976                String[] data = {orgName,hostEntityId,idpEntityID};
977                LogUtil.error(Level.INFO,
978                              LogUtil.IDP_META_NOT_FOUND,
979                              data,
980                              null);
981                SAMLUtils.sendError(request, response,
982                    response.SC_INTERNAL_SERVER_ERROR,
983                    "failedToGetIDPSSODescriptor", se.getMessage());
984                throw se;
985           }
986           if (needPOSTResponseSigned) {
987               X509Certificate cert = KeyUtil.getVerificationCert(
988                idp, idpEntityID, SAML2Constants.IDP_ROLE);
989                if (!resp.isSigned() || !resp.isSignatureValid(cert)) {
990                    SAML2Utils.debug.error(classMethod +
991                         " Signature in Response is invalid "); 
992                    String[] data = { orgName , hostEntityId , idpEntityID };
993                    LogUtil.error(Level.INFO,
994                        LogUtil.POST_RESPONSE_INVALID_SIGNATURE,data,null);
995                    SAMLUtils.sendError(request, response,
996                        response.SC_INTERNAL_SERVER_ERROR, "invalidSignature",
997                        SAML2Utils.bundle.getString("invalidSignature"));
998                    throw new SAML2Exception(
999                       SAML2Utils.bundle.getString("invalidSignInResponse"));
1000               }
1001            }
1002            String[] data = {""};
1003            if (LogUtil.isAccessLoggable(Level.FINE)) {
1004                data[0] = resp.toXMLString();
1005            }
1006            LogUtil.access(Level.INFO,
1007                           LogUtil.GOT_RESPONSE_FROM_POST,
1008                           data,
1009                           null);
1010            return (new ResponseInfo(resp, SAML2Constants.HTTP_POST, null));
1011        }
1012        if (SAML2Utils.debug.messageEnabled()) {
1013            SAML2Utils.debug.message("SPACSUtils.getResponse: Decoded response, " +
1014                                     "resp is null");
1015        }
1016        return null;
1017    }
1018
1019    /**
1020     * Authenticates user with <code>Response</code>.
1021     * Auth session upgrade will be called if input session is
1022     * not null.
1023     * Otherwise, saml2 auth module is called. The name of the auth module
1024     * is retrieved from <code>SPSSOConfig</code>. If not found, "SAML2" will
1025     * be used.
1026     *
1027     * @param request HTTP Servlet request
1028     * @param response HTTP Servlet response.
1029     * @param metaAlias metaAlias for the service provider
1030     * @param session input session object. It could be null.
1031     * @param respInfo <code>ResponseInfo</code> to be verified.
1032     * @param realm realm or organization name of the service provider.
1033     * @param hostEntityId hosted service provider Entity ID.
1034     * @param metaManager <code>SAML2MetaManager</code> instance for meta
1035     *                operation.
1036     * @return <code>Object</code> which holds result of the session.
1037     * @throws SAML2Exception if the processing failed.
1038     */
1039    public static Object processResponse(
1040        HttpServletRequest request, HttpServletResponse response,
1041        String metaAlias, Object session, ResponseInfo respInfo,
1042        String realm, String hostEntityId, SAML2MetaManager metaManager
1043    ) throws SAML2Exception {
1044
1045        String classMethod = "SPACSUtils.processResponse: ";
1046        if (SAML2Utils.debug.messageEnabled()) {
1047            SAML2Utils.debug.message(classMethod + "Response : " +
1048                                     respInfo.getResponse());
1049        }        
1050        Map smap = null;
1051        try {
1052            // check Response/Assertion and get back a Map of relevant data
1053            smap = SAML2Utils.verifyResponse(request, response,
1054                respInfo.getResponse(), realm, hostEntityId,
1055                respInfo.getProfileBinding());
1056        } catch (SAML2Exception se) {
1057            // invoke SPAdapter for failure
1058            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1059                request, response, smap, respInfo, 
1060                SAML2ServiceProviderAdapter.INVALID_RESPONSE, se);
1061            throw se;
1062        }
1063        
1064        com.sun.identity.saml2.assertion.Subject assertionSubject =
1065            (com.sun.identity.saml2.assertion.Subject)
1066            smap.get(SAML2Constants.SUBJECT);
1067        NameID nameId = assertionSubject.getNameID();
1068        EncryptedID encId = assertionSubject.getEncryptedID();
1069        Assertion authnAssertion =
1070            (Assertion) smap.get(SAML2Constants.POST_ASSERTION);
1071        String sessionIndex = (String)smap.get(SAML2Constants.SESSION_INDEX);
1072        respInfo.setSessionIndex(sessionIndex);
1073        Integer authLevel = (Integer) smap.get(SAML2Constants.AUTH_LEVEL);
1074        Long maxSessionTime = (Long) smap.get(SAML2Constants.MAX_SESSION_TIME);
1075        String inRespToResp = (String) smap.get(SAML2Constants.IN_RESPONSE_TO);
1076        List assertions = (List) smap.get(SAML2Constants.ASSERTIONS);
1077        
1078        if (SAML2Utils.debug.messageEnabled()) {
1079            SAML2Utils.debug.message(classMethod + "Assertions : " +
1080                                     assertions);
1081        }
1082       
1083        SPSSOConfigElement spssoconfig =
1084            metaManager.getSPSSOConfig(realm, hostEntityId);
1085
1086        Map attributes = SAML2MetaUtils.getAttributes(spssoconfig);
1087
1088        // get mappers
1089        SPAccountMapper acctMapper = getSPAccountMapper(attributes);
1090        SPAttributeMapper attrMapper =
1091            getSPAttributeMapper(attributes);
1092        
1093        boolean needAttributeEncrypted = false;
1094        boolean needNameIDEncrypted = false;
1095        String assertionEncryptedAttr =
1096            SAML2Utils.getAttributeValueFromSPSSOConfig(
1097                spssoconfig,
1098                SAML2Constants.WANT_ASSERTION_ENCRYPTED);
1099        if (assertionEncryptedAttr == null ||
1100            !assertionEncryptedAttr.equals("true"))
1101        {
1102            String attrEncryptedStr =
1103                SAML2Utils.getAttributeValueFromSPSSOConfig(
1104                    spssoconfig,
1105                    SAML2Constants.WANT_ATTRIBUTE_ENCRYPTED);
1106            if (attrEncryptedStr != null &&
1107                attrEncryptedStr.equals("true"))
1108            {
1109                needAttributeEncrypted = true;
1110            }
1111            String idEncryptedStr =
1112                SAML2Utils.getAttributeValueFromSPSSOConfig(
1113                    spssoconfig,
1114                    SAML2Constants.WANT_NAMEID_ENCRYPTED);
1115            if (idEncryptedStr != null &&
1116                idEncryptedStr.equals("true"))
1117            {
1118                needNameIDEncrypted = true;
1119            }
1120        }
1121        PrivateKey decryptionKey = KeyUtil.getDecryptionKey(spssoconfig);
1122        if (needNameIDEncrypted && encId == null) {
1123            SAML2Utils.debug.error(classMethod +
1124                                   "process: NameID was not encrypted.");
1125            SAML2Exception se = new SAML2Exception(SAML2Utils.bundle.getString(
1126                "nameIDNotEncrypted"));
1127            // invoke SPAdapter for failure
1128            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1129                request, response, smap, respInfo,
1130                SAML2ServiceProviderAdapter.INVALID_RESPONSE, se);
1131            throw se;
1132        }
1133        if (encId != null) {
1134            try {
1135                nameId = encId.decrypt(decryptionKey);
1136            } catch (SAML2Exception se) {
1137                // invoke SPAdapter for failure
1138                invokeSPAdapterForSSOFailure(hostEntityId, realm,
1139                    request, response, smap, respInfo,
1140                    SAML2ServiceProviderAdapter.INVALID_RESPONSE, se);
1141                throw se;
1142            }
1143        }
1144        respInfo.setNameId(nameId);
1145
1146        SPSSODescriptorElement spDesc = null;
1147        try {
1148            spDesc = metaManager.getSPSSODescriptor(realm, hostEntityId);
1149        } catch (SAML2MetaException ex) {
1150            SAML2Utils.debug.error(classMethod, ex);
1151        }
1152        if (spDesc == null) {
1153            SAML2Exception se = new SAML2Exception(SAML2Utils.bundle.getString(
1154                "metaDataError"));
1155            invokeSPAdapterForSSOFailure(hostEntityId, realm, request,
1156                response, smap, respInfo,
1157                SAML2ServiceProviderAdapter.SSO_FAILED_META_DATA_ERROR, se);
1158            throw se;
1159        }
1160        String nameIDFormat = nameId.getFormat();
1161        if (nameIDFormat != null) {
1162            List spNameIDFormatList = spDesc.getNameIDFormat();
1163
1164            if ((spNameIDFormatList != null) && (!spNameIDFormatList.isEmpty())
1165                && (!spNameIDFormatList.contains(nameIDFormat))) {
1166
1167                Object[] args = { nameIDFormat };
1168                SAML2Exception se = new SAML2Exception(SAML2Utils.BUNDLE_NAME,
1169                    "unsupportedNameIDFormatSP", args);
1170
1171                invokeSPAdapterForSSOFailure(hostEntityId, realm, request,
1172                    response, smap, respInfo,
1173                    SAML2ServiceProviderAdapter.INVALID_RESPONSE, se);
1174                throw se;
1175            }
1176        }
1177
1178        boolean ignoreProfile = false;
1179        String existUserName = null;
1180        SessionProvider sessionProvider = null;
1181        try {
1182            sessionProvider = SessionManager.getProvider();
1183            ignoreProfile = SAML2Utils.isIgnoreProfileSet(session);
1184        } catch (SessionException se) {
1185            // invoke SPAdapter for failure
1186            SAML2Exception se2 = new SAML2Exception(se);
1187            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1188                request, response, smap, respInfo, 
1189                SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2);
1190            throw se2;
1191        }
1192        if (session != null) {
1193            try {
1194                existUserName = sessionProvider.
1195                    getPrincipalName(session);
1196            } catch (SessionException se) {
1197                // invoke SPAdapter for failure
1198                SAML2Exception se2 = new SAML2Exception(se);
1199                invokeSPAdapterForSSOFailure(hostEntityId, realm,
1200                    request, response, smap, respInfo, 
1201                    SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2);
1202                throw se2;
1203            }
1204        }
1205        String userName;
1206        try {
1207            userName = acctMapper.getIdentity(
1208                authnAssertion, hostEntityId, realm);
1209        } catch (SAML2Exception se) {
1210            // invoke SPAdapter for failure
1211            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1212                request, response, smap, respInfo, 
1213                SAML2ServiceProviderAdapter.SSO_FAILED_NO_USER_MAPPING, se);
1214            throw se;
1215        }
1216        if (userName == null) {
1217            userName = existUserName;
1218        }
1219        if (SAML2Utils.debug.messageEnabled()) {
1220            SAML2Utils.debug.message(
1221                classMethod + "process: userName =[" + userName + "]");
1222        }
1223        List attrs = null;
1224        String remoteHostId = null;
1225        for (Iterator it = assertions.iterator(); it.hasNext(); ) {
1226            Assertion assertion = (Assertion)it.next();
1227            remoteHostId = assertion.getIssuer().getValue();
1228            List origAttrs = getSAMLAttributes(assertion,
1229                 needAttributeEncrypted,
1230                 decryptionKey);
1231            if (origAttrs != null && !origAttrs.isEmpty()) {
1232                if (attrs == null) {
1233                    attrs = new ArrayList();
1234                }
1235                attrs.addAll(origAttrs);
1236            }
1237        }
1238        Map attrMap = null;
1239        if (attrs != null) {
1240            try {
1241                attrMap = attrMapper.getAttributes(attrs, userName,
1242                    hostEntityId, remoteHostId, realm);
1243            } catch (SAML2Exception se) {
1244                // invoke SPAdapter for failure
1245                invokeSPAdapterForSSOFailure(hostEntityId, realm,
1246                    request, response, smap, respInfo, 
1247                    SAML2ServiceProviderAdapter.SSO_FAILED_ATTRIBUTE_MAPPING, 
1248                    se);
1249                throw se;
1250            }
1251        }
1252        if (SAML2Utils.debug.messageEnabled()) {
1253            SAML2Utils.debug.message(
1254                classMethod + "process: remoteHostId = " + remoteHostId);
1255            SAML2Utils.debug.message(
1256                classMethod + "process: attrMap = " + attrMap);
1257        }
1258        respInfo.setAttributeMap(attrMap);
1259
1260        // return error code for local user login
1261        if ((userName == null) || (userName.length() == 0)) {
1262            throw new SAML2Exception(
1263                SAML2Utils.bundle.getString("noUserMapping"));
1264        }
1265
1266        // Even if the user profile is set to ignore, we must attempt to persist
1267        // if the NameIDFormat is set to persistent.
1268        if (ignoreProfile && SAML2Constants.PERSISTENT.equals(nameIDFormat)) {
1269            ignoreProfile = false;
1270            SAML2Utils.debug.warning(classMethod
1271                + "ignoreProfile was true but NameIDFormat is Persistent => setting ignoreProfile to false");        }
1272
1273        boolean isTransient = SAML2Constants.NAMEID_TRANSIENT_FORMAT.equals(
1274            nameId.getFormat());
1275        boolean spDoNotWriteFedInfo = isSPDoNotWriteFedInfo(realm, hostEntityId, metaManager) &&
1276                SAML2Constants.UNSPECIFIED.equals(nameId.getFormat());
1277        boolean writeFedInfo = ( (!ignoreProfile && !isTransient && !spDoNotWriteFedInfo) &&
1278                (!SAML2Utils.isFedInfoExists(
1279                    userName, hostEntityId, remoteHostId, nameId)));
1280            // TODO: check if this few lines are needed
1281            /*
1282                DN dnObject = new DN(userName);
1283                String [] array = dnObject.explodeDN(true);
1284                userName = array[0];
1285            */
1286
1287        if (SAML2Utils.debug.messageEnabled()) {
1288            SAML2Utils.debug.message(
1289                classMethod + "userName : " + userName);
1290            SAML2Utils.debug.message(
1291                classMethod + "writeFedInfo : " + writeFedInfo);
1292        }
1293        AuthnRequest authnRequest = null;
1294        if (smap != null) {
1295            authnRequest = (AuthnRequest) 
1296                smap.get(SAML2Constants.AUTHN_REQUEST);
1297        }
1298        if (inRespToResp != null && inRespToResp.length() != 0) {
1299            SPCache.requestHash.remove(inRespToResp);
1300        }
1301        Map sessionInfoMap = new HashMap();
1302        sessionInfoMap.put(SessionProvider.REALM, realm);
1303        sessionInfoMap.put(SessionProvider.PRINCIPAL_NAME, userName);
1304        // set client info. always use client IP address to prevent
1305        // reverse host lookup
1306        String clientAddr = ClientUtils.getClientIPAddress(request);
1307        sessionInfoMap.put(SessionProvider.HOST, clientAddr);
1308        sessionInfoMap.put(SessionProvider.HOST_NAME, clientAddr);
1309        sessionInfoMap.put(SessionProvider.AUTH_LEVEL, 
1310            String.valueOf(authLevel));
1311        try {
1312            session = sessionProvider.createSession(
1313                sessionInfoMap, request, response, null);
1314        } catch (SessionException se) {
1315            // invoke SPAdapter for failure
1316            int failureCode = 
1317                SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_GENERATION;
1318            int sessCode =  se.getErrCode();
1319            if (sessCode == SessionException.AUTH_USER_INACTIVE) {
1320                failureCode =
1321                    SAML2ServiceProviderAdapter.SSO_FAILED_AUTH_USER_INACTIVE;
1322            } else if (sessCode == SessionException.AUTH_USER_LOCKED) {
1323                failureCode =
1324                    SAML2ServiceProviderAdapter.SSO_FAILED_AUTH_USER_LOCKED;
1325            } else if (sessCode == SessionException.AUTH_ACCOUNT_EXPIRED) {
1326                failureCode =
1327                    SAML2ServiceProviderAdapter.SSO_FAILED_AUTH_ACCOUNT_EXPIRED;
1328            }
1329            if (SAML2Utils.debug.messageEnabled()) {
1330                SAML2Utils.debug.message(
1331                    "SPACSUtils.processResponse : error code=" + sessCode, se);
1332            }
1333            SAML2Exception se2 = new SAML2Exception(se);
1334            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1335                request, response, smap, respInfo, failureCode, se2);
1336            throw se2;
1337        }
1338
1339        // set metaAlias
1340        String[] values = { metaAlias };
1341        try {
1342            setAttrMapInSession(sessionProvider, attrMap, session);
1343            setDiscoBootstrapCredsInSSOToken(sessionProvider, authnAssertion,
1344                session);
1345            sessionProvider.setProperty(
1346                session, SAML2Constants.SP_METAALIAS, values);
1347        } catch (SessionException se) {
1348            // invoke SPAdapter for failure
1349            SAML2Exception se2 = new SAML2Exception(se);
1350            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1351                request, response, smap, respInfo, 
1352                SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2);
1353            throw se2;
1354        }
1355
1356        NameIDInfo info = null;
1357        String affiID = nameId.getSPNameQualifier();
1358        AffiliationDescriptorType affiDesc =
1359            metaManager.getAffiliationDescriptor(realm, affiID);
1360        boolean isDualRole = SAML2Utils.isDualRole(hostEntityId, realm);
1361        if (affiDesc != null) {
1362            if (!affiDesc.getAffiliateMember().contains(hostEntityId)) {
1363                throw new SAML2Exception(SAML2Utils.bundle.getString(
1364                    "spNotAffiliationMember"));
1365            }
1366            if (isDualRole) {
1367                info = new NameIDInfo(affiID, remoteHostId, nameId,
1368                    SAML2Constants.DUAL_ROLE, true);
1369            } else {
1370                info = new NameIDInfo(affiID, remoteHostId, nameId,
1371                    SAML2Constants.SP_ROLE, true);
1372            }
1373        } else {
1374            if (isDualRole) {
1375                info = new NameIDInfo(hostEntityId, remoteHostId, nameId,
1376                    SAML2Constants.DUAL_ROLE, false);
1377            } else {
1378                info = new NameIDInfo(hostEntityId, remoteHostId, nameId,
1379                    SAML2Constants.SP_ROLE, false);
1380            }
1381        }
1382        Map props = new HashMap();
1383        String nameIDValueString = info.getNameIDValue();
1384        props.put(LogUtil.NAME_ID, info.getNameIDValue());
1385        try {
1386            userName = sessionProvider.getPrincipalName(session);
1387        } catch (SessionException se) {
1388            // invoke SPAdapter for failure
1389            SAML2Exception se2 = new SAML2Exception(se);
1390            invokeSPAdapterForSSOFailure(hostEntityId, realm,
1391                request, response, smap, respInfo, 
1392                SAML2ServiceProviderAdapter.SSO_FAILED_SESSION_ERROR, se2);
1393            throw se2;
1394        }
1395        String[] data1 = {userName, nameIDValueString};
1396        LogUtil.access(Level.INFO, LogUtil.SUCCESS_FED_SSO, data1, session,
1397            props);
1398        // write fed info into data store
1399        if (writeFedInfo) {
1400            try {
1401                AccountUtils.setAccountFederation(info, userName);
1402            } catch (SAML2Exception se) {
1403                // invoke SPAdapter for failure
1404                invokeSPAdapterForSSOFailure(hostEntityId, realm,
1405                    request, response, smap, respInfo, 
1406                    SAML2ServiceProviderAdapter.FEDERATION_FAILED_WRITING_ACCOUNT_INFO, se);
1407               throw se;
1408            }
1409            String[] data = {userName, ""};
1410            if (LogUtil.isAccessLoggable(Level.FINE)) {
1411                data[1] = info.toValueString();
1412            }
1413            LogUtil.access(Level.INFO,
1414                           LogUtil.FED_INFO_WRITTEN,
1415                           data,
1416                           session,
1417                           props);
1418        }
1419        String requestID = respInfo.getResponse().getInResponseTo();
1420        // save info in memory for logout
1421        saveInfoInMemory(sessionProvider, session, sessionIndex, metaAlias,
1422            info, IDPProxyUtil.isIDPProxyEnabled(requestID), isTransient);
1423
1424        // invoke SP Adapter
1425        SAML2ServiceProviderAdapter spAdapter =
1426            SAML2Utils.getSPAdapterClass(hostEntityId, realm);
1427        if (spAdapter != null) {
1428            boolean redirected = spAdapter.postSingleSignOnSuccess(
1429                hostEntityId, realm, request, 
1430                response, session, authnRequest, respInfo.getResponse(), 
1431                respInfo.getProfileBinding(), writeFedInfo);
1432            String[] value = null;
1433            if (redirected) {
1434                value = new String[] {"true"};
1435            } else {
1436                value = new String[] {"false"};
1437            }
1438            try {
1439                sessionProvider.setProperty(session, 
1440                    SAML2Constants.RESPONSE_REDIRECTED, value);
1441            } catch (SessionException ex) {
1442                SAML2Utils.debug.warning("SPSingleLogout.processResp", ex);
1443            } catch (UnsupportedOperationException ex) {
1444                SAML2Utils.debug.warning("SPSingleLogout.processResp", ex);
1445            }
1446        }
1447     
1448        String assertionID=authnAssertion.getID();
1449        if (respInfo.getProfileBinding().equals(SAML2Constants.HTTP_POST)) {
1450            SPCache.assertionByIDCache.put(assertionID, SAML2Constants.ONETIME);
1451            try {
1452                if (SAML2Utils.isSAML2FailOverEnabled()) {
1453                    SAML2RepositoryFactory.getInstance().saveSAML2Token(
1454                            assertionID,
1455                            SAML2Constants.ONETIME,
1456                            ((Long) smap.get(SAML2Constants.NOTONORAFTER)).longValue() / 1000,
1457                            null);
1458                }
1459            } catch (StoreException se) {
1460                SAML2Utils.debug.error(classMethod + "DB error!", se);
1461            } catch (SAML2Exception e) {
1462                SAML2Utils.debug.error(classMethod + "DB error!", e); 
1463            }
1464        }
1465        respInfo.setAssertion(authnAssertion);
1466 
1467        return session;
1468    }
1469
1470   
1471    private static void invokeSPAdapterForSSOFailure(String hostEntityId,
1472        String realm, HttpServletRequest request, HttpServletResponse response,
1473        Map smap, ResponseInfo respInfo, int errorCode, 
1474        SAML2Exception se) { 
1475        SAML2ServiceProviderAdapter spAdapter = null;
1476        try {
1477            spAdapter = SAML2Utils.getSPAdapterClass(hostEntityId, realm);
1478        } catch (SAML2Exception e) {
1479            if (SAML2Utils.debug.messageEnabled()) {
1480                SAML2Utils.debug.message(
1481                    "SPACSUtils.invokeSPAdapterForSSOFailure", e);
1482            }
1483        }
1484        if (spAdapter != null) {
1485            AuthnRequest authnRequest = null;
1486            if (smap != null) {
1487                authnRequest = (AuthnRequest) 
1488                    smap.get(SAML2Constants.AUTHN_REQUEST);
1489            }
1490            boolean redirected = spAdapter.postSingleSignOnFailure(
1491                hostEntityId, realm, request, response, authnRequest,
1492                respInfo.getResponse(), respInfo.getProfileBinding(),
1493                errorCode);
1494            se.setRedirectionDone(redirected);
1495        }
1496    }
1497
1498    /**
1499     * Gets the <code>SPAccountMapper</code>
1500     *
1501     * @param attributes the Attribute Map
1502     * @return the <code>SPAccountMapper
1503     * @throws SAML2Exception if the processing failed. 
1504     */
1505    private static SPAccountMapper getSPAccountMapper(
1506        Map attributes) throws SAML2Exception {
1507            
1508        SPAccountMapper acctMapper = null;
1509        List acctMapperList = (List)attributes.get(
1510            SAML2Constants.SP_ACCOUNT_MAPPER);
1511        if (acctMapperList != null) {
1512            try {
1513                acctMapper = (SPAccountMapper)
1514                    (Class.forName((String)acctMapperList.get(0)).
1515                     newInstance());
1516                if (SAML2Utils.debug.messageEnabled()) {
1517                    SAML2Utils.debug.message(
1518                        "SPACSUtils.getSPAccountMapper: mapper = " +
1519                        (String)acctMapperList.get(0));
1520                }
1521            } catch (ClassNotFoundException cfe) {
1522                throw new SAML2Exception(cfe);
1523            } catch (InstantiationException ie) {
1524                throw new SAML2Exception(ie);
1525            } catch (IllegalAccessException iae) {
1526                throw new SAML2Exception(iae);
1527            }
1528        }
1529        if (acctMapper == null) {
1530            throw new SAML2Exception(
1531                SAML2Utils.bundle.getString("failedAcctMapper"));
1532        }
1533        return acctMapper;
1534    }
1535
1536    /**
1537     * Gets the <code>SPAttributeMapper</code>
1538     *
1539     * @param attributes the Attribute Map
1540     * @return the <code>SPAttributeMapper
1541     * @throws SAML2Exception if the processing failed. 
1542     */
1543    private static SPAttributeMapper getSPAttributeMapper(
1544        Map attributes) throws SAML2Exception {
1545            
1546        SPAttributeMapper attrMapper = null;
1547        List attrMapperList = (List)attributes.get(
1548            SAML2Constants.SP_ATTRIBUTE_MAPPER);
1549        if (attrMapperList != null) {
1550            try {
1551                attrMapper = (SPAttributeMapper)
1552                    (Class.forName((String)attrMapperList.get(0)).
1553                     newInstance());
1554            } catch (ClassNotFoundException cfe) {
1555                throw new SAML2Exception(cfe);
1556            } catch (InstantiationException ie) {
1557                throw new SAML2Exception(ie);
1558            } catch (IllegalAccessException iae) {
1559                    throw new SAML2Exception(iae);
1560            }
1561        }
1562        if (attrMapper == null) {
1563            throw new SAML2Exception(
1564                SAML2Utils.bundle.getString("failedAttrMapper"));
1565        }
1566        return attrMapper;
1567    }
1568
1569    private static void saveInfoInMemory(SessionProvider sessionProvider,
1570        Object session, String sessionIndex, String metaAlias,
1571        NameIDInfo info, boolean isIDPProxy, boolean isTransient)
1572        throws SAML2Exception {
1573        
1574        String infoKeyString = (new NameIDInfoKey(
1575            info.getNameIDValue(),
1576            info.getHostEntityID(),
1577            info.getRemoteEntityID())).toValueString();
1578        String infoKeyAttribute =
1579            AccountUtils.getNameIDInfoKeyAttribute();
1580        String[] fromToken = null;
1581        try {
1582            fromToken = sessionProvider.
1583                getProperty(session, infoKeyAttribute);
1584            if (fromToken == null || fromToken.length == 0 ||
1585                fromToken[0] == null || fromToken[0].length() == 0) {
1586                String[] values = { infoKeyString };
1587                sessionProvider.setProperty(
1588                    session, infoKeyAttribute, values);
1589            } else {
1590                if (fromToken[0].indexOf(infoKeyString) == -1) {
1591                    String[] values = { fromToken[0] +
1592                                        SAML2Constants.SECOND_DELIM +
1593                                        infoKeyString }; 
1594                    sessionProvider.setProperty(
1595                        session, infoKeyAttribute, values);
1596                }
1597            }
1598            if (isTransient) {
1599                String nameIDInfoStr = info.toValueString();
1600                String infoAttribute = AccountUtils.getNameIDInfoAttribute();
1601                String[] nameIDInfoStrs = sessionProvider.getProperty(session,
1602                    infoAttribute);
1603                if (nameIDInfoStrs == null) {
1604                    nameIDInfoStrs = new String[1];
1605                    nameIDInfoStrs[0] = nameIDInfoStr;
1606                } else {
1607                    Set nameIDInfoStrSet = new HashSet();
1608                    for(int i=0; i<nameIDInfoStrs.length; i++) {
1609                        nameIDInfoStrSet.add(nameIDInfoStrs[i]);
1610                    }
1611                    nameIDInfoStrSet.add(nameIDInfoStr);
1612                    nameIDInfoStrs = (String[])nameIDInfoStrSet.toArray(
1613                        new String[nameIDInfoStrSet.size()]);
1614                }
1615                sessionProvider.setProperty(session, infoAttribute,
1616                    nameIDInfoStrs);
1617            }
1618        } catch (SessionException sessE) {
1619            throw new SAML2Exception(sessE);
1620        }
1621        String tokenID = sessionProvider.getSessionID(session);
1622        if (!SPCache.isFedlet) {
1623            List fedSessions = (List)
1624                SPCache.fedSessionListsByNameIDInfoKey.get(infoKeyString);
1625            if (fedSessions == null) {
1626                synchronized (SPCache.fedSessionListsByNameIDInfoKey) {
1627                    fedSessions = (List)
1628                    SPCache.fedSessionListsByNameIDInfoKey.get(infoKeyString);
1629                    if (fedSessions == null) {
1630                        fedSessions = new ArrayList();
1631                    }
1632                }  
1633                synchronized (fedSessions) {
1634                    fedSessions.add(new SPFedSession(sessionIndex, tokenID,
1635                        info, metaAlias));
1636                    SPCache.fedSessionListsByNameIDInfoKey.put(
1637                        infoKeyString, fedSessions);
1638                }
1639                if ((agent != null) && agent.isRunning() && (saml2Svc != null)){
1640                    saml2Svc.setFedSessionCount(
1641                        (long)SPCache.fedSessionListsByNameIDInfoKey.size());
1642                }
1643
1644                if (isIDPProxy) {
1645                    //IDP Proxy 
1646                    IDPSession idpSess = (IDPSession)
1647                        IDPCache.idpSessionsBySessionID.get(
1648                        tokenID);
1649                    if (idpSess == null) {
1650                        idpSess = new IDPSession(session);
1651                        IDPCache.idpSessionsBySessionID.put(
1652                            tokenID, idpSess);
1653                    }
1654                    if (SAML2Utils.debug.messageEnabled()) {
1655                        SAML2Utils.debug.message("Add Session Partner: " +
1656                            info.getRemoteEntityID());
1657                    } 
1658                    idpSess.addSessionPartner(new SAML2SessionPartner(
1659                        info.getRemoteEntityID(), true));
1660                    // end of IDP Proxy        
1661                }
1662            } else {
1663                synchronized (fedSessions) {
1664                    Iterator iter = fedSessions.iterator();
1665                    boolean found = false;
1666                    while (iter.hasNext()) {
1667                        SPFedSession temp = (SPFedSession) iter.next();
1668                        String idpSessionIndex = null;
1669                        if(temp != null) {
1670                           idpSessionIndex = temp.idpSessionIndex; 
1671                        }
1672                        if ((idpSessionIndex != null) &&
1673                                (idpSessionIndex.equals(sessionIndex))) {
1674                            temp.spTokenID = tokenID;
1675                            temp.info = info;
1676                            found = true;
1677                            break;
1678                        }
1679                    }    
1680                    if (!found) {
1681                        fedSessions.add(
1682                            new SPFedSession(sessionIndex, tokenID, info,
1683                                             metaAlias));
1684                        SPCache.fedSessionListsByNameIDInfoKey.put(
1685                            infoKeyString, fedSessions);
1686                        if ((agent != null) &&
1687                            agent.isRunning() &&
1688                            (saml2Svc != null))
1689                        {
1690                            saml2Svc.setFedSessionCount(
1691                                (long)SPCache.fedSessionListsByNameIDInfoKey.
1692                                    size());
1693                        }
1694                    }
1695               }    
1696            }
1697            SPCache.fedSessionListsByNameIDInfoKey.put(infoKeyString,
1698                                                   fedSessions);
1699            if ((agent != null) && agent.isRunning() && (saml2Svc != null)) {
1700                saml2Svc.setFedSessionCount(
1701                    (long)SPCache.fedSessionListsByNameIDInfoKey.size());
1702            }
1703        }
1704        try {
1705            sessionProvider.addListener(
1706                session, new SPSessionListener(infoKeyString, tokenID));
1707        } catch (SessionException e) {
1708            SAML2Utils.debug.error(
1709                "SPACSUtils.saveInfoInMemory: "+
1710                "Unable to add session listener.");
1711        }
1712    }
1713    
1714    /** Sets the attribute map in the session
1715     *
1716     *  @param sessionProvider Session provider
1717     *  @param attrMap the Attribute Map
1718     *  @param session the valid session object
1719     *  @throws com.sun.identity.plugin.session.SessionException 
1720     */
1721    public static void setAttrMapInSession(
1722        SessionProvider sessionProvider,
1723        Map attrMap, Object session)
1724        throws SessionException {
1725        if (attrMap != null && !attrMap.isEmpty()) {
1726            Set entrySet = attrMap.entrySet();
1727            for(Iterator iter = entrySet.iterator(); iter.hasNext();) {
1728                Map.Entry entry = (Map.Entry)iter.next();
1729                String attrName = (String)entry.getKey();
1730                Set attrValues = (Set)entry.getValue();
1731                if(attrValues != null && !attrValues.isEmpty()) {
1732                   sessionProvider.setProperty(
1733                       session, attrName,
1734                       (String[]) attrValues.toArray(
1735                       new String[attrValues.size()]));
1736                   if (SAML2Utils.debug.messageEnabled()) {
1737                       SAML2Utils.debug.message(
1738                           "SPACSUtils.setAttrMapInSessioin: AttrMap:" +
1739                           attrName + " , " + attrValues);
1740                   }
1741                }
1742            }
1743        }
1744    }
1745
1746    /** Sets Discovery bootstrap credentials in the SSOToken
1747     *
1748     *  @param sessionProvider session provider.
1749     *  @param assertion assertion.
1750     *  @param session the valid session object.
1751     */
1752    private static void setDiscoBootstrapCredsInSSOToken(
1753        SessionProvider sessionProvider, Assertion assertion, Object session)
1754        throws SessionException {
1755
1756        if (assertion == null) {
1757            return;
1758        }
1759
1760        Set discoBootstrapCreds = null;
1761        Advice advice = assertion.getAdvice();
1762        if (advice != null) {
1763            List creds = advice.getAdditionalInfo();
1764            if ((creds != null) && !creds.isEmpty()) {
1765                if (discoBootstrapCreds == null) {
1766                    discoBootstrapCreds = new HashSet();
1767                }
1768                discoBootstrapCreds.addAll(creds);
1769            }
1770        }
1771
1772        if (discoBootstrapCreds != null) {
1773            sessionProvider.setProperty(session,
1774                SAML2Constants.DISCOVERY_BOOTSTRAP_CREDENTIALS,
1775                (String[])discoBootstrapCreds.toArray(
1776                new String[discoBootstrapCreds.size()]));
1777        }
1778    }
1779
1780    /**
1781     * Obtains relay state. Retrieves the relay state from relay state cache.
1782     * If input relay state is null, retrieve it from <code>SPSSOConfig</code>.
1783     *
1784     * @param relayStateID relay state value received from http request.
1785     * @param orgName realm or organization name the service provider resides in
1786     * @param hostEntityId Entity ID of the hosted service provider
1787     * @param sm <code>SAML2MetaManager</code> instance.
1788     * @return final relay state. Or <code>null</code> if the input 
1789     *         relayStateID is null and no default relay state is configured.
1790     */
1791    public static String getRelayState(
1792        String relayStateID,
1793        String orgName,
1794        String hostEntityId,
1795        SAML2MetaManager sm
1796    ) {
1797        String relayStateUrl = null;
1798
1799        if ((relayStateID != null) && (relayStateID.trim().length() != 0)) {
1800            CacheObject cache = (CacheObject)SPCache.relayStateHash.remove(
1801                relayStateID);
1802
1803            if (cache != null) {
1804                relayStateUrl = (String)cache.getObject();
1805            } else if (SAML2Utils.isSAML2FailOverEnabled()) {
1806                try {
1807                    // Try and retrieve the value from the SAML2 repository
1808                    // The key is this way to make it unique compared to when
1809                    // the same key is used to store a copy of the AuthnRequestInfo
1810                    String relayState = (String) SAML2RepositoryFactory.getInstance().retrieveSAML2Token(relayStateID + relayStateID);
1811                    if (relayState != null) {
1812                        // Get back the relayState
1813                        relayStateUrl = relayState;
1814                        if (SAML2Utils.debug.messageEnabled()) {
1815                            SAML2Utils.debug.message("SPACUtils.getRelayState: relayState"
1816                                + " retrieved from SAML2 repository for relayStateID: " + relayStateID);
1817                        }
1818                    }
1819                } catch (StoreException se) {
1820                    SAML2Utils.debug.error("SPACUtils.getRelayState: Unable to retrieve relayState for relayStateID "
1821                            + relayStateID, se);
1822                } catch (SAML2Exception ex) {                    
1823                    SAML2Utils.debug.error("SPACUtils.getRelayState: Unable to retrieve relayState for relayStateID "
1824                            + relayStateID, ex);                    
1825                }
1826            } else {
1827                // !SAML2Utils.isSAML2FailOverEnabled()
1828                if (SAML2Utils.debug.messageEnabled()) {
1829                    SAML2Utils.debug.message("SPACUtils.getRelayState: relayState"
1830                        + " is null for relayStateID: " + relayStateID + ", SAML2 failover is disabled");
1831                }
1832            }
1833            
1834            if ((relayStateUrl == null) || (relayStateUrl.trim().length() == 0)
1835            ) {
1836                relayStateUrl = relayStateID;
1837            }
1838        }
1839        
1840        if (relayStateUrl == null || relayStateUrl.trim().length() == 0) {
1841            relayStateUrl = getAttributeValueFromSPSSOConfig(
1842                orgName, hostEntityId, sm, SAML2Constants.DEFAULT_RELAY_STATE);
1843        }
1844        
1845        return relayStateUrl;
1846    }
1847
1848    /**
1849     * Retrieves intermediate redirect url from SP sso config. This url is used
1850     * if you want to goto some place before the final relay state.
1851     *
1852     * @param orgName realm or organization name the service provider resides in
1853     * @param hostEntityId Entity ID of the hosted service provider
1854     * @param sm <code>SAML2MetaManager</code> instance.
1855     * @return intermediate redirect url; or <code>null</code> if the url is
1856     *                is not configured or an error occured during the retrieval
1857     *                process.
1858     */
1859    public static String getIntermediateURL(String orgName,
1860                                        String hostEntityId,
1861                                        SAML2MetaManager sm)
1862    {
1863        return getAttributeValueFromSPSSOConfig(orgName, hostEntityId, sm,
1864                                        SAML2Constants.INTERMEDIATE_URL);
1865    }
1866
1867    /**
1868     * Saves response for later retrieval and retrieves local auth url from
1869     * <code>SPSSOConfig</code>.
1870     * If the url does not exist, generate one from request URI.
1871     * If still cannot get it, (shouldn't happen), get it from
1872     * <code>AMConfig.properties</code>.
1873     *
1874     * @param orgName realm or organization name the service provider resides in
1875     * @param hostEntityId Entity ID of the hosted service provider
1876     * @param sm <code>SAML2MetaManager</code> instance to perform meta
1877     *                operation.
1878     * @param respInfo to be cached <code>ResponseInfo</code>.
1879     * @param requestURI http request URI.
1880     * @return local login url.
1881     */
1882    public static String prepareForLocalLogin(
1883                                        String orgName,
1884                                        String hostEntityId,
1885                                        SAML2MetaManager sm,
1886                                        ResponseInfo respInfo,
1887                                        String requestURI)
1888    {
1889        String localLoginUrl = getAttributeValueFromSPSSOConfig(
1890                orgName, hostEntityId, sm, SAML2Constants.LOCAL_AUTH_URL);
1891        if ((localLoginUrl == null) || (localLoginUrl.length() == 0)) {
1892            // get it from request
1893            try {
1894                int index = requestURI.indexOf("Consumer/metaAlias");
1895                if (index != -1) {
1896                    localLoginUrl = requestURI.substring(0, index)
1897                        + "UI/Login?org="
1898                        + orgName;
1899                }
1900            } catch (IndexOutOfBoundsException e) {
1901                localLoginUrl = null;
1902            }
1903            if ((localLoginUrl == null) || (localLoginUrl.length() == 0)) {
1904                // shouldn't be here, but in case
1905                localLoginUrl =
1906                        SystemConfigurationUtil.getProperty(SAMLConstants.SERVER_PROTOCOL)
1907                        + "://"
1908                        + SystemConfigurationUtil.getProperty(SAMLConstants.SERVER_HOST)
1909                        + SystemConfigurationUtil.getProperty(SAMLConstants.SERVER_PORT)
1910                        + "/UI/Login?org="
1911                        + orgName;
1912            }
1913        }
1914        synchronized (SPCache.responseHash) {
1915           SPCache.responseHash.put(respInfo.getResponse().getID(), 
1916               respInfo);
1917        }   
1918        if (SAML2Utils.debug.messageEnabled()) {
1919            SAML2Utils.debug.message("SPACSUtils:prepareForLocalLogin: " +
1920                "localLoginUrl = " + localLoginUrl);
1921        }
1922        return localLoginUrl;
1923    }
1924
1925    /**
1926     * Retrieves attribute value for a given attribute name from 
1927     * <code>SPSSOConfig</code>.
1928     * @param orgName realm or organization name the service provider resides in
1929     * @param hostEntityId hosted service provider's Entity ID.
1930     * @param sm <code>SAML2MetaManager</code> instance to perform meta
1931     *                operations.
1932     * @param attrName name of the attribute whose value ot be retrived.
1933     * @return value of the attribute; or <code>null</code> if the attribute
1934     *                if not configured, or an error occured in the process.
1935     */ 
1936    private static String getAttributeValueFromSPSSOConfig(String orgName,
1937                                                        String hostEntityId,
1938                                                        SAML2MetaManager sm,
1939                                                        String attrName)
1940    {
1941        String result = null;
1942        try {
1943            SPSSOConfigElement config = sm.getSPSSOConfig(orgName,
1944                                                        hostEntityId);
1945            if (config == null) {
1946                return null;
1947            }
1948            Map attrs = SAML2MetaUtils.getAttributes(config);
1949            List value = (List) attrs.get(attrName);
1950            if (value != null && value.size() != 0) {
1951                result = ((String) value.iterator().next()).trim();
1952            }
1953        } catch (SAML2MetaException sme) {
1954            if (SAML2Utils.debug.messageEnabled()) {
1955                SAML2Utils.debug.message("SPACSUtils.getAttributeValueFromSPSSO"
1956                        + "Config:", sme);
1957            }
1958            result = null;
1959        }
1960        return result;
1961    }
1962
1963    // gets the attributes from AttibuteStates in the assertions.
1964    private static List getSAMLAttributes(Assertion assertion,
1965                                boolean needAttributeEncrypted,
1966                                PrivateKey decryptionKey)
1967    {
1968        List attrList = null;
1969        if (assertion != null) {
1970            List statements = assertion.getAttributeStatements();
1971            if (statements != null && statements.size() > 0 ) {
1972                for (Iterator it = statements.iterator(); it.hasNext(); ) {
1973                    AttributeStatement statement =
1974                        (AttributeStatement)it.next();
1975                    List attributes = statement.getAttribute();
1976                    if (needAttributeEncrypted &&
1977                        attributes != null && !attributes.isEmpty())
1978                    {
1979                        SAML2Utils.debug.error("Attribute not encrypted.");
1980                        return null;
1981                    }
1982                    if (attributes != null) {
1983                        if (attrList == null) {
1984                            attrList = new ArrayList();
1985                        }
1986                        attrList.addAll(attributes);
1987                    }
1988                    List encAttrs = statement.getEncryptedAttribute();
1989                    if (encAttrs != null) {
1990                        for (Iterator encIter = encAttrs.iterator();
1991                                encIter.hasNext(); )
1992                        {
1993                            if (attrList == null) {
1994                                attrList = new ArrayList();
1995                            }
1996                            try {
1997                                attrList.add(
1998                                    ((EncryptedAttribute) encIter.next()).
1999                                        decrypt(decryptionKey));
2000                            } catch (SAML2Exception se) {
2001                                SAML2Utils.debug.error("Decryption error:", se);
2002                                return null;
2003                            }
2004                        }
2005                    }
2006                }
2007            }
2008        }
2009        return attrList;
2010    }
2011
2012    /**
2013     * Processes response from Identity Provider to Fedlet (SP).
2014     * This will do all required protocol processing, include signature,
2015     * issuer and audience validation etc. A map containing processing
2016     * result will be returned. <br>
2017     * Here is a list of keys and values for the returned map: <br>
2018     * SAML2Constants.ATTRIBUTE_MAP -- Attribute map containing all attributes
2019     *                                 passed down from IDP inside the 
2020     *                                 Assertion. The value is a 
2021     *                                 <code>java.util.Map</code> whose keys 
2022     *                                 are attribute names and values are 
2023     *                                 <code>java.util.Set</code> of string 
2024     *                                 values for the attributes. <br>
2025     * SAML2Constants.RELAY_STATE -- Relay state, value is a string <br>
2026     * SAML2Constants.IDPENTITYID -- IDP entity ID, value is a string<br>
2027     * SAML2Constants.RESPONSE    -- Response object, value is an instance of 
2028     *                               com.sun.identity.saml2.protocol.Response
2029     * SAML2Constants.ASSERTION   -- Assertion object, value is an instance of 
2030     *                               com.sun.identity.saml2.assertion.Assertion
2031     * SAML2Constants.SUBJECT     -- Subject object, value is an instance of 
2032     *                               com.sun.identity.saml2.assertion.Subject
2033     * SAML2Constants.NAMEID      -- NameID object, value is an instance of 
2034     *                               com.sun.identity.saml2.assertion.NameID
2035     *
2036     * @param request HTTP Servlet request
2037     * @param response HTTP Servlet response.
2038     *
2039     * @return <code>Map</code> which holds result of the processing.
2040     * @throws SAML2Exception if the processing failed due to server error.
2041     * @throws IOException if the processing failed due to IO error.
2042     * @throws SessionException if the processing failed due to session error.
2043     * @throws ServletException if the processing failed due to request error.
2044     *
2045     * @supported.api
2046     */  
2047    public static Map processResponseForFedlet (HttpServletRequest request,
2048        HttpServletResponse response) throws SAML2Exception, IOException,
2049        SessionException, ServletException {
2050        if ((request == null) || (response == null)) {
2051            throw new ServletException(
2052                SAML2SDKUtils.bundle.getString("nullInput"));
2053        }
2054        
2055        String requestURL = request.getRequestURL().toString();
2056        SAML2MetaManager metaManager = new SAML2MetaManager();
2057        if (metaManager == null) {
2058            throw new SAML2Exception(
2059                    SAML2SDKUtils.bundle.getString("errorMetaManager"));
2060        }
2061        String metaAlias = SAML2MetaUtils.getMetaAliasByUri(requestURL);
2062        if ((metaAlias ==  null) || (metaAlias.length() == 0)) {
2063            // Check in case metaAlias has been supplied as a parameter
2064            metaAlias = request.getParameter(SAML2MetaManager.NAME_META_ALIAS_IN_URI);
2065            if (metaAlias == null || metaAlias.length() == 0) {
2066                // pick the first available one
2067                List spMetaAliases =
2068                        metaManager.getAllHostedServiceProviderMetaAliases("/");
2069                if ((spMetaAliases != null) && !spMetaAliases.isEmpty()) {
2070                    // get first one
2071                    metaAlias = (String) spMetaAliases.get(0);
2072                }
2073                if ((metaAlias ==  null) || (metaAlias.length() == 0)) {
2074                    throw new ServletException(
2075                            SAML2SDKUtils.bundle.getString("nullSPEntityID"));
2076                }
2077            }
2078        }
2079        String hostEntityId = null;
2080        try {
2081            hostEntityId = metaManager.getEntityByMetaAlias(metaAlias);
2082        } catch (SAML2MetaException sme) {
2083            SAML2SDKUtils.debug.error("SPACSUtils.processResponseForFedlet",
2084                sme);
2085            throw new SAML2Exception( 
2086                    SAML2SDKUtils.bundle.getString("metaDataError"));
2087        }
2088        if (hostEntityId == null) {
2089            // logging?
2090            throw new SAML2Exception( 
2091                    SAML2SDKUtils.bundle.getString("metaDataError"));
2092        }
2093        // organization is always root org
2094        String orgName = "/";
2095        String relayState = request.getParameter(SAML2Constants.RELAY_STATE);
2096        SessionProvider sessionProvider = null;
2097        ResponseInfo respInfo = null;
2098        try {
2099            sessionProvider = SessionManager.getProvider();
2100        } catch (SessionException se) {
2101            SAML2SDKUtils.debug.error("SPACSUtils.processResponseForFedlet",
2102                se);
2103            throw new SAML2Exception(se);
2104        }
2105        respInfo = SPACSUtils.getResponse(
2106                request, response, orgName, hostEntityId, metaManager);
2107        
2108        Object newSession = null;
2109
2110        // Throws a SAML2Exception if the response cannot be validated
2111        // or contains a non-Success StatusCode, invoking the SPAdapter SPI
2112        // for taking action on the failed validation.
2113        // The resulting exception has its redirectionDone flag set if
2114        // the SPAdapter issued a HTTP redirect.
2115        newSession = SPACSUtils.processResponse(
2116                    request, response, metaAlias, null, respInfo,
2117                    orgName, hostEntityId, metaManager);
2118        
2119        SAML2SDKUtils.debug.message("SSO SUCCESS");
2120        String[] redirected = sessionProvider.getProperty(newSession,
2121                SAML2Constants.RESPONSE_REDIRECTED);
2122        if ((redirected != null) && (redirected.length != 0) &&
2123                redirected[0].equals("true")) {
2124            SAML2SDKUtils.debug.message("Already redirected in SPAdapter.");
2125            // response redirected already in SPAdapter
2126            return createMapForFedlet(respInfo, null, hostEntityId);
2127        }
2128        // redirect to relay state
2129        String finalUrl = SPACSUtils.getRelayState(
2130                relayState, orgName, hostEntityId, metaManager);
2131        String realFinalUrl = finalUrl;
2132        if (finalUrl != null && finalUrl.length() != 0) {
2133            try {
2134                realFinalUrl =
2135                    sessionProvider.rewriteURL(newSession, finalUrl);
2136            } catch (SessionException se) {
2137                SAML2SDKUtils.debug.message("SPACSUtils.processRespForFedlet",
2138                    se);
2139                realFinalUrl = finalUrl;
2140            }
2141        }
2142        String redirectUrl = SPACSUtils.getIntermediateURL(
2143                orgName, hostEntityId, metaManager);
2144        String realRedirectUrl = null;
2145        if (redirectUrl != null && redirectUrl.length() != 0) {
2146            if (realFinalUrl != null && realFinalUrl.length() != 0) {
2147                if (redirectUrl.indexOf("?") != -1) {
2148                    redirectUrl += "&goto=";
2149                } else {
2150                    redirectUrl += "?goto=";
2151                }
2152                redirectUrl += URLEncDec.encode(realFinalUrl);
2153                try {
2154                    realRedirectUrl = sessionProvider.rewriteURL(
2155                            newSession, redirectUrl);
2156                } catch (SessionException se) {
2157                    SAML2SDKUtils.debug.message(
2158                      "SPACSUtils.processRespForFedlet: rewriting failed.", se);
2159                    realRedirectUrl = redirectUrl;
2160                }
2161            } else {
2162                realRedirectUrl = redirectUrl;
2163            }
2164        } else {
2165            realRedirectUrl = finalUrl;
2166        }
2167        return createMapForFedlet(respInfo, realRedirectUrl, hostEntityId); 
2168    }
2169
2170     /**
2171     * Returns  <code>true</code> or <code>false</code>
2172     * depending if the flag  spDoNotWriteFederationInfo is set in the
2173     * SP Extended metadata
2174     *
2175     * @param realm the realm name
2176     * @param spEntityID the entity id of the Service Provider
2177     * @param metaManager the SAML2MetaMAnager used to read the extendede metadata
2178     * @return the <code>true/false</code>
2179     * @exception SAML2Exception if the operation is not successful
2180     */
2181    private static Boolean isSPDoNotWriteFedInfo(
2182                                 String realm, String spEntityID, SAML2MetaManager metaManager)
2183        throws SAML2Exception {
2184        String methodName = "isSPDoNotWriteFedInfo";
2185
2186        Boolean isSPDoNotWriteFedInfoEnabled = false;
2187        SAML2SDKUtils.debug.message("SPACSUtils." + methodName + "Entering");
2188
2189        try {
2190            String SPDoNotWriteFedInfo = getAttributeValueFromSPSSOConfig(realm,
2191                    spEntityID, metaManager,
2192                    SAML2Constants.SP_DO_NOT_WRITE_FEDERATION_INFO);
2193
2194            if (SPDoNotWriteFedInfo != null && !SPDoNotWriteFedInfo.isEmpty()) {
2195                SAML2SDKUtils.debug.message("SPACSUtils." + methodName +
2196                        ": SPDoNotWriteFedInfo is: " +  SPDoNotWriteFedInfo);
2197                isSPDoNotWriteFedInfoEnabled = SPDoNotWriteFedInfo.equalsIgnoreCase("true");
2198            } else {
2199                SAML2SDKUtils.debug.message("SPACSUtils." + methodName +
2200                        ": SPDoNotWriteFedInfo is: not configured");
2201                isSPDoNotWriteFedInfoEnabled = false;
2202            }
2203        } catch (Exception ex) {
2204            SAML2Utils.debug.error(methodName +
2205                "Unable to get the SPDoNotWriteFedInfo flag.", ex);
2206            throw new SAML2Exception(ex);
2207        }
2208
2209        return isSPDoNotWriteFedInfoEnabled ;
2210    }
2211
2212
2213    private static Map createMapForFedlet(
2214        ResponseInfo respInfo, String relayUrl, String hostedEntityId) {
2215        Map map = new HashMap();
2216        if (relayUrl != null) {
2217            map.put(SAML2Constants.RELAY_STATE, relayUrl);
2218        }
2219        Response samlResp = respInfo.getResponse();
2220        map.put(SAML2Constants.RESPONSE, samlResp);
2221        Assertion assertion = respInfo.getAssertion();
2222        map.put(SAML2Constants.ASSERTION, assertion); 
2223        map.put(SAML2Constants.SUBJECT, assertion.getSubject());
2224        map.put(SAML2Constants.IDPENTITYID, assertion.getIssuer().getValue()); 
2225        map.put(SAML2Constants.SPENTITYID, hostedEntityId);
2226        map.put(SAML2Constants.NAMEID, respInfo.getNameId());
2227        map.put(SAML2Constants.ATTRIBUTE_MAP, respInfo.getAttributeMap());
2228        map.put(SAML2Constants.SESSION_INDEX, respInfo.getSessionIndex());
2229        return map;
2230    }
2231}