From 9a99a9484f673655d55c35c15ef0ee596299a117 Mon Sep 17 00:00:00 2001 From: Bogumil Zebek Date: Tue, 16 Jun 2020 08:36:09 +0200 Subject: Increase code coverage Issue-ID: OPTFRA-776 Signed-off-by: Zebek Bogumil Change-Id: I80b775420a91cf6fcc06369043fc13b5081b23f7 --- .../org/onap/optf/cmso/aaf/AafClientCache.java | 4 +- .../onap/optf/cmso/aaf/AafContainerFilters.java | 44 ++++-- .../org/onap/optf/cmso/aaf/AafClientCacheTest.java | 169 +++++++++++++++++++++ .../optf/cmso/aaf/AafContainerFiltersTest.java | 115 ++++++++++++++ 4 files changed, 315 insertions(+), 17 deletions(-) create mode 100644 cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafClientCacheTest.java create mode 100644 cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafContainerFiltersTest.java (limited to 'cmso-service') diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafClientCache.java b/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafClientCache.java index 847836b..3b55a84 100755 --- a/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafClientCache.java +++ b/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafClientCache.java @@ -90,7 +90,7 @@ public class AafClientCache { if (!env.getProperty(AafProperties.aafEnabled.toString(), Boolean.class, true)) { return AuthorizationResult.Authorized; } - Map auth = getUserPasssword(requestContext); + Map auth = getUserPassword(requestContext); String permissions = getPermissions(auth); if (permissions == null) { return AuthorizationResult.AuthenticationFailure; @@ -209,7 +209,7 @@ public class AafClientCache { return AuthorizationResult.AuthenticationFailure; } - private Map getUserPasssword(ContainerRequestContext requestContext) { + private Map getUserPassword(ContainerRequestContext requestContext) { String header = requestContext.getHeaderString("Authorization"); Map userPassword = getUserPasswordFromAuthorizationHeader(header); diff --git a/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafContainerFilters.java b/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafContainerFilters.java index a8d860d..f23dca0 100755 --- a/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafContainerFilters.java +++ b/cmso-service/src/main/java/org/onap/optf/cmso/aaf/AafContainerFilters.java @@ -1,6 +1,7 @@ /* * Copyright (c) 2019 AT&T Intellectual Property. * Modifications Copyright © 2018 IBM. + * Modifications Copyright © 2020 Nokia. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,30 +54,43 @@ import org.springframework.stereotype.Component; @Profile(SpringProfiles.AAF_AUTHENTICATION) public class AafContainerFilters implements ContainerRequestFilter { + private static final String EMPTY_ENTITY_CONTENT = ""; + @Autowired - AafClientCache aafClientCache; + private AafClientCache aafClientCache; @Override public void filter(ContainerRequestContext requestContext) throws IOException { - ResponseBuilder builder = null; - AuthorizationResult status = null; - try { - status = aafClientCache.authorize(requestContext); - } catch (Exception e) { - Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); - status = AuthorizationResult.AuthenticationFailure; - } - switch (status) { + AuthorizationResult authorizationStatus = getAuthorizationResult(requestContext); + switch (authorizationStatus) { case AuthenticationFailure: - builder = Response.status(Response.Status.UNAUTHORIZED).entity(""); - builder.header("WWW-Authenticate", "Basic realm=\"Realm\""); - throw new WebApplicationException(builder.build()); + throw new WebApplicationException(createAuthenticationErrorResponse()); case AuthorizationFailure: - builder = Response.status(Response.Status.FORBIDDEN).entity(""); - throw new WebApplicationException(builder.build()); + throw new WebApplicationException(createAuthorizationErrorResponse()); case Authorized: case Authenticated: default: } } + + private AuthorizationResult getAuthorizationResult(ContainerRequestContext requestContext) { + AuthorizationResult status; + try { + status = aafClientCache.authorize(requestContext); + } catch (Exception e) { + Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + status = AuthorizationResult.AuthenticationFailure; + } + return status; + } + + private Response createAuthenticationErrorResponse() { + ResponseBuilder builder = Response.status(Response.Status.UNAUTHORIZED).entity(EMPTY_ENTITY_CONTENT); + builder.header("WWW-Authenticate", "Basic realm=\"Realm\""); + return builder.build(); + } + + private Response createAuthorizationErrorResponse() { + return Response.status(Response.Status.FORBIDDEN).entity(EMPTY_ENTITY_CONTENT).build(); + } } diff --git a/cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafClientCacheTest.java b/cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafClientCacheTest.java new file mode 100644 index 0000000..ef2e425 --- /dev/null +++ b/cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafClientCacheTest.java @@ -0,0 +1,169 @@ +package org.onap.optf.cmso.aaf; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.optf.cmso.common.exceptions.CmsoException; +import org.springframework.core.env.Environment; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class AafClientCacheTest { + + @Mock + Environment env; + + @Mock + AafClient aafClient; + + @Mock + AafUserRoleProperties aafUserRoleProperties; + + @Mock + SecurityContext securityContext; + + @Mock + ContainerRequestContext requestContext; + + @Mock + UriInfo uriInfo; + + @Mock + Response aafResponse; + + @InjectMocks + AafClientCache aafClientCache; + + @Test + public void shouldAuthorizeActorWhenAafIsDisabled() { + // given + when(env.getProperty( + eq(AafProperties.aafEnabled.toString()), + eq(Boolean.class), + eq(true)) + ).thenReturn(false); + + // when + final AafClientCache.AuthorizationResult result = aafClientCache.authorize(requestContext); + + // then + assertThat(result).isEqualTo(AafClientCache.AuthorizationResult.Authorized); + } + + @Test + public void shouldAuthorizeActorToResourceWhenActorHasProperPermissions() throws URISyntaxException, CmsoException, JsonProcessingException { + // given + when(env.getProperty( + eq(AafProperties.aafEnabled.toString()), + eq(Boolean.class), + eq(true)) + ).thenReturn(true); + + AafUserRole requiredRole = new AafUserRole("/context/someMethod","org\\.onap\\.osaaf\\.resources\\.access\\|rest\\|read"); + + // configure request context + setRequestContextWithAuthorizationHeader(); + + // configure aaf response + configureAafClientToReturnRequiredRole(requiredRole); + + // define which role is required/expected for selected url and method + when(aafUserRoleProperties.getForUrlMethod(eq("/context"), eq("someMethod"))).thenReturn(List.of(requiredRole)); + + // when + final AafClientCache.AuthorizationResult result = aafClientCache.authorize(requestContext); + + // then + assertThat(result).isEqualTo(AafClientCache.AuthorizationResult.Authorized); + } + + @Test + public void shouldReportThatActorDoesNotHaveAccessToResourceWhenRolesDoNotMatch() throws URISyntaxException, CmsoException, JsonProcessingException { + // given + when(env.getProperty( + eq(AafProperties.aafEnabled.toString()), + eq(Boolean.class), + eq(true)) + ).thenReturn(true); + + AafUserRole requiredRole = new AafUserRole("/context/someMethod","org\\.onap\\.osaaf\\.resources\\.access\\|rest\\|read"); + AafUserRole roleReturnedByAaf = new AafUserRole("/context/someMethod","org\\.onap\\.osaaf\\.resources\\.access\\|rest\\|write"); + + // configure request context + setRequestContextWithAuthorizationHeader(); + + // configure aaf response + configureAafClientToReturnRequiredRole(roleReturnedByAaf); + + // define which role is required/expected for selected url and method + when(aafUserRoleProperties.getForUrlMethod(eq("/context"), eq("someMethod"))).thenReturn(List.of(requiredRole)); + + // when + final AafClientCache.AuthorizationResult result = aafClientCache.authorize(requestContext); + + // then + assertThat(result).isEqualTo(AafClientCache.AuthorizationResult.AuthorizationFailure); + } + + @Test + public void shouldReportThatActorDoesNotHaveAccessToResourceWhenUserAndPasswordWasNotSet() throws URISyntaxException { + // given + when(env.getProperty( + eq(AafProperties.aafEnabled.toString()), + eq(Boolean.class), + eq(true)) + ).thenReturn(true); + + setDefaultRequestContextConfiguration(); + + // when + final AafClientCache.AuthorizationResult result = aafClientCache.authorize(requestContext); + + // then + assertThat(result).isEqualTo(AafClientCache.AuthorizationResult.AuthenticationFailure); + } + + private void setRequestContextWithAuthorizationHeader() throws URISyntaxException { + when(requestContext.getHeaderString(eq("Authorization"))).thenReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l"); + setDefaultRequestContextConfiguration(); + } + + private void setDefaultRequestContextConfiguration() throws URISyntaxException { + when(requestContext.getUriInfo()).thenReturn(uriInfo); + when(uriInfo.getAbsolutePath()).thenReturn(new URI("/context")); + when(requestContext.getMethod()).thenReturn("someMethod"); + when(requestContext.getSecurityContext()).thenReturn(securityContext); + } + + private void configureAafClientToReturnRequiredRole(AafUserRole requiredRole) throws JsonProcessingException, CmsoException { + when(aafResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode()); + when(aafResponse.getStatusInfo()).thenReturn(Response.Status.OK); + when(aafResponse.readEntity(Mockito.eq(String.class))).thenReturn(givenAafResponse(requiredRole)); + + when(aafClient.getAuthz(anyMap())).thenReturn(aafResponse); + } + + private String givenAafResponse(AafUserRole role) throws JsonProcessingException { + ObjectMapper om = new ObjectMapper(); + final AafPermResponse aafPermResponse = new AafPermResponse(); + aafPermResponse.setPerm(role.getAafPerms()); + return om.writeValueAsString(aafPermResponse); + } +} diff --git a/cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafContainerFiltersTest.java b/cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafContainerFiltersTest.java new file mode 100644 index 0000000..95ad4aa --- /dev/null +++ b/cmso-service/src/test/java/org/onap/optf/cmso/aaf/AafContainerFiltersTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020 Nokia. + * + * 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. + * + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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. + */ + +package org.onap.optf.cmso.aaf; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.container.ContainerRequestContext; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.fail; + +@RunWith(MockitoJUnitRunner.class) +public class AafContainerFiltersTest { + + @Mock + AafClientCache aafClientCache; + + @Mock + ContainerRequestContext requestContext; + + @InjectMocks + AafContainerFilters aafContainerFilters; + + @Test + public void shouldReportUnauthorizedErrorWhenErrorOccursDuringFetchingDataFromAafCache() { + + // given + Mockito.doThrow(new IllegalArgumentException("For JUnit only!")) + .when(aafClientCache) + .authorize(Mockito.any()); + + // when/then + assertThatThrownBy(() -> aafContainerFilters.filter(requestContext)) + .isInstanceOf(WebApplicationException.class) + .hasMessage("HTTP 401 Unauthorized"); + } + + + @Test + public void shouldReportAuthorizationErrorWhenAccessToResourceIsForbidden() { + + // given + Mockito.when(aafClientCache.authorize(Mockito.any())) + .thenReturn(AafClientCache.AuthorizationResult.AuthorizationFailure); + + // when/then + assertThatThrownBy(() -> aafContainerFilters.filter(requestContext)) + .isInstanceOf(WebApplicationException.class) + .hasMessage("HTTP 403 Forbidden"); + } + + @Test + public void shouldAcceptRequestWhenActorWasAuthenticated() { + + // given + Mockito.when(aafClientCache.authorize(Mockito.any())) + .thenReturn(AafClientCache.AuthorizationResult.Authenticated); + + // when/then + try { + aafContainerFilters.filter(requestContext); + } catch (Exception e) { + fail("Operation should pass!"); + } + } + + @Test + public void shouldAcceptRequestWhenActorWasAuthorized() { + + // given + Mockito.when(aafClientCache.authorize(Mockito.any())) + .thenReturn(AafClientCache.AuthorizationResult.Authorized); + + // when/then + try { + aafContainerFilters.filter(requestContext); + } catch (Exception e) { + fail("Operation should pass!"); + } + } +} -- cgit 1.2.3-korg