Search in sources :

Example 1 with SAML2RequestTO

use of org.apache.syncope.common.lib.to.SAML2RequestTO in project syncope by apache.

the class SAML2SPLogic method createLogoutRequest.

@PreAuthorize("isAuthenticated() and not(hasRole('" + StandardEntitlement.ANONYMOUS + "'))")
public SAML2RequestTO createLogoutRequest(final String accessToken, final String spEntityID) {
    check();
    // 1. fetch the current JWT used for Syncope authentication
    JwsJwtCompactConsumer consumer = new JwsJwtCompactConsumer(accessToken);
    if (!consumer.verifySignatureWith(jwsSignatureVerifier)) {
        throw new IllegalArgumentException("Invalid signature found in Access Token");
    }
    // 2. look for IdP
    String idpEntityID = (String) consumer.getJwtClaims().getClaim(JWT_CLAIM_IDP_ENTITYID);
    if (idpEntityID == null) {
        throw new NotFoundException("No SAML 2.0 IdP information found in the access token");
    }
    SAML2IdPEntity idp = cache.get(idpEntityID);
    if (idp == null) {
        throw new NotFoundException("SAML 2.0 IdP '" + idpEntityID + "'");
    }
    if (idp.getSLOLocation(idp.getBindingType()) == null) {
        throw new IllegalArgumentException("No SingleLogoutService available for " + idp.getId());
    }
    // 3. create LogoutRequest
    LogoutRequest logoutRequest = new LogoutRequestBuilder().buildObject();
    logoutRequest.setID("_" + UUID_GENERATOR.generate().toString());
    logoutRequest.setDestination(idp.getSLOLocation(idp.getBindingType()).getLocation());
    DateTime now = new DateTime();
    logoutRequest.setIssueInstant(now);
    logoutRequest.setNotOnOrAfter(now.plusMinutes(5));
    Issuer issuer = new IssuerBuilder().buildObject();
    issuer.setValue(spEntityID);
    logoutRequest.setIssuer(issuer);
    NameID nameID = new NameIDBuilder().buildObject();
    nameID.setFormat((String) consumer.getJwtClaims().getClaim(JWT_CLAIM_NAMEID_FORMAT));
    nameID.setValue((String) consumer.getJwtClaims().getClaim(JWT_CLAIM_NAMEID_VALUE));
    logoutRequest.setNameID(nameID);
    SessionIndex sessionIndex = new SessionIndexBuilder().buildObject();
    sessionIndex.setSessionIndex((String) consumer.getJwtClaims().getClaim(JWT_CLAIM_SESSIONINDEX));
    logoutRequest.getSessionIndexes().add(sessionIndex);
    SAML2RequestTO requestTO = new SAML2RequestTO();
    requestTO.setIdpServiceAddress(logoutRequest.getDestination());
    requestTO.setBindingType(idp.getBindingType());
    try {
        // 3. generate relay state as JWT
        Map<String, Object> claims = new HashMap<>();
        claims.put(JWT_CLAIM_IDP_DEFLATE, idp.getBindingType() == SAML2BindingType.REDIRECT ? true : idp.isUseDeflateEncoding());
        Triple<String, String, Date> relayState = accessTokenDataBinder.generateJWT(logoutRequest.getID(), JWT_RELAY_STATE_DURATION, claims);
        requestTO.setRelayState(relayState.getMiddle());
        // 4. sign and encode AuthnRequest
        switch(idp.getBindingType()) {
            case REDIRECT:
                requestTO.setContent(saml2rw.encode(logoutRequest, true));
                requestTO.setSignAlg(saml2rw.getSigAlgo());
                requestTO.setSignature(saml2rw.sign(requestTO.getContent(), requestTO.getRelayState()));
                break;
            case POST:
            default:
                saml2rw.sign(logoutRequest);
                requestTO.setContent(saml2rw.encode(logoutRequest, idp.isUseDeflateEncoding()));
        }
    } catch (Exception e) {
        LOG.error("While generating LogoutRequest", e);
        SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown);
        sce.getElements().add(e.getMessage());
        throw sce;
    }
    return requestTO;
}
Also used : SessionIndexBuilder(org.opensaml.saml.saml2.core.impl.SessionIndexBuilder) SAML2RequestTO(org.apache.syncope.common.lib.to.SAML2RequestTO) Issuer(org.opensaml.saml.saml2.core.Issuer) NameID(org.opensaml.saml.saml2.core.NameID) HashMap(java.util.HashMap) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) NotFoundException(org.apache.syncope.core.persistence.api.dao.NotFoundException) XSString(org.opensaml.core.xml.schema.XSString) DateTime(org.joda.time.DateTime) Date(java.util.Date) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) NotFoundException(org.apache.syncope.core.persistence.api.dao.NotFoundException) NameIDBuilder(org.opensaml.saml.saml2.core.impl.NameIDBuilder) LogoutRequestBuilder(org.opensaml.saml.saml2.core.impl.LogoutRequestBuilder) SAML2IdPEntity(org.apache.syncope.core.logic.saml2.SAML2IdPEntity) SessionIndex(org.opensaml.saml.saml2.core.SessionIndex) JwsJwtCompactConsumer(org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer) LogoutRequest(org.opensaml.saml.saml2.core.LogoutRequest) XMLObject(org.opensaml.core.xml.XMLObject) IssuerBuilder(org.opensaml.saml.saml2.core.impl.IssuerBuilder) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 2 with SAML2RequestTO

