Refactoring of XACML code
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/8176b1b0 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/8176b1b0 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/8176b1b0 Branch: refs/heads/master Commit: 8176b1b0faad2de44a4ff85083c74b5a4b74918a Parents: 2804875 Author: Colm O hEigeartaigh <cohei...@apache.org> Authored: Fri Jul 17 12:43:20 2015 +0100 Committer: Colm O hEigeartaigh <cohei...@apache.org> Committed: Fri Jul 17 15:17:01 2015 +0100 ---------------------------------------------------------------------- .../AbstractXACMLAuthorizingInterceptor.java | 167 ---------- .../saml/xacml/DefaultXACMLRequestBuilder.java | 218 ------------- .../saml/xacml/RequestComponentBuilder.java | 183 ----------- .../saml/xacml/SamlRequestComponentBuilder.java | 118 ------- .../saml/xacml/XACMLAuthorizingInterceptor.java | 89 ------ .../saml/xacml/XACMLRequestBuilder.java | 62 ---- .../saml/xacml/pdp/api/PolicyDecisionPoint.java | 35 --- .../saml/xacml2/DefaultXACMLRequestBuilder.java | 210 +++++++++++++ .../saml/xacml2/PolicyDecisionPoint.java | 36 +++ .../saml/xacml2/RequestComponentBuilder.java | 183 +++++++++++ .../xacml2/SamlRequestComponentBuilder.java | 118 +++++++ .../xacml2/XACMLAuthorizingInterceptor.java | 167 ++++++++++ .../saml/xacml2/XACMLRequestBuilder.java | 45 +++ .../cxf/rt/security/saml/xacml/DummyPDP.java | 153 --------- .../saml/xacml/RequestComponentBuilderTest.java | 222 ------------- .../xacml/SamlRequestComponentBuilderTest.java | 153 --------- .../xacml/XACMLAuthorizingInterceptorTest.java | 127 -------- .../saml/xacml/XACMLRequestBuilderTest.java | 308 ------------------- .../cxf/rt/security/saml/xacml2/DummyPDP.java | 113 +++++++ .../xacml2/RequestComponentBuilderTest.java | 222 +++++++++++++ .../xacml2/SamlRequestComponentBuilderTest.java | 153 +++++++++ .../xacml2/XACMLAuthorizingInterceptorTest.java | 124 ++++++++ .../saml/xacml2/XACMLRequestBuilderTest.java | 308 +++++++++++++++++++ .../ws/saml/PolicyDecisionPointMockImpl.java | 45 +-- .../org/apache/cxf/systest/ws/saml/server.xml | 2 +- .../apache/cxf/systest/ws/saml/stax-server.xml | 2 +- 26 files changed, 1684 insertions(+), 1879 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/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 deleted file mode 100644 index 69ca071..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/AbstractXACMLAuthorizingInterceptor.java +++ /dev/null @@ -1,167 +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.cxf.rt.security.saml.xacml; - -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.w3c.dom.Document; -import org.w3c.dom.Element; - -import org.apache.cxf.common.logging.LogUtils; -import org.apache.cxf.helpers.DOMUtils; -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; -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 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. - */ -public abstract class AbstractXACMLAuthorizingInterceptor extends AbstractPhaseInterceptor<Message> { - - private static final Logger LOG = LogUtils.getL7dLogger(AbstractXACMLAuthorizingInterceptor.class); - - private XACMLRequestBuilder requestBuilder = new DefaultXACMLRequestBuilder(); - - 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 { - if (authorize(principal, roles, 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 boolean authorize( - Principal principal, List<String> roles, Message message - ) throws Exception { - RequestType request = requestBuilder.createRequest(principal, roles, message); - if (LOG.isLoggable(Level.FINE)) { - Document doc = DOMUtils.createDocument(); - Element requestElement = OpenSAMLUtil.toDom(request, doc); - LOG.log(Level.FINE, DOM2Writer.nodeToString(requestElement)); - } - - ResponseType response = performRequest(request, message); - - 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; - } - - public abstract ResponseType performRequest(RequestType request, Message message) throws Exception; - - /** - * 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/8176b1b0/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 deleted file mode 100644 index 1040a56..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/DefaultXACMLRequestBuilder.java +++ /dev/null @@ -1,218 +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.cxf.rt.security.saml.xacml; - -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.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.RequestType; -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 DefaultXACMLRequestBuilder 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 RequestType 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; - } - - @Override - public List<String> getResources(Message message) { - throw new IllegalAccessError("Deprecated"); - } - - @Override - public String getResource(Message message) { - throw new IllegalAccessError("Deprecated"); - } - -} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/RequestComponentBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/RequestComponentBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/RequestComponentBuilder.java deleted file mode 100644 index 08f8da8..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/RequestComponentBuilder.java +++ /dev/null @@ -1,183 +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.cxf.rt.security.saml.xacml; - -import java.util.List; - -import org.opensaml.core.xml.XMLObjectBuilderFactory; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -import org.opensaml.xacml.XACMLObjectBuilder; -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.RequestType; -import org.opensaml.xacml.ctx.ResourceContentType; -import org.opensaml.xacml.ctx.ResourceType; -import org.opensaml.xacml.ctx.SubjectType; - -/** - * A set of utility methods to construct XACML 2.0 Request statements - */ -public final class RequestComponentBuilder { - private static volatile XACMLObjectBuilder<AttributeValueType> attributeValueTypeBuilder; - - private static volatile XACMLObjectBuilder<AttributeType> attributeTypeBuilder; - - private static volatile XACMLObjectBuilder<SubjectType> subjectTypeBuilder; - - private static volatile XACMLObjectBuilder<ResourceType> resourceTypeBuilder; - - private static volatile XACMLObjectBuilder<ActionType> actionTypeBuilder; - - private static volatile XACMLObjectBuilder<EnvironmentType> environmentTypeBuilder; - - private static volatile XACMLObjectBuilder<RequestType> requestTypeBuilder; - - private static volatile XMLObjectBuilderFactory builderFactory = - XMLObjectProviderRegistrySupport.getBuilderFactory(); - - private RequestComponentBuilder() { - // complete - } - - @SuppressWarnings("unchecked") - public static AttributeValueType createAttributeValueType( - String value - ) { - if (attributeValueTypeBuilder == null) { - attributeValueTypeBuilder = (XACMLObjectBuilder<AttributeValueType>) - builderFactory.getBuilder(AttributeValueType.DEFAULT_ELEMENT_NAME); - } - AttributeValueType attributeValue = attributeValueTypeBuilder.buildObject(); - attributeValue.setValue(value); - - return attributeValue; - } - - @SuppressWarnings("unchecked") - public static AttributeType createAttributeType( - String attributeId, - String dataType, - String issuer, - List<AttributeValueType> attributeValues - ) { - if (attributeTypeBuilder == null) { - attributeTypeBuilder = (XACMLObjectBuilder<AttributeType>) - builderFactory.getBuilder(AttributeType.DEFAULT_ELEMENT_NAME); - } - AttributeType attributeType = attributeTypeBuilder.buildObject(); - attributeType.setAttributeID(attributeId); - attributeType.setDataType(dataType); - attributeType.setIssuer(issuer); - attributeType.getAttributeValues().addAll(attributeValues); - - return attributeType; - } - - @SuppressWarnings("unchecked") - public static SubjectType createSubjectType( - List<AttributeType> attributes, - String subjectCategory - ) { - if (subjectTypeBuilder == null) { - subjectTypeBuilder = (XACMLObjectBuilder<SubjectType>) - builderFactory.getBuilder(SubjectType.DEFAULT_ELEMENT_NAME); - } - SubjectType subject = subjectTypeBuilder.buildObject(); - if (attributes != null) { - subject.getAttributes().addAll(attributes); - } - subject.setSubjectCategory(subjectCategory); - - return subject; - } - - @SuppressWarnings("unchecked") - public static ResourceType createResourceType( - List<AttributeType> attributes, - ResourceContentType resourceContent - ) { - if (resourceTypeBuilder == null) { - resourceTypeBuilder = (XACMLObjectBuilder<ResourceType>) - builderFactory.getBuilder(ResourceType.DEFAULT_ELEMENT_NAME); - } - ResourceType resource = resourceTypeBuilder.buildObject(); - if (attributes != null) { - resource.getAttributes().addAll(attributes); - } - resource.setResourceContent(resourceContent); - - return resource; - } - - @SuppressWarnings("unchecked") - public static ActionType createActionType( - List<AttributeType> attributes - ) { - if (actionTypeBuilder == null) { - actionTypeBuilder = (XACMLObjectBuilder<ActionType>) - builderFactory.getBuilder(ActionType.DEFAULT_ELEMENT_NAME); - } - ActionType action = actionTypeBuilder.buildObject(); - if (attributes != null) { - action.getAttributes().addAll(attributes); - } - - return action; - } - - @SuppressWarnings("unchecked") - public static EnvironmentType createEnvironmentType( - List<AttributeType> attributes - ) { - if (environmentTypeBuilder == null) { - environmentTypeBuilder = (XACMLObjectBuilder<EnvironmentType>) - builderFactory.getBuilder(EnvironmentType.DEFAULT_ELEMENT_NAME); - } - EnvironmentType enviroment = environmentTypeBuilder.buildObject(); - if (attributes != null) { - enviroment.getAttributes().addAll(attributes); - } - - return enviroment; - } - - @SuppressWarnings("unchecked") - public static RequestType createRequestType( - List<SubjectType> subjects, - List<ResourceType> resources, - ActionType action, - EnvironmentType environment - ) { - if (requestTypeBuilder == null) { - requestTypeBuilder = (XACMLObjectBuilder<RequestType>) - builderFactory.getBuilder(RequestType.DEFAULT_ELEMENT_NAME); - } - RequestType request = requestTypeBuilder.buildObject(); - request.getSubjects().addAll(subjects); - request.getResources().addAll(resources); - request.setAction(action); - request.setEnvironment(environment); - - return request; - } - -} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/SamlRequestComponentBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/SamlRequestComponentBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/SamlRequestComponentBuilder.java deleted file mode 100644 index c0d8255..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/SamlRequestComponentBuilder.java +++ /dev/null @@ -1,118 +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.cxf.rt.security.saml.xacml; - -import java.util.UUID; - -import org.joda.time.DateTime; -import org.opensaml.core.xml.XMLObjectBuilderFactory; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -import org.opensaml.saml.common.SAMLObjectBuilder; -import org.opensaml.saml.common.SAMLVersion; -import org.opensaml.saml.saml2.core.Issuer; -import org.opensaml.xacml.XACMLObjectBuilder; -import org.opensaml.xacml.ctx.RequestType; -import org.opensaml.xacml.profile.saml.SAMLProfileConstants; -import org.opensaml.xacml.profile.saml.XACMLAuthzDecisionQueryType; - -/** - * A set of utility methods to construct XACML SAML Request statements, based on the - * SAML 2.0 profile of XACML v2.0 specification. - */ -public final class SamlRequestComponentBuilder { - private static volatile XACMLObjectBuilder<XACMLAuthzDecisionQueryType> xacmlAuthzDecisionQueryTypeBuilder; - - private static volatile SAMLObjectBuilder<Issuer> issuerBuilder; - - private static volatile XMLObjectBuilderFactory builderFactory = - XMLObjectProviderRegistrySupport.getBuilderFactory(); - - private SamlRequestComponentBuilder() { - // complete - } - - /** - * Create an AuthzDecisionQuery using the defaults - */ - public static XACMLAuthzDecisionQueryType createAuthzDecisionQuery( - String issuerValue, - RequestType request, - String namespace - ) { - return createAuthzDecisionQuery(false, false, issuerValue, request, namespace); - } - - @SuppressWarnings("unchecked") - public static XACMLAuthzDecisionQueryType createAuthzDecisionQuery( - boolean inputContextOnly, - boolean returnContext, - String issuerValue, - RequestType request, - String namespace - ) { - if (xacmlAuthzDecisionQueryTypeBuilder == null) { - xacmlAuthzDecisionQueryTypeBuilder = (XACMLObjectBuilder<XACMLAuthzDecisionQueryType>) - builderFactory.getBuilder(XACMLAuthzDecisionQueryType.DEFAULT_ELEMENT_NAME_XACML20); - } - XACMLAuthzDecisionQueryType authzQuery = - xacmlAuthzDecisionQueryTypeBuilder.buildObject( - namespace, - XACMLAuthzDecisionQueryType.DEFAULT_ELEMENT_LOCAL_NAME, - SAMLProfileConstants.SAML20XACMLPROTOCOL_PREFIX - ); - authzQuery.setID("_" + UUID.randomUUID().toString()); - authzQuery.setVersion(SAMLVersion.VERSION_20); - authzQuery.setIssueInstant(new DateTime()); - authzQuery.setInputContextOnly(Boolean.valueOf(inputContextOnly)); - authzQuery.setReturnContext(Boolean.valueOf(returnContext)); - - if (issuerValue != null) { - Issuer issuer = createIssuer(issuerValue); - authzQuery.setIssuer(issuer); - } - - authzQuery.setRequest(request); - - return authzQuery; - } - - - /** - * Create an Issuer object - * - * @param issuerValue of type String - * @return an Issuer object - */ - @SuppressWarnings("unchecked") - public static Issuer createIssuer(String issuerValue) { - if (issuerBuilder == null) { - issuerBuilder = (SAMLObjectBuilder<Issuer>) - builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME); - - } - Issuer issuer = issuerBuilder.buildObject(); - // - // The SAML authority that is making the claim(s) in the assertion. The issuer SHOULD - // be unambiguous to the intended relying parties. - issuer.setValue(issuerValue); - return issuer; - } - -} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/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 deleted file mode 100644 index 78875a3..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLAuthorizingInterceptor.java +++ /dev/null @@ -1,89 +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.cxf.rt.security.saml.xacml; - -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.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.opensaml.xacml.ctx.RequestType; -import org.opensaml.xacml.ctx.ResponseType; - -/** - * An 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. - */ -public class XACMLAuthorizingInterceptor extends AbstractXACMLAuthorizingInterceptor { - private PolicyDecisionPoint pdp; - - public XACMLAuthorizingInterceptor(PolicyDecisionPoint pdp) { - super(); - this.pdp = pdp; - } - - @Override - public ResponseType performRequest(RequestType request, Message message) throws Exception { - Source requestSource = requestType2Source(request); - Source responseSource = this.pdp.evaluate(requestSource); - return responseSourceToResponseType(responseSource); - } - - 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); - } - - private ResponseType responseSourceToResponseType(Source responseSource) { - try { - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer transformer = transformerFactory.newTransformer(); - - DOMResult res = new DOMResult(); - transformer.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); - } - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/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 deleted file mode 100644 index d3bd32c..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/XACMLRequestBuilder.java +++ /dev/null @@ -1,62 +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.cxf.rt.security.saml.xacml; - -import java.security.Principal; -import java.util.List; - -import org.apache.cxf.message.Message; -import org.opensaml.xacml.ctx.RequestType; - - -/** - * 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 OpenSAML RequestType object - * @throws Exception - */ - RequestType createRequest(Principal principal, List<String> roles, Message message) throws Exception; - - /** - * Return the list of Resources that have been inserted into the Request. - * - * @param message The Message from which to retrieve the resource - * @return the list of Resources that have been inserted into the Request - */ - @Deprecated - List<String> getResources(Message message); - - /** - * Return the Resource that has been inserted into the Request. - * - * @param message The Message from which to retrieve the resource - * @return the Resource that has been inserted into the Request - */ - @Deprecated - String getResource(Message message); -} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pdp/api/PolicyDecisionPoint.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pdp/api/PolicyDecisionPoint.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pdp/api/PolicyDecisionPoint.java deleted file mode 100644 index 80e1623..0000000 --- a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml/pdp/api/PolicyDecisionPoint.java +++ /dev/null @@ -1,35 +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.cxf.rt.security.saml.xacml.pdp.api; - -import javax.xml.transform.Source; - -/** - * An interface that describes a PolicyDecisionPoint (PDP). - */ -public interface PolicyDecisionPoint { - - /** - * Evaluate an XACML Request and return a Response - * @param request an XACML Request as a Source - * @return the XACML Response as a Source - */ - Source evaluate(Source request); - -} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/DefaultXACMLRequestBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/DefaultXACMLRequestBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/DefaultXACMLRequestBuilder.java new file mode 100644 index 0000000..468d875 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/DefaultXACMLRequestBuilder.java @@ -0,0 +1,210 @@ +/** + * 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.xacml2; + +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.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.RequestType; +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 DefaultXACMLRequestBuilder 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 RequestType 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/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/PolicyDecisionPoint.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/PolicyDecisionPoint.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/PolicyDecisionPoint.java new file mode 100644 index 0000000..1bf1bdb --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/PolicyDecisionPoint.java @@ -0,0 +1,36 @@ +/** + * 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.xacml2; + +import org.opensaml.xacml.ctx.RequestType; +import org.opensaml.xacml.ctx.ResponseType; + +/** + * An interface that describes a PolicyDecisionPoint (PDP). + */ +public interface PolicyDecisionPoint { + + /** + * Evaluate an XACML Request and return a Response + * @param request an XACML Request as a RequestType + * @return the XACML Response as a ResponseType + */ + ResponseType evaluate(RequestType request); + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/RequestComponentBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/RequestComponentBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/RequestComponentBuilder.java new file mode 100644 index 0000000..61d1a61 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/RequestComponentBuilder.java @@ -0,0 +1,183 @@ +/** + * 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.xacml2; + +import java.util.List; + +import org.opensaml.core.xml.XMLObjectBuilderFactory; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.xacml.XACMLObjectBuilder; +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.RequestType; +import org.opensaml.xacml.ctx.ResourceContentType; +import org.opensaml.xacml.ctx.ResourceType; +import org.opensaml.xacml.ctx.SubjectType; + +/** + * A set of utility methods to construct XACML 2.0 Request statements + */ +public final class RequestComponentBuilder { + private static volatile XACMLObjectBuilder<AttributeValueType> attributeValueTypeBuilder; + + private static volatile XACMLObjectBuilder<AttributeType> attributeTypeBuilder; + + private static volatile XACMLObjectBuilder<SubjectType> subjectTypeBuilder; + + private static volatile XACMLObjectBuilder<ResourceType> resourceTypeBuilder; + + private static volatile XACMLObjectBuilder<ActionType> actionTypeBuilder; + + private static volatile XACMLObjectBuilder<EnvironmentType> environmentTypeBuilder; + + private static volatile XACMLObjectBuilder<RequestType> requestTypeBuilder; + + private static volatile XMLObjectBuilderFactory builderFactory = + XMLObjectProviderRegistrySupport.getBuilderFactory(); + + private RequestComponentBuilder() { + // complete + } + + @SuppressWarnings("unchecked") + public static AttributeValueType createAttributeValueType( + String value + ) { + if (attributeValueTypeBuilder == null) { + attributeValueTypeBuilder = (XACMLObjectBuilder<AttributeValueType>) + builderFactory.getBuilder(AttributeValueType.DEFAULT_ELEMENT_NAME); + } + AttributeValueType attributeValue = attributeValueTypeBuilder.buildObject(); + attributeValue.setValue(value); + + return attributeValue; + } + + @SuppressWarnings("unchecked") + public static AttributeType createAttributeType( + String attributeId, + String dataType, + String issuer, + List<AttributeValueType> attributeValues + ) { + if (attributeTypeBuilder == null) { + attributeTypeBuilder = (XACMLObjectBuilder<AttributeType>) + builderFactory.getBuilder(AttributeType.DEFAULT_ELEMENT_NAME); + } + AttributeType attributeType = attributeTypeBuilder.buildObject(); + attributeType.setAttributeID(attributeId); + attributeType.setDataType(dataType); + attributeType.setIssuer(issuer); + attributeType.getAttributeValues().addAll(attributeValues); + + return attributeType; + } + + @SuppressWarnings("unchecked") + public static SubjectType createSubjectType( + List<AttributeType> attributes, + String subjectCategory + ) { + if (subjectTypeBuilder == null) { + subjectTypeBuilder = (XACMLObjectBuilder<SubjectType>) + builderFactory.getBuilder(SubjectType.DEFAULT_ELEMENT_NAME); + } + SubjectType subject = subjectTypeBuilder.buildObject(); + if (attributes != null) { + subject.getAttributes().addAll(attributes); + } + subject.setSubjectCategory(subjectCategory); + + return subject; + } + + @SuppressWarnings("unchecked") + public static ResourceType createResourceType( + List<AttributeType> attributes, + ResourceContentType resourceContent + ) { + if (resourceTypeBuilder == null) { + resourceTypeBuilder = (XACMLObjectBuilder<ResourceType>) + builderFactory.getBuilder(ResourceType.DEFAULT_ELEMENT_NAME); + } + ResourceType resource = resourceTypeBuilder.buildObject(); + if (attributes != null) { + resource.getAttributes().addAll(attributes); + } + resource.setResourceContent(resourceContent); + + return resource; + } + + @SuppressWarnings("unchecked") + public static ActionType createActionType( + List<AttributeType> attributes + ) { + if (actionTypeBuilder == null) { + actionTypeBuilder = (XACMLObjectBuilder<ActionType>) + builderFactory.getBuilder(ActionType.DEFAULT_ELEMENT_NAME); + } + ActionType action = actionTypeBuilder.buildObject(); + if (attributes != null) { + action.getAttributes().addAll(attributes); + } + + return action; + } + + @SuppressWarnings("unchecked") + public static EnvironmentType createEnvironmentType( + List<AttributeType> attributes + ) { + if (environmentTypeBuilder == null) { + environmentTypeBuilder = (XACMLObjectBuilder<EnvironmentType>) + builderFactory.getBuilder(EnvironmentType.DEFAULT_ELEMENT_NAME); + } + EnvironmentType enviroment = environmentTypeBuilder.buildObject(); + if (attributes != null) { + enviroment.getAttributes().addAll(attributes); + } + + return enviroment; + } + + @SuppressWarnings("unchecked") + public static RequestType createRequestType( + List<SubjectType> subjects, + List<ResourceType> resources, + ActionType action, + EnvironmentType environment + ) { + if (requestTypeBuilder == null) { + requestTypeBuilder = (XACMLObjectBuilder<RequestType>) + builderFactory.getBuilder(RequestType.DEFAULT_ELEMENT_NAME); + } + RequestType request = requestTypeBuilder.buildObject(); + request.getSubjects().addAll(subjects); + request.getResources().addAll(resources); + request.setAction(action); + request.setEnvironment(environment); + + return request; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/SamlRequestComponentBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/SamlRequestComponentBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/SamlRequestComponentBuilder.java new file mode 100644 index 0000000..674dc67 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/SamlRequestComponentBuilder.java @@ -0,0 +1,118 @@ +/** + * 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.xacml2; + +import java.util.UUID; + +import org.joda.time.DateTime; +import org.opensaml.core.xml.XMLObjectBuilderFactory; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.saml.common.SAMLObjectBuilder; +import org.opensaml.saml.common.SAMLVersion; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.xacml.XACMLObjectBuilder; +import org.opensaml.xacml.ctx.RequestType; +import org.opensaml.xacml.profile.saml.SAMLProfileConstants; +import org.opensaml.xacml.profile.saml.XACMLAuthzDecisionQueryType; + +/** + * A set of utility methods to construct XACML SAML Request statements, based on the + * SAML 2.0 profile of XACML v2.0 specification. + */ +public final class SamlRequestComponentBuilder { + private static volatile XACMLObjectBuilder<XACMLAuthzDecisionQueryType> xacmlAuthzDecisionQueryTypeBuilder; + + private static volatile SAMLObjectBuilder<Issuer> issuerBuilder; + + private static volatile XMLObjectBuilderFactory builderFactory = + XMLObjectProviderRegistrySupport.getBuilderFactory(); + + private SamlRequestComponentBuilder() { + // complete + } + + /** + * Create an AuthzDecisionQuery using the defaults + */ + public static XACMLAuthzDecisionQueryType createAuthzDecisionQuery( + String issuerValue, + RequestType request, + String namespace + ) { + return createAuthzDecisionQuery(false, false, issuerValue, request, namespace); + } + + @SuppressWarnings("unchecked") + public static XACMLAuthzDecisionQueryType createAuthzDecisionQuery( + boolean inputContextOnly, + boolean returnContext, + String issuerValue, + RequestType request, + String namespace + ) { + if (xacmlAuthzDecisionQueryTypeBuilder == null) { + xacmlAuthzDecisionQueryTypeBuilder = (XACMLObjectBuilder<XACMLAuthzDecisionQueryType>) + builderFactory.getBuilder(XACMLAuthzDecisionQueryType.DEFAULT_ELEMENT_NAME_XACML20); + } + XACMLAuthzDecisionQueryType authzQuery = + xacmlAuthzDecisionQueryTypeBuilder.buildObject( + namespace, + XACMLAuthzDecisionQueryType.DEFAULT_ELEMENT_LOCAL_NAME, + SAMLProfileConstants.SAML20XACMLPROTOCOL_PREFIX + ); + authzQuery.setID("_" + UUID.randomUUID().toString()); + authzQuery.setVersion(SAMLVersion.VERSION_20); + authzQuery.setIssueInstant(new DateTime()); + authzQuery.setInputContextOnly(Boolean.valueOf(inputContextOnly)); + authzQuery.setReturnContext(Boolean.valueOf(returnContext)); + + if (issuerValue != null) { + Issuer issuer = createIssuer(issuerValue); + authzQuery.setIssuer(issuer); + } + + authzQuery.setRequest(request); + + return authzQuery; + } + + + /** + * Create an Issuer object + * + * @param issuerValue of type String + * @return an Issuer object + */ + @SuppressWarnings("unchecked") + public static Issuer createIssuer(String issuerValue) { + if (issuerBuilder == null) { + issuerBuilder = (SAMLObjectBuilder<Issuer>) + builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME); + + } + Issuer issuer = issuerBuilder.buildObject(); + // + // The SAML authority that is making the claim(s) in the assertion. The issuer SHOULD + // be unambiguous to the intended relying parties. + issuer.setValue(issuerValue); + return issuer; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLAuthorizingInterceptor.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLAuthorizingInterceptor.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLAuthorizingInterceptor.java new file mode 100644 index 0000000..ca76382 --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLAuthorizingInterceptor.java @@ -0,0 +1,167 @@ +/** + * 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.xacml2; + +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.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.helpers.DOMUtils; +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; +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 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. + */ +public class XACMLAuthorizingInterceptor extends AbstractPhaseInterceptor<Message> { + private static final Logger LOG = LogUtils.getL7dLogger(XACMLAuthorizingInterceptor.class); + + private XACMLRequestBuilder requestBuilder = new DefaultXACMLRequestBuilder(); + private PolicyDecisionPoint pdp; + + public XACMLAuthorizingInterceptor(PolicyDecisionPoint pdp) { + super(Phase.PRE_INVOKE); + org.apache.wss4j.common.saml.OpenSAMLUtil.initSamlEngine(); + this.pdp = pdp; + } + + 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 { + if (authorize(principal, roles, 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 boolean authorize( + Principal principal, List<String> roles, Message message + ) throws Exception { + RequestType request = requestBuilder.createRequest(principal, roles, message); + if (LOG.isLoggable(Level.FINE)) { + Document doc = DOMUtils.createDocument(); + Element requestElement = OpenSAMLUtil.toDom(request, doc); + LOG.log(Level.FINE, DOM2Writer.nodeToString(requestElement)); + } + + ResponseType response = performRequest(request, message); + + 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; + } + + /** + * Handle any Obligations returned by the PDP + */ + protected void handleObligations( + RequestType request, + Principal principal, + Message message, + ResultType result + ) throws Exception { + // Do nothing by default + } + + protected ResponseType performRequest(RequestType request, Message message) throws Exception { + return this.pdp.evaluate(request); + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLRequestBuilder.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLRequestBuilder.java b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLRequestBuilder.java new file mode 100644 index 0000000..8aa6e4c --- /dev/null +++ b/rt/security-saml/src/main/java/org/apache/cxf/rt/security/saml/xacml2/XACMLRequestBuilder.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.cxf.rt.security.saml.xacml2; + +import java.security.Principal; +import java.util.List; + +import org.apache.cxf.message.Message; +import org.opensaml.xacml.ctx.RequestType; + + +/** + * 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 OpenSAML RequestType object + * @throws Exception + */ + RequestType createRequest(Principal principal, List<String> roles, Message message) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/8176b1b0/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/DummyPDP.java ---------------------------------------------------------------------- diff --git a/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/DummyPDP.java b/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/DummyPDP.java deleted file mode 100644 index a096208..0000000 --- a/rt/security-saml/src/test/java/org/apache/cxf/rt/security/saml/xacml/DummyPDP.java +++ /dev/null @@ -1,153 +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.cxf.rt.security.saml.xacml; - -import java.util.List; - -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.helpers.DOMUtils; -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.opensaml.core.xml.XMLObjectBuilderFactory; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -import org.opensaml.xacml.XACMLObjectBuilder; -import org.opensaml.xacml.ctx.AttributeType; -import org.opensaml.xacml.ctx.DecisionType; -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.StatusCodeType; -import org.opensaml.xacml.ctx.StatusType; -import org.opensaml.xacml.ctx.SubjectType; - -/** - * A test implementation of AbstractXACMLAuthorizingInterceptor. It just mocks up a Response - * object based on the role of the Subject. If the role is "manager" then it permits the - * request, otherwise it denies it. - */ -public class DummyPDP implements PolicyDecisionPoint { - - public Source evaluate(Source requestSource) { - RequestType request = requestSourceToRequestType(requestSource); - String role = getSubjectRole(request); - DECISION decision = "manager".equals(role) ? DecisionType.DECISION.Permit : DecisionType.DECISION.Deny; - ResponseType response = createResponse(decision); - return responseType2Source(response); - } - - private RequestType requestSourceToRequestType(Source requestSource) { - try { - Transformer trans = TransformerFactory.newInstance().newTransformer(); - DOMResult res = new DOMResult(); - trans.transform(requestSource, res); - Node nd = res.getNode(); - if (nd instanceof Document) { - nd = ((Document)nd).getDocumentElement(); - } - return (RequestType)OpenSAMLUtil.fromDom((Element)nd); - } catch (Exception e) { - throw new RuntimeException("Error converting pdp response to ResponseType", e); - } - } - - private Source responseType2Source(ResponseType response) { - Document doc = DOMUtils.createDocument(); - Element responseElement; - try { - responseElement = OpenSAMLUtil.toDom(response, doc); - } catch (WSSecurityException e) { - throw new RuntimeException("Error converting PDP RequestType to Dom", e); - } - return new DOMSource(responseElement); - } - - private ResponseType createResponse(DECISION decision) { - XMLObjectBuilderFactory builderFactory = XMLObjectProviderRegistrySupport.getBuilderFactory(); - - @SuppressWarnings("unchecked") - XACMLObjectBuilder<ResponseType> responseTypeBuilder = - (XACMLObjectBuilder<ResponseType>) - builderFactory.getBuilder(ResponseType.DEFAULT_ELEMENT_NAME); - - @SuppressWarnings("unchecked") - XACMLObjectBuilder<ResultType> resultTypeBuilder = - (XACMLObjectBuilder<ResultType>) - builderFactory.getBuilder(ResultType.DEFAULT_ELEMENT_NAME); - - @SuppressWarnings("unchecked") - XACMLObjectBuilder<DecisionType> decisionTypeBuilder = - (XACMLObjectBuilder<DecisionType>) - builderFactory.getBuilder(DecisionType.DEFAULT_ELEMENT_NAME); - - @SuppressWarnings("unchecked") - XACMLObjectBuilder<StatusType> statusTypeBuilder = - (XACMLObjectBuilder<StatusType>) - builderFactory.getBuilder(StatusType.DEFAULT_ELEMENT_NAME); - - @SuppressWarnings("unchecked") - XACMLObjectBuilder<StatusCodeType> statusCodeTypeBuilder = - (XACMLObjectBuilder<StatusCodeType>) - builderFactory.getBuilder(StatusCodeType.DEFAULT_ELEMENT_NAME); - - ResultType result = resultTypeBuilder.buildObject(); - - DecisionType decisionType = decisionTypeBuilder.buildObject(); - decisionType.setDecision(decision); - result.setDecision(decisionType); - - StatusType status = statusTypeBuilder.buildObject(); - StatusCodeType statusCode = statusCodeTypeBuilder.buildObject(); - statusCode.setValue("urn:oasis:names:tc:xacml:1.0:status:ok"); - status.setStatusCode(statusCode); - result.setStatus(status); - - ResponseType response = responseTypeBuilder.buildObject(); - response.getResults().add(result); - return response; - } - - private String getSubjectRole(RequestType request) { - List<SubjectType> subjects = request.getSubjects(); - if (subjects != null) { - for (SubjectType subject : subjects) { - List<AttributeType> attributes = subject.getAttributes(); - if (attributes != null) { - for (AttributeType attribute : attributes) { - if (XACMLConstants.SUBJECT_ROLE.equals(attribute.getAttributeId())) { - return attribute.getAttributeValues().get(0).getValue(); - } - } - } - } - } - return null; - } - -}