You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2013/07/29 15:36:54 UTC

svn commit: r1508064 - in /cxf/trunk/rt/security/src: main/java/org/apache/cxf/rt/security/xacml/ test/java/org/apache/cxf/rt/security/xacml/

Author: coheigea
Date: Mon Jul 29 13:36:53 2013
New Revision: 1508064

URL: http://svn.apache.org/r1508064
Log:
[CXF-5154,CXF-5155] - Some changes to the PEP -> PDP request

Removed:
    cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/CXFMessageParserTest.java
Modified:
    cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/CXFMessageParser.java
    cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java
    cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java
    cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java
    cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java

Modified: cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/CXFMessageParser.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/CXFMessageParser.java?rev=1508064&r1=1508063&r2=1508064&view=diff
==============================================================================
--- cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/CXFMessageParser.java (original)
+++ cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/CXFMessageParser.java Mon Jul 29 13:36:53 2013
@@ -18,12 +18,9 @@
  */
 package org.apache.cxf.rt.security.xacml;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import javax.xml.namespace.QName;
 
 import org.w3c.dom.Element;
-
 import org.apache.cxf.interceptor.security.SAMLSecurityContext;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.security.SecurityContext;
@@ -35,32 +32,41 @@ public class CXFMessageParser {
 
     /**
      * @param message
-     * @param fullRequestURL 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 CXFMessageParser(Message message) {
         this.message = message;
     }
+    
+    public boolean isSOAPService() {
+        return !(getWSDLService() == null || getWSDLOperation() == null);
+    }
 
-    /**
-     * Return the Resources that have been inserted into the Request
-     */
-    public List<String> getResources(boolean fullRequestURL) {
-        if (message == null) {
-            return Collections.emptyList();
+    public QName getWSDLOperation() {
+        if (message != null && message.get(Message.WSDL_OPERATION) != null) {
+            return (QName)message.get(Message.WSDL_OPERATION);
         }
-        List<String> resources = new ArrayList<String>();
-        if (message.get(Message.WSDL_OPERATION) != null) {
-            resources.add(message.get(Message.WSDL_OPERATION).toString());
+        return null;
+    }
+    
+    public QName getWSDLService() {
+        if (message != null && message.get(Message.WSDL_SERVICE) != null) {
+            return (QName)message.get(Message.WSDL_SERVICE);
         }
+        return null;
+    }
+    
+    /**
+     * @param fullRequestURL 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 String getResourceURI(boolean fullRequestURL) {
         String property = fullRequestURL ? Message.REQUEST_URL : Message.REQUEST_URI;
-        String request = (String)message.get(property);
-        if (request != null) {
-            resources.add(request);
+        if (message != null && message.get(property) != null) {
+            return (String)message.get(property);
         }
-        return resources;
+        return null;
     }
 
     public String getAction(String defaultSOAPAction) {

Modified: cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java?rev=1508064&r1=1508063&r2=1508064&view=diff
==============================================================================
--- cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java (original)
+++ cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java Mon Jul 29 13:36:53 2013
@@ -24,6 +24,8 @@ 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;
@@ -35,18 +37,26 @@ import org.opensaml.xacml.ctx.ResourceTy
 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". The
- * resource is the WSDL Operation for a SOAP service, and the request URI for a REST service. You can also
- * configure the ability to send the full request URL instead for a SOAP or REST service. The current DateTime
- * is also sent in an Environment, however this can be disabled via configuration.
+ * 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;
+    private boolean sendFullRequestURL = true;
 
     /**
      * Create an XACML Request given a Principal, list of roles and Message.
@@ -55,11 +65,11 @@ public class DefaultXACMLRequestBuilder 
         throws Exception {
         CXFMessageParser messageParser = new CXFMessageParser(message);
         String issuer = messageParser.getIssuer();
-        List<String> resources = messageParser.getResources(sendFullRequestURL);
+        
         String actionToUse = messageParser.getAction(action);
 
         SubjectType subjectType = createSubjectType(principal, roles, issuer);
-        ResourceType resourceType = createResourceType(resources);
+        ResourceType resourceType = createResourceType(messageParser);
         AttributeType actionAttribute = createAttribute(XACMLConstants.ACTION_ID, XACMLConstants.XS_STRING,
                                                         null, actionToUse);
         ActionType actionType = RequestComponentBuilder.createActionType(Collections.singletonList(actionAttribute));
@@ -70,14 +80,47 @@ public class DefaultXACMLRequestBuilder 
                                                          createEnvironmentType());
     }
 
-    private ResourceType createResourceType(List<String> resources) {
+    private ResourceType createResourceType(CXFMessageParser messageParser) {
         List<AttributeType> attributes = new ArrayList<AttributeType>();
-        for (String resource : resources) {
-            if (resource != null) {
-                attributes.add(createAttribute(XACMLConstants.RESOURCE_ID, XACMLConstants.XS_STRING, null,
-                                               resource));
+        
+        // Resource-id
+        String resourceId = null;
+        boolean isSoapService = messageParser.isSOAPService();
+        if (isSoapService) {
+            QName serviceName = messageParser.getWSDLService();
+            QName operationName = messageParser.getWSDLOperation();
+            
+            resourceId = serviceName.toString() + "#";
+            if (serviceName.getNamespaceURI() != null 
+                && serviceName.getNamespaceURI().equals(operationName.getNamespaceURI())) {
+                resourceId += operationName.getLocalPart();
+            } 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();
+            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()));
+            
+            // Resource URI
+            String resourceURI = messageParser.getResourceURI(sendFullRequestURL);
+            attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_URI_ID, XACMLConstants.XS_STRING, null,
+                                           resourceURI));
         }
+        
         return RequestComponentBuilder.createResourceType(attributes, null);
     }
 

Modified: cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java?rev=1508064&r1=1508063&r2=1508064&view=diff
==============================================================================
--- cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java (original)
+++ cxf/trunk/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java Mon Jul 29 13:36:53 2013
@@ -73,6 +73,15 @@ public final class XACMLConstants {
         "urn:oasis:names:tc:xacml:1.0:resource:resource-location";
     public static final String RESOURCE_ID = 
         "urn:oasis:names:tc:xacml:1.0:resource:resource-id";
+    
+    // Non-standard (CXF-specific) tags for sending information about SOAP services to the PDP
+    public static final String RESOURCE_WSDL_OPERATION_ID = 
+        "urn:cxf:apache:org:wsdl:operation-id";
+    public static final String RESOURCE_WSDL_SERVICE_ID = 
+        "urn:cxf:apache:org:wsdl:service-id";
+    public static final String RESOURCE_WSDL_URI_ID = 
+        "urn:cxf:apache:org:wsdl:resource-id";
+
     public static final String RESOURCE_FILE_NAME = 
         "urn:oasis:names:tc:xacml:1.0:resource:simple-file-name";
     public static final String ACTION_ID = 

Modified: cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java?rev=1508064&r1=1508063&r2=1508064&view=diff
==============================================================================
--- cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java (original)
+++ cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java Mon Jul 29 13:36:53 2013
@@ -24,6 +24,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import javax.security.auth.Subject;
+import javax.xml.namespace.QName;
 
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageImpl;
@@ -47,7 +48,11 @@ public class XACMLAuthorizingInterceptor
         
         String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt";
         MessageImpl msg = new MessageImpl();
-        msg.put(Message.WSDL_OPERATION, operation);
+        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 resourceURI = "https://localhost:8080/doubleit";
+        msg.put(Message.REQUEST_URI, resourceURI);
         msg.put(SecurityContext.class, sc);
         
         AbstractXACMLAuthorizingInterceptor authorizingInterceptor = 
@@ -62,7 +67,11 @@ public class XACMLAuthorizingInterceptor
         
         String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt";
         MessageImpl msg = new MessageImpl();
-        msg.put(Message.WSDL_OPERATION, operation);
+        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 resourceURI = "https://localhost:8080/doubleit";
+        msg.put(Message.REQUEST_URI, resourceURI);
         msg.put(SecurityContext.class, sc);
         
         AbstractXACMLAuthorizingInterceptor authorizingInterceptor = 

Modified: cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java?rev=1508064&r1=1508063&r2=1508064&view=diff
==============================================================================
--- cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java (original)
+++ cxf/trunk/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java Mon Jul 29 13:36:53 2013
@@ -21,10 +21,15 @@ package org.apache.cxf.rt.security.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;
 
 
 /**
@@ -47,7 +52,11 @@ public class XACMLRequestBuilderTest ext
         
         String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt";
         MessageImpl msg = new MessageImpl();
-        msg.put(Message.WSDL_OPERATION, operation);
+        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 = 
@@ -67,7 +76,11 @@ public class XACMLRequestBuilderTest ext
         
         String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt";
         MessageImpl msg = new MessageImpl();
-        msg.put(Message.WSDL_OPERATION, operation);
+        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 = 
@@ -98,7 +111,11 @@ public class XACMLRequestBuilderTest ext
         
         String operation = "{http://www.example.org/contract/DoubleIt}DoubleIt";
         MessageImpl msg = new MessageImpl();
-        msg.put(Message.WSDL_OPERATION, operation);
+        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 = 
@@ -112,4 +129,179 @@ public class XACMLRequestBuilderTest ext
         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_URI_ID.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_URI_ID.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);
+        }
+    }
 }