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 17:04:48 UTC

svn commit: r1508092 - in /cxf/branches/2.7.x-fixes/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 15:04:47 2013
New Revision: 1508092

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


Conflicts:
	rt/security/src/main/java/org/apache/cxf/rt/security/xacml/CXFMessageParser.java
	rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java
	rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java

Modified:
    cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/AbstractXACMLAuthorizingInterceptor.java
    cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java
    cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java
    cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilder.java
    cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java
    cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java

Modified: cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/AbstractXACMLAuthorizingInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/AbstractXACMLAuthorizingInterceptor.java?rev=1508092&r1=1508091&r2=1508092&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/AbstractXACMLAuthorizingInterceptor.java (original)
+++ cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/AbstractXACMLAuthorizingInterceptor.java Mon Jul 29 15:04:47 2013
@@ -129,19 +129,11 @@ public abstract class AbstractXACMLAutho
         // Handle any Obligations returned by the PDP
         handleObligations(request, principal, message, result);
         
-        List<String> resources = requestBuilder.getResources(message);
         if (result != null 
-            && (result.getDecision().getDecision() == DecisionType.DECISION.Permit)) {
-            if (result.getResourceId() == null) {
-                LOG.fine("XACML authorization permitted");
-                return true;
-            }
-            for (String resource : resources) {
-                if (resource.equals(result.getResourceId())) {
-                    LOG.fine("XACML authorization permitted");
-                    return true;
-                }
-            }
+            && (result.getDecision().getDecision() == DecisionType.DECISION.Permit)
+            && (result.getResourceId() == null)) {
+            LOG.fine("XACML authorization permitted");
+            return true;
         }
         LOG.fine("XACML authorization not permitted:");
         if (result != null && result.getStatus() != null) {

Modified: cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java?rev=1508092&r1=1508091&r2=1508092&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java (original)
+++ cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/DefaultXACMLRequestBuilder.java Mon Jul 29 15:04:47 2013
@@ -24,8 +24,9 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.w3c.dom.Element;
+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;
@@ -42,20 +43,26 @@ import org.opensaml.xacml.ctx.SubjectTyp
 
 
 /**
- * This class constructs an XACML Request given a Principal, list of roles and MessageContext,
+ * 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.
+ * 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.
  * 
- * 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. 
+ * 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 String action = "execute";
     private boolean sendDateTime = true;
-    private boolean sendFullRequestURL;
+    private boolean sendFullRequestURL = true;
     
     /**
      * Set a new Action String to use
@@ -78,7 +85,6 @@ public class DefaultXACMLRequestBuilder 
         Principal principal, List<String> roles, Message message
     ) throws Exception {
         String issuer = getIssuer(message);
-        List<String> resources = getResources(message);
         String actionToUse = getAction(message);
         
         // Subject
@@ -118,22 +124,7 @@ public class DefaultXACMLRequestBuilder 
         SubjectType subjectType = RequestComponentBuilder.createSubjectType(attributes, null);
         
         // Resource
-        attributes.clear();
-        for (String resource : resources) {
-            if (resource != null) {
-                AttributeValueType resourceAttributeValue = 
-                    RequestComponentBuilder.createAttributeValueType(resource);
-                AttributeType resourceAttribute = 
-                    RequestComponentBuilder.createAttributeType(
-                            XACMLConstants.RESOURCE_ID,
-                            XACMLConstants.XS_STRING,
-                            null,
-                            Collections.singletonList(resourceAttributeValue)
-                    );
-                attributes.add(resourceAttribute);
-            }
-        }
-        ResourceType resourceType = RequestComponentBuilder.createResourceType(attributes, null);
+        ResourceType resourceType = createResourceType(message);
         
         // Action
         AttributeValueType actionAttributeValue = 
@@ -179,6 +170,50 @@ public class DefaultXACMLRequestBuilder 
         return request;
     }
     
+    private ResourceType createResourceType(Message message) {
+        List<AttributeType> attributes = new ArrayList<AttributeType>();
+        
+        // Resource-id
+        String resourceId = null;
+        boolean isSoapService = isSOAPService(message);
+        if (isSoapService) {
+            QName serviceName = getWSDLService(message);
+            QName operationName = getWSDLOperation(message);
+            
+            resourceId = serviceName.toString() + "#";
+            if (serviceName.getNamespaceURI() != null 
+                && serviceName.getNamespaceURI().equals(operationName.getNamespaceURI())) {
+                resourceId += operationName.getLocalPart();
+            } else {
+                resourceId += operationName.toString();
+            }
+        } else {
+            resourceId = getResourceURI(message, sendFullRequestURL);
+        }
+        
+        attributes.add(createAttribute(XACMLConstants.RESOURCE_ID, XACMLConstants.XS_STRING, null,
+                                           resourceId));
+        
+        if (isSoapService) {
+            // WSDL Service
+            QName wsdlService = getWSDLService(message);
+            attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_SERVICE_ID, XACMLConstants.XS_STRING, null,
+                                           wsdlService.toString()));
+            
+            // WSDL Operation
+            QName wsdlOperation = getWSDLOperation(message);
+            attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_OPERATION_ID, XACMLConstants.XS_STRING, null,
+                                           wsdlOperation.toString()));
+            
+            // Resource URI
+            String resourceURI = getResourceURI(message, sendFullRequestURL);
+            attributes.add(createAttribute(XACMLConstants.RESOURCE_WSDL_URI_ID, XACMLConstants.XS_STRING, null,
+                                           resourceURI));
+        }
+        
+        return RequestComponentBuilder.createResourceType(attributes, null);
+    }
+    
     /**
      * Get the Issuer of the SAML Assertion
      */
@@ -211,46 +246,43 @@ public class DefaultXACMLRequestBuilder 
     /**
      * 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).
+     * to false, 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;
     }
     
-    
-    /**
-     * Return the Resources that have been inserted into the Request
-     */
-    public List<String> getResources(Message message) {
-        if (message == null) {
-            return Collections.emptyList();
-        }
-        List<String> resources = new ArrayList<String>();
-        if (message.get(Message.WSDL_OPERATION) != null) {
-            resources.add(message.get(Message.WSDL_OPERATION).toString());
-        } 
-        if (sendFullRequestURL) {
-            resources.add((String)message.get(Message.REQUEST_URL));
-        } else {
-            resources.add((String)message.get(Message.REQUEST_URI));
+    private boolean isSOAPService(Message message) {
+        return !(getWSDLService(message) == null || getWSDLOperation(message) == null);
+    }
+
+    private QName getWSDLOperation(Message message) {
+        if (message != null && message.get(Message.WSDL_OPERATION) != null) {
+            return (QName)message.get(Message.WSDL_OPERATION);
         }
-        return resources;
+        return null;
     }
     
-    public String getResource(Message message) {
-        if (message == null) {
-            return null;
+    private QName getWSDLService(Message message) {
+        if (message != null && message.get(Message.WSDL_SERVICE) != null) {
+            return (QName)message.get(Message.WSDL_SERVICE);
         }
-        String resource = null;
-        if (sendFullRequestURL) {
-            resource = (String)message.get(Message.REQUEST_URL);
-        } else if (message.get(Message.WSDL_OPERATION) != null) {
-            resource = message.get(Message.WSDL_OPERATION).toString();
-        } else {
-            resource = (String)message.get(Message.REQUEST_URI);
+        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, 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)
+     */
+    private String getResourceURI(Message message, boolean fullRequestURL) {
+        String property = fullRequestURL ? Message.REQUEST_URL : Message.REQUEST_URI;
+        if (message != null && message.get(property) != null) {
+            return (String)message.get(property);
         }
-        return resource;
+        return null;
     }
     
     private String getAction(Message message) {
@@ -262,4 +294,14 @@ public class DefaultXACMLRequestBuilder 
         }
         return actionToUse;
     }
+    
+    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)));
+    }
+
 }

