From: efiacor Date: Wed, 17 Jul 2019 12:44:17 +0000 (+0000) Subject: Authz unit test and code cleanup X-Git-Tag: 2.1.3~22^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?p=dmaap%2Fdatarouter.git;a=commitdiff_plain;h=00cc27b0fa1346435c7685300286f1adc98b69fb Authz unit test and code cleanup Change-Id: I5c6a099ca4e6479df37505aa6bc645d8a26a42e1 Issue-ID: DMAAP-1226 Signed-off-by: efiacor --- diff --git a/datarouter-prov/pom.xml b/datarouter-prov/pom.xml index c71d877b..cbcfc71f 100755 --- a/datarouter-prov/pom.xml +++ b/datarouter-prov/pom.xml @@ -36,7 +36,8 @@ /content/sites/site/${project.groupId}/${project.artifactId}/${project.version} ${basedir}/target/${project.artifactId} ${docker.image.root}${project.artifactId} - **/src/main/java/org/onap/dmaap/datarouter/reports/** + **/src/main/java/org/onap/dmaap/datarouter/reports/**, + **/src/main/java/org/onap/dmaap/authz/impl/AuthRespSupplementImpl.java java false @@ -435,6 +436,7 @@ **/src/main/java/org/onap/dmaap/datarouter/reports/** + **/src/main/java/org/onap/dmaap/authz/impl/AuthRespSupplementImpl.java 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 f3278332..c7d71996 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 @@ public class AuthRespImpl implements AuthorizationResponse { /** 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 (true) - * or something else (false). + * or something else (false). * @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 advice, List obligations) { + private AuthRespImpl(boolean authorized, List advice, + List obligations) { this.authorized = authorized; - this.advice = (advice == null ? null : new ArrayList (advice)); - this.obligations = (obligations == null ? null : new ArrayList (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 (true) or something else (false). + * @param authorized flag indicating whether the response carried a permit (true) + * or something else (false). */ - public AuthRespImpl(boolean authorized) { + AuthRespImpl(boolean authorized) { this(authorized, null, null); } @@ -69,25 +71,25 @@ public class AuthRespImpl implements AuthorizationResponse { */ @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 AuthorizationResponseSupplement interface, with each object representing an - * advice element from the authorization response. + * @return A list of objects implementing the AuthorizationResponseSupplement interface, + * with each object representing an advice element from the authorization response. */ @Override public List getAdvice() { - return advice; + return advice; } /** * Returns any obligation elements that were included in the authorization response. * - * @return A list of objects implementing the AuthorizationResponseSupplement interface, with each object representing an - * obligation element from the authorization response. + * @return A list of objects implementing the AuthorizationResponseSupplement interface, + * with each object representing an obligation element from the authorization response. */ @Override public List 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 d995270e..b61c00e5 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 @@ import org.onap.dmaap.datarouter.authz.AuthorizationResponseSupplement; */ public class AuthRespSupplementImpl implements AuthorizationResponseSupplement { - private String id = null; - private Map attributes = null; + private String id; + private Map 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 attributes) { + AuthRespSupplementImpl(String id, Map attributes) { this.id = id; - this.attributes = new HashMap(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 0357fa74..c248468f 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 @@ import java.util.regex.Pattern; /** 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: - *
    *
  • 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. *
  • @@ -53,10 +52,10 @@ public class AuthzResource { 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 class AuthzResource { */ public enum ResourceType { FEEDS_COLLECTION("((://[^/]+/)|(^/))(?)$"), - SUBS_COLLECTION ("((://[^/]+/)|(^/{0,1}))subscribe/(?[^/]+)$"), + SUBS_COLLECTION("((://[^/]+/)|(^/{0,1}))subscribe/(?[^/]+)$"), FEED("((://[^/]+/)|(^/{0,1}))feed/(?[^/]+)$"), SUB("((://[^/]+/)|(^/{0,1}))subs/(?[^/]+)$"); 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 745e339d..595b626c 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 @@ public class ProvAuthorizer implements Authorizer { 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 @@ public class ProvAuthorizer implements Authorizer { */ @Override public AuthorizationResponse decide(HttpServletRequest request) { - return this.decide(request, null); + return this.decide(request, null); } /** @@ -79,80 +78,66 @@ public class ProvAuthorizer implements Authorizer { @Override public AuthorizationResponse decide(HttpServletRequest request, Map 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 - - log.trace("Method: " + method + " -- Type: " + resource.getType() + " -- Id: " + resource.getId() + - " -- Subject: " + subject); + 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); // 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 @@ public class ProvAuthorizer implements Authorizer { 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 00000000..7de4ea91 --- /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()); + } + +}