Search in sources :

Example 21 with AuthnRequest

use of com.sun.identity.saml2.protocol.AuthnRequest in project OpenAM by OpenRock.

the class IDPSSOUtil method sendResponseToACS.

/**
     * Sends <code>Response</code> containing an <code>Assertion</code>
     * back to the requesting service provider
     *
     * @param request              the <code>HttpServletRequest</code> object
     * @param response             the <code>HttpServletResponse</code> object
     * @param out                  the print writer for writing out presentation
     * @param session              user session
     * @param authnReq             the <code>AuthnRequest</code> object
     * @param spEntityID           the entity id of the service provider
     * @param idpEntityID          the entity id of the identity provider
     * @param idpMetaAlias         the meta alias of the identity provider
     * @param realm                the realm
     * @param nameIDFormat         the <code>NameIDFormat</code>
     * @param relayState           the relay state
     * @param matchingAuthnContext the <code>AuthnContext</code> used to find
     *                             authentication type and scheme.
     */
public static void sendResponseToACS(HttpServletRequest request, HttpServletResponse response, PrintWriter out, Object session, AuthnRequest authnReq, String spEntityID, String idpEntityID, String idpMetaAlias, String realm, String nameIDFormat, String relayState, AuthnContext matchingAuthnContext) throws SAML2Exception {
    StringBuffer returnedBinding = new StringBuffer();
    String acsURL = IDPSSOUtil.getACSurl(spEntityID, realm, authnReq, request, returnedBinding);
    String acsBinding = returnedBinding.toString();
    if ((acsURL == null) || (acsURL.trim().length() == 0)) {
        SAML2Utils.debug.error("IDPSSOUtil.sendResponseToACS:" + " no ACS URL found.");
        String[] data = { idpMetaAlias };
        LogUtil.error(Level.INFO, LogUtil.NO_ACS_URL, data, session);
        throw new SAML2Exception(SAML2Utils.bundle.getString("UnableTofindACSURL"));
    }
    if ((acsBinding == null) || (acsBinding.trim().length() == 0)) {
        SAML2Utils.debug.error("IDPSSOUtil.sendResponseToACS:" + " no return binding found.");
        String[] data = { idpMetaAlias };
        LogUtil.error(Level.INFO, LogUtil.NO_RETURN_BINDING, data, session);
        throw new SAML2Exception(SAML2Utils.bundle.getString("UnableTofindBinding"));
    }
    String affiliationID = request.getParameter(SAML2Constants.AFFILIATION_ID);
    //check first if there is already an existing sessionindex associated with this SSOToken, if there is, then
    //we need to redirect the request internally to the holder of the idpsession.
    //The remoteServiceURL will be null if there is no sessionindex for this SSOToken, or there is, but it's
    //local. If the remoteServiceURL is not null, we can start to send the request to the original server.
    String remoteServiceURL = SAML2Utils.getRemoteServiceURL(getSessionIndex(session));
    if (remoteServiceURL != null) {
        remoteServiceURL += SAML2Utils.removeDeployUri(request.getRequestURI()) + "?" + request.getQueryString();
        if (SAML2Utils.debug.messageEnabled()) {
            SAML2Utils.debug.message("SessionIndex for this SSOToken is not local, forwarding the request to: " + remoteServiceURL);
        }
        String redirectUrl = null;
        String outputData = null;
        String responseCode = null;
        HashMap<String, String> remoteRequestData = SAML2Utils.sendRequestToOrigServer(request, response, remoteServiceURL);
        if (remoteRequestData != null && !remoteRequestData.isEmpty()) {
            redirectUrl = remoteRequestData.get(SAML2Constants.AM_REDIRECT_URL);
            outputData = remoteRequestData.get(SAML2Constants.OUTPUT_DATA);
            responseCode = remoteRequestData.get(SAML2Constants.RESPONSE_CODE);
        }
        try {
            if (redirectUrl != null && !redirectUrl.isEmpty()) {
                response.sendRedirect(redirectUrl);
            } else {
                if (responseCode != null) {
                    response.setStatus(Integer.valueOf(responseCode));
                }
                // no redirect, perhaps an error page, return the content
                if (outputData != null && !outputData.isEmpty()) {
                    SAML2Utils.debug.message("Printing the forwarded response");
                    response.setContentType("text/html; charset=UTF-8");
                    out.println(outputData);
                    return;
                }
            }
        } catch (IOException ioe) {
            if (SAML2Utils.debug.messageEnabled()) {
                SAML2Utils.debug.message("IDPSSOUtil.sendResponseToACS() error in Request Routing", ioe);
            }
        }
        return;
    }
    //end of request proxy
    // generate a response for the authn request
    Response res = getResponse(request, session, authnReq, spEntityID, idpEntityID, idpMetaAlias, realm, nameIDFormat, acsURL, affiliationID, matchingAuthnContext);
    if (res == null) {
        SAML2Utils.debug.error("IDPSSOUtil.sendResponseToACS:" + " response is null");
        String errorMsg = SAML2Utils.bundle.getString("UnableToCreateAssertion");
        if (authnReq == null) {
            //idp initiated case, will not send error response to sp
            throw new SAML2Exception(errorMsg);
        }
        res = SAML2Utils.getErrorResponse(authnReq, SAML2Constants.RESPONDER, null, errorMsg, idpEntityID);
    } else {
        try {
            String[] values = { idpMetaAlias };
            sessionProvider.setProperty(session, SAML2Constants.IDP_META_ALIAS, values);
        } catch (SessionException e) {
            SAML2Utils.debug.error("IDPSSOUtil.sendResponseToACS:" + " error setting idpMetaAlias into the session: ", e);
        }
    }
    if (res != null) {
        // call multi-federation protocol to set the protocol
        MultiProtocolUtils.addFederationProtocol(session, SingleLogoutManager.SAML2);
        // check if the COT cookie needs to be set
        if (setCOTCookie(request, response, acsBinding, spEntityID, idpEntityID, idpMetaAlias, realm, relayState, acsURL, res, session)) {
            if (SAML2Utils.debug.messageEnabled()) {
                SAML2Utils.debug.message("IDPSSOUtil.sendResponseToACS:" + " Redirected to set COT cookie.");
            }
            return;
        }
        if (SAML2Utils.debug.messageEnabled()) {
            SAML2Utils.debug.message("IDPSSOUtil.sendResponseToACS:" + " Doesn't set COT cookie.");
            SAML2Utils.debug.message("IDPSSOUtil.sendResponseToACS:" + " Response is:  " + res.toXMLString());
        }
        try {
            SAML2Utils.debug.message("IDPSSOUtil.sendResponseToACS: Invoking the IDP Adapter");
            SAML2IdentityProviderAdapter idpAdapter = IDPSSOUtil.getIDPAdapterClass(realm, idpEntityID);
            if (idpAdapter != null) {
                idpAdapter.preSignResponse(authnReq, res, idpEntityID, realm, request, session, relayState);
            }
        } catch (SAML2Exception se) {
            SAML2Utils.debug.error("IDPSSOUtil.sendResponseToACS: There was a problem when invoking the " + "preSendResponse of the IDP Adapter: ", se);
        }
        sendResponse(request, response, out, acsBinding, spEntityID, idpEntityID, idpMetaAlias, realm, relayState, acsURL, res, session);
    } else {
        SAML2Utils.debug.error("IDPSSOUtil.sendResponseToACS:" + " error response is null");
        throw new SAML2Exception(SAML2Utils.bundle.getString("UnableToCreateErrorResponse"));
    }
}
Also used : SAML2Exception(com.sun.identity.saml2.common.SAML2Exception) ECPResponse(com.sun.identity.saml2.ecp.ECPResponse) Response(com.sun.identity.saml2.protocol.Response) HttpServletResponse(javax.servlet.http.HttpServletResponse) SessionException(com.sun.identity.plugin.session.SessionException) IOException(java.io.IOException) SAML2IdentityProviderAdapter(com.sun.identity.saml2.plugins.SAML2IdentityProviderAdapter)

