From 642622502dc1222af8570a3de2b0223fa5474500 Mon Sep 17 00:00:00 2001 From: "Lott, Christopher (cl778h)" Date: Fri, 27 Sep 2019 10:26:24 -0400 Subject: [PATCH] Improve doc for Portal API configuration Refactor some classes but no functional changes, so did not bump the version number. Change-Id: I42dcba55ba980f94a956c0d3990f2f6d4a9cce11 Signed-off-by: Lott, Christopher (cl778h) --- docs/config-deploy.rst | 111 +++++++++++++++------ docs/release-notes.rst | 4 +- .../dashboard/config/PortalApiConfiguration.java | 57 +++++++++++ .../dashboard/config/WebSecurityConfiguration.java | 17 ---- .../config/PortalApIMockConfiguration.java | 83 +++++++++++++++ .../config/WebSecurityMockConfiguration.java | 46 --------- .../controller/PortalRestCentralServiceTest.java | 10 +- 7 files changed, 228 insertions(+), 100 deletions(-) create mode 100644 webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/PortalApiConfiguration.java create mode 100644 webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/PortalApIMockConfiguration.java diff --git a/docs/config-deploy.rst b/docs/config-deploy.rst index e11c1e40..5f62be40 100644 --- a/docs/config-deploy.rst +++ b/docs/config-deploy.rst @@ -20,32 +20,36 @@ RIC Dashboard Configuration and Deployment ========================================== This documents the configuration and deployment of the O-RAN SC RIC -Dashboard web application. +Dashboard web application, which is often deployed together with the +ONAP Portal. Configuration ------------- -The application requires the following configuration files. In the -usual Kubernetes deployment, all files are provided by a configuration -map:: +The application requires the following configuration files:: application.properties key.properties portal.properties +In the usual Kubernetes deployment, all file contents are provided by +a configuration map. Application Properties ^^^^^^^^^^^^^^^^^^^^^^ -This Spring-Boot application reads key-value pairs from the file -``application.properties`` in the current working directory when -launched, or from the same file in a ``config`` subdirectory. Many -properties have default values cached within the application, in file -``src/main/resources/application.properties``. Properties with +The file ``application.properties`` must be provided when the +application is launched, either in the current working directory or in +a ``config`` subdirectory (latter is preferred). The Helm chart that +deploys the application should mount this file appropriately. + +Many properties have default values cached within the application, in +file ``src/main/resources/application.properties``. Properties with default values do NOT need to be repeated in a deployment-specific configuration. Properties without default values MUST be specified in -a deployment-specific configuration. The properties are listed below -in alphabetical order. +a deployment-specific configuration. + +The properties are listed below in alphabetical order. ``a1med.url.prefix`` @@ -99,7 +103,14 @@ Java class that decrypts ciphertext from Portal. Default is ``portalapi.password`` -Application password expected at ONAP portal. No default value. +REST password expected at ONAP portal. No default value. + +``portalapi.security`` + +Boolean flag whether the Dashboard limits access to users (browsers) +that present security tokens set by the ONAP Portal. If false, no +access control is performed, which is only appropriate for isolated +lab testing. ``portalapi.usercookie`` @@ -107,7 +118,7 @@ Name of request cookie with user ID. Default is ``UserId`` ``portalapi.username`` -Application user name expected at ONAP portal. No default value. +REST user name expected at ONAP portal. No default value. ``server.port`` @@ -126,9 +137,12 @@ Key Properties ^^^^^^^^^^^^^^ The file ``key.properties`` must be provided on the Java classpath for -the EPSDK-FW library. A sample file is in directory -``src/test/resources``. The file must contain the following entries, -listed here in alphabetical order. +the Spring-Boot application, as required by the EPSDK-FW library. The +Helm chart for the application should mount this file appropriately. +A sample file is in directory ``src/test/resources``. + +The file must contain the following entries, listed here in +alphabetical order. ``cipher.enc.key`` @@ -139,19 +153,23 @@ Portal Properties ^^^^^^^^^^^^^^^^^ The file ``portal.properties`` must be provided on the Java classpath -for the EPSDK-FW library. A sample file is in directory -``src/test/resources``. The file must contain the following entries, -listed here in alphabetical order. +for the application, as required by the EPSDK-FW library. The Helm +chart for the application should mount this file appropriately. A +sample file is in directory ``src/test/resources``. + +The file must contain the following entries, listed here in +alphabetical order. ``ecomp_redirect_url`` -URL of ONAP Portal. No default value. Usually a value like +Portal URL that is reachable by a user's browser. This is a value +like ``https://portal.api.simpledemo.onap.org:30225/ONAPPORTAL/login.htm`` ``ecomp_rest_url`` -URL of ONAP Portal REST endpoint. No default value. Usually a value -like ``http://portal-app.onap:8989/ONAPPORTAL/auxapi`` +Portal REST URL that is reachable by the Dashboard back-end. +This is a value like ``http://portal-app.onap:8989/ONAPPORTAL/auxapi`` ``portal.api.impl.class`` @@ -172,14 +190,47 @@ Deployment ---------- A production server requires the configuration files listed above. -All files should be placed in a ``config`` directory. That name is important; -Spring automatically searches that directory for the ``application.properties`` -file. Further, that directory can easily be placed on the Java classpath so -the additional files can be found at runtime. - -After creating and mounting Kubernetes config maps appropriately, launch -the server with this command-line invocation to include the ``config`` directory -on the Java classpath:: +All files should be placed in a ``config`` directory. That name is +important; Spring automatically searches that directory for the +``application.properties`` file. Further, that directory can easily be +placed on the Java classpath so the additional files can be found at +runtime. + + +On-Board Dashboard to ONAP Portal +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When on-boarding the Dashboard to the ONAP Portal the administrator +must supply the following information about the deployed instance: + +- Dashboard URL that is reachable by a user's browser. The domain of + this host name must match the Portal URL that is similarly reachable + by a user's browser for cookie-based authentication to function as + expected. This should be a value like + ``http://dashboard.simpledemo.onap.org:8080`` +- Dashboard REST URL that is reachable by the Portal back-end server. + This can be a host name or an IP address, because it does not use + cookie-based authentication. This should be a value like + ``http://192.168.1.1:8080/auxapi/v3`` + +The Dashboard server only listens on a single port, so the examples +above both use the same port number. Different port numbers might be +required if an ingress controller or other proxy server is used. + +After the on-boarding process is complete, the administrator must +enter values from the Portal for the following properties explained +above: + +- ``portalapi.password`` +- ``portalapi.username`` +- ``ueb_app_key`` + +Launch Server +^^^^^^^^^^^^^ + +After creating, populating and mounting Kubernetes config maps +appropriately, launch the server with this command-line invocation to +include the ``config`` directory on the Java classpath:: java -cp config:target/ric-dash-be-1.2.0-SNAPSHOT.jar \ -Dloader.main=org.oransc.ric.portal.dashboard.DashboardApplication \ diff --git a/docs/release-notes.rst b/docs/release-notes.rst index b574db31..2453d603 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -19,9 +19,9 @@ RIC Dashboard Release Notes =========================== -Version 1.2.2, 23 Sep 2019 +Version 1.2.2, 27 Sep 2019 -------------------------- -* Supoprt Portal security using EPSDK-FW cookie and user management +* Support Portal security using EPSDK-FW cookie and user management Version 1.2.1, 20 Sep 2019 -------------------------- diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/PortalApiConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/PortalApiConfiguration.java new file mode 100644 index 00000000..b71ed227 --- /dev/null +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/PortalApiConfiguration.java @@ -0,0 +1,57 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 AT&T Intellectual Property and 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. + * ========================LICENSE_END=================================== + */ +package org.oransc.ric.portal.dashboard.config; + +import java.lang.invoke.MethodHandles; + +import org.onap.portalsdk.core.onboarding.crossapi.PortalRestAPIProxy; +import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("!test") +public class PortalApiConfiguration { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + /** + * Instantiates the EPSDK-FW servlet that implements the API called by Portal. + * Needed because this app is not configured to scan the EPSDK-FW packages; + * there's also a chance that Spring-Boot does not automatically + * process @WebServlet annotations. + * + * @return Servlet registration bean for the Portal Rest API proxy servlet. + */ + @Bean + public ServletRegistrationBean portalApiProxyServletBean() { + logger.debug("portalApiProxyServletBean"); + PortalRestAPIProxy servlet = new PortalRestAPIProxy(); + final ServletRegistrationBean servletBean = new ServletRegistrationBean<>(servlet, + PortalApiConstants.API_PREFIX + "/*"); + servletBean.setName("PortalRestApiProxyServlet"); + return servletBean; + } + +} diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java index 686b9cb1..edb80c8e 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; -import org.onap.portalsdk.core.onboarding.crossapi.PortalRestAPIProxy; import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; import org.oransc.ric.portal.dashboard.DashboardConstants; import org.oransc.ric.portal.dashboard.LoginServlet; @@ -145,22 +144,6 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { return portalAuthenticationFilter; } - /** - * Instantiates the EPSDK-FW servlet. Needed because this app is not configured - * to scan the EPSDK-FW packages; there's also a chance that Spring-Boot does - * not automatically process @WebServlet annotations. - * - * @return Servlet registration bean for the Portal Rest API proxy servlet. - */ - @Bean - public ServletRegistrationBean portalApiProxyServletBean() { - PortalRestAPIProxy servlet = new PortalRestAPIProxy(); - final ServletRegistrationBean servletBean = new ServletRegistrationBean<>(servlet, - PortalApiConstants.API_PREFIX + "/*"); - servletBean.setName("PortalRestApiProxyServlet"); - return servletBean; - } - /** * Instantiates a trivial login servlet that serves a basic page with a link to * authenticate at Portal. The login filter redirects to this page instead of diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/PortalApIMockConfiguration.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/PortalApIMockConfiguration.java new file mode 100644 index 00000000..6eeae85f --- /dev/null +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/PortalApIMockConfiguration.java @@ -0,0 +1,83 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 AT&T Intellectual Property and 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. + * ========================LICENSE_END=================================== + */ +package org.oransc.ric.portal.dashboard.config; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; + +import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.portalsdk.core.onboarding.crossapi.PortalRestAPIProxy; +import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; +import org.oransc.ric.portal.dashboard.portalapi.PortalAuthManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("test") +public class PortalApIMockConfiguration { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + // Unfortunately EPSDK-FW does not define these as constants + public static final String PORTAL_USERNAME_HEADER_KEY = "username"; + public static final String PORTAL_PASSWORD_HEADER_KEY = "password"; + + @Bean + public ServletRegistrationBean portalApiProxyServlet() { + PortalRestAPIProxy servlet = new PortalRestAPIProxy(); + final ServletRegistrationBean servletBean = new ServletRegistrationBean<>(servlet, + PortalApiConstants.API_PREFIX + "/*"); + servletBean.setName("PortalRestApiProxyServlet"); + return servletBean; + } + + @Bean + public PortalAuthManager portalAuthManager() throws Exception { + PortalAuthManager mockManager = mock(PortalAuthManager.class); + final Map credentialsMap = new HashMap<>(); + credentialsMap.put("appName", "appName"); + credentialsMap.put(PORTAL_USERNAME_HEADER_KEY, PORTAL_USERNAME_HEADER_KEY); + credentialsMap.put(PORTAL_PASSWORD_HEADER_KEY, PORTAL_PASSWORD_HEADER_KEY); + doAnswer(inv -> { + logger.debug("getAppCredentials"); + return credentialsMap; + }).when(mockManager).getAppCredentials(); + doAnswer(inv -> { + logger.debug("getUserId"); + return "userId"; + }).when(mockManager).valdiateEcompSso(any(HttpServletRequest.class)); + doAnswer(inv -> { + logger.debug("getAppCredentials"); + return credentialsMap; + }).when(mockManager).getAppCredentials(); + return mockManager; + } + +} diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/WebSecurityMockConfiguration.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/WebSecurityMockConfiguration.java index cc9a3088..8d066934 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/WebSecurityMockConfiguration.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/WebSecurityMockConfiguration.java @@ -19,29 +19,18 @@ */ package org.oransc.ric.portal.dashboard.config; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; - import java.io.File; import java.io.IOException; import java.lang.invoke.MethodHandles; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpServletRequest; - -import org.onap.portalsdk.core.onboarding.crossapi.PortalRestAPIProxy; import org.onap.portalsdk.core.onboarding.exception.PortalAPIException; -import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; import org.onap.portalsdk.core.restful.domain.EcompRole; import org.onap.portalsdk.core.restful.domain.EcompUser; import org.oransc.ric.portal.dashboard.DashboardConstants; import org.oransc.ric.portal.dashboard.LoginServlet; import org.oransc.ric.portal.dashboard.portalapi.DashboardUserManager; -import org.oransc.ric.portal.dashboard.portalapi.PortalAuthManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -67,10 +56,6 @@ public class WebSecurityMockConfiguration extends WebSecurityConfigurerAdapter { public static final String TEST_CRED_ADMIN = "admin"; public static final String TEST_CRED_STANDARD = "standard"; - // Unfortunately EPSDK-FW does not define these as constants - public static final String PORTAL_USERNAME_HEADER_KEY = "username"; - public static final String PORTAL_PASSWORD_HEADER_KEY = "password"; - private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); public WebSecurityMockConfiguration(@Value("${userfile}") final String userFilePath) { @@ -116,37 +101,6 @@ public class WebSecurityMockConfiguration extends WebSecurityConfigurerAdapter { return servletBean; } - @Bean - public ServletRegistrationBean portalApiProxyServlet() { - PortalRestAPIProxy servlet = new PortalRestAPIProxy(); - final ServletRegistrationBean servletBean = new ServletRegistrationBean<>(servlet, - PortalApiConstants.API_PREFIX + "/*"); - servletBean.setName("PortalRestApiProxyServlet"); - return servletBean; - } - - @Bean - public PortalAuthManager portalAuthManager() throws Exception { - PortalAuthManager mockManager = mock(PortalAuthManager.class); - final Map credentialsMap = new HashMap<>(); - credentialsMap.put("appName", "appName"); - credentialsMap.put(PORTAL_USERNAME_HEADER_KEY, PORTAL_USERNAME_HEADER_KEY); - credentialsMap.put(PORTAL_PASSWORD_HEADER_KEY, PORTAL_PASSWORD_HEADER_KEY); - doAnswer(inv -> { - logger.debug("getAppCredentials"); - return credentialsMap; - }).when(mockManager).getAppCredentials(); - doAnswer(inv -> { - logger.debug("getUserId"); - return "userId"; - }).when(mockManager).valdiateEcompSso(any(HttpServletRequest.class)); - doAnswer(inv -> { - logger.debug("getAppCredentials"); - return credentialsMap; - }).when(mockManager).getAppCredentials(); - return mockManager; - } - // This implementation is so light it can be used during tests. @Bean public DashboardUserManager dashboardUserManager() throws IOException, PortalAPIException { diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/PortalRestCentralServiceTest.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/PortalRestCentralServiceTest.java index 509dda7c..bb310282 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/PortalRestCentralServiceTest.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/PortalRestCentralServiceTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test; import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; import org.onap.portalsdk.core.restful.domain.EcompUser; import org.oransc.ric.portal.dashboard.DashboardConstants; -import org.oransc.ric.portal.dashboard.config.WebSecurityMockConfiguration; +import org.oransc.ric.portal.dashboard.config.PortalApIMockConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpEntity; @@ -62,10 +62,10 @@ public class PortalRestCentralServiceTest extends AbstractControllerTest { private HttpEntity getEntityWithHeaders(Object body) { HttpHeaders headers = new HttpHeaders(); - headers.set(WebSecurityMockConfiguration.PORTAL_USERNAME_HEADER_KEY, - WebSecurityMockConfiguration.PORTAL_USERNAME_HEADER_KEY); - headers.set(WebSecurityMockConfiguration.PORTAL_PASSWORD_HEADER_KEY, - WebSecurityMockConfiguration.PORTAL_PASSWORD_HEADER_KEY); + headers.set(PortalApIMockConfiguration.PORTAL_USERNAME_HEADER_KEY, + PortalApIMockConfiguration.PORTAL_USERNAME_HEADER_KEY); + headers.set(PortalApIMockConfiguration.PORTAL_PASSWORD_HEADER_KEY, + PortalApIMockConfiguration.PORTAL_PASSWORD_HEADER_KEY); HttpEntity entity = new HttpEntity<>(body, headers); return entity; } -- 2.16.6