From: Lott, Christopher (cl778h) Date: Wed, 7 Aug 2019 18:46:08 +0000 (-0400) Subject: Postpone authentication to version 1.2.1 X-Git-Tag: R2~48 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=beea5ee48a0efddde5e868eb0c99ba4ba67f1d46;p=portal%2Fric-dashboard.git Postpone authentication to version 1.2.1 Change-Id: I9a86348dca7dd79c2080019156b568f103f11dbe Signed-off-by: Lott, Christopher (cl778h) --- diff --git a/docs/release-notes.rst b/docs/release-notes.rst index a214b213..cfe16ace 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -20,16 +20,19 @@ RIC Dashboard Release Notes =========================== +Version 1.2.1, ? Aug 2019 +------------------------- +* Add EPSDK-FW user management and Portal security + Version 1.2.0, 7 Aug 2019 ------------------------- * Split URL properties into prefix/suffix parts * Add jacoco plugin to back-end for code coverage -* Compile with Java version 11, run with image openjdk:11 +* Compile with Java version 11, use base openjdk:11-jre-slim * Clean code of issues reported by Sonar * Drop mock RAN names feature that supported R1 testing * Extend mock endpoints to simulate delay seen in tests * Move mock configuration classes into test area -* Add EPSDK-FW user management and Portal security * Update A1 mediator client to spec version 0.10.0 * Update App manager client to spec version 0.1.7 diff --git a/webapp-backend/README.md b/webapp-backend/README.md index 6751ef99..67e4a3b6 100644 --- a/webapp-backend/README.md +++ b/webapp-backend/README.md @@ -14,9 +14,14 @@ server, see below. This server requires several configuration files: - application.properties (in launch directory) - key.properties (on Java classpath) - portal.properties (on Java classpath) + application.properties - read from filesystem + key.properties - read from Java classpath + portal.properties - read from 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 is placed on the Java classpath so the additional +files can be read at runtime. These steps are required: @@ -24,14 +29,15 @@ These steps are required: files from templates as needed. E.g., copy "key.properties.template" to "key.properties". 2. Add the config folder to the Java classpath -3a. Launch the server with this command-line invocation: +3a. Launch the server with this command-line invocation that includes 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 \ org.springframework.boot.loader.PropertiesLauncher -3b. To use the configuration in the "application-abc.properties" file, addd a -key-value pair for "spring.config.name" and launch with an invocation like this: +3b. Alternately, to use the configuration in the "application-abc.properties" file, +add a key-value pair for "spring.config.name" and launch with this invocation: java -cp config:target/ric-dash-be-1.2.0-SNAPSHOT.jar \ -Dspring.config.name=application-abc \ @@ -40,6 +46,8 @@ key-value pair for "spring.config.name" and launch with an invocation like this: ### Production user authentication +TODO AUTH: Authentication temporarily disabled for Sprint 2 testing! + The regular server authenticates requests using cookies that are set by the ONAP Portal: 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 44297016..6dc65633 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 @@ -31,7 +31,6 @@ import org.oransc.ric.portal.dashboard.controller.AdminController; import org.oransc.ric.portal.dashboard.controller.AnrXappController; import org.oransc.ric.portal.dashboard.controller.AppManagerController; import org.oransc.ric.portal.dashboard.controller.E2ManagerController; -import org.oransc.ric.portal.dashboard.controller.SimpleErrorController; import org.oransc.ric.portal.dashboard.portalapi.DashboardUserManager; import org.oransc.ric.portal.dashboard.portalapi.PortalAuthManager; import org.oransc.ric.portal.dashboard.portalapi.PortalAuthenticationFilter; @@ -48,6 +47,7 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; @Configuration @EnableWebSecurity @@ -76,7 +76,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { logger.debug("configure: portalapi.username {}", userName); // A chain of ".and()" always baffles me http.authorizeRequests().anyRequest().authenticated(); - // http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); + http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); http.addFilterBefore(portalAuthenticationFilterBean(), BasicAuthenticationFilter.class); } @@ -101,8 +101,8 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { AppManagerController.CONTROLLER_PATH + "/" + AppManagerController.VERSION_METHOD, // E2ManagerController.CONTROLLER_PATH + "/" + E2ManagerController.HEALTH_METHOD, // E2ManagerController.CONTROLLER_PATH + "/" + E2ManagerController.VERSION_METHOD, // - DashboardConstants.LOGIN_PAGE, // - SimpleErrorController.ERROR_PATH }; + DashboardConstants.LOGIN_PAGE // + }; @Override public void configure(WebSecurity web) throws Exception { diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CustomResponseEntityExceptionHandler.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CustomResponseEntityExceptionHandler.java index b1ac2e8f..6d8afa7d 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CustomResponseEntityExceptionHandler.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CustomResponseEntityExceptionHandler.java @@ -24,10 +24,8 @@ import java.lang.invoke.MethodHandles; import org.oransc.ric.portal.dashboard.model.ErrorTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.client.HttpStatusCodeException; @@ -41,11 +39,6 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep * * Why 502? I quote:
HTTP server received an invalid response from a * server it consulted when acting as a proxy or gateway.
- * - * This class and the methods are not strictly necessary, the - * SimpleErrorController is invoked when any controller method takes an uncaught - * exception, but this approach provides a better response to the front end and - * doesn't signal internal server error. * * Also see:
* https://www.baeldung.com/exception-handling-for-rest-with-spring @@ -61,11 +54,6 @@ public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptio * Generates the response when a REST controller method takes an * HttpStatusCodeException. * - * It appears that the container internally redirects to /error because the web - * request that arrives here has URI /error, and {@link - * org.oransc.ric.portal.dashboard.controller.SimpleErrorController} runs before - * this. - * * @param ex The exception * * @param request The original request @@ -81,21 +69,4 @@ public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptio HttpStatus.BAD_GATEWAY); } - /* - * This exception also happens when Spring security denies access to a method - * due to missing/wrong roles (granted authorities). Override the method to - * answer permission denied, even though that may obscure a genuine developer - * error. - * - * The web request that arrives here has URI /error; how to obtain the URI of - * the original request?!? - */ - @Override - public final ResponseEntity handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, - HttpHeaders headers, HttpStatus status, WebRequest request) { - log.warn("handleHttpRequestMethodNotSupported: answering 'permission denied' for method {}", ex.getMethod()); - return new ResponseEntity(new ErrorTransport(HttpStatus.UNAUTHORIZED.value(), - "Permission denied for method " + ex.getMethod(), ex), HttpStatus.UNAUTHORIZED); - } - } diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/SimpleErrorController.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/SimpleErrorController.java deleted file mode 100644 index 531ea173..00000000 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/SimpleErrorController.java +++ /dev/null @@ -1,108 +0,0 @@ -/*- - * ========================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.controller; - -import java.lang.invoke.MethodHandles; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.servlet.error.ErrorAttributes; -import org.springframework.boot.web.servlet.error.ErrorController; -import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.context.request.WebRequest; - -import springfox.documentation.annotations.ApiIgnore; - -/** - * Provides an endpoint that returns JSON, which is invoked following any error - * within the Spring-managed context. This is NOT called for errors outside the - * context; e.g., resource not found. - * - * If trace is requested via request parameter ("?trace=true") and available, - * adds stack trace information to the standard JSON error response. - * - * Excluded from Swagger API documentation. - * - * https://stackoverflow.com/questions/25356781/spring-boot-remove-whitelabel-error-page - * https://www.baeldung.com/spring-boot-custom-error-page - */ -@ApiIgnore -@RestController -public class SimpleErrorController implements ErrorController { - - private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - public static final String ERROR_PATH = "/error"; - private static final String TRACE = "trace"; - private final ErrorAttributes errorAttributes; - - /** - * Constructor - * - * @param errorAttributes - * error attributes must not be null - */ - @Autowired - public SimpleErrorController(ErrorAttributes errorAttributes) { - Assert.notNull(errorAttributes, "ErrorAttributes must not be null"); - this.errorAttributes = errorAttributes; - } - - @Override - public String getErrorPath() { - return ERROR_PATH; - } - - /** - * Builds a map with error details - * - * @param aRequest - * HttpServletRequest - * @return Map of String to Object - */ - @GetMapping(ERROR_PATH) - public Map error(HttpServletRequest aRequest) { - Map body = getErrorAttributes(aRequest, getTraceParameter(aRequest)); - logger.warn("Failed in request for {}", body.get("path")); - body.put("decorated-by", SimpleErrorController.class.getName()); - body.computeIfPresent(TRACE, (key, value) -> body.put(TRACE, ((String) value).split("\n\t"))); - return body; - } - - private boolean getTraceParameter(HttpServletRequest request) { - String parameter = request.getParameter(TRACE); - if (parameter == null) - return false; - return !"false".equalsIgnoreCase(parameter); - } - - private Map getErrorAttributes(HttpServletRequest aRequest, boolean includeStackTrace) { - WebRequest webRequest = new ServletWebRequest(aRequest); - return errorAttributes.getErrorAttributes(webRequest, includeStackTrace); - } - -} diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthenticationFilter.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthenticationFilter.java index 2ec5938d..95a3573b 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthenticationFilter.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthenticationFilter.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.invoke.MethodHandles; import java.net.URLEncoder; +import java.util.HashSet; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -36,11 +37,13 @@ import javax.servlet.http.HttpServletResponse; import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; import org.onap.portalsdk.core.onboarding.util.PortalApiProperties; +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.model.EcompUserDetails; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; @@ -99,13 +102,45 @@ public class PortalAuthenticationFilter implements Filter { // No resources to release } - /** + /* + * Populates security context with a mock user in the admin role. + * + * TODO: AUTH + */ + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + throws IOException, ServletException { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || auth.getAuthorities().isEmpty()) { + logger.debug("doFilter adding auth to request {}", req); + EcompRole admin = new EcompRole(); + admin.setId(1L); + admin.setName(DashboardConstants.ROLE_ADMIN); + HashSet roles = new HashSet<>(); + roles.add(admin); + EcompUser user = new EcompUser(); + user.setLoginId("fakeLoginId"); + user.setRoles(roles); + user.setActive(true); + EcompUserDetails userDetails = new EcompUserDetails(user); + PreAuthenticatedAuthenticationToken authToken = new PreAuthenticatedAuthenticationToken(userDetails, + "fakeCredentials", userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authToken); + } + else { + logger.debug("doFilter: authorities {}", auth.getAuthorities()); + } + chain.doFilter(req, res); + } + + /* * Checks for valid cookies and allows request to be served if found; redirects * to Portal otherwise. Requests for pages ignored in the web security config do * not hit this filter. + * + * TODO: AUTH */ - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + public void doFilter_EPSDKFW(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { logger.debug("doFilter {}", req); HttpServletRequest request = (HttpServletRequest) req; diff --git a/webapp-backend/src/main/resources/logback.xml b/webapp-backend/src/main/resources/logback.xml index b17cbe2c..8a4efcad 100644 --- a/webapp-backend/src/main/resources/logback.xml +++ b/webapp-backend/src/main/resources/logback.xml @@ -70,4 +70,8 @@ + +