Example 22 with AuthnRequest

use of com.sun.identity.saml2.protocol.AuthnRequest in project OpenAM by OpenRock.

the class IDPProxyUtil method sendProxyAuthnRequest.

/**
     * Sends a new AuthnRequest to the authenticating provider. 
     * @param authnRequest original AuthnRequest sent by the service provider.
     * @param preferredIDP IDP to be proxied. 
     * @param spSSODescriptor SPSSO Descriptor Element
     * @param hostedEntityId hosted provider ID 
     * @param request HttpServletRequest 
     * @param response HttpServletResponse
     * @param realm Realm
     * @param relayState the Relay State 
     * @param originalBinding The binding used to send the original AuthnRequest.
     * @exception SAML2Exception for any SAML2 failure.
     * @exception IOException if there is a failure in redirection.
     */
public static void sendProxyAuthnRequest(AuthnRequest authnRequest, String preferredIDP, SPSSODescriptorElement spSSODescriptor, String hostedEntityId, HttpServletRequest request, HttpServletResponse response, String realm, String relayState, String originalBinding) throws SAML2Exception, IOException {
    String classMethod = "IDPProxyUtil.sendProxyAuthnRequest: ";
    String destination = null;
    SPSSODescriptorElement localDescriptor = null;
    SPSSOConfigElement localDescriptorConfig = null;
    IDPSSODescriptorElement idpDescriptor = null;
    String binding;
    try {
        idpDescriptor = IDPSSOUtil.metaManager.getIDPSSODescriptor(realm, preferredIDP);
        List<SingleSignOnServiceElement> ssoServiceList = idpDescriptor.getSingleSignOnService();
        SingleSignOnServiceElement endpoint = getMatchingSSOEndpoint(ssoServiceList, originalBinding);
        if (endpoint == null) {
            SAML2Utils.debug.error(classMethod + "Single Sign-on service is not found for the proxying IDP.");
            throw new SAML2Exception(SAML2Utils.bundle.getString("ssoServiceNotFoundIDPProxy"));
        }
        binding = endpoint.getBinding();
        destination = endpoint.getLocation();
        localDescriptor = IDPSSOUtil.metaManager.getSPSSODescriptor(realm, hostedEntityId);
        localDescriptorConfig = IDPSSOUtil.metaManager.getSPSSOConfig(realm, hostedEntityId);
    } catch (SAML2MetaException e) {
        SAML2Utils.debug.error(classMethod, e);
        throw new SAML2Exception(e.getMessage());
    }
    AuthnRequest newAuthnRequest = getNewAuthnRequest(hostedEntityId, destination, realm, authnRequest);
    // invoke SP Adapter class if registered
    SAML2ServiceProviderAdapter spAdapter = SAML2Utils.getSPAdapterClass(hostedEntityId, realm);
    if (spAdapter != null) {
        spAdapter.preSingleSignOnRequest(hostedEntityId, preferredIDP, realm, request, response, newAuthnRequest);
    }
    if (SAML2Utils.debug.messageEnabled()) {
        SAML2Utils.debug.message(classMethod + "New Authentication request:" + newAuthnRequest.toXMLString());
    }
    String requestID = newAuthnRequest.getID();
    // save the AuthnRequest in the IDPCache so that it can be
    // retrieved later when the user successfully authenticates
    IDPCache.authnRequestCache.put(requestID, newAuthnRequest);
    // save the original AuthnRequest
    IDPCache.proxySPAuthnReqCache.put(requestID, authnRequest);
    boolean signingNeeded = idpDescriptor.isWantAuthnRequestsSigned() || localDescriptor.isAuthnRequestsSigned();
    // check if relayState is present and get the unique
    // id which will be appended to the SSO URL before
    // redirecting
    String relayStateID = null;
    if (relayState != null && relayState.length() > 0) {
        relayStateID = SPSSOFederate.getRelayStateID(relayState, authnRequest.getID());
    }
    if (binding.equals(SAML2Constants.HTTP_POST)) {
        if (signingNeeded) {
            String certAlias = SPSSOFederate.getParameter(SAML2MetaUtils.getAttributes(localDescriptorConfig), SAML2Constants.SIGNING_CERT_ALIAS);
            SPSSOFederate.signAuthnRequest(certAlias, newAuthnRequest);
        }
        String authXMLString = newAuthnRequest.toXMLString(true, true);
        String encodedReqMsg = SAML2Utils.encodeForPOST(authXMLString);
        SAML2Utils.postToTarget(request, response, "SAMLRequest", encodedReqMsg, "RelayState", relayStateID, destination);
    } else {
        String authReqXMLString = newAuthnRequest.toXMLString(true, true);
        if (SAML2Utils.debug.messageEnabled()) {
            SAML2Utils.debug.message(classMethod + " AuthnRequest: " + authReqXMLString);
        }
        String encodedXML = SAML2Utils.encodeForRedirect(authReqXMLString);
        StringBuffer queryString = new StringBuffer().append(SAML2Constants.SAML_REQUEST).append(SAML2Constants.EQUAL).append(encodedXML);
        //TODO:  should it be newAuthnRequest??? 
        if (relayStateID != null && relayStateID.length() > 0) {
            queryString.append("&").append(SAML2Constants.RELAY_STATE).append("=").append(URLEncDec.encode(relayStateID));
        }
        StringBuffer redirectURL = new StringBuffer().append(destination).append(destination.contains("?") ? "&" : "?");
        if (signingNeeded) {
            String certAlias = SPSSOFederate.getParameter(SAML2MetaUtils.getAttributes(localDescriptorConfig), SAML2Constants.SIGNING_CERT_ALIAS);
            String signedQueryStr = SPSSOFederate.signQueryString(queryString.toString(), certAlias);
            redirectURL.append(signedQueryStr);
        } else {
            redirectURL.append(queryString);
        }
        response.sendRedirect(redirectURL.toString());
    }
    String[] data = { destination };
    LogUtil.access(Level.INFO, LogUtil.REDIRECT_TO_SP, data, null);
    AuthnRequestInfo reqInfo = new AuthnRequestInfo(request, response, realm, hostedEntityId, preferredIDP, newAuthnRequest, relayState, null);
    synchronized (SPCache.requestHash) {
        SPCache.requestHash.put(requestID, reqInfo);
    }
    if (SAML2FailoverUtils.isSAML2FailoverEnabled()) {
        try {
            // sessionExpireTime is counted in seconds
            long sessionExpireTime = System.currentTimeMillis() / 1000 + SPCache.interval;
            SAML2FailoverUtils.saveSAML2TokenWithoutSecondaryKey(requestID, new AuthnRequestInfoCopy(reqInfo), sessionExpireTime);
            if (SAML2Utils.debug.messageEnabled()) {
                SAML2Utils.debug.message(classMethod + " SAVE AuthnRequestInfoCopy for requestID " + requestID);
            }
        } catch (SAML2TokenRepositoryException se) {
            SAML2Utils.debug.error(classMethod + " SAVE AuthnRequestInfoCopy for requestID " + requestID + ", failed!", se);
        }
    }
}
Also used : SPSSODescriptorElement(com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement) SPSSOConfigElement(com.sun.identity.saml2.jaxb.entityconfig.SPSSOConfigElement) SingleSignOnServiceElement(com.sun.identity.saml2.jaxb.metadata.SingleSignOnServiceElement) SAML2Exception(com.sun.identity.saml2.common.SAML2Exception) AuthnRequest(com.sun.identity.saml2.protocol.AuthnRequest) SAML2TokenRepositoryException(org.forgerock.openam.federation.saml2.SAML2TokenRepositoryException) SAML2ServiceProviderAdapter(com.sun.identity.saml2.plugins.SAML2ServiceProviderAdapter) SAML2MetaException(com.sun.identity.saml2.meta.SAML2MetaException) IDPSSODescriptorElement(com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement)

