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);
+ }
+ }
}