001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2008 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: AssertionIDRequestUtil.java,v 1.8 2009/06/12 22:21:40 mallas Exp $
026 *
027 * Portions Copyrighted 2013-2015 ForgeRock AS.
028 */
029package com.sun.identity.saml2.profile;
030
031import java.io.BufferedInputStream;
032import java.io.BufferedOutputStream;
033import java.io.IOException;
034import java.io.UnsupportedEncodingException;
035import java.net.HttpURLConnection;
036import java.net.MalformedURLException;
037import java.net.URL;
038import java.security.PrivateKey;
039import java.security.cert.X509Certificate;
040import java.util.ArrayList;
041import java.util.Date;
042import java.util.Hashtable;
043import java.util.Iterator;
044import java.util.List;
045import java.util.Set;
046import javax.servlet.http.HttpServletRequest;
047import javax.servlet.http.HttpServletResponse;
048import javax.xml.soap.SOAPException;
049import javax.xml.soap.SOAPMessage;
050
051import com.sun.identity.saml2.common.SAML2FailoverUtils;
052import com.sun.identity.saml2.common.SOAPCommunicator;
053import org.forgerock.openam.federation.saml2.SAML2TokenRepositoryException;
054import com.sun.identity.common.HttpURLConnectionManager;
055import org.w3c.dom.Element;
056
057import com.sun.identity.saml.xmlsig.KeyProvider;
058import com.sun.identity.saml.common.SAMLUtils;
059import com.sun.identity.saml2.assertion.Assertion;
060import com.sun.identity.saml2.assertion.AssertionFactory;
061import com.sun.identity.saml2.assertion.AssertionIDRef;
062import com.sun.identity.saml2.assertion.Issuer;
063import com.sun.identity.saml2.common.SAML2Constants;
064import com.sun.identity.saml2.common.SAML2Exception;
065import com.sun.identity.saml2.common.SAML2Utils;
066import com.sun.identity.saml2.jaxb.entityconfig.BaseConfigType;
067import com.sun.identity.saml2.jaxb.metadata.AttributeAuthorityDescriptorElement;
068import com.sun.identity.saml2.jaxb.metadata.AssertionIDRequestServiceElement;
069import com.sun.identity.saml2.jaxb.metadata.AuthnAuthorityDescriptorElement;
070import com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement;
071import com.sun.identity.saml2.jaxb.metadata.RoleDescriptorType;
072import com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement;
073import com.sun.identity.saml2.key.KeyUtil;
074import com.sun.identity.saml2.meta.SAML2MetaException;
075import com.sun.identity.saml2.meta.SAML2MetaManager;
076import com.sun.identity.saml2.plugins.AssertionIDRequestMapper;
077import com.sun.identity.saml2.protocol.AssertionIDRequest;
078import com.sun.identity.saml2.protocol.ProtocolFactory;
079import com.sun.identity.saml2.protocol.Response;
080import com.sun.identity.saml2.protocol.Status;
081import com.sun.identity.saml2.protocol.StatusCode;
082
083/**
084 * This class provides methods to send or process
085 * <code>AssertionIDRequest</code>.
086 *
087 * @supported.api
088 */
089public class AssertionIDRequestUtil {
090
091    static KeyProvider keyProvider = KeyUtil.getKeyProviderInstance(); 
092    static SAML2MetaManager metaManager = SAML2Utils.getSAML2MetaManager();
093    static Hashtable assertionIDRequestMapperCache = new Hashtable(); 
094    static final String MIME_TYPE_ASSERTION = "application/samlassertion+xml";
095
096    private AssertionIDRequestUtil() {
097    }
098
099    /**
100     * Sends the <code>AssertionIDRequest</code> to specifiied Assertion ID
101     * Request Service and returns <code>Response</code> coming from the
102     * Assertion ID Request Service.
103     *
104     * @param assertionIDRequest the <code>AssertionIDRequest</code> object
105     * @param samlAuthorityEntityID entity ID of SAML authority
106     * @param role SAML authority role, for example,
107     * <code>SAML2Constants.ATTR_AUTH_ROLE</code>, 
108     * <code>SAML2Constants.AUTHN_AUTH_ROLE</code> or
109     * <code>SAML2Constants.IDP_ROLE</code>
110     * @param realm the realm of hosted entity
111     * @param binding the binding
112     *
113     * @return the <code>Response</code> object
114     * @exception SAML2Exception if the operation is not successful
115     *
116     * @supported.api
117     */
118    public static Response sendAssertionIDRequest(
119        AssertionIDRequest assertionIDRequest, String samlAuthorityEntityID,
120        String role, String realm, String binding) throws SAML2Exception {
121
122        StringBuffer location = new StringBuffer();
123        RoleDescriptorType roled = getRoleDescriptorAndLocation(
124            samlAuthorityEntityID, role, realm, binding, location);
125
126        if (binding.equalsIgnoreCase(SAML2Constants.SOAP)) {
127            signAssertionIDRequest(assertionIDRequest, realm, false);
128            return sendAssertionIDRequestBySOAP(assertionIDRequest,
129                location.toString(), realm, samlAuthorityEntityID, role, roled);
130        } else {
131            throw new SAML2Exception(
132                SAML2Utils.bundle.getString("unsupportedBinding"));
133        }
134    }
135
136    /**
137     * Sends the Assertion ID to specifiied Assertion ID Request Service and
138     * returns <code>Assertion</code> coming from the Assertion ID Request
139     * Service.
140     *
141     * @param assertionID the asssertionID</code> object
142     * @param samlAuthorityEntityID entity ID of SAML authority
143     * @param role SAML authority role, for example,
144     * <code>SAML2Constants.ATTR_AUTH_ROLE</code>, 
145     * <code>SAML2Constants.AUTHN_AUTH_ROLE</code> or
146     * <code>SAML2Constants.IDP_ROLE</code>
147     * @param realm the realm of hosted entity
148     *
149     * @return the <code>Assertion</code> object
150     * @exception SAML2Exception if the operation is not successful
151     *
152     * @supported.api
153     */
154    public static Assertion sendAssertionIDRequestURI(
155        String assertionID, String samlAuthorityEntityID,
156        String role, String realm) throws SAML2Exception {
157
158        StringBuffer locationSB = new StringBuffer();
159        getRoleDescriptorAndLocation(samlAuthorityEntityID, role, realm,
160            SAML2Constants.URI, locationSB);
161        if (locationSB.indexOf("?") == -1) {
162            locationSB.append("?");
163        } else {
164            locationSB.append("&");
165        }
166        locationSB.append("ID=").append(assertionID);
167        String location = fillInBasicAuthInfo(locationSB.toString(), realm,
168            samlAuthorityEntityID, role); 
169
170        URL url = null;
171        try {
172            url = new URL(location);
173        } catch (MalformedURLException me) {
174            throw new SAML2Exception(me.getMessage());
175        }
176
177        try {
178            HttpURLConnection conn = HttpURLConnectionManager.getConnection(url);
179            conn.setInstanceFollowRedirects(false);
180            conn.setUseCaches(false);
181            conn.setDoOutput(false);
182            conn.connect();
183
184            int respCode = conn.getResponseCode();
185            if (SAML2Utils.debug.messageEnabled()) {
186                SAML2Utils.debug.message(
187                    "AssertionIDRequestUtil.sendAssertionIDRequestURI: " +
188                    "Response code = " + respCode + ", Response message = " +
189                    conn.getResponseMessage());
190            }
191            if (respCode != HttpURLConnection.HTTP_OK) {
192                return null;
193            }
194
195            String contentType = conn.getContentType();
196            if (SAML2Utils.debug.messageEnabled()) {
197                SAML2Utils.debug.message(
198                    "AssertionIDRequestUtil.sendAssertionIDRequestURI: " +
199                    "Content type = " + contentType);
200            }
201            if ((contentType == null) ||
202                (contentType.indexOf(MIME_TYPE_ASSERTION) == -1)) {
203
204                return null;
205            }
206
207            int contentLength = conn.getContentLength();
208            if (SAML2Utils.debug.messageEnabled()) {
209                SAML2Utils.debug.message(
210                    "AssertionIDRequestUtil.sendAssertionIDRequestURI: " +
211                    "Content length = " + contentLength);
212            }
213
214            BufferedInputStream bin =
215                new BufferedInputStream(conn.getInputStream());
216            StringBuffer contentSB = new StringBuffer();
217            byte content[] = new byte[2048];
218
219            if (contentLength != -1) {
220                int read = 0, totalRead = 0;
221                int left;
222                while (totalRead < contentLength) {
223                    left = contentLength - totalRead;
224                    read = bin.read(content, 0,
225                        left < content.length ? left : content.length);
226                    if (read == -1) {
227                        // We need to close connection !!
228                        break;
229                    } else {
230                        if (read > 0) {
231                            totalRead += read;
232                            contentSB.append(new String(content, 0, read));
233                        }
234                    }
235                }
236            } else {
237                int numbytes;
238                int totalRead = 0;
239
240                while (true) {
241                    numbytes = bin.read(content);
242                    if (numbytes == -1) {
243                        break;
244                    }
245
246                    totalRead += numbytes;
247                    contentSB.append(new String(content, 0, numbytes));
248                }
249            }
250
251            return AssertionFactory.getInstance().createAssertion(
252                contentSB.toString());
253        } catch (IOException ioex) {
254            SAML2Utils.debug.error(
255                "AssertionIDRequest.sendAssertionIDRequestURI:", ioex);
256            throw new SAML2Exception(ioex.getMessage());
257        }
258    }
259
260    /**
261     * Gets assertion ID from URI and returns assertion if found.
262     *
263     * @param request the <code>HttpServletRequest</code> object
264     * @param response the <code>HttpServletResponse</code> object
265     * @param samlAuthorityEntityID entity ID of SAML authority
266     * @param role SAML authority role
267     * @param realm the realm of hosted entity
268     *
269     * @exception IOException if response can't be sent
270     */
271    public static void processAssertionIDRequestURI(HttpServletRequest request,
272        HttpServletResponse response, String samlAuthorityEntityID,
273        String role, String realm) throws IOException {
274
275        String assertionID = request.getParameter("ID");
276        if (assertionID == null) {
277            SAMLUtils.sendError(request, response, 
278                HttpServletResponse.SC_BAD_REQUEST, "nullAssertionID",
279                SAML2Utils.bundle.getString("nullAssertionID"));
280            return;
281        }
282
283        AssertionIDRequestMapper aidReqMapper = null;
284        try {
285            aidReqMapper = getAssertionIDRequestMapper(realm,
286                samlAuthorityEntityID, role);
287        } catch (SAML2Exception ex) {
288            SAMLUtils.sendError(request, response, 
289                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
290                "failedToGetAssertionIDRequestMapper", ex.getMessage());
291            return;
292        }
293
294        try {
295            aidReqMapper.authenticateRequesterURI(request, response,
296                samlAuthorityEntityID, role, realm);
297        } catch (SAML2Exception ex) {
298            SAMLUtils.sendError(request, response, 
299                HttpServletResponse.SC_FORBIDDEN,
300                "failedToAuthenticateRequesterURI", ex.getMessage());
301            return;
302        }
303
304        Assertion assertion = (Assertion)IDPCache.assertionByIDCache.get(
305            assertionID);
306
307        if ((assertion == null) || (!assertion.isTimeValid())) {
308            SAMLUtils.sendError(request, response, 
309                HttpServletResponse.SC_NOT_FOUND,
310                "invalidAssertionID",
311                SAML2Utils.bundle.getString("invalidAssertionID"));
312            return;
313        }
314
315        response.setContentType(MIME_TYPE_ASSERTION);
316        response.addHeader("Cache-Control", "no-cache, no-store");
317        response.addHeader("Pragma", "no-cache");
318
319        String content = null;
320        try {
321            content = assertion.toXMLString(true, true);
322        } catch (SAML2Exception ex) {
323            if (SAML2Utils.debug.messageEnabled()) {
324                SAML2Utils.debug.message("AssertionIDRequestUtil." +
325                "processAssertionIDRequestURI:", ex);
326            }
327            SAMLUtils.sendError(request, response, 
328                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
329                "invalidAssertion", ex.getMessage());
330            return;
331        }
332
333        byte[] bytes = null;
334        try {
335            bytes = content.getBytes("UTF-8");
336        } catch(UnsupportedEncodingException ueex) {
337            if (SAML2Utils.debug.messageEnabled()) {
338                SAML2Utils.debug.message("AssertionIDRequestUtil." +
339                "processAssertionIDRequestURI:", ueex);
340            }
341            SAMLUtils.sendError(request, response, 
342                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
343                "unsupportedEncoding", ueex.getMessage());
344            return;
345        }
346        response.setContentLength(bytes.length);
347
348        BufferedOutputStream bos = null;
349        try {
350            bos = new BufferedOutputStream(response.getOutputStream());
351            bos.write(bytes, 0, bytes.length);
352        } catch (IOException ioex) {
353            SAML2Utils.debug.error("AssertionIDRequestUtil." +
354                "processAssertionIDRequestURI:", ioex);
355        } finally {
356            if (bos != null) {
357                try {
358                    bos.close();
359                } catch (IOException ioex) {
360                    SAML2Utils.debug.error("AssertionIDRequestUtil." +
361                        "processAssertionIDRequestURI:", ioex);
362                }
363            }
364        }
365    }
366
367    /**
368     * This method processes the <code>AssertionIDRequest</code> coming
369     * from a requester.
370     *
371     * @param assertionIDRequest the <code>AssertionIDRequest</code> object
372     * @param request the <code>HttpServletRequest</code> object
373     * @param response the <code>HttpServletResponse</code> object
374     * @param samlAuthorityEntityID entity ID of SAML authority
375     * @param role the role of SAML authority
376     * @param realm the realm of SAML authority
377     * @return the <code>Response</code> object
378     * @exception SAML2Exception if the operation is not successful
379     */
380    public static Response processAssertionIDRequest(
381        AssertionIDRequest assertionIDRequest, HttpServletRequest request, 
382        HttpServletResponse response, String samlAuthorityEntityID,
383        String role, String realm) throws SAML2Exception {
384
385        try {
386            verifyAssertionIDRequest(assertionIDRequest, samlAuthorityEntityID,
387                role, realm);
388        } catch(SAML2Exception se) {
389            SAML2Utils.debug.error("AssertionIDRequestUtil." +
390                "processAssertionIDRequest:", se);
391            return SAML2Utils.getErrorResponse(assertionIDRequest,
392                SAML2Constants.REQUESTER, null, se.getMessage(),
393                samlAuthorityEntityID);
394        }
395
396        Issuer issuer = assertionIDRequest.getIssuer();
397        String spEntityID = issuer.getValue();        
398
399        RoleDescriptorType roled = null;
400        try {
401            if (SAML2Constants.IDP_ROLE.equals(role)) {
402                roled = metaManager.getIDPSSODescriptor(realm,
403                    samlAuthorityEntityID);
404            } else if (SAML2Constants.AUTHN_AUTH_ROLE.equals(role)) {
405                roled = metaManager.getAuthnAuthorityDescriptor(realm,
406                    samlAuthorityEntityID);
407            } else if (SAML2Constants.ATTR_AUTH_ROLE.equals(role)) {
408                roled = metaManager.getAttributeAuthorityDescriptor(realm,
409                    samlAuthorityEntityID);
410            }
411        } catch (SAML2MetaException sme) {
412            SAML2Utils.debug.error("AssertionIDRequestUtil." +
413                "processAssertionIDRequest:", sme);
414            return SAML2Utils.getErrorResponse(assertionIDRequest,
415                SAML2Constants.RESPONDER, null, sme.getMessage(),
416                samlAuthorityEntityID);
417        }
418
419        if (roled == null) {
420            return SAML2Utils.getErrorResponse(assertionIDRequest,
421                SAML2Constants.REQUESTER, null, SAML2Utils.bundle.getString(
422                "samlAuthorityNotFound"), samlAuthorityEntityID);
423        }
424
425        List returnAssertions = null;
426        List assertionIDRefs = assertionIDRequest.getAssertionIDRefs();
427        for(Iterator iter = assertionIDRefs.iterator(); iter.hasNext();) {
428            AssertionIDRef assertionIDRef = (AssertionIDRef)iter.next();
429            String assertionID = assertionIDRef.getValue();
430
431            Assertion assertion = (Assertion)IDPCache.assertionByIDCache.get(
432                assertionID);
433            if ((assertion == null) && (SAML2FailoverUtils.isSAML2FailoverEnabled())) {
434                if (SAML2Utils.debug.messageEnabled()) {
435                    SAML2Utils.debug.message("AssertionIDRequestUtil.processAssertionIDRequest: " +
436                        "reading assertion from the SAML2 Token Repository using assertionID:" + assertionID);
437                }
438                String assertionStr = null;
439                try {
440                    assertionStr = (String) SAML2FailoverUtils.retrieveSAML2Token(assertionID);
441                } catch (SAML2TokenRepositoryException se) {
442                    SAML2Utils.debug.error("AssertionIDRequestUtil.processAssertionIDRequest: " +
443                         "There was a problem reading assertion from the SAML2 Token Repository using assertionID:"
444                            + assertionID, se);
445                }
446                if (assertionStr != null) {
447                    assertion = AssertionFactory.getInstance().createAssertion(
448                        assertionStr);
449                }
450            }
451
452            if ((assertion != null) && (assertion.isTimeValid())) {
453                if (returnAssertions == null) {
454                    returnAssertions = new ArrayList();
455                }
456                returnAssertions.add(assertion);
457            }
458        }        
459
460        ProtocolFactory protocolFactory = ProtocolFactory.getInstance();
461        Response samlResp = protocolFactory.createResponse();
462        samlResp.setAssertion(returnAssertions);
463
464        samlResp.setID(SAML2Utils.generateID());
465        samlResp.setInResponseTo(assertionIDRequest.getID());
466
467        samlResp.setVersion(SAML2Constants.VERSION_2_0);
468        samlResp.setIssueInstant(new Date());
469    
470        Status status = protocolFactory.createStatus();
471        StatusCode statusCode = protocolFactory.createStatusCode();
472        statusCode.setValue(SAML2Constants.SUCCESS);
473        status.setStatusCode(statusCode);
474        samlResp.setStatus(status);
475
476        Issuer respIssuer = AssertionFactory.getInstance().createIssuer();
477        respIssuer.setValue(samlAuthorityEntityID);
478        samlResp.setIssuer(respIssuer);
479
480        signResponse(samlResp, samlAuthorityEntityID, role, realm, false);
481
482        return samlResp;
483    }
484
485    private static RoleDescriptorType getRoleDescriptorAndLocation(
486        String samlAuthorityEntityID, String role, String realm,
487        String binding, StringBuffer location) throws SAML2Exception {
488
489        List aIDReqServices = null;
490        RoleDescriptorType roled = null;
491        try {
492            if (role == null) {
493                throw new SAML2Exception(SAML2Utils.bundle.getString(
494                    "unsupportedRole"));
495            } else if (role.equals(SAML2Constants.IDP_ROLE)) {
496                IDPSSODescriptorElement idpd =
497                    metaManager.getIDPSSODescriptor(realm,
498                    samlAuthorityEntityID);
499                if (idpd == null) {
500                    throw new SAML2Exception(SAML2Utils.bundle.getString(
501                        "idpNotFound"));
502                }
503                aIDReqServices = idpd.getAssertionIDRequestService();
504                roled = idpd;
505            } else if (role.equals(SAML2Constants.AUTHN_AUTH_ROLE)) {
506                AuthnAuthorityDescriptorElement attrd =
507                    metaManager.getAuthnAuthorityDescriptor(realm,
508                    samlAuthorityEntityID);
509                if (attrd == null) {
510                    throw new SAML2Exception(SAML2Utils.bundle.getString(
511                        "authnAuthorityNotFound"));
512                }
513                aIDReqServices = attrd.getAssertionIDRequestService();
514                roled = attrd;
515            } else if (role.equals(SAML2Constants.ATTR_AUTH_ROLE)) {
516                AttributeAuthorityDescriptorElement aad =
517                    metaManager.getAttributeAuthorityDescriptor(realm,
518                    samlAuthorityEntityID);
519                if (aad == null) {
520                    throw new SAML2Exception(SAML2Utils.bundle.getString(
521                        "attrAuthorityNotFound"));
522                }
523                aIDReqServices = aad.getAssertionIDRequestService();
524                roled = aad;
525            } else {
526                throw new SAML2Exception(SAML2Utils.bundle.getString(
527                    "unsupportedRole"));
528            }
529        } catch (SAML2MetaException sme) {
530            SAML2Utils.debug.error(
531                "AssertionIDRequest.getRoleDescriptorAndLocation:", sme);
532            throw new SAML2Exception(SAML2Utils.bundle.getString(
533                "metaDataError"));
534        }
535
536        if (binding == null) {
537            throw new SAML2Exception(
538                SAML2Utils.bundle.getString("unsupportedBinding"));
539        }
540
541        if ((aIDReqServices == null) || (aIDReqServices.isEmpty())) {
542            throw new SAML2Exception(
543                SAML2Utils.bundle.getString("aIDReqServiceNotFound"));
544        }
545
546        for(Iterator iter = aIDReqServices.iterator(); iter.hasNext(); ) {
547            AssertionIDRequestServiceElement aIDReqService =
548                (AssertionIDRequestServiceElement)iter.next();
549            if (binding.equalsIgnoreCase(aIDReqService.getBinding())) {
550                location.append(aIDReqService.getLocation());
551                break;
552            }
553        }
554        if (location.length() == 0) {
555            throw new SAML2Exception(
556                SAML2Utils.bundle.getString("unsupportedBinding"));
557        }
558
559        return roled;
560    }
561
562    private static void signAssertionIDRequest(
563        AssertionIDRequest assertionIDRequest,
564        String realm, boolean includeCert) throws SAML2Exception {
565
566        String spEntityID = assertionIDRequest.getIssuer().getValue();
567        
568        String alias = SAML2Utils.getSigningCertAlias(realm, spEntityID,
569            SAML2Constants.SP_ROLE);
570
571        PrivateKey signingKey = keyProvider.getPrivateKey(alias);
572        X509Certificate signingCert = null;
573        if (includeCert) {
574            signingCert = keyProvider.getX509Certificate(alias);
575        }
576        
577        if (signingKey != null) {
578            assertionIDRequest.sign(signingKey, signingCert);
579        }
580    }
581
582    private static void verifyAssertionIDRequest(
583        AssertionIDRequest assertionIDRequest, String samlAuthorityEntityID,
584        String role, String realm) throws SAML2Exception {
585
586        Issuer issuer = assertionIDRequest.getIssuer();
587        String requestedEntityID = issuer.getValue();
588
589        if (!SAML2Utils.isSourceSiteValid(issuer, realm,
590            samlAuthorityEntityID)) {
591
592            throw new SAML2Exception(SAML2Utils.bundle.getString(
593                "assertionIDRequestIssuerInvalid"));
594        }
595
596        SPSSODescriptorElement spSSODesc = metaManager.getSPSSODescriptor(
597            realm, requestedEntityID);
598        if (spSSODesc == null) {
599            throw new SAML2Exception(SAML2Utils.bundle.getString(
600                "assertionIDRequestIssuerNotFound"));
601        }
602
603        Set<X509Certificate> verificationCerts = KeyUtil.getVerificationCerts(spSSODesc, requestedEntityID,
604                SAML2Constants.SP_ROLE);
605
606        if (!verificationCerts.isEmpty()) {
607            boolean valid = assertionIDRequest.isSignatureValid(verificationCerts);
608            if (SAML2Utils.debug.messageEnabled()) {
609                SAML2Utils.debug.message(
610                    "AssertionIDRequestUtil.verifyAssertionIDRequest: " +
611                    "Signature validity is : " + valid);
612            }
613            if (!valid) {
614                throw new SAML2Exception(SAML2Utils.bundle.getString(
615                    "invalidSignatureAssertionIDRequest"));
616            }
617        } else {
618            throw new SAML2Exception(
619                    SAML2Utils.bundle.getString("missingSigningCertAlias"));
620        }
621    }
622
623    private static void signResponse(Response response,
624        String samlAuthorityEntityID, String role, String realm,
625        boolean includeCert) throws SAML2Exception {
626        
627        String alias = SAML2Utils.getSigningCertAlias(realm, samlAuthorityEntityID, role);
628
629        String encryptedKeyPass = SAML2Utils.getSigningCertEncryptedKeyPass(realm, samlAuthorityEntityID, role);
630        PrivateKey signingKey;
631        if (encryptedKeyPass == null  || encryptedKeyPass.isEmpty()) {
632            signingKey = keyProvider.getPrivateKey(alias);
633        } else {
634            signingKey = keyProvider.getPrivateKey(alias, encryptedKeyPass);
635        }
636        X509Certificate signingCert = null;
637        if (includeCert) {
638            signingCert = keyProvider.getX509Certificate(alias);
639        }
640        
641        if (signingKey != null) {
642            response.sign(signingKey, signingCert);
643        }
644    }
645
646    private static String fillInBasicAuthInfo(String location, String realm,
647        String samlAuthorityEntityID, String role) {
648
649        BaseConfigType config = null;
650        try {
651            if (role.equals(SAML2Constants.IDP_ROLE)) {
652                config = metaManager.getIDPSSOConfig(realm,
653                    samlAuthorityEntityID);
654            } else if (role.equals(SAML2Constants.AUTHN_AUTH_ROLE)) {
655                config = metaManager.getAuthnAuthorityConfig(realm,
656                    samlAuthorityEntityID);
657            } else if (role.equals(SAML2Constants.ATTR_AUTH_ROLE)) {
658                config = metaManager.getAttributeAuthorityConfig(realm,
659                    samlAuthorityEntityID);
660            }
661        } catch (SAML2MetaException sme) {
662            if (SAML2Utils.debug.messageEnabled()) {
663                SAML2Utils.debug.message(
664                    "AssertionIDRequestUtil.getSSOConfig:", sme);
665            }
666        }
667
668        return SAML2Utils.fillInBasicAuthInfo(config, location); 
669    }
670
671    private static Response sendAssertionIDRequestBySOAP(
672        AssertionIDRequest assertionIDRequest, String location, String realm,
673        String samlAuthorityEntityID, String role, RoleDescriptorType roled)
674        throws SAML2Exception {
675
676        String aIDReqStr = assertionIDRequest.toXMLString(true, true);
677        if (SAML2Utils.debug.messageEnabled()) {
678            SAML2Utils.debug.message(
679                "AssertionIDRequestUtil.sendAssertionIDRequestBySOAP: " +
680                "assertionIDRequest = " + aIDReqStr);
681            SAML2Utils.debug.message(
682                "AssertionIDRequestUtil.sendAssertionIDRequestBySOAP: " +
683                "location = " + location);
684        }
685
686        location = fillInBasicAuthInfo(location, realm, samlAuthorityEntityID,
687            role); 
688
689        SOAPMessage resMsg = null;
690        try {
691            resMsg = SOAPCommunicator.getInstance().sendSOAPMessage(aIDReqStr, location, true);
692        } catch (SOAPException se) {
693            SAML2Utils.debug.error(
694                "AssertionIDRequestUtil.sendAssertionIDRequestBySOAP:", se);
695            throw new SAML2Exception(
696                SAML2Utils.bundle.getString("errorSendingAssertionIDRequest"));
697        }
698        
699        Element respElem = SOAPCommunicator.getInstance().getSamlpElement(resMsg, "Response");
700        Response response =
701            ProtocolFactory.getInstance().createResponse(respElem);
702        
703        if (SAML2Utils.debug.messageEnabled()) {
704            SAML2Utils.debug.message(
705                "AssertionIDRequestUtil.sendAssertionIDRequestBySOAP: " +
706                "response = " + response.toXMLString(true, true));
707        }
708
709        verifyResponse(response, assertionIDRequest, samlAuthorityEntityID,
710            role, roled);
711
712        return response;
713    }
714
715    private static void verifyResponse(Response response,
716        AssertionIDRequest assertionIDRequest, String samlAuthorityEntityID,
717        String role, RoleDescriptorType roled) throws SAML2Exception {
718
719        String aIDReqID = assertionIDRequest.getID();
720        if ((aIDReqID != null) &&
721            (!aIDReqID.equals(response.getInResponseTo()))) {
722
723            throw new SAML2Exception(SAML2Utils.bundle.getString(
724                "invalidInResponseToAssertionIDRequest"));
725        }
726
727        Issuer respIssuer = response.getIssuer();
728        if (respIssuer == null) {
729            return;
730        }
731
732        if (!samlAuthorityEntityID.equals(respIssuer.getValue())) {
733            throw new SAML2Exception(SAML2Utils.bundle.getString(
734                "responseIssuerMismatch"));
735        }
736
737
738        Set<X509Certificate> signingCerts = KeyUtil.getVerificationCerts(roled, samlAuthorityEntityID, role);
739
740        if (!signingCerts.isEmpty()) {
741            boolean valid = response.isSignatureValid(signingCerts);
742            if (SAML2Utils.debug.messageEnabled()) {
743                SAML2Utils.debug.message(
744                    "AssertionIDRequestUtil .verifyResponse: " +
745                    "Signature validity is : " + valid);
746            }
747            if (!valid) {
748                throw new SAML2Exception(SAML2Utils.bundle.getString(
749                    "invalidSignatureOnResponse"));
750            }
751        } else {
752            throw new SAML2Exception(SAML2Utils.bundle.getString("missingSigningCertAlias"));
753        }
754
755    }
756
757    private static AssertionIDRequestMapper getAssertionIDRequestMapper(
758        String realm, String samlAuthorityEntityID, String role)
759        throws SAML2Exception {
760
761        String aidReqMapperName = null;
762        AssertionIDRequestMapper aidReqMapper = null;
763        try {
764            aidReqMapperName = SAML2Utils.getAttributeValueFromSSOConfig(realm,
765                samlAuthorityEntityID, role,
766                SAML2Constants.ASSERTION_ID_REQUEST_MAPPER);
767
768            if (aidReqMapperName == null) {
769                aidReqMapperName = 
770                    SAML2Constants.DEFAULT_ASSERTION_ID_REQUEST_MAPPER_CLASS;
771                if (SAML2Utils.debug.messageEnabled()) {
772                    SAML2Utils.debug.message(
773                        "AssertionIDRequestUtil.getAssertionIDRequestMapper:" +
774                        " use "+ aidReqMapperName);
775                }
776            }
777            aidReqMapper = (AssertionIDRequestMapper)
778                assertionIDRequestMapperCache.get(aidReqMapperName);
779            if (aidReqMapper == null) {
780                aidReqMapper = (AssertionIDRequestMapper)
781                    Class.forName(aidReqMapperName).newInstance();
782                assertionIDRequestMapperCache.put(aidReqMapperName,
783                    aidReqMapper);
784            } else {
785                if (SAML2Utils.debug.messageEnabled()) {
786                    SAML2Utils.debug.message(
787                        "AssertionIDRequestUtil.getAssertionIDRequestMapper:" +
788                        " got the AssertionIDRequestMapper from cache");
789                }
790            }
791        } catch (Exception ex) {
792            SAML2Utils.debug.error(
793                "AssertionIDRequestUtil.getAssertionIDRequestMapper:", ex);
794            throw new SAML2Exception(ex);
795        }
796
797        return aidReqMapper;
798    }
799
800}