Example 23 with AuthnRequest

use of com.sun.identity.saml2.protocol.AuthnRequest in project OpenAM by OpenRock.

the class SAML2Utils method verifyResponse.

/**
     * Verifies single sign on <code>Response</code> and returns information
     * to SAML2 auth module for further processing. This method is used by
     * SAML2 auth module only.
     *
     * @param httpRequest    HttpServletRequest
     * @param httpResponse   HttpServletResponse
     * @param response       Single Sign On <code>Response</code>.
     * @param orgName        name of the realm or organization the provider is in.
     * @param hostEntityId   Entity ID of the hosted provider.
     * @param profileBinding Profile binding used.
     * @return A Map of information extracted from the Response. The keys of
     * map are:
     * <code>SAML2Constants.SUBJECT</code>,
     * <code>SAML2Constants.POST_ASSERTION</code>,
     * <code>SAML2Constants.ASSERTIONS</code>,
     * <code>SAML2Constants.SESSION_INDEX</code>,
     * <code>SAML2Constants.AUTH_LEVEL</code>,
     * <code>SAML2Constants.MAX_SESSION_TIME</code>.
     * @throws SAML2Exception if the Response is not valid according to the
     *                        processing rules.
     */
public static Map verifyResponse(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse, final Response response, final String orgName, final String hostEntityId, final String profileBinding) throws SAML2Exception {
    final String method = "SAML2Utils.verifyResponse:";
    if (response == null || orgName == null || orgName.length() == 0) {
        if (debug.messageEnabled()) {
            debug.message(method + "response or orgName is null.");
        }
        throw new SAML2Exception(bundle.getString("nullInput"));
    }
    String respID = response.getID();
    AuthnRequestInfo reqInfo = null;
    String inRespToResp = response.getInResponseTo();
    if (inRespToResp != null && inRespToResp.length() != 0) {
        reqInfo = (AuthnRequestInfo) SPCache.requestHash.get(inRespToResp);
        if (reqInfo == null) {
            if (SAML2FailoverUtils.isSAML2FailoverEnabled()) {
                // Attempt to read AuthnRequestInfoCopy from SAML2 repository
                AuthnRequestInfoCopy reqInfoCopy = null;
                try {
                    reqInfoCopy = (AuthnRequestInfoCopy) SAML2FailoverUtils.retrieveSAML2Token(inRespToResp);
                } catch (SAML2TokenRepositoryException se) {
                    debug.error(method + "AuthnRequestInfoCopy" + " unable to retrieve from SAML2 repository for inResponseTo: " + inRespToResp);
                }
                if (reqInfoCopy != null) {
                    // Get back the AuthnRequestInfo
                    reqInfo = reqInfoCopy.getAuthnRequestInfo(httpRequest, httpResponse);
                    if (debug.messageEnabled()) {
                        debug.message(method + "AuthnRequestInfoCopy" + " retrieved from SAML2 repository for inResponseTo: " + inRespToResp);
                    }
                } else {
                    debug.error(method + "InResponseTo attribute in Response" + " is invalid: " + inRespToResp + ", SAML2 failover is enabled");
                    String[] data = { respID };
                    LogUtil.error(Level.INFO, LogUtil.INVALID_INRESPONSETO_RESPONSE, data, null);
                    throw new SAML2Exception(bundle.getString("invalidInResponseToInResponse"));
                }
            } else {
                AuthnRequestInfoCopy reqInfoCopy = (AuthnRequestInfoCopy) SAML2Store.getTokenFromStore(inRespToResp);
                if (reqInfoCopy != null) {
                    // Get back the AuthnRequestInfo
                    reqInfo = reqInfoCopy.getAuthnRequestInfo(httpRequest, httpResponse);
                    if (debug.messageEnabled()) {
                        debug.message(method + "AuthnRequestInfoCopy" + " retrieved from SAML2 repository for inResponseTo: " + inRespToResp);
                    }
                } else {
                    debug.error(method + "InResponseTo attribute in Response" + " is invalid: " + inRespToResp + ", SAML2 failover is enabled");
                    String[] data = { respID };
                    LogUtil.error(Level.INFO, LogUtil.INVALID_INRESPONSETO_RESPONSE, data, null);
                    throw new SAML2Exception(bundle.getString("invalidInResponseToInResponse"));
                }
            }
        }
    }
    // reqInfo can remain null and will do for IDP initiated SSO requests
    // invoke SP Adapter
    SAML2ServiceProviderAdapter spAdapter = SAML2Utils.getSPAdapterClass(hostEntityId, orgName);
    if (spAdapter != null) {
        AuthnRequest authnRequest = null;
        if (reqInfo != null) {
            authnRequest = reqInfo.getAuthnRequest();
        }
        spAdapter.preSingleSignOnProcess(hostEntityId, orgName, httpRequest, httpResponse, authnRequest, response, profileBinding);
    }
    String idpEntityId = null;
    Issuer respIssuer = response.getIssuer();
    if (respIssuer != null) {
        // optional
        if (!isSourceSiteValid(respIssuer, orgName, hostEntityId)) {
            if (debug.messageEnabled()) {
                debug.message(method + "Issuer in Response is not valid.");
            }
            String[] data = { hostEntityId, orgName, respID };
            LogUtil.error(Level.INFO, LogUtil.INVALID_ISSUER_RESPONSE, data, null);
            throw new SAML2Exception(bundle.getString("invalidIssuerInResponse"));
        } else {
            idpEntityId = respIssuer.getValue();
        }
    }
    Status status = response.getStatus();
    if (status == null || !status.getStatusCode().getValue().equals(SAML2Constants.SUCCESS)) {
        String statusCode = (status == null) ? "" : status.getStatusCode().getValue();
        if (debug.messageEnabled()) {
            debug.message(method + "Response's status code is not success: " + statusCode);
        }
        String[] data = { respID, "" };
        if (LogUtil.isErrorLoggable(Level.FINE)) {
            data[1] = statusCode;
        }
        LogUtil.error(Level.INFO, LogUtil.WRONG_STATUS_CODE, data, null);
        if (SAML2Constants.RESPONDER.equals(statusCode)) {
            //In case of passive authentication the NoPassive response will be sent using two StatusCode nodes:
            //the outer StatusCode will be Responder and the inner StatusCode will contain the NoPassive URN
            StatusCode secondLevelStatusCode = status.getStatusCode().getStatusCode();
            if (secondLevelStatusCode != null && SAML2Constants.NOPASSIVE.equals(secondLevelStatusCode.getValue())) {
                throw new SAML2Exception(SAML2Utils.BUNDLE_NAME, "noPassiveResponse", null);
            }
        } else if (SAML2Constants.REQUESTER.equals(statusCode)) {
            // when is AllowCreate=false mode the auth module gets here with a
            // statusCode of urn:oasis:names:tc:SAML:2.0:status:Requester
            StatusCode secondLevelStatusCode = status.getStatusCode().getStatusCode();
            if (secondLevelStatusCode != null && SAML2Constants.INVALID_NAME_ID_POLICY.equals(secondLevelStatusCode.getValue())) {
                throw new SAML2Exception(SAML2Utils.BUNDLE_NAME, "nameIDMReqInvalidNameIDPolicy", null);
            }
        }
        throw new SAML2Exception(bundle.getString("invalidStatusCodeInResponse"));
    }
    if (saml2MetaManager == null) {
        throw new SAML2Exception(bundle.getString("nullMetaManager"));
    }
    SPSSOConfigElement spConfig = null;
    SPSSODescriptorElement spDesc = null;
    spConfig = saml2MetaManager.getSPSSOConfig(orgName, hostEntityId);
    spDesc = saml2MetaManager.getSPSSODescriptor(orgName, hostEntityId);
    if (debug.messageEnabled()) {
        debug.message(method + "binding is :" + profileBinding);
    }
    // SAML spec processing
    //  4.1.4.3   Verify any signatures present on the assertion(s) or the response
    boolean responseIsSigned = false;
    if (response.isSigned()) {
        IDPSSODescriptorElement idpSSODescriptor = null;
        try {
            idpSSODescriptor = saml2MetaManager.getIDPSSODescriptor(orgName, idpEntityId);
        } catch (SAML2MetaException sme) {
            String[] data = { orgName, idpEntityId };
            LogUtil.error(Level.INFO, LogUtil.IDP_METADATA_ERROR, data, null);
            throw new SAML2Exception(sme);
        }
        if (idpSSODescriptor != null) {
            Set<X509Certificate> verificationCerts = KeyUtil.getVerificationCerts(idpSSODescriptor, idpEntityId, SAML2Constants.IDP_ROLE);
            if (CollectionUtils.isEmpty(verificationCerts) || !response.isSignatureValid(verificationCerts)) {
                debug.error(method + "Response is not signed or signature is not valid.");
                String[] data = { orgName, hostEntityId, idpEntityId };
                LogUtil.error(Level.INFO, LogUtil.POST_RESPONSE_INVALID_SIGNATURE, data, null);
                throw new SAML2Exception(bundle.getString("invalidSignInResponse"));
            }
        } else {
            String[] data = { idpEntityId };
            LogUtil.error(Level.INFO, LogUtil.IDP_METADATA_ERROR, data, null);
            throw new SAML2Exception(SAML2Utils.bundle.getString("metaDataError"));
        }
        responseIsSigned = true;
    }
    if (debug.messageEnabled()) {
        debug.message(method + "responseIsSigned is :" + responseIsSigned);
    }
    // assertion encryption check
    boolean needAssertionEncrypted = false;
    String assertionEncryptedAttr = getAttributeValueFromSPSSOConfig(spConfig, SAML2Constants.WANT_ASSERTION_ENCRYPTED);
    needAssertionEncrypted = Boolean.parseBoolean(assertionEncryptedAttr);
    if (debug.messageEnabled()) {
        debug.message(method + "NeedAssertionEncrypted is :" + needAssertionEncrypted);
    }
    List<Assertion> assertions = response.getAssertion();
    if (needAssertionEncrypted && !CollectionUtils.isEmpty(assertions)) {
        String[] data = { respID };
        LogUtil.error(Level.INFO, LogUtil.ASSERTION_NOT_ENCRYPTED, data, null);
        throw new SAML2Exception(SAML2Utils.bundle.getString("assertionNotEncrypted"));
    }
    Set<PrivateKey> decryptionKeys;
    List<EncryptedAssertion> encAssertions = response.getEncryptedAssertion();
    if (encAssertions != null) {
        decryptionKeys = KeyUtil.getDecryptionKeys(spConfig);
        for (EncryptedAssertion encAssertion : encAssertions) {
            Assertion assertion = encAssertion.decrypt(decryptionKeys);
            if (assertions == null) {
                assertions = new ArrayList<>();
            }
            assertions.add(assertion);
        }
    }
    if (CollectionUtils.isEmpty(assertions)) {
        if (debug.messageEnabled()) {
            debug.message(method + "no assertion in the Response.");
        }
        String[] data = { respID };
        LogUtil.error(Level.INFO, LogUtil.MISSING_ASSERTION, data, null);
        throw new SAML2Exception(SAML2Utils.bundle.getString("missingAssertion"));
    }
    boolean wantAssertionsSigned = spDesc.isWantAssertionsSigned();
    if (debug.messageEnabled()) {
        debug.message(method + "wantAssertionsSigned is :" + wantAssertionsSigned);
    }
    // validate the assertions
    Map smap = null;
    Map bearerMap = null;
    IDPSSODescriptorElement idp = null;
    Set<X509Certificate> verificationCerts = null;
    boolean allAssertionsSigned = true;
    for (Assertion assertion : assertions) {
        String assertionID = assertion.getID();
        Issuer issuer = assertion.getIssuer();
        if (!isSourceSiteValid(issuer, orgName, hostEntityId)) {
            debug.error("assertion's source site is not valid.");
            String[] data = { assertionID };
            LogUtil.error(Level.INFO, LogUtil.INVALID_ISSUER_ASSERTION, data, null);
            throw new SAML2Exception(bundle.getString("invalidIssuerInAssertion"));
        }
        if (idpEntityId == null) {
            idpEntityId = issuer.getValue();
        } else {
            if (!idpEntityId.equals(issuer.getValue())) {
                if (debug.messageEnabled()) {
                    debug.message(method + "Issuer in Assertion doesn't " + "match the Issuer in Response or other " + "Assertions in the Response.");
                }
                String[] data = { assertionID };
                LogUtil.error(Level.INFO, LogUtil.MISMATCH_ISSUER_ASSERTION, data, null);
                throw new SAML2Exception(SAML2Utils.bundle.getString("mismatchIssuer"));
            }
        }
        if (assertion.isSigned()) {
            if (verificationCerts == null) {
                idp = saml2MetaManager.getIDPSSODescriptor(orgName, idpEntityId);
                verificationCerts = KeyUtil.getVerificationCerts(idp, idpEntityId, SAML2Constants.IDP_ROLE);
            }
            if (CollectionUtils.isEmpty(verificationCerts) || !assertion.isSignatureValid(verificationCerts)) {
                debug.error(method + "Assertion is not signed or signature is not valid.");
                String[] data = { assertionID };
                LogUtil.error(Level.INFO, LogUtil.INVALID_SIGNATURE_ASSERTION, data, null);
                throw new SAML2Exception(bundle.getString("invalidSignatureOnAssertion"));
            }
        } else {
            allAssertionsSigned = false;
        }
        List authnStmts = assertion.getAuthnStatements();
        if (authnStmts != null && !authnStmts.isEmpty()) {
            Subject subject = assertion.getSubject();
            if (subject == null) {
                continue;
            }
            List subjectConfirms = subject.getSubjectConfirmation();
            if (subjectConfirms == null || subjectConfirms.isEmpty()) {
                continue;
            }
            bearerMap = isBearerSubjectConfirmation(subjectConfirms, inRespToResp, spDesc, spConfig, assertionID);
            if (!((Boolean) bearerMap.get(SAML2Constants.IS_BEARER))) {
                continue;
            }
            boolean foundAssertion = false;
            if ((SPCache.assertionByIDCache != null) && (SPCache.assertionByIDCache.containsKey(assertionID))) {
                foundAssertion = true;
            }
            if ((!foundAssertion) && SAML2FailoverUtils.isSAML2FailoverEnabled()) {
                try {
                    if (SAML2FailoverUtils.retrieveSAML2Token(assertionID) != null) {
                        foundAssertion = true;
                    }
                } catch (SAML2TokenRepositoryException e) {
                    if (debug.messageEnabled()) {
                        debug.message("Session not found in AMTokenSAML2Repository.", e);
                    }
                }
            }
            if (foundAssertion) {
                debug.error("Bearer Assertion is one time use only!");
                throw new SAML2Exception(bundle.getString("usedBearAssertion"));
            }
            checkAudience(assertion.getConditions(), hostEntityId, assertionID);
            if (smap == null) {
                smap = fillMap(authnStmts, subject, assertion, assertions, reqInfo, inRespToResp, orgName, hostEntityId, idpEntityId, spConfig, (Date) bearerMap.get(SAML2Constants.NOTONORAFTER));
            }
        }
    // end of having authnStmt
    }
    if (smap == null) {
        debug.error("No Authentication Assertion in Response.");
        throw new SAML2Exception(bundle.getString("missingAuthnAssertion"));
    }
    // the enclosing element
    if (wantAssertionsSigned && !(responseIsSigned || allAssertionsSigned)) {
        debug.error(method + "WantAssertionsSigned is true and response or all assertions are not signed");
        String[] data = { orgName, hostEntityId, idpEntityId };
        LogUtil.error(Level.INFO, LogUtil.INVALID_SIGNATURE_ASSERTION, data, null);
        throw new SAML2Exception(bundle.getString("assertionNotSigned"));
    }
    // signing each individual <Assertion> element or by signing the <Response> element.
    if (profileBinding.equals(SAML2Constants.HTTP_POST)) {
        boolean wantPostResponseSigned = SAML2Utils.wantPOSTResponseSigned(orgName, hostEntityId, SAML2Constants.SP_ROLE);
        if (debug.messageEnabled()) {
            debug.message(method + "wantPostResponseSigned is :" + wantPostResponseSigned);
        }
        if (wantPostResponseSigned && !responseIsSigned) {
            debug.error(method + "wantPostResponseSigned is true but response is not signed");
            String[] data = { orgName, hostEntityId, idpEntityId };
            LogUtil.error(Level.INFO, LogUtil.POST_RESPONSE_INVALID_SIGNATURE, data, null);
            throw new SAML2Exception(bundle.getString("responseNotSigned"));
        }
        if (!responseIsSigned && !allAssertionsSigned) {
            debug.error(method + "WantAssertionsSigned is true but some or all assertions are not signed");
            String[] data = { orgName, hostEntityId, idpEntityId };
            LogUtil.error(Level.INFO, LogUtil.INVALID_SIGNATURE_ASSERTION, data, null);
            throw new SAML2Exception(bundle.getString("assertionNotSigned"));
        }
    }
    return smap;
}
Also used : PrivateKey(java.security.PrivateKey) Issuer(com.sun.identity.saml2.assertion.Issuer) AuthnRequestInfo(com.sun.identity.saml2.profile.AuthnRequestInfo) SPSSODescriptorElement(com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement) StatusCode(com.sun.identity.saml2.protocol.StatusCode) ArrayList(java.util.ArrayList) List(java.util.List) AuthnRequestInfoCopy(com.sun.identity.saml2.profile.AuthnRequestInfoCopy) SAML2ServiceProviderAdapter(com.sun.identity.saml2.plugins.SAML2ServiceProviderAdapter) SAML2MetaException(com.sun.identity.saml2.meta.SAML2MetaException) Status(com.sun.identity.saml2.protocol.Status) SPSSOConfigElement(com.sun.identity.saml2.jaxb.entityconfig.SPSSOConfigElement) EncryptedAssertion(com.sun.identity.saml2.assertion.EncryptedAssertion) Assertion(com.sun.identity.saml2.assertion.Assertion) X509Certificate(java.security.cert.X509Certificate) Subject(com.sun.identity.saml2.assertion.Subject) Date(java.util.Date) AuthnRequest(com.sun.identity.saml2.protocol.AuthnRequest) EncryptedAssertion(com.sun.identity.saml2.assertion.EncryptedAssertion) SAML2TokenRepositoryException(org.forgerock.openam.federation.saml2.SAML2TokenRepositoryException) Map(java.util.Map) HashMap(java.util.HashMap) IDPSSODescriptorElement(com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement)

