Postpone authentication to version 1.2.1 59/659/2
authorLott, Christopher (cl778h) <cl778h@att.com>
Wed, 7 Aug 2019 18:46:08 +0000 (14:46 -0400)
committerLott, Christopher (cl778h) <cl778h@att.com>
Wed, 7 Aug 2019 21:12:32 +0000 (17:12 -0400)
Change-Id: I9a86348dca7dd79c2080019156b568f103f11dbe
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
docs/release-notes.rst
webapp-backend/README.md
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CustomResponseEntityExceptionHandler.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/SimpleErrorController.java [deleted file]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthenticationFilter.java
webapp-backend/src/main/resources/logback.xml

index a214b21..cfe16ac 100644 (file)
 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
 
index 6751ef9..67e4a3b 100644 (file)
@@ -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:
 
index 4429701..6dc6563 100644 (file)
@@ -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 {
index b1ac2e8..6d8afa7 100644 (file)
@@ -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: <blockquote>HTTP server received an invalid response from a
  * server it consulted when acting as a proxy or gateway.</blockquote>
- *
- * 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:<br>
  * 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<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
-                       HttpHeaders headers, HttpStatus status, WebRequest request) {
-               log.warn("handleHttpRequestMethodNotSupported: answering 'permission denied' for method {}", ex.getMethod());
-               return new ResponseEntity<Object>(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 (file)
index 531ea17..0000000
+++ /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<String, Object> error(HttpServletRequest aRequest) {
-               Map<String, Object> 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<String, Object> getErrorAttributes(HttpServletRequest aRequest, boolean includeStackTrace) {
-               WebRequest webRequest = new ServletWebRequest(aRequest);
-               return errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
-       }
-
-}
index 2ec5938..95a3573 100644 (file)
@@ -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<EcompRole> 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;
index b17cbe2..8a4efca 100644 (file)
@@ -70,4 +70,8 @@
        <!-- Report request URLs -->
        <logger name="org.springframework.web.client.RestTemplate" level="DEBUG" />
 
+       <!-- for debugging security
+       <logger name="org.springframework.security" level="DEBUG" />
+       -->
+
 </configuration>