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




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.