Example 24 with AuthnRequest

use of com.sun.identity.saml2.protocol.AuthnRequest in project OpenAM by OpenRock.

the class SAML2Utils method fillMap.

private static Map fillMap(final List authnStmts, final Subject subject, final Assertion assertion, final List assertions, final AuthnRequestInfo reqInfo, final String inRespToResp, final String orgName, final String hostEntityId, final String idpEntityId, final SPSSOConfigElement spConfig, final Date notOnOrAfterTime) throws SAML2Exception {
    // use the first AuthnStmt
    AuthnStatement authnStmt = (AuthnStatement) authnStmts.get(0);
    int authLevel = -1;
    String mapperClass = getAttributeValueFromSPSSOConfig(spConfig, SAML2Constants.SP_AUTHCONTEXT_MAPPER);
    SPAuthnContextMapper mapper = getSPAuthnContextMapper(orgName, hostEntityId, mapperClass);
    RequestedAuthnContext reqContext = null;
    AuthnRequest authnRequest = null;
    if (reqInfo != null) {
        reqContext = (reqInfo.getAuthnRequest()).getRequestedAuthnContext();
        authnRequest = reqInfo.getAuthnRequest();
    }
    authLevel = mapper.getAuthLevel(reqContext, authnStmt.getAuthnContext(), orgName, hostEntityId, idpEntityId);
    String sessionIndex = authnStmt.getSessionIndex();
    Date sessionNotOnOrAfter = authnStmt.getSessionNotOnOrAfter();
    Map smap = new HashMap();
    smap.put(SAML2Constants.SUBJECT, subject);
    smap.put(SAML2Constants.POST_ASSERTION, assertion);
    smap.put(SAML2Constants.ASSERTIONS, assertions);
    if (authnRequest != null) {
        smap.put(SAML2Constants.AUTHN_REQUEST, authnRequest);
    }
    String[] data = { assertion.getID(), "", "" };
    if (LogUtil.isAccessLoggable(Level.FINE)) {
        data[1] = subject.toXMLString();
    }
    if (sessionIndex != null && sessionIndex.length() != 0) {
        data[2] = sessionIndex;
        smap.put(SAML2Constants.SESSION_INDEX, sessionIndex);
    }
    if (authLevel >= 0) {
        smap.put(SAML2Constants.AUTH_LEVEL, new Integer(authLevel));
    }
    // SessionNotOnOrAfter
    if (sessionNotOnOrAfter != null) {
        long maxSessionTime = (sessionNotOnOrAfter.getTime() - System.currentTimeMillis()) / 60000;
        if (maxSessionTime > 0) {
            smap.put(SAML2Constants.MAX_SESSION_TIME, new Long(maxSessionTime));
        }
    }
    if (inRespToResp != null && inRespToResp.length() != 0) {
        smap.put(SAML2Constants.IN_RESPONSE_TO, inRespToResp);
    }
    if (debug.messageEnabled()) {
        debug.message("SAML2Utils.fillMap: Found valid authentication " + "assertion.");
    }
    if (notOnOrAfterTime != null) {
        smap.put(SAML2Constants.NOTONORAFTER, new Long(notOnOrAfterTime.getTime()));
    }
    LogUtil.access(Level.INFO, LogUtil.FOUND_AUTHN_ASSERTION, data, null);
    return smap;
}
Also used : HashMap(java.util.HashMap) Date(java.util.Date) RequestedAuthnContext(com.sun.identity.saml2.protocol.RequestedAuthnContext) AuthnRequest(com.sun.identity.saml2.protocol.AuthnRequest) AuthnStatement(com.sun.identity.saml2.assertion.AuthnStatement) SPAuthnContextMapper(com.sun.identity.saml2.plugins.SPAuthnContextMapper) DefaultSPAuthnContextMapper(com.sun.identity.saml2.plugins.DefaultSPAuthnContextMapper) Map(java.util.Map) HashMap(java.util.HashMap)