use of org.apache.syncope.common.lib.to.SAML2RequestTO in project syncope by apache.

the class SAML2SPLogic method createLoginRequest.

@PreAuthorize("hasRole('" + StandardEntitlement.ANONYMOUS + "')")
public SAML2RequestTO createLoginRequest(final String spEntityID, final String idpEntityID) {
    check();
    // 1. look for IdP
    SAML2IdPEntity idp = StringUtils.isBlank(idpEntityID) ? cache.getFirst() : cache.get(idpEntityID);
    if (idp == null) {
        if (StringUtils.isBlank(idpEntityID)) {
            List<SAML2IdP> all = saml2IdPDAO.findAll();
            if (!all.isEmpty()) {
                idp = getIdP(all.get(0).getKey());
            }
        } else {
            idp = getIdP(idpEntityID);
        }
    }
    if (idp == null) {
        throw new NotFoundException(StringUtils.isBlank(idpEntityID) ? "Any SAML 2.0 IdP" : "SAML 2.0 IdP '" + idpEntityID + "'");
    }
    if (idp.getSSOLocation(idp.getBindingType()) == null) {
        throw new IllegalArgumentException("No SingleSignOnService available for " + idp.getId());
    }
    // 2. create AuthnRequest
    Issuer issuer = new IssuerBuilder().buildObject();
    issuer.setValue(spEntityID);
    NameIDPolicy nameIDPolicy = new NameIDPolicyBuilder().buildObject();
    if (idp.supportsNameIDFormat(NameIDType.TRANSIENT)) {
        nameIDPolicy.setFormat(NameIDType.TRANSIENT);
    } else if (idp.supportsNameIDFormat(NameIDType.PERSISTENT)) {
        nameIDPolicy.setFormat(NameIDType.PERSISTENT);
    } else {
        throw new IllegalArgumentException("Could not find supported NameIDFormat for IdP " + idpEntityID);
    }
    nameIDPolicy.setAllowCreate(true);
    nameIDPolicy.setSPNameQualifier(spEntityID);
    AuthnContextClassRef authnContextClassRef = new AuthnContextClassRefBuilder().buildObject();
    authnContextClassRef.setAuthnContextClassRef(AuthnContext.PPT_AUTHN_CTX);
    RequestedAuthnContext requestedAuthnContext = new RequestedAuthnContextBuilder().buildObject();
    requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT);
    requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef);
    AuthnRequest authnRequest = new AuthnRequestBuilder().buildObject();
    authnRequest.setID("_" + UUID_GENERATOR.generate().toString());
    authnRequest.setForceAuthn(false);
    authnRequest.setIsPassive(false);
    authnRequest.setVersion(SAMLVersion.VERSION_20);
    authnRequest.setProtocolBinding(idp.getBindingType().getUri());
    authnRequest.setIssueInstant(new DateTime());
    authnRequest.setIssuer(issuer);
    authnRequest.setNameIDPolicy(nameIDPolicy);
    authnRequest.setRequestedAuthnContext(requestedAuthnContext);
    authnRequest.setDestination(idp.getSSOLocation(idp.getBindingType()).getLocation());
    SAML2RequestTO requestTO = new SAML2RequestTO();
    requestTO.setIdpServiceAddress(authnRequest.getDestination());
    requestTO.setBindingType(idp.getBindingType());
    try {
        // 3. generate relay state as JWT
        Map<String, Object> claims = new HashMap<>();
        claims.put(JWT_CLAIM_IDP_DEFLATE, idp.isUseDeflateEncoding());
        Triple<String, String, Date> relayState = accessTokenDataBinder.generateJWT(authnRequest.getID(), JWT_RELAY_STATE_DURATION, claims);
        // 4. sign and encode AuthnRequest
        switch(idp.getBindingType()) {
            case REDIRECT:
                requestTO.setRelayState(URLEncoder.encode(relayState.getMiddle(), StandardCharsets.UTF_8.name()));
                requestTO.setContent(URLEncoder.encode(saml2rw.encode(authnRequest, true), StandardCharsets.UTF_8.name()));
                requestTO.setSignAlg(URLEncoder.encode(saml2rw.getSigAlgo(), StandardCharsets.UTF_8.name()));
                requestTO.setSignature(URLEncoder.encode(saml2rw.sign(requestTO.getContent(), requestTO.getRelayState()), StandardCharsets.UTF_8.name()));
                break;
            case POST:
            default:
                requestTO.setRelayState(relayState.getMiddle());
                saml2rw.sign(authnRequest);
                requestTO.setContent(saml2rw.encode(authnRequest, idp.isUseDeflateEncoding()));
        }
    } catch (Exception e) {
        LOG.error("While generating AuthnRequest", e);
        SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown);
        sce.getElements().add(e.getMessage());
        throw sce;
    }
    return requestTO;
}
Also used : SAML2RequestTO(org.apache.syncope.common.lib.to.SAML2RequestTO) Issuer(org.opensaml.saml.saml2.core.Issuer) HashMap(java.util.HashMap) NotFoundException(org.apache.syncope.core.persistence.api.dao.NotFoundException) AuthnRequestBuilder(org.opensaml.saml.saml2.core.impl.AuthnRequestBuilder) XSString(org.opensaml.core.xml.schema.XSString) AuthnContextClassRefBuilder(org.opensaml.saml.saml2.core.impl.AuthnContextClassRefBuilder) DateTime(org.joda.time.DateTime) SAML2IdP(org.apache.syncope.core.persistence.api.entity.SAML2IdP) NameIDPolicyBuilder(org.opensaml.saml.saml2.core.impl.NameIDPolicyBuilder) NameIDPolicy(org.opensaml.saml.saml2.core.NameIDPolicy) AuthnContextClassRef(org.opensaml.saml.saml2.core.AuthnContextClassRef) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) Date(java.util.Date) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) NotFoundException(org.apache.syncope.core.persistence.api.dao.NotFoundException) RequestedAuthnContextBuilder(org.opensaml.saml.saml2.core.impl.RequestedAuthnContextBuilder) RequestedAuthnContext(org.opensaml.saml.saml2.core.RequestedAuthnContext) SAML2IdPEntity(org.apache.syncope.core.logic.saml2.SAML2IdPEntity) AuthnRequest(org.opensaml.saml.saml2.core.AuthnRequest) XMLObject(org.opensaml.core.xml.XMLObject) IssuerBuilder(org.opensaml.saml.saml2.core.impl.IssuerBuilder) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 3 with SAML2RequestTO

