package org.pac4j.saml.sso.impl; import java.util.Optional; import org.apache.commons.lang.RandomStringUtils; import org.joda.time.DateTime; import org.opensaml.core.xml.XMLObjectBuilderFactory; import org.opensaml.saml.common.SAMLObjectBuilder; import org.opensaml.saml.common.SAMLVersion; import org.opensaml.saml.common.messaging.context.SAMLSelfEntityContext; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.core.Issuer; import org.opensaml.saml.saml2.core.LogoutRequest; import org.opensaml.saml.saml2.core.NameID; import org.opensaml.saml.saml2.core.SessionIndex; import org.opensaml.saml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml.saml2.metadata.SingleLogoutService; import org.pac4j.core.profile.ProfileManager; import org.pac4j.core.profile.UserProfile; import org.pac4j.saml.context.SAML2MessageContext; import org.pac4j.saml.profile.SAML2Profile; import org.pac4j.saml.sso.SAML2ObjectBuilder; import org.pac4j.saml.util.Configuration; /** * Build a SAML2 Logout Request * * @author Matthieu Taggiasco * @since 2.0.0 */ public class SAML2LogoutRequestBuilder implements SAML2ObjectBuilder<LogoutRequest> { private String bindingType = SAMLConstants.SAML2_POST_BINDING_URI; private int issueInstantSkewSeconds = 0; private final XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); /** * Instantiates a new Saml 2 logout request builder. * * @param bindingType the binding type */ public SAML2LogoutRequestBuilder(final String bindingType) { this.bindingType = bindingType; } @Override public LogoutRequest build(SAML2MessageContext context) { final SingleLogoutService ssoService = context.getIDPSingleLogoutService(this.bindingType); final AssertionConsumerService assertionConsumerService = context.getSPAssertionConsumerService(); return buildLogoutRequest(context, assertionConsumerService, ssoService); } @SuppressWarnings("unchecked") protected final LogoutRequest buildLogoutRequest(final SAML2MessageContext context, final AssertionConsumerService assertionConsumerService, final SingleLogoutService ssoService) { final SAMLObjectBuilder<LogoutRequest> builder = (SAMLObjectBuilder<LogoutRequest>) this.builderFactory .getBuilder(LogoutRequest.DEFAULT_ELEMENT_NAME); final LogoutRequest request = builder.buildObject(); final SAMLSelfEntityContext selfContext = context.getSAMLSelfEntityContext(); request.setID(generateID()); request.setIssuer(getIssuer(selfContext.getEntityId())); request.setIssueInstant(DateTime.now().plusSeconds(this.issueInstantSkewSeconds)); request.setVersion(SAMLVersion.VERSION_20); request.setDestination(ssoService.getLocation()); // very very bad... ProfileManager manager = new ProfileManager(context.getWebContext()); Optional<UserProfile> p = manager.get(true); if(p.isPresent() && p.get() instanceof SAML2Profile) { final SAML2Profile samlP = (SAML2Profile) p.get(); // name id added (id of profile) final SAMLObjectBuilder<NameID> nameIdBuilder = (SAMLObjectBuilder<NameID>) this.builderFactory.getBuilder(NameID.DEFAULT_ELEMENT_NAME); final NameID nameId = nameIdBuilder.buildObject(); nameId.setValue(samlP.getId()); request.setNameID(nameId); // session index added final String sessIdx = (String) samlP.getAttribute("sessionindex"); final SAMLObjectBuilder<SessionIndex> sessionIndexBuilder = (SAMLObjectBuilder<SessionIndex>) this.builderFactory.getBuilder(SessionIndex.DEFAULT_ELEMENT_NAME); final SessionIndex sessionIdx = sessionIndexBuilder.buildObject(); sessionIdx.setSessionIndex(sessIdx); request.getSessionIndexes().add(sessionIdx); } return request; } @SuppressWarnings("unchecked") protected final Issuer getIssuer(final String spEntityId) { final SAMLObjectBuilder<Issuer> issuerBuilder = (SAMLObjectBuilder<Issuer>) this.builderFactory .getBuilder(Issuer.DEFAULT_ELEMENT_NAME); final Issuer issuer = issuerBuilder.buildObject(); issuer.setValue(spEntityId); return issuer; } protected final String generateID() { return "_".concat(RandomStringUtils.randomAlphanumeric(39)).toLowerCase(); } public void setIssueInstantSkewSeconds(final int issueInstantSkewSeconds) { this.issueInstantSkewSeconds = issueInstantSkewSeconds; } }