Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 88AD3200C54 for ; Wed, 12 Apr 2017 17:10:52 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 87740160BAD; Wed, 12 Apr 2017 15:10:52 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 62428160B8A for ; Wed, 12 Apr 2017 17:10:51 +0200 (CEST) Received: (qmail 79874 invoked by uid 500); 12 Apr 2017 15:10:50 -0000 Mailing-List: contact commits-help@syncope.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@syncope.apache.org Delivered-To: mailing list commits@syncope.apache.org Received: (qmail 79841 invoked by uid 99); 12 Apr 2017 15:10:50 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Apr 2017 15:10:50 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id DC1EFE9638; Wed, 12 Apr 2017 15:10:49 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: ilgrosso@apache.org To: commits@syncope.apache.org Date: Wed, 12 Apr 2017 15:10:51 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [3/4] syncope git commit: [SYNCOPE-1061] Both POST and Redirect binding profiles are now supported; if both are available for a given IdP, the one to be used is configurable, with POST predefined archived-at: Wed, 12 Apr 2017 15:10:52 -0000 http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java deleted file mode 100644 index 87c5220..0000000 --- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2Signer.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.core.logic.saml2; - -import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import javax.xml.transform.TransformerException; -import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder; -import org.apache.syncope.core.logic.init.SAML2SPLoader; -import org.apache.wss4j.common.ext.WSSecurityException; -import org.apache.wss4j.common.saml.OpenSAMLUtil; -import org.opensaml.saml.common.SignableSAMLObject; -import org.opensaml.saml.saml2.core.RequestAbstractType; -import org.opensaml.security.SecurityException; -import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator; -import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory; -import org.opensaml.xmlsec.signature.Signature; -import org.opensaml.xmlsec.signature.support.SignatureConstants; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class SAML2Signer { - - @Autowired - private SAML2SPLoader loader; - - @Autowired - private SAML2ReaderWriter saml2rw; - - private KeyInfoGenerator keyInfoGenerator; - - private String signatureAlgorithm; - - public void init() { - X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); - keyInfoGeneratorFactory.setEmitEntityCertificate(true); - keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); - - signatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1; - String pubKeyAlgo = loader.getCredential().getPublicKey().getAlgorithm(); - if (pubKeyAlgo.equalsIgnoreCase("DSA")) { - signatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_DSA_SHA1; - } - } - - public String signAndEncode(final RequestAbstractType request, final boolean useDeflateEncoding) - throws SecurityException, WSSecurityException, TransformerException, IOException { - - // 1. sign request - Signature signature = OpenSAMLUtil.buildSignature(); - signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); - signature.setSignatureAlgorithm(signatureAlgorithm); - signature.setSigningCredential(loader.getCredential()); - signature.setKeyInfo(keyInfoGenerator.generate(loader.getCredential())); - - SignableSAMLObject signableObject = (SignableSAMLObject) request; - signableObject.setSignature(signature); - signableObject.releaseDOM(); - signableObject.releaseChildrenDOM(true); - - // 2. serialize and encode request - StringWriter writer = new StringWriter(); - saml2rw.write(writer, request, true); - writer.close(); - - String requestMessage = writer.toString(); - byte[] deflatedBytes; - // not correct according to the spec but required by some IdPs. - if (useDeflateEncoding) { - deflatedBytes = new DeflateEncoderDecoder(). - deflateToken(requestMessage.getBytes(StandardCharsets.UTF_8)); - } else { - deflatedBytes = requestMessage.getBytes(StandardCharsets.UTF_8); - } - - return Base64.getEncoder().encodeToString(deflatedBytes); - } - -} http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSPCallbackHandler.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSPCallbackHandler.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSPCallbackHandler.java new file mode 100644 index 0000000..33badc4 --- /dev/null +++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSPCallbackHandler.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.core.logic.saml2; + +import java.io.IOException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import org.apache.wss4j.common.ext.WSPasswordCallback; + +public class SAMLSPCallbackHandler implements CallbackHandler { + + private final String keyPass; + + public SAMLSPCallbackHandler(final String keyPass) { + this.keyPass = keyPass; + } + + @Override + public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (Callback callback : callbacks) { + if (callback instanceof WSPasswordCallback) { + WSPasswordCallback wspc = (WSPasswordCallback) callback; + wspc.setPassword(keyPass); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/persistence-api/pom.xml ---------------------------------------------------------------------- diff --git a/ext/saml2sp/persistence-api/pom.xml b/ext/saml2sp/persistence-api/pom.xml index 80bfd3a..843c8aa 100644 --- a/ext/saml2sp/persistence-api/pom.xml +++ b/ext/saml2sp/persistence-api/pom.xml @@ -43,6 +43,11 @@ under the License. syncope-core-persistence-api ${project.version} + + org.apache.syncope.ext.saml2sp + syncope-ext-saml2sp-common-lib + ${project.version} + http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java b/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java index a71579f..b6fc4c3 100644 --- a/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java +++ b/ext/saml2sp/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/SAML2IdP.java @@ -19,6 +19,7 @@ package org.apache.syncope.core.persistence.api.entity; import java.util.List; +import org.apache.syncope.common.lib.types.SAML2BindingType; import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; public interface SAML2IdP extends Entity { @@ -39,6 +40,10 @@ public interface SAML2IdP extends Entity { void setUseDeflateEncoding(boolean useDeflateEncoding); + SAML2BindingType getBindingType(); + + void setBindingType(SAML2BindingType bindingType); + MappingItem getConnObjectKeyItem(); void setConnObjectKeyItem(MappingItem item); http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java index 879b3e5..1a41bbc 100644 --- a/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java +++ b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPASAML2IdP.java @@ -34,6 +34,7 @@ import javax.validation.constraints.Min; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.Predicate; import org.apache.commons.lang3.ArrayUtils; +import org.apache.syncope.common.lib.types.SAML2BindingType; import org.apache.syncope.core.persistence.api.entity.SAML2IdP; import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMappingItem; @@ -67,6 +68,9 @@ public class JPASAML2IdP extends AbstractGeneratedKeyEntity implements SAML2IdP @Column(nullable = false) private Integer useDeflateEncoding; + @Column(nullable = false) + private SAML2BindingType bindingType; + @Override public String getEntityID() { return entityID; @@ -108,6 +112,16 @@ public class JPASAML2IdP extends AbstractGeneratedKeyEntity implements SAML2IdP } @Override + public SAML2BindingType getBindingType() { + return bindingType; + } + + @Override + public void setBindingType(final SAML2BindingType bindingType) { + this.bindingType = bindingType; + } + + @Override public boolean add(final MappingItem item) { checkType(item, JPAMappingItem.class); return mappingItems.contains((JPAMappingItem) item) || mappingItems.add((JPAMappingItem) item); http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java index 351c487..5eba217 100644 --- a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java +++ b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java @@ -172,6 +172,7 @@ public class SAML2IdPDataBinderImpl implements SAML2IdPDataBinder { idp.setName(idpTO.getName()); idp.setMetadata(Base64.decode(idpTO.getMetadata())); idp.setUseDeflateEncoding(idpTO.isUseDeflateEncoding()); + idp.setBindingType(idpTO.getBindingType()); idp.getMappingItems().clear(); AnyTypeClassTO allowedSchemas = new AnyTypeClassTO(); @@ -214,6 +215,7 @@ public class SAML2IdPDataBinderImpl implements SAML2IdPDataBinder { idpTO.setEntityID(idp.getEntityID()); idpTO.setName(idp.getName()); idpTO.setUseDeflateEncoding(idp.isUseDeflateEncoding()); + idpTO.setBindingType(idp.getBindingType()); idpTO.setMetadata(Base64.encode(idp.getMetadata())); populateMappingTO(idp, idpTO); http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPService.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPService.java b/ext/saml2sp/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPService.java index f9c2cf4..f3d420c 100644 --- a/ext/saml2sp/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPService.java +++ b/ext/saml2sp/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPService.java @@ -18,7 +18,7 @@ */ package org.apache.syncope.common.rest.api.service; -import java.io.InputStream; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -28,6 +28,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.syncope.common.lib.to.SAML2RequestTO; import org.apache.syncope.common.lib.to.SAML2LoginResponseTO; +import org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO; /** * REST operations for the provided SAML 2.0 Service Provider. @@ -39,11 +40,12 @@ public interface SAML2SPService extends JAXRSService { * Returns the XML metadata for the provided SAML 2.0 Service Provider. * * @param spEntityID SAML 2.0 SP entity ID. + * @param urlContext SAML 2.0 SP agent URL context * @return XML metadata for the provided SAML 2.0 Service Provider */ @GET @Produces({ MediaType.APPLICATION_XML }) - Response getMetadata(@QueryParam("spEntityID") String spEntityID); + Response getMetadata(@QueryParam("spEntityID") String spEntityID, @QueryParam("urlContext") String urlContext); /** * Generates SAML 2.0 authentication request for the IdP matching the provided entity ID. @@ -62,13 +64,14 @@ public interface SAML2SPService extends JAXRSService { /** * Validates the received SAML 2.0 authentication response and creates JWT for the matching user, if found. * - * @param response SAML 2.0 authentication response + * @param response SAML response and relay state * @return JWT for the matching user plus attributes returned in the response */ @POST @Path("loginResponse") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - SAML2LoginResponseTO validateLoginResponse(InputStream response); + SAML2LoginResponseTO validateLoginResponse(SAML2ReceivedResponseTO response); /** * Generates SAML 2.0 logout request for the IdP matching the requesting access token. @@ -84,10 +87,11 @@ public interface SAML2SPService extends JAXRSService { /** * Validates the received SAML 2.0 logout response. * - * @param response SAML 2.0 logout response + * @param response SAML response and relay state */ @POST @Path("logoutResponse") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - void validateLogoutResponse(InputStream response); + void validateLogoutResponse(SAML2ReceivedResponseTO response); } http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java b/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java index d9d3dc6..191081f 100644 --- a/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java +++ b/ext/saml2sp/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPServiceImpl.java @@ -19,7 +19,6 @@ package org.apache.syncope.core.rest.cxf.service; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -27,6 +26,7 @@ import javax.ws.rs.core.StreamingOutput; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.to.SAML2RequestTO; import org.apache.syncope.common.lib.to.SAML2LoginResponseTO; +import org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO; import org.apache.syncope.common.rest.api.RESTHeaders; import org.apache.syncope.common.rest.api.service.SAML2SPService; import org.apache.syncope.core.logic.SAML2SPLogic; @@ -40,12 +40,12 @@ public class SAML2SPServiceImpl extends AbstractServiceImpl implements SAML2SPSe private SAML2SPLogic logic; @Override - public Response getMetadata(final String spEntityID) { + public Response getMetadata(final String spEntityID, final String urlContext) { StreamingOutput sout = new StreamingOutput() { @Override public void write(final OutputStream os) throws IOException { - logic.getMetadata(StringUtils.appendIfMissing(spEntityID, "/"), os); + logic.getMetadata(StringUtils.appendIfMissing(spEntityID, "/"), urlContext, os); } }; return Response.ok(sout). @@ -61,8 +61,8 @@ public class SAML2SPServiceImpl extends AbstractServiceImpl implements SAML2SPSe } @Override - public SAML2LoginResponseTO validateLoginResponse(final InputStream response) { - return logic.validateLoginResponse(response); + public SAML2LoginResponseTO validateLoginResponse(final SAML2ReceivedResponseTO reponse) { + return logic.validateLoginResponse(reponse); } @Override @@ -73,10 +73,8 @@ public class SAML2SPServiceImpl extends AbstractServiceImpl implements SAML2SPSe } @Override - public void validateLogoutResponse(final InputStream response) { - logic.validateLogoutResponse( - messageContext.getHttpHeaders().getHeaderString(RESTHeaders.TOKEN), - response); + public void validateLogoutResponse(final SAML2ReceivedResponseTO response) { + logic.validateLogoutResponse(messageContext.getHttpHeaders().getHeaderString(RESTHeaders.TOKEN), response); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/fit/core-reference/src/test/java/org/apache/syncope/fit/SAML2SPDetector.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/SAML2SPDetector.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/SAML2SPDetector.java index 88c4473..52604c1 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/SAML2SPDetector.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/SAML2SPDetector.java @@ -39,7 +39,7 @@ public class SAML2SPDetector { setContentType(SyncopeClientFactoryBean.ContentType.XML). create(new AnonymousAuthenticationHandler( AbstractITCase.ANONYMOUS_UNAME, AbstractITCase.ANONYMOUS_KEY)). - getService(SAML2SPService.class).getMetadata("http://localhost:9080/syncope"); + getService(SAML2SPService.class).getMetadata("http://localhost:9080/syncope", "saml2sp"); ENABLED = true; } catch (Exception e) { // ignore http://git-wip-us.apache.org/repos/asf/syncope/blob/847e0c9b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java index 5e1647b..ece9e6c 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java @@ -100,7 +100,7 @@ public class SAML2ITCase extends AbstractITCase { try { SAML2SPService service = anonymous.getService(SAML2SPService.class); WebClient.client(service).accept(MediaType.APPLICATION_XML_TYPE); - Response response = service.getMetadata(ADDRESS); + Response response = service.getMetadata(ADDRESS, "saml2sp"); assertNotNull(response); Document responseDoc = StaxUtils.read(