use of org.apache.syncope.common.lib.to.SAML2RequestTO in project syncope by apache.

the class Login method doGet.

@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
    String idp = request.getParameter(Constants.PARAM_IDP);
    SyncopeClient anonymous = (SyncopeClient) request.getServletContext().getAttribute(Constants.SYNCOPE_ANONYMOUS_CLIENT);
    try {
        SAML2RequestTO requestTO = anonymous.getService(SAML2SPService.class).createLoginRequest(StringUtils.substringBefore(request.getRequestURL().toString(), "/saml2sp"), idp);
        prepare(response, requestTO);
    } catch (Exception e) {
        LOG.error("While preparing authentication request to IdP", e);
        String errorURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGIN_ERROR_URL);
        if (errorURL == null) {
            request.setAttribute("exception", e);
            request.getRequestDispatcher("loginError.jsp").forward(request, response);
            e.printStackTrace(response.getWriter());
        } else {
            response.sendRedirect(errorURL + "?errorMessage=" + URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8.name()));
        }
    }
}
Also used : SAML2SPService(org.apache.syncope.common.rest.api.service.SAML2SPService) SAML2RequestTO(org.apache.syncope.common.lib.to.SAML2RequestTO) SyncopeClient(org.apache.syncope.client.lib.SyncopeClient) ServletException(javax.servlet.ServletException) IOException(java.io.IOException)

Example 4 with SAML2RequestTO

use of org.apache.syncope.common.lib.to.SAML2RequestTO in project syncope by apache.

the class Logout method doGet.

