Merge "Authz unit test and code cleanup"
diff --git a/datarouter-prov/pom.xml b/datarouter-prov/pom.xml
index c71d877..cbcfc71 100755
--- a/datarouter-prov/pom.xml
+++ b/datarouter-prov/pom.xml
@@ -36,7 +36,8 @@
<sitePath>/content/sites/site/${project.groupId}/${project.artifactId}/${project.version}</sitePath>
<docker.location>${basedir}/target/${project.artifactId}</docker.location>
<datarouter.prov.image.name>${docker.image.root}${project.artifactId}</datarouter.prov.image.name>
- <sonar.exclusions>**/src/main/java/org/onap/dmaap/datarouter/reports/**</sonar.exclusions>
+ <sonar.exclusions>**/src/main/java/org/onap/dmaap/datarouter/reports/**,
+ **/src/main/java/org/onap/dmaap/authz/impl/AuthRespSupplementImpl.java</sonar.exclusions>
<sonar.language>java</sonar.language>
<sonar.skip>false</sonar.skip>
</properties>
@@ -435,6 +436,7 @@
<configuration>
<excludes>
<exclude>**/src/main/java/org/onap/dmaap/datarouter/reports/**</exclude>
+ <exclude>**/src/main/java/org/onap/dmaap/authz/impl/AuthRespSupplementImpl.java</exclude>
</excludes>
</configuration>
</plugin>
diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespImpl.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespImpl.java
index f327833..c7d7199 100644
--- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespImpl.java
+++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespImpl.java
@@ -44,21 +44,23 @@
/** Constructor. This version will not be used in Data Router R1 since we will not have advice and obligations.
*
* @param authorized flag indicating whether the response carried a permit response (<code>true</code>)
- * or something else (<code>false</code>).
+ * or something else (<code>false</code>).
* @param advice list of advice elements returned in the response.
* @param obligations list of obligation elements returned in the response.
*/
- public AuthRespImpl(boolean authorized, List<AuthorizationResponseSupplement> advice, List<AuthorizationResponseSupplement> obligations) {
+ private AuthRespImpl(boolean authorized, List<AuthorizationResponseSupplement> advice,
+ List<AuthorizationResponseSupplement> obligations) {
this.authorized = authorized;
- this.advice = (advice == null ? null : new ArrayList<AuthorizationResponseSupplement> (advice));
- this.obligations = (obligations == null ? null : new ArrayList<AuthorizationResponseSupplement> (obligations));
+ this.advice = (advice == null ? null : new ArrayList<>(advice));
+ this.obligations = (obligations == null ? null : new ArrayList<>(obligations));
}
/** Constructor. Simple version for authorization responses that have no advice and no obligations.
*
- * @param authorized flag indicating whether the response carried a permit (<code>true</code>) or something else (<code>false</code>).
+ * @param authorized flag indicating whether the response carried a permit (<code>true</code>)
+ * or something else (<code>false</code>).
*/
- public AuthRespImpl(boolean authorized) {
+ AuthRespImpl(boolean authorized) {
this(authorized, null, null);
}
@@ -69,25 +71,25 @@
*/
@Override
public boolean isAuthorized() {
- return authorized;
+ return authorized;
}
/**
* Returns any advice elements that were included in the authorization response.
*
- * @return A list of objects implementing the <code>AuthorizationResponseSupplement</code> interface, with each object representing an
- * advice element from the authorization response.
+ * @return A list of objects implementing the <code>AuthorizationResponseSupplement</code> interface,
+ * with each object representing an advice element from the authorization response.
*/
@Override
public List<AuthorizationResponseSupplement> getAdvice() {
- return advice;
+ return advice;
}
/**
* Returns any obligation elements that were included in the authorization response.
*
- * @return A list of objects implementing the <code>AuthorizationResponseSupplement</code> interface, with each object representing an
- * obligation element from the authorization response.
+ * @return A list of objects implementing the <code>AuthorizationResponseSupplement</code> interface,
+ * with each object representing an obligation element from the authorization response.
*/
@Override
public List<AuthorizationResponseSupplement> getObligations() {
diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespSupplementImpl.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespSupplementImpl.java
index d995270..b61c00e 100644
--- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespSupplementImpl.java
+++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthRespSupplementImpl.java
@@ -36,17 +36,17 @@
*/
public class AuthRespSupplementImpl implements AuthorizationResponseSupplement {
- private String id = null;
- private Map<String, String> attributes = null;
+ private String id;
+ private Map<String, String> attributes;
/** Constructor, available within the package.
*
* @param id The identifier for the advice or obligation element
* @param attributes The attributes (name-value pairs) for the advice or obligation element.
*/
- AuthRespSupplementImpl (String id, Map<String, String> attributes) {
+ AuthRespSupplementImpl(String id, Map<String, String> attributes) {
this.id = id;
- this.attributes = new HashMap<String,String>(attributes);
+ this.attributes = new HashMap<>(attributes);
}
/** Return the identifier for the supplementary information element.
diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthzResource.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthzResource.java
index 0357fa7..c248468 100644
--- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthzResource.java
+++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/AuthzResource.java
@@ -30,7 +30,6 @@
/** Internal representation of an authorization resource (the entity to which access is being requested). Consists
* of a type and an identifier. The constructor takes the request URI from an HTTP request and checks it against
* patterns for the the different resource types. In DR R1, there are four resource types:
- * <ul>
* <li>the feeds collection resource, the target of POST requests to create a new feed and GET requests to list
* the existing feeds. This is the root resource for the DR provisioning system, and it has no explicit id.
* </li>
@@ -53,10 +52,10 @@
private String id = "";
/* Construct an AuthzResource by matching a request URI against the various patterns */
- public AuthzResource(String rURI) {
- if (rURI != null) {
+ AuthzResource(String requestUri) {
+ if (requestUri != null) {
for (ResourceType t : ResourceType.values()) {
- Matcher m = t.getPattern().matcher(rURI);
+ Matcher m = t.getPattern().matcher(requestUri);
if (m.find(0)) {
this.type = t;
if (m.group("id") != null) {
@@ -83,13 +82,13 @@
*/
public enum ResourceType {
FEEDS_COLLECTION("((://[^/]+/)|(^/))(?<id>)$"),
- SUBS_COLLECTION ("((://[^/]+/)|(^/{0,1}))subscribe/(?<id>[^/]+)$"),
+ SUBS_COLLECTION("((://[^/]+/)|(^/{0,1}))subscribe/(?<id>[^/]+)$"),
FEED("((://[^/]+/)|(^/{0,1}))feed/(?<id>[^/]+)$"),
SUB("((://[^/]+/)|(^/{0,1}))subs/(?<id>[^/]+)$");
private Pattern uriPattern;
- private ResourceType(String patternString) {
+ ResourceType(String patternString) {
this.uriPattern = Pattern.compile(patternString);
}
diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthorizer.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthorizer.java
index 745e339..595b626 100644
--- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthorizer.java
+++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthorizer.java
@@ -23,17 +23,15 @@
package org.onap.dmaap.datarouter.authz.impl;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-
import com.att.eelf.configuration.EELFLogger;
import com.att.eelf.configuration.EELFManager;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
import org.onap.dmaap.datarouter.authz.AuthorizationResponse;
import org.onap.dmaap.datarouter.authz.Authorizer;
import org.onap.dmaap.datarouter.authz.impl.AuthzResource.ResourceType;
-/** Authorizer for the provisioning API for Data Router R1
+/** Authorizer for the provisioning API for Data Router R1.
*
* @author J. F. Lucas
*
@@ -45,6 +43,7 @@
private static final String SUBJECT_HEADER = "X-DMAAP-DR-ON-BEHALF-OF"; // HTTP header carrying requester identity
private static final String SUBJECT_HEADER_GROUP = "X-DMAAP-DR-ON-BEHALF-OF-GROUP"; // HTTP header carrying requester identity by group Rally : US708115
+
/** Constructor. For the moment, do nothing special. Make it a singleton?
*
*/
@@ -63,7 +62,7 @@
*/
@Override
public AuthorizationResponse decide(HttpServletRequest request) {
- return this.decide(request, null);
+ return this.decide(request, null);
}
/**
@@ -79,80 +78,66 @@
@Override
public AuthorizationResponse decide(HttpServletRequest request,
Map<String, String> additionalAttrs) {
- log.trace ("Entering decide()");
-
+ log.trace("Entering decide()");
boolean decision = false;
-
// Extract interesting parts of the HTTP request
String method = request.getMethod();
AuthzResource resource = new AuthzResource(request.getRequestURI());
- String subject = (request.getHeader(SUBJECT_HEADER)); // identity of the requester
- String subjectgroup = (request.getHeader(SUBJECT_HEADER_GROUP)); // identity of the requester by group Rally : US708115
+ String subject = (request.getHeader(SUBJECT_HEADER));
+ String subjectgroup = (request.getHeader(SUBJECT_HEADER_GROUP));
- log.trace("Method: " + method + " -- Type: " + resource.getType() + " -- Id: " + resource.getId() +
- " -- Subject: " + subject);
-
+ log.trace("Method: " + method + " -- Type: " + resource.getType() + " -- Id: " + resource.getId()
+ + " -- Subject: " + subject);
// Choose authorization method based on the resource type
ResourceType resourceType = resource.getType();
if (resourceType != null) {
-
switch (resourceType) {
-
- case FEEDS_COLLECTION:
- decision = allowFeedsCollectionAccess(resource, method, subject, subjectgroup);
- break;
-
- case SUBS_COLLECTION:
- decision = allowSubsCollectionAccess(resource, method, subject, subjectgroup);
- break;
-
- case FEED:
- decision = allowFeedAccess(resource, method, subject, subjectgroup);
- break;
-
- case SUB:
- decision = allowSubAccess(resource, method, subject, subjectgroup);
- break;
-
- default:
- decision = false;
- break;
+ case FEEDS_COLLECTION:
+ decision = allowFeedsCollectionAccess(method);
+ break;
+ case SUBS_COLLECTION:
+ decision = allowSubsCollectionAccess(method);
+ break;
+ case FEED:
+ decision = allowFeedAccess(resource, method, subject, subjectgroup);
+ break;
+ case SUB:
+ decision = allowSubAccess(resource, method, subject, subjectgroup);
+ break;
+ default:
+ decision = false;
+ break;
}
}
- log.debug("Exit decide(): " + method + "|" + resourceType + "|" + resource.getId() + "|" + subject + " ==> " + decision);
+ log.debug("Exit decide(): " + method + "|" + resourceType + "|" + resource.getId() + "|"
+ + subject + " ==> " + decision);
return new AuthRespImpl(decision);
}
- private boolean allowFeedsCollectionAccess(AuthzResource resource, String method, String subject, String subjectgroup) {
-
+ private boolean allowFeedsCollectionAccess(String method) {
// Allow GET or POST unconditionally
return method != null && ("GET".equalsIgnoreCase(method) || "POST".equalsIgnoreCase(method));
}
- private boolean allowSubsCollectionAccess(AuthzResource resource, String method, String subject, String subjectgroup) {
-
+ private boolean allowSubsCollectionAccess(String method) {
// Allow GET or POST unconditionally
return method != null && ("GET".equalsIgnoreCase(method) || "POST".equalsIgnoreCase(method));
}
- private boolean allowFeedAccess(AuthzResource resource, String method, String subject, String subjectgroup) {
+ private boolean allowFeedAccess(AuthzResource resource, String method, String subject, String subjectgroup) {
boolean decision = false;
-
// Allow GET, PUT, or DELETE if requester (subject) is the owner (publisher) of the feed
- if ( method != null && ("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method) ||
- "DELETE".equalsIgnoreCase(method))) {
+ if ( method != null && ("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method) || "DELETE".equalsIgnoreCase(method))) {
String owner = provData.getFeedOwner(resource.getId());
decision = (owner != null) && owner.equals(subject);
-
//Verifying by group Rally : US708115
- if(subjectgroup != null) {
- String feedowner = provData.getGroupByFeedGroupId(subject, resource.getId());
- decision = (feedowner != null) && feedowner.equals(subjectgroup);
+ if (subjectgroup != null) {
+ String feedOwner = provData.getGroupByFeedGroupId(subject, resource.getId());
+ decision = (feedOwner != null) && feedOwner.equals(subjectgroup);
}
}
-
return decision;
}
@@ -160,14 +145,13 @@
boolean decision = false;
// Allow GET, PUT, or DELETE if requester (subject) is the owner of the subscription (subscriber)
- if (method != null && ("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method) ||
- "DELETE".equalsIgnoreCase(method) || "POST".equalsIgnoreCase(method))) {
+ if (method != null && ("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method) || "DELETE".equalsIgnoreCase(method) || "POST".equalsIgnoreCase(method))) {
String owner = provData.getSubscriptionOwner(resource.getId());
decision = (owner != null) && owner.equals(subject);
//Verifying by group Rally : US708115
- if(subjectgroup != null) {
+ if (subjectgroup != null) {
String feedowner = provData.getGroupBySubGroupId(subject, resource.getId());
decision = (feedowner != null) && feedowner.equals(subjectgroup);
}
diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthTest.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthTest.java
new file mode 100644
index 0000000..7de4ea9
--- /dev/null
+++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/authz/impl/ProvAuthTest.java
@@ -0,0 +1,134 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.datarouter.authz.impl;
+
+import static org.mockito.Mockito.when;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.servlet.http.HttpServletRequest;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.onap.dmaap.datarouter.authz.AuthorizationResponse;
+import org.onap.dmaap.datarouter.authz.impl.ProvAuthorizer;
+import org.onap.dmaap.datarouter.provisioning.StatisticsServlet;
+import org.onap.dmaap.datarouter.provisioning.utils.DB;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+public class ProvAuthTest {
+
+ @Mock
+ private HttpServletRequest request;
+
+ @Mock
+ private StatisticsServlet statisticsServlet;
+
+ private ProvAuthorizer provAuthorizer;
+
+ private static EntityManagerFactory emf;
+ private static EntityManager em;
+ private DB db;
+
+ @BeforeClass
+ public static void init() {
+ emf = Persistence.createEntityManagerFactory("dr-unit-tests");
+ em = emf.createEntityManager();
+ System.setProperty(
+ "org.onap.dmaap.datarouter.provserver.properties",
+ "src/test/resources/h2Database.properties");
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ em.clear();
+ em.close();
+ emf.close();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ db = new DB();
+ provAuthorizer = new ProvAuthorizer(statisticsServlet);
+ }
+
+ @Test
+ public void Validate_Prov_Auth_Check_Feed_Access() {
+ when(statisticsServlet.getFeedOwner(Mockito.anyString())).thenReturn("dr-admin");
+ when(statisticsServlet.getGroupByFeedGroupId(Mockito.anyString(), Mockito.anyString())).thenReturn("stub_auth_id");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF")).thenReturn("dr-admin");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_auth_id");
+ when(request.getMethod()).thenReturn("PUT");
+ when(request.getRequestURI()).thenReturn("http://the-request-uri:443/feed/1?1");
+ AuthorizationResponse authResp;
+ authResp = provAuthorizer.decide(request);
+ Assert.assertTrue(authResp.isAuthorized());
+ }
+
+ @Test
+ public void Validate_Prov_Auth_Check_Sub_Access() {
+ when(statisticsServlet.getSubscriptionOwner(Mockito.anyString())).thenReturn("dr-admin");
+ when(statisticsServlet.getGroupBySubGroupId(Mockito.anyString(), Mockito.anyString())).thenReturn("stub_auth_id");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF")).thenReturn("dr-admin");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_auth_id");
+ when(request.getMethod()).thenReturn("PUT");
+ when(request.getRequestURI()).thenReturn("http://the-request-uri:443/subs/1?1");
+ AuthorizationResponse authResp;
+ authResp = provAuthorizer.decide(request);
+ Assert.assertTrue(authResp.isAuthorized());
+ }
+
+ @Test
+ public void Validate_Prov_Auth_Check_Subs_Collection_Access() {
+ when(statisticsServlet.getSubscriptionOwner(Mockito.anyString())).thenReturn("dr-admin");
+ when(statisticsServlet.getGroupBySubGroupId(Mockito.anyString(), Mockito.anyString())).thenReturn("stub_auth_id");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF")).thenReturn("dr-admin");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_auth_id");
+ when(request.getMethod()).thenReturn("POST");
+ when(request.getRequestURI()).thenReturn("http://the-request-uri:443/subscribe/1?1");
+ AuthorizationResponse authResp;
+ authResp = provAuthorizer.decide(request);
+ Assert.assertTrue(authResp.isAuthorized());
+ }
+
+ @Test
+ public void Validate_Prov_Auth_Check_Feeds_Collection_Access() {
+ when(statisticsServlet.getFeedOwner(Mockito.anyString())).thenReturn("dr-admin");
+ when(statisticsServlet.getGroupByFeedGroupId(Mockito.anyString(), Mockito.anyString())).thenReturn("stub_auth_id");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF")).thenReturn("dr-admin");
+ when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_auth_id");
+ when(request.getMethod()).thenReturn("POST");
+ when(request.getRequestURI()).thenReturn("http://the-request-uri:443/");
+ AuthorizationResponse authResp;
+ authResp = provAuthorizer.decide(request);
+ Assert.assertTrue(authResp.isAuthorized());
+ Assert.assertNull(authResp.getAdvice());
+ Assert.assertNull(authResp.getObligations());
+ }
+
+}