Modified: cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java?rev=1508092&r1=1508091&r2=1508092&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java (original)
+++ cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLConstants.java Mon Jul 29 15:04:47 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/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilder.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilder.java?rev=1508092&r1=1508091&r2=1508092&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilder.java (original)
+++ cxf/branches/2.7.x-fixes/rt/security/src/main/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilder.java Mon Jul 29 15:04:47 2013
@@ -44,20 +44,4 @@ public interface XACMLRequestBuilder {
         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
-     */
-    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);
 }

Modified: cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java?rev=1508092&r1=1508091&r2=1508092&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java (original)
+++ cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLAuthorizingInterceptorTest.java Mon Jul 29 15:04:47 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;
@@ -48,7 +49,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);
         
         XACMLAuthorizingInterceptor authorizingInterceptor = 
@@ -63,7 +68,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);
         
         XACMLAuthorizingInterceptor authorizingInterceptor = 

Modified: cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java?rev=1508092&r1=1508091&r2=1508092&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java (original)
+++ cxf/branches/2.7.x-fixes/rt/security/src/test/java/org/apache/cxf/rt/security/xacml/XACMLRequestBuilderTest.java Mon Jul 29 15:04:47 2013
@@ -21,11 +21,16 @@ 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.apache.ws.security.saml.ext.OpenSAMLUtil;
+import org.opensaml.xacml.ctx.AttributeType;
 import org.opensaml.xacml.ctx.RequestType;