@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
    String samlResponse = request.getParameter(SSOConstants.SAML_RESPONSE);
    String relayState = request.getParameter(SSOConstants.RELAY_STATE);
    if (samlResponse == null) {
        // prepare logout response
        SyncopeClientFactoryBean clientFactory = (SyncopeClientFactoryBean) request.getServletContext().getAttribute(Constants.SYNCOPE_CLIENT_FACTORY);
        try {
            String accessToken = (String) request.getSession().getAttribute(Constants.SAML2SPJWT);
            if (StringUtils.isBlank(accessToken)) {
                throw new IllegalArgumentException("No access token found ");
            }
            SyncopeClient client = clientFactory.create(accessToken);
            SAML2RequestTO requestTO = client.getService(SAML2SPService.class).createLogoutRequest(StringUtils.substringBefore(request.getRequestURL().toString(), "/saml2sp"));
            prepare(response, requestTO);
        } catch (Exception e) {
            LOG.error("While preparing logout request to IdP", e);
            String errorURL = getServletContext().getInitParameter(Constants.CONTEXT_PARAM_LOGOUT_ERROR_URL);
            if (errorURL == null) {
                request.setAttribute("exception", e);
                request.getRequestDispatcher("logoutError.jsp").forward(request, response);
                e.printStackTrace(response.getWriter());
            } else {
                response.sendRedirect(errorURL + "?errorMessage=" + URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8.name()));
            }
        }
    } else {
        // process REDIRECT binding logout response
        SAML2ReceivedResponseTO receivedResponse = new SAML2ReceivedResponseTO();
        receivedResponse.setSamlResponse(samlResponse);
        receivedResponse.setRelayState(relayState);
        doLogout(receivedResponse, request, response);
    }
}
Also used : SAML2SPService(org.apache.syncope.common.rest.api.service.SAML2SPService) SAML2RequestTO(org.apache.syncope.common.lib.to.SAML2RequestTO) SAML2ReceivedResponseTO(org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO) SyncopeClientFactoryBean(org.apache.syncope.client.lib.SyncopeClientFactoryBean) SyncopeClient(org.apache.syncope.client.lib.SyncopeClient) ServletException(javax.servlet.ServletException) IOException(java.io.IOException)

Example 5 with SAML2RequestTO

use of org.apache.syncope.common.lib.to.SAML2RequestTO in project syncope by apache.

the class SAML2ITCase method unsignedAssertionInLoginResponse.

@Test
public void unsignedAssertionInLoginResponse() throws Exception {
    assumeTrue(SAML2SPDetector.isSAML2SPAvailable());
    // Get a valid login request for the Fediz realm
    SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
    SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
    assertNotNull(loginRequest);
    SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
    response.setSpEntityID("http://recipient.apache.org/");
    response.setUrlContext("saml2sp");
    response.setRelayState(loginRequest.getRelayState());
    // Create a SAML Response using WSS4J
    JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
    String inResponseTo = relayState.getJwtClaims().getSubject();
    org.opensaml.saml.saml2.core.Response samlResponse = createResponse(inResponseTo, false, SAML2Constants.CONF_SENDER_VOUCHES, "urn:org:apache:cxf:fediz:idp:realm-A");
    Document doc = DOMUtils.newDocument();
    Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
    String responseStr = DOM2Writer.nodeToString(responseElement);
    // Validate the SAML Response
    response.setSamlResponse(Base64.getEncoder().encodeToString(responseStr.getBytes()));
    try {
        saml2Service.validateLoginResponse(response);
        fail("Failure expected on an unsigned Assertion");
    } catch (SyncopeClientException e) {
        assertNotNull(e);
    }
}
Also used : SAML2SPService(org.apache.syncope.common.rest.api.service.SAML2SPService) SAML2RequestTO(org.apache.syncope.common.lib.to.SAML2RequestTO) SAML2ReceivedResponseTO(org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO) Element(org.w3c.dom.Element) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) JwsJwtCompactConsumer(org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer) Document(org.w3c.dom.Document) Test(org.junit.jupiter.api.Test)

Aggregations

SAML2RequestTO (org.apache.syncope.common.lib.to.SAML2RequestTO)8 SAML2SPService (org.apache.syncope.common.rest.api.service.SAML2SPService)6 SyncopeClientException (org.apache.syncope.common.lib.SyncopeClientException)5 JwsJwtCompactConsumer (org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer)4 SAML2ReceivedResponseTO (org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO)4 Test (org.junit.jupiter.api.Test)4 Document (org.w3c.dom.Document)3 Element (org.w3c.dom.Element)3 IOException (java.io.IOException)2 Date (java.util.Date)2 HashMap (java.util.HashMap)2 ServletException (javax.servlet.ServletException)2 SyncopeClient (org.apache.syncope.client.lib.SyncopeClient)2 SAML2IdPEntity (org.apache.syncope.core.logic.saml2.SAML2IdPEntity)2 NotFoundException (org.apache.syncope.core.persistence.api.dao.NotFoundException)2 DateTime (org.joda.time.DateTime)2 XMLObject (org.opensaml.core.xml.XMLObject)2 XSString (org.opensaml.core.xml.schema.XSString)2 Issuer (org.opensaml.saml.saml2.core.Issuer)2 IssuerBuilder (org.opensaml.saml.saml2.core.impl.IssuerBuilder)2