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




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.