+import org.opensaml.xacml.ctx.ResourceType;
 
 
 /**
@@ -48,7 +53,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 = 
@@ -57,7 +66,7 @@ public class XACMLRequestBuilderTest ext
     }
     
     @org.junit.Test
-    public void testResource() throws Exception {
+    public void testAction() throws Exception {
         // Mock up a request
         Principal principal = new Principal() {
             public String getName() {
@@ -67,37 +76,61 @@ 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 = 
             builder.createRequest(principal, Collections.singletonList("manager"), msg);
         assertNotNull(request); 
         
-        assertTrue(builder.getResources(msg).contains(operation));
-        
-        operation = "user/list.json";
-        msg = new MessageImpl();
-        msg.put(Message.REQUEST_URI, operation);
+        String action = 
+            request.getAction().getAttributes().get(0).getAttributeValues().get(0).getValue();
+        assertEquals(action, "execute");
         
+        ((DefaultXACMLRequestBuilder)builder).setAction("write");
         request = builder.createRequest(principal, Collections.singletonList("manager"), msg);
         assertNotNull(request); 
         
-        assertTrue(builder.getResources(msg).contains(operation));
+        action = 
+            request.getAction().getAttributes().get(0).getAttributeValues().get(0).getValue();
+        assertEquals(action, "write");
+    }
+    
+    @org.junit.Test
+    public void testEnvironment() throws Exception {
+        // Mock up a request
+        Principal principal = new Principal() {
+            public String getName() {
+                return "alice";
+            }
+        };
         
-        operation = "https://localhost:8080/user/list.json";
-        msg = new MessageImpl();
-        msg.put(Message.REQUEST_URL, operation);
+        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);
         
-        ((DefaultXACMLRequestBuilder)builder).setSendFullRequestURL(true);
-        request = builder.createRequest(principal, Collections.singletonList("manager"), msg);
-        assertNotNull(request); 
+        XACMLRequestBuilder builder = new DefaultXACMLRequestBuilder();
+        RequestType request = 
+            builder.createRequest(principal, Collections.singletonList("manager"), msg);
+        assertNotNull(request);
+        assertFalse(request.getEnvironment().getAttributes().isEmpty());
         
-        assertTrue(builder.getResources(msg).contains(operation));
+        ((DefaultXACMLRequestBuilder)builder).setSendDateTime(false);
+        request = builder.createRequest(principal, Collections.singletonList("manager"), msg);
+        assertNotNull(request);
+        assertTrue(request.getEnvironment().getAttributes().isEmpty());
     }
     
     @org.junit.Test
-    public void testAction() throws Exception {
+    public void testSOAPResource() throws Exception {
         // Mock up a request
         Principal principal = new Principal() {
             public String getName() {
@@ -107,28 +140,52 @@ 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 = 
             builder.createRequest(principal, Collections.singletonList("manager"), msg);
-        assertNotNull(request); 
-        
-        String action = 
-            request.getAction().getAttributes().get(0).getAttributeValues().get(0).getValue();
-        assertEquals(action, "execute");
+        assertNotNull(request);
         
-        ((DefaultXACMLRequestBuilder)builder).setAction("write");
-        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;
+            }
+        }
         
-        action = 
-            request.getAction().getAttributes().get(0).getAttributeValues().get(0).getValue();
-        assertEquals(action, "write");
+        assertTrue(resourceIdSatisfied && soapServiceSatisfied && soapOperationSatisfied
+                   && resourceURISatisfied);
     }
     
     @org.junit.Test
-    public void testEnvironment() throws Exception {
+    public void testSOAPResourceDifferentNamespace() throws Exception {
         // Mock up a request
         Principal principal = new Principal() {
             public String getName() {
@@ -138,18 +195,113 @@ 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/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);
-        assertFalse(request.getEnvironment().getAttributes().isEmpty());
         
-        ((DefaultXACMLRequestBuilder)builder).setSendDateTime(false);
-        request = builder.createRequest(principal, Collections.singletonList("manager"), msg);
+        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);
-        assertTrue(request.getEnvironment().getAttributes().isEmpty());
+        
+        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);
+        }
+    }
 }