Example 25 with AuthnRequest

use of com.sun.identity.saml2.protocol.AuthnRequest in project OpenAM by OpenRock.

the class IDPSSOUtil method getAuthnStatement.

/**
     * Returns a <code>SAML AuthnStatement</code> object.
     *
     * @param request The HTTP request.
     * @param session The user's session.
     * @param isNewSessionIndex A returned flag from which the caller knows if the session index in the returned
     *                          <code>AuthnStatement</code> is a new session index.
     * @param authnReq The <code>AuthnRequest</code> object.
     * @param idpEntityID The entity ID of the identity provider.
     * @param realm The realm name.
     * @param matchingAuthnContext The <code>AuthnContext</code> used to find authentication type and scheme.
     * @return The <code>SAML AuthnStatement</code> object.
     * @throws SAML2Exception If the operation is not successful.
     */
private static AuthnStatement getAuthnStatement(HttpServletRequest request, Object session, NewBoolean isNewSessionIndex, AuthnRequest authnReq, String idpEntityID, String realm, AuthnContext matchingAuthnContext) throws SAML2Exception {
    String classMethod = "IDPSSOUtil.getAuthnStatement: ";
    AuthnStatement authnStatement = AssertionFactory.getInstance().createAuthnStatement();
    Date authInstant = null;
    // will be used when we add SubjectLocality to the statement
    try {
        String[] values = sessionProvider.getProperty(session, SessionProvider.AUTH_INSTANT);
        if (values != null && values.length != 0 && values[0] != null && values[0].length() != 0) {
            authInstant = DateUtils.stringToDate(values[0]);
        }
    } catch (Exception e) {
        SAML2Utils.debug.error(classMethod + "exception retrieving info from the session: ", e);
        throw new SAML2Exception(SAML2Utils.bundle.getString("errorGettingAuthnStatement"));
    }
    if (authInstant == null) {
        authInstant = new Date();
    }
    authnStatement.setAuthnInstant(authInstant);
    AuthnContext authnContext = matchingAuthnContext;
    if (authnContext == null) {
        String authLevel = null;
        try {
            String[] values = sessionProvider.getProperty(session, SessionProvider.AUTH_LEVEL);
            if (values != null && values.length != 0 && values[0] != null && values[0].length() != 0) {
                authLevel = values[0];
            }
        } catch (Exception e) {
            SAML2Utils.debug.error(classMethod + "exception retrieving auth level info from the session: ", e);
            throw new SAML2Exception(SAML2Utils.bundle.getString("errorGettingAuthnStatement"));
        }
        IDPAuthnContextMapper idpAuthnContextMapper = getIDPAuthnContextMapper(realm, idpEntityID);
        authnContext = idpAuthnContextMapper.getAuthnContextFromAuthLevel(authLevel, realm, idpEntityID);
    }
    final Response idpResponse = (Response) request.getAttribute(SAML2Constants.SAML_PROXY_IDP_RESPONSE_KEY);
    if (idpResponse != null) {
        // IdP proxy case: we already received an assertion from the remote IdP and now the IdP proxy is generating
        // a new SAML response for the SP.
        Set<String> authenticatingAuthorities = new LinkedHashSet<String>();
        final List<Assertion> assertions = idpResponse.getAssertion();
        for (Assertion assertion : assertions) {
            authenticatingAuthorities.addAll(extractAuthenticatingAuthorities(assertion));
        }
        // According to SAML profile 4.1.4.2 each assertion within the SAML Response MUST have the same issuer, so
        // this should suffice. We should have at least one assertion, since the IdP proxy's SP already accepted it.
        authenticatingAuthorities.add(assertions.iterator().next().getIssuer().getValue());
        authnContext.setAuthenticatingAuthority(new ArrayList<String>(authenticatingAuthorities));
    }
    authnStatement.setAuthnContext(authnContext);
    String sessionIndex = getSessionIndex(session);
    if (sessionIndex == null) {
        // new sessionIndex
        sessionIndex = SAML2Utils.generateIDWithServerID();
        try {
            String[] values = { sessionIndex };
            sessionProvider.setProperty(session, SAML2Constants.IDP_SESSION_INDEX, values);
        } catch (SessionException e) {
            SAML2Utils.debug.error(classMethod + "error setting session index into the session: ", e);
            throw new SAML2Exception(SAML2Utils.bundle.getString("errorGettingAuthnStatement"));
        }
        isNewSessionIndex.setValue(true);
    } else {
        isNewSessionIndex.setValue(false);
    }
    if (SAML2Utils.debug.messageEnabled()) {
        SAML2Utils.debug.message(classMethod + "SessionIndex (in AuthnStatement) =" + sessionIndex);
    }
    if (sessionIndex != null) {
        Set authContextSet = (HashSet) IDPCache.authnContextCache.get(sessionIndex);
        if (authContextSet == null || authContextSet.isEmpty()) {
            authContextSet = new HashSet();
        }
        authContextSet.add(authnContext);
        // cache the AuthContext to use in the case of session upgrade.
        IDPCache.authnContextCache.put(sessionIndex, authContextSet);
        authnStatement.setSessionIndex(sessionIndex);
    }
    return authnStatement;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) IDPAuthnContextMapper(com.sun.identity.saml2.plugins.IDPAuthnContextMapper) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) EncryptedAssertion(com.sun.identity.saml2.assertion.EncryptedAssertion) Assertion(com.sun.identity.saml2.assertion.Assertion) SessionException(com.sun.identity.plugin.session.SessionException) Date(java.util.Date) SAML2InvalidNameIDPolicyException(com.sun.identity.saml2.common.SAML2InvalidNameIDPolicyException) SessionException(com.sun.identity.plugin.session.SessionException) COTException(com.sun.identity.cot.COTException) SAML2MetaException(com.sun.identity.saml2.meta.SAML2MetaException) SAML2TokenRepositoryException(org.forgerock.openam.federation.saml2.SAML2TokenRepositoryException) IOException(java.io.IOException) SAML2Exception(com.sun.identity.saml2.common.SAML2Exception) AuthnContext(com.sun.identity.saml2.assertion.AuthnContext) SAML2Exception(com.sun.identity.saml2.common.SAML2Exception) ECPResponse(com.sun.identity.saml2.ecp.ECPResponse) Response(com.sun.identity.saml2.protocol.Response) HttpServletResponse(javax.servlet.http.HttpServletResponse) AuthnStatement(com.sun.identity.saml2.assertion.AuthnStatement) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Aggregations

