Repository: cxf Updated Branches: refs/heads/master 75115ee15 -> 7a5263686
Adding a new PEP interceptor which is opensaml-agnostic Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/7a526368 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/7a526368 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/7a526368 Branch: refs/heads/master Commit: 7a52636862d2d920a2a6d5c5f00821611b7faa37 Parents: 75115ee Author: Colm O hEigeartaigh <cohei...@apache.org> Authored: Thu Jul 16 14:10:01 2015 +0100 Committer: Colm O hEigeartaigh <cohei...@apache.org> Committed: Thu Jul 16 14:10:01 2015 +0100 ---------------------------------------------------------------------- .../AbstractXACMLAuthorizingInterceptor.java | 2 +- .../saml/xacml/DefaultXACMLRequestBuilder.java | 3 + .../saml/xacml/XACMLAuthorizingInterceptor.java | 12 +- .../saml/xacml/XACMLRequestBuilder.java | 3 + .../AbstractXACMLAuthorizingInterceptor.java | 112 +++++++ .../OpenSAMLXACMLAuthorizingInterceptor.java | 158 ++++++++++ .../xacml/pep/OpenSAMLXACMLRequestBuilder.java | 209 +++++++++++++ .../saml/xacml/pep/XACMLRequestBuilder.java | 44 +++ .../saml/xacml/OldXACMLRequestBuilderTest.java | 308 +++++++++++++++++++ .../saml/xacml/XACMLRequestBuilderTest.java | 39 +-- .../cxf/systest/ws/saml/SamlTokenTest.java | 48 +++ .../cxf/systest/ws/saml/DoubleItSaml.wsdl | 3 + .../org/apache/cxf/systest/ws/saml/client.xml | 6 + .../org/apache/cxf/systest/ws/saml/server.xml | 13 + .../apache/cxf/systest/ws/saml/stax-server.xml | 15 + 15 files changed, 953 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/AbstractXACMLAuthorizingInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/AbstractXACMLAuthorizingInterceptor.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/AbstractXACMLAuthorizingInterceptor.java index 590b324..3ece64a 100644 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/AbstractXACMLAuthorizingInterceptor.java +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/AbstractXACMLAuthorizingInterceptor.java @@ -55,7 +55,7 @@ import org.opensaml.xacml.ctx.StatusType; * * This class must be subclassed to actually perform the request to the PDP. * - * @deprecated: Use XACMLAuthorizingInterceptor instead + * @deprecated: Use pep.AbstractXACMLAuthorizingInterceptor instead */ @Deprecated public abstract class AbstractXACMLAuthorizingInterceptor extends AbstractPhaseInterceptor<Message> { http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/DefaultXACMLRequestBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/DefaultXACMLRequestBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/DefaultXACMLRequestBuilder.java index 02d115f..ded3025 100644 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/DefaultXACMLRequestBuilder.java +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/DefaultXACMLRequestBuilder.java @@ -51,7 +51,10 @@ import org.opensaml.xacml.ctx.SubjectType; * For a REST service the request URL is the resource. You can also configure the ability to * send the truncated request URI instead for a SOAP or REST service. The current DateTime is * also sent in an Environment, however this can be disabled via configuration. + * + * @deprecated: Use pep.OpenSAMLXACMLRequestBuilder instead */ +@Deprecated public class DefaultXACMLRequestBuilder implements XACMLRequestBuilder { private boolean sendDateTime = true; http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLAuthorizingInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLAuthorizingInterceptor.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLAuthorizingInterceptor.java index 065c5a9..d198c43 100644 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLAuthorizingInterceptor.java +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLAuthorizingInterceptor.java @@ -19,6 +19,7 @@ package org.apache.cxf.rt.security.saml.xacml; +import javax.xml.XMLConstants; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; @@ -41,8 +42,10 @@ import org.opensaml.xacml.ctx.ResponseType; * and make an authorization decision based on the response. It takes the principal and roles * from the SecurityContext, and uses the XACMLRequestBuilder to construct an XACML Request * statement. + * + * @deprecated: Use pep.OpenSAMLXACMLAuthorizingInterceptor instead */ -@SuppressWarnings("deprecation") +@Deprecated public class XACMLAuthorizingInterceptor extends AbstractXACMLAuthorizingInterceptor { private PolicyDecisionPoint pdp; @@ -71,9 +74,12 @@ public class XACMLAuthorizingInterceptor extends AbstractXACMLAuthorizingInterce private ResponseType responseSourceToResponseType(Source responseSource) { try { - Transformer trans = TransformerFactory.newInstance().newTransformer(); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer transformer = transformerFactory.newTransformer(); + DOMResult res = new DOMResult(); - trans.transform(responseSource, res); + transformer.transform(responseSource, res); Node nd = res.getNode(); if (nd instanceof Document) { nd = ((Document)nd).getDocumentElement(); http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilder.java index d3bd32c..f41c447 100644 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilder.java +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilder.java @@ -28,7 +28,10 @@ import org.opensaml.xacml.ctx.RequestType; /** * This interface defines a way to create an XACML Request. + * + * @deprecated use pep.XACMLRequestBuilder instead */ +@Deprecated public interface XACMLRequestBuilder { /** http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/AbstractXACMLAuthorizingInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/AbstractXACMLAuthorizingInterceptor.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/AbstractXACMLAuthorizingInterceptor.java new file mode 100644 index 0000000..5337a5c --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/AbstractXACMLAuthorizingInterceptor.java @@ -0,0 +1,112 @@ +/** + * 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.rt.security.saml.xacml.pep; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.interceptor.security.AccessDeniedException; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.AbstractPhaseInterceptor; +import org.apache.cxf.phase.Phase; +import org.apache.cxf.security.LoginSecurityContext; +import org.apache.cxf.security.SecurityContext; + + +/** + * An abstract interceptor to perform an XACML authorization request to a remote PDP, + * and make an authorization decision based on the response. It takes the principal and roles + * from the SecurityContext, and uses the XACMLRequestBuilder to construct an XACML Request + * statement. + * + * This class must be subclassed to actually perform the request to the PDP and to parse + * the response. + */ +public abstract class AbstractXACMLAuthorizingInterceptor extends AbstractPhaseInterceptor<Message> { + + private static final Logger LOG = LogUtils.getL7dLogger(AbstractXACMLAuthorizingInterceptor.class); + + private XACMLRequestBuilder requestBuilder = new OpenSAMLXACMLRequestBuilder(); + + public AbstractXACMLAuthorizingInterceptor() { + super(Phase.PRE_INVOKE); + org.apache.wss4j.common.saml.OpenSAMLUtil.initSamlEngine(); + } + + public void handleMessage(Message message) throws Fault { + SecurityContext sc = message.get(SecurityContext.class); + + if (sc instanceof LoginSecurityContext) { + Principal principal = sc.getUserPrincipal(); + + LoginSecurityContext loginSecurityContext = (LoginSecurityContext)sc; + Set<Principal> principalRoles = loginSecurityContext.getUserRoles(); + List<String> roles = new ArrayList<>(); + if (principalRoles != null) { + for (Principal p : principalRoles) { + if (p != principal) { + roles.add(p.getName()); + } + } + } + + try { + Object request = requestBuilder.createRequest(principal, roles, message); + + if (authorize(request, principal, message)) { + return; + } + } catch (Exception e) { + LOG.log(Level.FINE, "Unauthorized: " + e.getMessage(), e); + throw new AccessDeniedException("Unauthorized"); + } + } else { + LOG.log( + Level.FINE, + "The SecurityContext was not an instance of LoginSecurityContext. No authorization " + + "is possible as a result" + ); + } + + throw new AccessDeniedException("Unauthorized"); + } + + public XACMLRequestBuilder getRequestBuilder() { + return requestBuilder; + } + + public void setRequestBuilder(XACMLRequestBuilder requestBuilder) { + this.requestBuilder = requestBuilder; + } + + /** + * Perform a (remote) authorization decision and return a boolean depending on the result + */ + protected abstract boolean authorize( + Object xacmlRequest, Principal principal, Message message + ) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLAuthorizingInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLAuthorizingInterceptor.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLAuthorizingInterceptor.java new file mode 100644 index 0000000..9b8b3d7 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLAuthorizingInterceptor.java @@ -0,0 +1,158 @@ +/** + * 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.rt.security.saml.xacml.pep; + +import java.security.Principal; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.XMLConstants; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.helpers.DOMUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.rt.security.saml.xacml.pdp.api.PolicyDecisionPoint; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.OpenSAMLUtil; +import org.apache.wss4j.common.util.DOM2Writer; +import org.opensaml.xacml.ctx.DecisionType.DECISION; +import org.opensaml.xacml.ctx.RequestType; +import org.opensaml.xacml.ctx.ResponseType; +import org.opensaml.xacml.ctx.ResultType; +import org.opensaml.xacml.ctx.StatusType; + +/** + * An interceptor to perform an XACML 2.0 authorization request to a remote PDP using OpenSAML, + * and make an authorization decision based on the response. It takes the principal and roles + * from the SecurityContext, and uses the XACMLRequestBuilder to construct an XACML Request + * statement. + */ +public class OpenSAMLXACMLAuthorizingInterceptor extends AbstractXACMLAuthorizingInterceptor { + private static final Logger LOG = LogUtils.getL7dLogger(OpenSAMLXACMLAuthorizingInterceptor.class); + + private PolicyDecisionPoint pdp; + + public OpenSAMLXACMLAuthorizingInterceptor(PolicyDecisionPoint pdp) { + super(); + this.pdp = pdp; + } + + /** + * Perform a (remote) authorization decision and return a boolean depending on the result + */ + @Override + protected boolean authorize( + Object xacmlRequest, Principal principal, Message message + ) throws Exception { + if (!(xacmlRequest instanceof RequestType)) { + String error = "XACMLRequest parameter is not an instance of OpenSAML RequestType!"; + LOG.warning(error); + throw new Exception(error); + } + + RequestType request = (RequestType)xacmlRequest; + if (LOG.isLoggable(Level.FINE)) { + Document doc = DOMUtils.createDocument(); + Element requestElement = OpenSAMLUtil.toDom(request, doc); + LOG.log(Level.FINE, DOM2Writer.nodeToString(requestElement)); + } + + // Evaluate the request + Source responseSource = this.pdp.evaluate(requestType2Source(request)); + + // Parse the Response into an OpenSAML ResponseType Object + ResponseType response = responseSourceToResponseType(responseSource); + List<ResultType> results = response.getResults(); + + if (results == null) { + return false; + } + + for (ResultType result : results) { + // Handle any Obligations returned by the PDP + handleObligations(request, principal, message, result); + + DECISION decision = result.getDecision() != null ? result.getDecision().getDecision() : DECISION.Deny; + String code = ""; + String statusMessage = ""; + if (result.getStatus() != null) { + StatusType status = result.getStatus(); + code = status.getStatusCode() != null ? status.getStatusCode().getValue() : ""; + statusMessage = status.getStatusMessage() != null ? status.getStatusMessage().getValue() : ""; + } + LOG.fine("XACML authorization result: " + decision + ", code: " + code + ", message: " + statusMessage); + return decision == DECISION.Permit; + } + + return false; + } + + private ResponseType responseSourceToResponseType(Source responseSource) { + try { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer trans = transformerFactory.newTransformer(); + + DOMResult res = new DOMResult(); + trans.transform(responseSource, res); + Node nd = res.getNode(); + if (nd instanceof Document) { + nd = ((Document)nd).getDocumentElement(); + } + return (ResponseType)OpenSAMLUtil.fromDom((Element)nd); + } catch (Exception e) { + throw new RuntimeException("Error converting pdp response to ResponseType", e); + } + } + + private Source requestType2Source(RequestType request) { + Document doc = DOMUtils.createDocument(); + Element requestElement; + try { + requestElement = OpenSAMLUtil.toDom(request, doc); + } catch (WSSecurityException e) { + throw new RuntimeException("Error converting PDP RequestType to Dom", e); + } + return new DOMSource(requestElement); + } + + /** + * Handle any Obligations returned by the PDP + */ + protected void handleObligations( + RequestType request, + Principal principal, + Message message, + ResultType result + ) throws Exception { + // Do nothing by default + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLRequestBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLRequestBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLRequestBuilder.java new file mode 100644 index 0000000..db78c12 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/OpenSAMLXACMLRequestBuilder.java @@ -0,0 +1,209 @@ +/** + * 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.rt.security.saml.xacml.pep; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.cxf.message.Message; +import org.apache.cxf.rt.security.saml.xacml.CXFMessageParser; +import org.apache.cxf.rt.security.saml.xacml.RequestComponentBuilder; +import org.apache.cxf.rt.security.saml.xacml.XACMLConstants; +import org.joda.time.DateTime; +import org.opensaml.xacml.ctx.ActionType; +import org.opensaml.xacml.ctx.AttributeType; +import org.opensaml.xacml.ctx.AttributeValueType; +import org.opensaml.xacml.ctx.EnvironmentType; +import org.opensaml.xacml.ctx.ResourceType; +import org.opensaml.xacml.ctx.SubjectType; + +/** + * This class constructs an XACML Request given a Principal, list of roles and MessageContext, + * following the SAML 2.0 profile of XACML 2.0. The principal name is inserted as the Subject ID, + * and the list of roles associated with that principal are inserted as Subject roles. The action + * to send defaults to "execute". + * + * For a SOAP Service, the resource-id Attribute refers to the + * "{serviceNamespace}serviceName#{operationNamespace}operationName" String (shortened to + * "{serviceNamespace}serviceName#operationName" if the namespaces are identical). The + * "{serviceNamespace}serviceName", "{operationNamespace}operationName" and resource URI are also + * sent to simplify processing at the PDP side. + * + * For a REST service the request URL is the resource. You can also configure the ability to + * send the truncated request URI instead for a SOAP or REST service. The current DateTime is + * also sent in an Environment, however this can be disabled via configuration. + */ +public class OpenSAMLXACMLRequestBuilder implements XACMLRequestBuilder { + + private boolean sendDateTime = true; + private String action = "execute"; + private boolean sendFullRequestURL = true; + + /** + * Create an XACML Request given a Principal, list of roles and Message. + */ + public Object createRequest(Principal principal, List<String> roles, Message message) + throws Exception { + CXFMessageParser messageParser = new CXFMessageParser(message); + String issuer = messageParser.getIssuer(); + + String actionToUse = messageParser.getAction(action); + + SubjectType subjectType = createSubjectType(principal, roles, issuer); + ResourceType resourceType = createResourceType(messageParser); + AttributeType actionAttribute = createAttribute(XACMLConstants.ACTION_ID, XACMLConstants.XS_STRING, + null, actionToUse); + ActionType actionType = RequestComponentBuilder.createActionType(Collections.singletonList(actionAttribute)); + + return RequestComponentBuilder.createRequestType(Collections.singletonList(subjectType), + Collections.singletonList(resourceType), + actionType, + createEnvironmentType()); + } + + private ResourceType createResourceType(CXFMessageParser messageParser) { + List<AttributeType> attributes = new ArrayList<>(); + + // Resource-id + String resourceId = null; + boolean isSoapService = messageParser.isSOAPService(); + if (isSoapService) { + QName serviceName = messageParser.getWSDLService(); + QName operationName = messageParser.getWSDLOperation(); + + if (serviceName != null) { + resourceId = serviceName.toString() + "#"; + if (serviceName.getNamespaceURI() != null + && serviceName.getNamespaceURI().equals(operationName.getNamespaceURI())) { + resourceId += operationName.getLocalPart(); + } else { + resourceId += operationName.toString(); + } + } else { + resourceId = operationName.toString(); + } + } else { + resourceId = messageParser.getResourceURI(sendFullRequestURL); + } + + attributes.add(createAttribute(XACMLConstants.RESOURCE_ID, XACMLConstants.XS_STRING, null, + resourceId)); + + if (isSoapService) { + // WSDL Service + QName wsdlService = messageParser.getWSDLService(); + if (wsdlService != null) { + attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_SERVICE_ID, XACMLConstants.XS_STRING, null, + wsdlService.toString())); + } + + // WSDL Operation + QName wsdlOperation = messageParser.getWSDLOperation(); + attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_OPERATION_ID, XACMLConstants.XS_STRING, null, + wsdlOperation.toString())); + + // WSDL Endpoint + String endpointURI = messageParser.getResourceURI(sendFullRequestURL); + attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_ENDPOINT, XACMLConstants.XS_STRING, null, + endpointURI)); + } + + return RequestComponentBuilder.createResourceType(attributes, null); + } + + private EnvironmentType createEnvironmentType() { + if (sendDateTime) { + List<AttributeType> attributes = new ArrayList<>(); + AttributeType environmentAttribute = createAttribute(XACMLConstants.CURRENT_DATETIME, + XACMLConstants.XS_DATETIME, null, + new DateTime().toString()); + attributes.add(environmentAttribute); + return RequestComponentBuilder.createEnvironmentType(attributes); + } + + List<AttributeType> attributes = Collections.emptyList(); + return RequestComponentBuilder.createEnvironmentType(attributes); + } + + private SubjectType createSubjectType(Principal principal, List<String> roles, String issuer) { + List<AttributeType> attributes = new ArrayList<>(); + attributes.add(createAttribute(XACMLConstants.SUBJECT_ID, XACMLConstants.XS_STRING, issuer, + principal.getName())); + + if (roles != null) { + List<AttributeValueType> roleAttributes = new ArrayList<>(); + for (String role : roles) { + if (role != null) { + AttributeValueType subjectRoleAttributeValue = + RequestComponentBuilder.createAttributeValueType(role); + roleAttributes.add(subjectRoleAttributeValue); + } + } + + if (!roleAttributes.isEmpty()) { + AttributeType subjectRoleAttribute = + createAttribute( + XACMLConstants.SUBJECT_ROLE, + XACMLConstants.XS_ANY_URI, + issuer, + roleAttributes + ); + attributes.add(subjectRoleAttribute); + } + } + + return RequestComponentBuilder.createSubjectType(attributes, null); + } + + private AttributeType createAttribute(String id, String type, String issuer, List<AttributeValueType> values) { + return RequestComponentBuilder.createAttributeType(id, type, issuer, values); + } + + private AttributeType createAttribute(String id, String type, String issuer, String value) { + return createAttribute(id, type, issuer, + Collections.singletonList(RequestComponentBuilder.createAttributeValueType(value))); + } + + /** + * Set a new Action String to use + */ + public void setAction(String action) { + this.action = action; + } + + public void setSendDateTime(boolean sendDateTime) { + this.sendDateTime = sendDateTime; + } + + /** + * Whether to send the full Request URL as the resource or not. If set to true, + * the full Request URL will be sent for both a JAX-WS and JAX-RS service. If set + * to false (the default), a JAX-WS service will send the "{namespace}operation" QName, + * and a JAX-RS service will send the RequestURI (i.e. minus the initial https:<ip> prefix). + */ + public void setSendFullRequestURL(boolean sendFullRequestURL) { + this.sendFullRequestURL = sendFullRequestURL; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/XACMLRequestBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/XACMLRequestBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/XACMLRequestBuilder.java new file mode 100644 index 0000000..c863264 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pep/XACMLRequestBuilder.java @@ -0,0 +1,44 @@ +/** + * 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.rt.security.saml.xacml.pep; + +import java.security.Principal; +import java.util.List; + +import org.apache.cxf.message.Message; + + +/** + * This interface defines a way to create an XACML Request. + */ +public interface XACMLRequestBuilder { + + /** + * Create an XACML Request given a Principal, list of roles and Message. + * + * @param principal The principal to insert into the Subject of the Request + * @param roles The list of roles associated with the principal + * @param message The Message from which to retrieve the resource + * @return An object representing the Request + * @throws Exception + */ + Object createRequest(Principal principal, List<String> roles, Message message) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/OldXACMLRequestBuilderTest.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/OldXACMLRequestBuilderTest.java b/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/OldXACMLRequestBuilderTest.java new file mode 100644 index 0000000..3bf9f6f --- /dev/null +++ b/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/OldXACMLRequestBuilderTest.java @@ -0,0 +1,308 @@ +/** + * 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.rt.security.saml.xacml; + +import java.security.Principal; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.cxf.message.Message; +import org.apache.cxf.message.MessageImpl; +import org.opensaml.xacml.ctx.AttributeType; +import org.opensaml.xacml.ctx.RequestType; +import org.opensaml.xacml.ctx.ResourceType; + + +/** + * Some unit tests to create a XACML Request via the XACMLRequestBuilder interface. + */ +@SuppressWarnings("deprecation") +public class OldXACMLRequestBuilderTest extends org.junit.Assert { + + static { + org.apache.wss4j.common.saml.OpenSAMLUtil.initSamlEngine(); + } + + @org.junit.Test + public void testXACMLRequestBuilder() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt"; + MessageImpl msg = new MessageImpl(); + msg.put(Message.WSDL_OPERATION, QName.valueOf(operation)); + String service = "{http://www.example.org/contract/DoubleIt}DoubleItService"; + msg.put(Message.WSDL_SERVICE, QName.valueOf(service)); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URI, resourceURL); + + XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + } + + + @org.junit.Test + public void testAction() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt"; + MessageImpl msg = new MessageImpl(); + msg.put(Message.WSDL_OPERATION, QName.valueOf(operation)); + String service = "{http://www.example.org/contract/DoubleIt}DoubleItService"; + msg.put(Message.WSDL_SERVICE, QName.valueOf(service)); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URI, resourceURL); + + DefaultXACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + + String action = + request.getAction().getAttributes().get(0).getAttributeValues().get(0).getValue(); + assertEquals("execute", action); + + builder.setAction("write"); + request = builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + + action = + request.getAction().getAttributes().get(0).getAttributeValues().get(0).getValue(); + assertEquals("write", action); + } + + @org.junit.Test + public void testEnvironment() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt"; + MessageImpl msg = new MessageImpl(); + msg.put(Message.WSDL_OPERATION, QName.valueOf(operation)); + String service = "{http://www.example.org/contract/DoubleIt}DoubleItService"; + msg.put(Message.WSDL_SERVICE, QName.valueOf(service)); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URL, resourceURL); + + XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + assertFalse(request.getEnvironment().getAttributes().isEmpty()); + + ((DefaultXACMLRequestBuilder)builder).setSendDateTime(false); + request = builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + assertTrue(request.getEnvironment().getAttributes().isEmpty()); + } + + @org.junit.Test + public void testSOAPResource() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt"; + MessageImpl msg = new MessageImpl(); + msg.put(Message.WSDL_OPERATION, QName.valueOf(operation)); + String service = "{http://www.example.org/contract/DoubleIt}DoubleItService"; + msg.put(Message.WSDL_SERVICE, QName.valueOf(service)); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URL, resourceURL); + + XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + + List<ResourceType> resources = request.getResources(); + assertNotNull(resources); + assertEquals(1, resources.size()); + + ResourceType resource = resources.get(0); + assertEquals(4, resource.getAttributes().size()); + + boolean resourceIdSatisfied = false; + boolean soapServiceSatisfied = false; + boolean soapOperationSatisfied = false; + boolean resourceURISatisfied = false; + for (AttributeType attribute : resource.getAttributes()) { + String attributeValue = attribute.getAttributeValues().get(0).getValue(); + if (XACMLConstants.RESOURCE_ID.equals(attribute.getAttributeId()) + && "{http://www.example.org/contract/DoubleIt}DoubleItService#DoubleIt".equals( + attributeValue)) { + resourceIdSatisfied = true; + } else if (XACMLConstants.RESOURCE_WSDL_SERVICE_ID.equals(attribute.getAttributeId()) + && service.equals(attributeValue)) { + soapServiceSatisfied = true; + } else if (XACMLConstants.RESOURCE_WSDL_OPERATION_ID.equals(attribute.getAttributeId()) + && operation.equals(attributeValue)) { + soapOperationSatisfied = true; + } else if (XACMLConstants.RESOURCE_WSDL_ENDPOINT.equals(attribute.getAttributeId()) + && resourceURL.equals(attributeValue)) { + resourceURISatisfied = true; + } + } + + assertTrue(resourceIdSatisfied && soapServiceSatisfied && soapOperationSatisfied + && resourceURISatisfied); + } + + @org.junit.Test + public void testSOAPResourceDifferentNamespace() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt"; + MessageImpl msg = new MessageImpl(); + msg.put(Message.WSDL_OPERATION, QName.valueOf(operation)); + String service = "{http://www.example.org/contract/DoubleItService}DoubleItService"; + msg.put(Message.WSDL_SERVICE, QName.valueOf(service)); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URL, resourceURL); + + XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + + List<ResourceType> resources = request.getResources(); + assertNotNull(resources); + assertEquals(1, resources.size()); + + ResourceType resource = resources.get(0); + assertEquals(4, resource.getAttributes().size()); + + boolean resourceIdSatisfied = false; + boolean soapServiceSatisfied = false; + boolean soapOperationSatisfied = false; + boolean resourceURISatisfied = false; + String expectedResourceId = + service + "#" + operation; + for (AttributeType attribute : resource.getAttributes()) { + String attributeValue = attribute.getAttributeValues().get(0).getValue(); + if (XACMLConstants.RESOURCE_ID.equals(attribute.getAttributeId()) + && expectedResourceId.equals(attributeValue)) { + resourceIdSatisfied = true; + } else if (XACMLConstants.RESOURCE_WSDL_SERVICE_ID.equals(attribute.getAttributeId()) + && service.equals(attributeValue)) { + soapServiceSatisfied = true; + } else if (XACMLConstants.RESOURCE_WSDL_OPERATION_ID.equals(attribute.getAttributeId()) + && operation.equals(attributeValue)) { + soapOperationSatisfied = true; + } else if (XACMLConstants.RESOURCE_WSDL_ENDPOINT.equals(attribute.getAttributeId()) + && resourceURL.equals(attributeValue)) { + resourceURISatisfied = true; + } + } + + assertTrue(resourceIdSatisfied && soapServiceSatisfied && soapOperationSatisfied + && resourceURISatisfied); + } + + @org.junit.Test + public void testRESTResource() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + MessageImpl msg = new MessageImpl(); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URL, resourceURL); + + XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + + List<ResourceType> resources = request.getResources(); + assertNotNull(resources); + assertEquals(1, resources.size()); + + ResourceType resource = resources.get(0); + assertEquals(1, resource.getAttributes().size()); + + for (AttributeType attribute : resource.getAttributes()) { + String attributeValue = attribute.getAttributeValues().get(0).getValue(); + assertEquals(attributeValue, resourceURL); + } + } + + @org.junit.Test + public void testRESTResourceTruncatedURI() throws Exception { + // Mock up a request + Principal principal = new Principal() { + public String getName() { + return "alice"; + } + }; + + MessageImpl msg = new MessageImpl(); + String resourceURL = "https://localhost:8080/doubleit"; + msg.put(Message.REQUEST_URL, resourceURL); + String resourceURI = "/doubleit"; + msg.put(Message.REQUEST_URI, resourceURI); + + XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + ((DefaultXACMLRequestBuilder)builder).setSendFullRequestURL(false); + RequestType request = + builder.createRequest(principal, Collections.singletonList("manager"), msg); + assertNotNull(request); + + List<ResourceType> resources = request.getResources(); + assertNotNull(resources); + assertEquals(1, resources.size()); + + ResourceType resource = resources.get(0); + assertEquals(1, resource.getAttributes().size()); + + for (AttributeType attribute : resource.getAttributes()) { + String attributeValue = attribute.getAttributeValues().get(0).getValue(); + assertEquals(attributeValue, resourceURI); + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilderTest.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilderTest.java b/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilderTest.java index ed34e7a..8647dd6 100644 --- a/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilderTest.java +++ b/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilderTest.java @@ -27,6 +27,9 @@ import javax.xml.namespace.QName; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageImpl; +import org.apache.cxf.rt.security.saml.xacml.pep.OpenSAMLXACMLRequestBuilder; +import org.apache.cxf.rt.security.saml.xacml.pep.XACMLRequestBuilder; + import org.opensaml.xacml.ctx.AttributeType; import org.opensaml.xacml.ctx.RequestType; import org.opensaml.xacml.ctx.ResourceType; @@ -58,9 +61,9 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURL = "https://localhost:8080/doubleit"; msg.put(Message.REQUEST_URI, resourceURL); - XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + XACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); } @@ -82,9 +85,9 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURL = "https://localhost:8080/doubleit"; msg.put(Message.REQUEST_URI, resourceURL); - DefaultXACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + OpenSAMLXACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); String action = @@ -92,7 +95,7 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { assertEquals("execute", action); builder.setAction("write"); - request = builder.createRequest(principal, Collections.singletonList("manager"), msg); + request = (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); action = @@ -117,14 +120,14 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURL = "https://localhost:8080/doubleit"; msg.put(Message.REQUEST_URL, resourceURL); - XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + XACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); assertFalse(request.getEnvironment().getAttributes().isEmpty()); - ((DefaultXACMLRequestBuilder)builder).setSendDateTime(false); - request = builder.createRequest(principal, Collections.singletonList("manager"), msg); + ((OpenSAMLXACMLRequestBuilder)builder).setSendDateTime(false); + request = (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); assertTrue(request.getEnvironment().getAttributes().isEmpty()); } @@ -146,9 +149,9 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURL = "https://localhost:8080/doubleit"; msg.put(Message.REQUEST_URL, resourceURL); - XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + XACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); List<ResourceType> resources = request.getResources(); @@ -201,9 +204,9 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURL = "https://localhost:8080/doubleit"; msg.put(Message.REQUEST_URL, resourceURL); - XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + XACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); List<ResourceType> resources = request.getResources(); @@ -253,9 +256,9 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURL = "https://localhost:8080/doubleit"; msg.put(Message.REQUEST_URL, resourceURL); - XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); + XACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); List<ResourceType> resources = request.getResources(); @@ -286,10 +289,10 @@ public class XACMLRequestBuilderTest extends org.junit.Assert { String resourceURI = "/doubleit"; msg.put(Message.REQUEST_URI, resourceURI); - XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder(); - ((DefaultXACMLRequestBuilder)builder).setSendFullRequestURL(false); + XACMLRequestBuilder builder = new OpenSAMLXACMLRequestBuilder(); + ((OpenSAMLXACMLRequestBuilder)builder).setSendFullRequestURL(false); RequestType request = - builder.createRequest(principal, Collections.singletonList("manager"), msg); + (RequestType)builder.createRequest(principal, Collections.singletonList("manager"), msg); assertNotNull(request); List<ResourceType> resources = request.getResources(); http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/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 36bc341..557ab62 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 @@ -938,6 +938,54 @@ public class SamlTokenTest extends AbstractBusClientServerTestBase { ((java.io.Closeable)saml2Port).close(); bus.shutdown(true); } + + @org.junit.Test + public void testSaml2OpenSAMLPEP() 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, "DoubleItSaml2PEP2Port"); + DoubleItPortType saml2Port = + service.getPort(portQName, DoubleItPortType.class); + updateAddressPort(saml2Port, test.getPort()); + + try { + saml2Port.doubleIt(25); + fail("Failure expected as Assertion doesn't contain Role information"); + } catch (javax.xml.ws.soap.SOAPFaultException ex) { + // expected + } + + SamlRoleCallbackHandler roleCallbackHandler = + new SamlRoleCallbackHandler(); + roleCallbackHandler.setSignAssertion(true); + roleCallbackHandler.setRoleName("manager"); + ((BindingProvider)saml2Port).getRequestContext().put( + "security.saml-callback-handler", roleCallbackHandler + ); + + int result = saml2Port.doubleIt(25); + assertTrue(result == 50); + + // Expected failure on incorrect role + roleCallbackHandler.setRoleName("boss"); + try { + saml2Port.doubleIt(25); + fail("Failure expected as Assertion doesn't contain correct role"); + } catch (javax.xml.ws.soap.SOAPFaultException ex) { + // expected + } + + ((java.io.Closeable)saml2Port).close(); + bus.shutdown(true); + } @org.junit.Test public void testSaml2Replay() throws Exception { http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/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 ea0d132..7cbc0e3 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 @@ -377,6 +377,9 @@ <wsdl:port name="DoubleItSaml2PEPPort" binding="tns:DoubleItSaml2SymmetricBinding"> <soap:address location="http://localhost:9001/DoubleItSaml2PEP"/> </wsdl:port> + <wsdl:port name="DoubleItSaml2PEP2Port" binding="tns:DoubleItSaml2SymmetricBinding"> + <soap:address location="http://localhost:9001/DoubleItSaml2PEP2"/> + </wsdl:port> <wsdl:port name="DoubleItSaml2TransportPort" binding="tns:DoubleItSaml2TransportBinding"> <soap:address location="https://localhost:9009/DoubleItSaml2Transport"/> </wsdl:port> http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/client.xml ---------------------------------------------------------------------- diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/client.xml b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/client.xml index 26c6b2f..de4425f 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/client.xml +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/saml/client.xml @@ -217,4 +217,10 @@ <entry key="security.encryption.username" value="bob"/> </jaxws:properties> </jaxws:client> + <jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItSaml2PEP2Port" createdFromAPI="true"> + <jaxws:properties> + <entry key="security.encryption.properties" value="bob.properties"/> + <entry key="security.encryption.username" value="bob"/> + </jaxws:properties> + </jaxws:client> </beans> http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/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 9d3895f..05e419e 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 @@ -243,6 +243,19 @@ <ref bean="XACMLInterceptor"/> </jaxws:inInterceptors> </jaxws:endpoint> + <bean class="org.apache.cxf.rt.security.saml.xacml.pep.OpenSAMLXACMLAuthorizingInterceptor" id="XACMLInterceptor2"> + <constructor-arg ref="MockPDP"/> + </bean> + <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="Saml2TokenOverSymmetricPEP2" address="http://localhost:${testutil.ports.saml.Server}/DoubleItSaml2PEP2" serviceName="s:DoubleItService" endpointName="s:DoubleItSaml2PEP2Port" implementor="org.apache.cxf.systest.ws.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl"> + <jaxws:properties> + <entry key="security.callback-handler" value="org.apache.cxf.systest.ws.common.KeystorePasswordCallback"/> + <entry key="security.signature.properties" value="bob.properties"/> + <entry key="ws-security.saml2.validator" value="org.apache.cxf.systest.ws.saml.CustomSaml2Validator"/> + </jaxws:properties> + <jaxws:inInterceptors> + <ref bean="XACMLInterceptor2"/> + </jaxws:inInterceptors> + </jaxws:endpoint> <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="Saml2TransportToken" address="https://localhost:${testutil.ports.saml.Server.2}/DoubleItSaml2Transport" serviceName="s:DoubleItService" endpointName="s:DoubleItSaml2TransportPort" 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="security.callback-handler" value="org.apache.cxf.systest.ws.common.KeystorePasswordCallback"/> http://git-wip-us.apache.org/repos/asf/cxf/blob/7a526368/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 91768b8..33aadf7 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 @@ -268,6 +268,21 @@ <ref bean="XACMLInterceptor"/> </jaxws:inInterceptors> </jaxws:endpoint> + <bean class="org.apache.cxf.rt.security.saml.xacml.pep.OpenSAMLXACMLAuthorizingInterceptor" id="XACMLInterceptor2"> + <constructor-arg ref="MockPDP"/> + </bean> + <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="Saml2TokenOverSymmetricPEP2" address="http://localhost:${testutil.ports.saml.StaxServer}/DoubleItSaml2PEP2" serviceName="s:DoubleItService" endpointName="s:DoubleItSaml2PEP2Port" implementor="org.apache.cxf.systest.ws.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/ws/saml/DoubleItSaml.wsdl"> + <jaxws:properties> + <entry key="security.callback-handler" value="org.apache.cxf.systest.ws.common.KeystorePasswordCallback"/> + <entry key="security.signature.properties" value="bob.properties"/> + <!--<entry key="ws-security.saml2.validator" + value="org.apache.cxf.systest.ws.saml.CustomSaml2Validator"/>--> + <entry key="ws-security.enable.streaming" value="true"/> + </jaxws:properties> + <jaxws:inInterceptors> + <ref bean="XACMLInterceptor2"/> + </jaxws:inInterceptors> + </jaxws:endpoint> <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="Saml2TransportToken" address="https://localhost:${testutil.ports.saml.StaxServer.2}/DoubleItSaml2Transport" serviceName="s:DoubleItService" endpointName="s:DoubleItSaml2TransportPort" 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="security.callback-handler" value="org.apache.cxf.systest.ws.common.KeystorePasswordCallback"/>