Repository: cxf Updated Branches: refs/heads/master 253f87685 -> 6d2723015
[CXF-5674] - CXF Support in "Audience Restriction" of SAML 2 (SOAP) Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/6d272301 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/6d272301 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/6d272301 Branch: refs/heads/master Commit: 6d272301503bf6e74866b3e6f5c024c1447e0e2a Parents: 253f876 Author: Colm O hEigeartaigh <[email protected]> Authored: Thu Apr 17 14:07:20 2014 +0100 Committer: Colm O hEigeartaigh <[email protected]> Committed: Thu Apr 17 14:07:20 2014 +0100 ---------------------------------------------------------------------- .../saml/Saml2AudienceRestrictionValidator.java | 92 ++++++++++++++++++++ .../cxf/systest/ws/saml/SamlTokenTest.java | 59 +++++++++++++ .../StaxSaml2AudienceRestrictionValidator.java | 82 +++++++++++++++++ .../cxf/systest/ws/saml/DoubleItSaml.wsdl | 3 + .../org/apache/cxf/systest/ws/saml/server.xml | 20 ++++- .../apache/cxf/systest/ws/saml/stax-server.xml | 21 ++++- 6 files changed, 275 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/6d272301/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/Saml2AudienceRestrictionValidator.java ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/Saml2AudienceRestrictionValidator.java b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/Saml2AudienceRestrictionValidator.java new file mode 100644 index 0000000..add4394 --- /dev/null +++ b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/Saml2AudienceRestrictionValidator.java @@ -0,0 +1,92 @@ +/** + * 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.cxf.systest.ws.saml; + +import java.util.List; + +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.SamlAssertionWrapper; +import org.apache.wss4j.dom.handler.RequestData; +import org.apache.wss4j.dom.validate.Credential; +import org.apache.wss4j.dom.validate.SamlAssertionValidator; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction; +import org.opensaml.saml2.core.Conditions; + +/** + * This class checks that the Audiences received as part of AudienceRestrictions match a set + * list of endpoints. + */ +public class Saml2AudienceRestrictionValidator extends SamlAssertionValidator { + + private List<String> endpointAddresses; + + @Override + public Credential validate(Credential credential, RequestData data) throws WSSecurityException { + Credential validatedCredential = super.validate(credential, data); + SamlAssertionWrapper assertion = validatedCredential.getSamlAssertion(); + + Assertion saml2Assertion = assertion.getSaml2(); + if (saml2Assertion == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + + return validatedCredential; + } + + @Override + public void checkConditions(SamlAssertionWrapper samlAssertion) throws WSSecurityException { + super.checkConditions(samlAssertion); + + if (endpointAddresses == null || endpointAddresses.isEmpty()) { + return; + } + + Conditions conditions = samlAssertion.getSaml2().getConditions(); + if (conditions != null && conditions.getAudienceRestrictions() != null) { + boolean foundAddress = false; + for (AudienceRestriction audienceRestriction : conditions.getAudienceRestrictions()) { + List<Audience> audiences = audienceRestriction.getAudiences(); + if (audiences != null) { + for (Audience audience : audiences) { + String audienceURI = audience.getAudienceURI(); + if (endpointAddresses.contains(audienceURI)) { + foundAddress = true; + break; + } + } + } + } + + if (!foundAddress) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + } + } + + public List<String> getEndpointAddresses() { + return endpointAddresses; + } + + public void setEndpointAddresses(List<String> endpointAddresses) { + this.endpointAddresses = endpointAddresses; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/6d272301/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/SamlTokenTest.java ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/SamlTokenTest.java b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/SamlTokenTest.java index b9b8c29..8291675 100644 --- a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/SamlTokenTest.java +++ b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/SamlTokenTest.java @@ -20,8 +20,11 @@ package org.apache.cxf.systest.ws.saml; import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.List; import javax.xml.namespace.QName; import javax.xml.ws.BindingProvider; @@ -39,6 +42,7 @@ import org.apache.cxf.systest.ws.saml.client.SamlRoleCallbackHandler; import org.apache.cxf.systest.ws.ut.SecurityHeaderCacheInterceptor; import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; import org.apache.cxf.ws.security.SecurityConstants; +import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean; import org.apache.wss4j.common.saml.bean.ConditionsBean; import org.apache.wss4j.common.saml.bean.KeyInfoBean.CERT_IDENTIFIER; import org.apache.wss4j.common.saml.builder.SAML1Constants; @@ -996,4 +1000,59 @@ public class SamlTokenTest extends AbstractBusClientServerTestBase { bus.shutdown(true); } + @org.junit.Test + public void testAudienceRestriction() throws Exception { + + SpringBusFactory bf = new SpringBusFactory(); + URL busFile = SamlTokenTest.class.getResource("client.xml"); + + Bus bus = bf.createBus(busFile.toString()); + SpringBusFactory.setDefaultBus(bus); + SpringBusFactory.setThreadDefaultBus(bus); + + URL wsdl = SamlTokenTest.class.getResource("DoubleItSaml.wsdl"); + Service service = Service.create(wsdl, SERVICE_QNAME); + QName portQName = new QName(NAMESPACE, "DoubleItSaml2TransportPort2"); + DoubleItPortType saml2Port = + service.getPort(portQName, DoubleItPortType.class); + String portNumber = PORT2; + if (STAX_PORT.equals(test.getPort())) { + portNumber = STAX_PORT2; + } + updateAddressPort(saml2Port, portNumber); + + // Create a SAML Token with an AudienceRestrictionCondition + ConditionsBean conditions = new ConditionsBean(); + List<AudienceRestrictionBean> audienceRestrictions = new ArrayList<AudienceRestrictionBean>(); + AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean(); + audienceRestriction.setAudienceURIs(Collections.singletonList( + "https://localhost:" + portNumber + "/DoubleItSaml2Transport2")); + audienceRestrictions.add(audienceRestriction); + conditions.setAudienceRestrictions(audienceRestrictions); + + SamlCallbackHandler callbackHandler = new SamlCallbackHandler(); + callbackHandler.setConditions(conditions); + ((BindingProvider)saml2Port).getRequestContext().put( + "ws-security.saml-callback-handler", callbackHandler + ); + + saml2Port.doubleIt(25); + + try { + // Now use an "unknown" audience restriction + audienceRestriction = new AudienceRestrictionBean(); + audienceRestriction.setAudienceURIs(Collections.singletonList( + "https://localhost:" + portNumber + "/DoubleItSaml2Transport2unknown")); + audienceRestrictions.clear(); + audienceRestrictions.add(audienceRestriction); + conditions.setAudienceRestrictions(audienceRestrictions); + callbackHandler.setConditions(conditions); + + saml2Port.doubleIt(25); + fail("Failure expected on unknown AudienceRestriction"); + } catch (javax.xml.ws.soap.SOAPFaultException ex) { + // expected + } + } + } http://git-wip-us.apache.org/repos/asf/cxf/blob/6d272301/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/StaxSaml2AudienceRestrictionValidator.java ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/StaxSaml2AudienceRestrictionValidator.java b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/StaxSaml2AudienceRestrictionValidator.java new file mode 100644 index 0000000..778c068 --- /dev/null +++ b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/saml/StaxSaml2AudienceRestrictionValidator.java @@ -0,0 +1,82 @@ +/** + * 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.cxf.systest.ws.saml; + +import java.util.List; + +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.SamlAssertionWrapper; +import org.apache.wss4j.stax.validate.SamlTokenValidatorImpl; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction; +import org.opensaml.saml2.core.Conditions; + +/** + * This class checks that the Audiences received as part of AudienceRestrictions match a set + * list of endpoints. + */ +public class StaxSaml2AudienceRestrictionValidator extends SamlTokenValidatorImpl { + + private List<String> endpointAddresses; + + @Override + public void checkConditions(SamlAssertionWrapper samlAssertion) throws WSSecurityException { + super.checkConditions(samlAssertion); + + Assertion saml2Assertion = samlAssertion.getSaml2(); + if (saml2Assertion == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + + if (endpointAddresses == null || endpointAddresses.isEmpty()) { + return; + } + + Conditions conditions = samlAssertion.getSaml2().getConditions(); + if (conditions != null && conditions.getAudienceRestrictions() != null) { + boolean foundAddress = false; + for (AudienceRestriction audienceRestriction : conditions.getAudienceRestrictions()) { + List<Audience> audiences = audienceRestriction.getAudiences(); + if (audiences != null) { + for (Audience audience : audiences) { + String audienceURI = audience.getAudienceURI(); + if (endpointAddresses.contains(audienceURI)) { + foundAddress = true; + break; + } + } + } + } + + if (!foundAddress) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + } + } + + public List<String> getEndpointAddresses() { + return endpointAddresses; + } + + public void setEndpointAddresses(List<String> endpointAddresses) { + this.endpointAddresses = endpointAddresses; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/6d272301/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl index 080f78b..755e2e1 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl @@ -380,6 +380,9 @@ <wsdl:port name="DoubleItSaml2TransportPort" binding="tns:DoubleItSaml2TransportBinding"> <soap:address location="https://localhost:9009/DoubleItSaml2Transport"/> </wsdl:port> + <wsdl:port name="DoubleItSaml2TransportPort2" binding="tns:DoubleItSaml2TransportBinding"> + <soap:address location="https://localhost:9009/DoubleItSaml2Transport2"/> + </wsdl:port> </wsdl:service> <wsp:Policy wsu:Id="DoubleItSaml1TransportPolicy"> <wsp:ExactlyOne> http://git-wip-us.apache.org/repos/asf/cxf/blob/6d272301/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/server.xml ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/server.xml b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/server.xml index ed1315c..97a6bfa 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/server.xml +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/server.xml @@ -17,7 +17,7 @@ specific language governing permissions and limitations under the License. --> -<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://cxf.apa che.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd "> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/sc hemas/configuration/http-conf.xsd http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd "> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> <cxf:bus> <cxf:features> @@ -258,4 +258,22 @@ <entry key="ws-security.subject.cert.constraints" value=".*O=apache.org.*"/> </jaxws:properties> </jaxws:endpoint> + + <bean id="audienceRestrictionValidator" class="org.apache.cxf.systest.ws.saml.Saml2AudienceRestrictionValidator"> + <property name="endpointAddresses"> + <list> + <value>https://localhost:${testutil.ports.Server.2}/DoubleItSaml2Transport2</value> + <value>https://localhost:${testutil.ports.StaxServer.2}/DoubleItSaml2Transport2</value> + </list> + </property> + </bean> + + <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="Saml2TransportToken2" address="https://localhost:${testutil.ports.Server.2}/DoubleItSaml2Transport2" serviceName="s:DoubleItService" endpointName="s:DoubleItSaml2TransportPort2" implementor="org.apache.cxf.systest.ws.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl" depends-on="tls-settings"> + <jaxws:properties> + <entry key="ws-security.callback-handler" value="org.apache.cxf.systest.ws.common.KeystorePasswordCallback"/> + <entry key="ws-security.signature.properties" value="bob.properties"/> + <entry key="ws-security.subject.cert.constraints" value=".*O=apache.org.*"/> + <entry key="ws-security.saml2.validator" value-ref="audienceRestrictionValidator"/> + </jaxws:properties> + </jaxws:endpoint> </beans> http://git-wip-us.apache.org/repos/asf/cxf/blob/6d272301/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/stax-server.xml ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/stax-server.xml b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/stax-server.xml index 4fb7310..0750c09 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/stax-server.xml +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/stax-server.xml @@ -17,7 +17,7 @@ specific language governing permissions and limitations under the License. --> -<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://cxf.apa che.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd "> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/sc hemas/configuration/http-conf.xsd http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd "> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> <cxf:bus> <cxf:features> @@ -284,4 +284,23 @@ <entry key="ws-security.enable.streaming" value="true"/> </jaxws:properties> </jaxws:endpoint> + + <bean id="audienceRestrictionValidator" class="org.apache.cxf.systest.ws.saml.StaxSaml2AudienceRestrictionValidator"> + <property name="endpointAddresses"> + <list> + <value>https://localhost:${testutil.ports.Server.2}/DoubleItSaml2Transport2</value> + <value>https://localhost:${testutil.ports.StaxServer.2}/DoubleItSaml2Transport2</value> + </list> + </property> + </bean> + + <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="Saml2TransportToken2" address="https://localhost:${testutil.ports.StaxServer.2}/DoubleItSaml2Transport2" serviceName="s:DoubleItService" endpointName="s:DoubleItSaml2TransportPort2" implementor="org.apache.cxf.systest.ws.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl" depends-on="tls-settings"> + <jaxws:properties> + <entry key="ws-security.callback-handler" value="org.apache.cxf.systest.ws.common.KeystorePasswordCallback"/> + <entry key="ws-security.signature.properties" value="bob.properties"/> + <entry key="ws-security.subject.cert.constraints" value=".*O=apache.org.*"/> + <entry key="ws-security.enable.streaming" value="true"/> + <entry key="ws-security.saml2.validator" value-ref="audienceRestrictionValidator"/> + </jaxws:properties> + </jaxws:endpoint> </beans>