SAML2Exception (com.sun.identity.saml2.common.SAML2Exception)27 List (java.util.List)18 SAML2MetaException (com.sun.identity.saml2.meta.SAML2MetaException)15 ArrayList (java.util.ArrayList)15 AuthnRequest (com.sun.identity.saml2.protocol.AuthnRequest)14 Map (java.util.Map)13 SessionException (com.sun.identity.plugin.session.SessionException)12 SPSSODescriptorElement (com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement)10 IOException (java.io.IOException)10 SAML2TokenRepositoryException (org.forgerock.openam.federation.saml2.SAML2TokenRepositoryException)10 SPSSOConfigElement (com.sun.identity.saml2.jaxb.entityconfig.SPSSOConfigElement)9 Date (java.util.Date)8 HashMap (java.util.HashMap)8 IDPSSODescriptorElement (com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement)7 SAML2ServiceProviderAdapter (com.sun.identity.saml2.plugins.SAML2ServiceProviderAdapter)7 Iterator (java.util.Iterator)7 Issuer (com.sun.identity.saml2.assertion.Issuer)6 Assertion (com.sun.identity.saml2.assertion.Assertion)5 IDPList (com.sun.identity.saml2.protocol.IDPList)5 Response (com.sun.identity.saml2.protocol.Response)5