From f07e4b397c60c21ae275a7c98471b64e60f14f04 Mon Sep 17 00:00:00 2001 From: PatrikBuhr Date: Wed, 5 Apr 2023 14:40:07 +0200 Subject: A1 PMS support for fine grained access control -A1 London Issue-ID: CCSDK-3885 Signed-off-by: PatrikBuhr Change-Id: I2ee8f40389d1d53cbfd9433232e0f35f2644361b --- .../OpenPolicyAgentSimulatorController.java | 112 +++++++++++++++++++++ .../controllers/v2/ApplicationTest.java | 78 +++++++++++++- 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/OpenPolicyAgentSimulatorController.java (limited to 'a1-policy-management/src/test') diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/OpenPolicyAgentSimulatorController.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/OpenPolicyAgentSimulatorController.java new file mode 100644 index 00000000..236c31b8 --- /dev/null +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/OpenPolicyAgentSimulatorController.java @@ -0,0 +1,112 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2023 Nordix Foundation. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.controllers; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +import java.lang.invoke.MethodHandles; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import lombok.Getter; + +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.AuthorizationConsts; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.AuthorizationResult; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; + +@RestController("OpenPolicyAgentSimulatorController") +@Tag(name = AuthorizationConsts.AUTH_API_NAME, description = AuthorizationConsts.AUTH_API_DESCRIPTION) +public class OpenPolicyAgentSimulatorController { + private static Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + public static final String ACCESS_CONTROL_URL = "/example-authz-check"; + public static final String ACCESS_CONTROL_URL_REJECT = "/example-authz-check-reject"; + + public static class TestResults { + + public List receivedRequests = + Collections.synchronizedList(new ArrayList()); + + public TestResults() {} + + public void reset() { + receivedRequests.clear(); + + } + } + + @Getter + private TestResults testResults = new TestResults(); + + @PostMapping(path = ACCESS_CONTROL_URL, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = AuthorizationConsts.GRANT_ACCESS_SUMMARY, + description = AuthorizationConsts.GRANT_ACCESS_DESCRIPTION) + @ApiResponses(value = { // + @ApiResponse(responseCode = "200", description = "OK", // + content = @Content(schema = @Schema(implementation = AuthorizationResult.class))) // + }) + public ResponseEntity performAccessControl( // + @RequestHeader Map headers, // + @RequestBody PolicyAuthorizationRequest request) { + logger.debug("Auth {}", request); + testResults.receivedRequests.add(request); + + String res = gson.toJson(AuthorizationResult.builder().result(true).build()); + return new ResponseEntity<>(res, HttpStatus.OK); + } + + @PostMapping(path = ACCESS_CONTROL_URL_REJECT, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Rejecting", description = "", hidden = true) + @ApiResponses(value = { // + @ApiResponse(responseCode = "200", description = "OK", // + content = @Content(schema = @Schema(implementation = VoidResponse.class))) // + }) + public ResponseEntity performAccessControlReject( // + @RequestHeader Map headers, // + @RequestBody PolicyAuthorizationRequest request) { + logger.debug("Auth Reject {}", request); + testResults.receivedRequests.add(request); + String res = gson.toJson(AuthorizationResult.builder().result(false).build()); + return new ResponseEntity<>(res, HttpStatus.OK); + } + +} diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java index 9f0473df..066adc48 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java @@ -46,6 +46,7 @@ import java.util.List; import org.json.JSONObject; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; @@ -58,7 +59,10 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationCo import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.OpenPolicyAgentSimulatorController; import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbackInfo; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest.Input.AccessType; import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType; @@ -145,6 +149,9 @@ class ApplicationTest { @Autowired SecurityContext securityContext; + @Autowired + OpenPolicyAgentSimulatorController openPolicyAgentSimulatorController; + private static Gson gson = new GsonBuilder().create(); /** @@ -174,6 +181,11 @@ class ApplicationTest { @LocalServerPort private int port; + @BeforeEach + void init() { + this.applicationConfig.setAuthProviderUrl(baseUrl() + OpenPolicyAgentSimulatorController.ACCESS_CONTROL_URL); + } + @AfterEach void reset() { rics.clear(); @@ -184,6 +196,7 @@ class ApplicationTest { this.rAppSimulator.getTestResults().clear(); this.a1ClientFactory.setPolicyTypes(policyTypes); // Default same types in RIC and in this app this.securityContext.setAuthTokenFilePath(null); + this.openPolicyAgentSimulatorController.getTestResults().reset(); } @AfterAll @@ -513,6 +526,15 @@ class ApplicationTest { this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE); restClient().put(url, policyBody).block(); + { + // Check the authorization request + OpenPolicyAgentSimulatorController.TestResults res = + this.openPolicyAgentSimulatorController.getTestResults(); + assertThat(res.receivedRequests).hasSize(1); + PolicyAuthorizationRequest req = res.receivedRequests.get(0); + assertThat(req.getInput().getAccessType()).isEqualTo(AccessType.WRITE); + assertThat(req.getInput().getPolicyTypeId()).isEqualTo(policyTypeName); + } Policy policy = policies.getPolicy(policyInstanceId); assertThat(policy).isNotNull(); @@ -550,6 +572,57 @@ class ApplicationTest { this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE); } + @Test + void testFineGrainedAuth() throws Exception { + final String POLICY_ID = "policyId"; + final String RIC_ID = "ric1"; + final String TYPE_ID = "typeName"; + addPolicy(POLICY_ID, TYPE_ID, null, RIC_ID); + assertThat(policies.size()).isEqualTo(1); + + this.applicationConfig + .setAuthProviderUrl(baseUrl() + OpenPolicyAgentSimulatorController.ACCESS_CONTROL_URL_REJECT); + + String url = "/policy-instances"; + String rsp = restClient().get(url).block(); + assertThat(rsp).as("Response contains no policy instance ID.").contains("[]"); + + url = "/policies/" + POLICY_ID; + testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized"); + + url = "/policies"; + String policyBody = putPolicyBody(null, RIC_ID, TYPE_ID, POLICY_ID, false, null); + testErrorCode(restClient().put(url, policyBody), HttpStatus.UNAUTHORIZED, "Not authorized"); + + rsp = restClient().get(url).block(); + assertThat(rsp).as("Response contains no policy instance ID.").contains("[]"); + } + + @Test + void testFineGrainedAuth_OPA_UNAVALIABLE() throws Exception { + final String POLICY_ID = "policyId"; + final String RIC_ID = "ric1"; + final String TYPE_ID = "typeName"; + addPolicy(POLICY_ID, TYPE_ID, null, RIC_ID); + assertThat(policies.size()).isEqualTo(1); + + this.applicationConfig.setAuthProviderUrl("junk"); + + String url = "/policy-instances"; + String rsp = restClient().get(url).block(); + assertThat(rsp).as("Response contains no policy instance ID.").contains("[]"); + + url = "/policies/" + POLICY_ID; + testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized"); + + url = "/policies"; + String policyBody = putPolicyBody(null, RIC_ID, TYPE_ID, POLICY_ID, false, null); + testErrorCode(restClient().put(url, policyBody), HttpStatus.UNAUTHORIZED, "Not authorized"); + + rsp = restClient().get(url).block(); + assertThat(rsp).as("Response contains no policy instance ID.").contains("[]"); + } + @Test @DisplayName("test Put Policy No Service No Status Uri") void testPutPolicy_NoServiceNoStatusUri() throws Exception { @@ -1042,6 +1115,7 @@ class ApplicationTest { @Test @DisplayName("test Concurrency") void testConcurrency() throws Exception { + this.applicationConfig.setAuthProviderUrl(""); logger.info("Concurrency test starting"); final Instant startTime = Instant.now(); List threads = new ArrayList<>(); @@ -1138,8 +1212,10 @@ class ApplicationTest { boolean expectApplicationProblemJsonMediaType) { assertTrue(throwable instanceof WebClientResponseException); WebClientResponseException responseException = (WebClientResponseException) throwable; + String body = responseException.getResponseBodyAsString(); + assertThat(body).contains(responseContains); assertThat(responseException.getStatusCode()).isEqualTo(expStatus); - assertThat(responseException.getResponseBodyAsString()).contains(responseContains); + if (expectApplicationProblemJsonMediaType) { assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON); } -- cgit 1.2.3-korg