Serve login page without using redirect 67/1067/4
authorLott, Christopher (cl778h) <cl778h@att.com>
Thu, 3 Oct 2019 19:58:33 +0000 (15:58 -0400)
committerLott, Christopher (cl778h) <cl778h@att.com>
Fri, 4 Oct 2019 18:42:47 +0000 (14:42 -0400)
This preserves original scheme, either HTTP or HTTPS.
Correct URL of Dashboard REST URL in config-deploy doc.
Bump version to 1.2.3.

Change-Id: Ia7da1e2a7a0f189c95072ddda51ac59a738d9247
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
20 files changed:
a1-med-client/pom.xml
anr-xapp-client/pom.xml
app-mgr-client/pom.xml
docs/config-deploy.rst
docs/release-notes.rst
e2-mgr-client/pom.xml
pom.xml
webapp-backend/pom.xml
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/DashboardConstants.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/LoginServlet.java [deleted file]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AdminController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/Html5PathsController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/DashboardUserManager.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthenticationFilter.java
webapp-backend/src/main/resources/application.properties
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/WebSecurityMockConfiguration.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/PortalRestCentralServiceTest.java
webapp-frontend/pom.xml

index d1dbf5c..8cfc29d 100644 (file)
@@ -25,7 +25,7 @@ limitations under the License.
        <parent>
                <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
                <artifactId>ric-dash-parent</artifactId>
-               <version>1.2.2-SNAPSHOT</version>
+               <version>1.2.3-SNAPSHOT</version>
        </parent>
        <!-- This groupId will NOT allow deployment in LF -->
        <groupId>org.o-ran-sc.ric.plt.a1med.client</groupId>
index 05cddf9..d7dcaff 100644 (file)
@@ -25,7 +25,7 @@ limitations under the License.
        <parent>
                <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
                <artifactId>ric-dash-parent</artifactId>
-               <version>1.2.2-SNAPSHOT</version>
+               <version>1.2.3-SNAPSHOT</version>
        </parent>
        <!-- This groupId will NOT allow deployment in LF -->
        <groupId>org.o-ran-sc.ric.xapp.anr.client</groupId>
index d27f10c..b6ea408 100644 (file)
@@ -25,7 +25,7 @@ limitations under the License.
        <parent>
                <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
                <artifactId>ric-dash-parent</artifactId>
-               <version>1.2.2-SNAPSHOT</version>
+               <version>1.2.3-SNAPSHOT</version>
        </parent>
        <!-- This groupId will NOT allow deployment in LF -->
        <groupId>org.o-ran-sc.ric.plt.appmgr.client</groupId>
index 5f62be4..c6d5086 100644 (file)
@@ -210,8 +210,8 @@ must supply the following information about the deployed instance:
   ``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``
+  cookie-based authentication.  This must be a URL with suffix "/api/v3"
+  for example ``http://192.168.1.1:8080/api/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
index 2453d60..2ab746f 100644 (file)
 RIC Dashboard Release Notes
 ===========================
 
+Version 1.2.3, 4 Oct 2019
+-------------------------
+* Serve unauthenticated user a login-at-portal page without using redirect
+* Upgrade to Spring-Boot 2.1.9.RELEASE
+
 Version 1.2.2, 27 Sep 2019
 --------------------------
 * Support Portal security using EPSDK-FW cookie and user management
index 723b4ab..4d4f897 100644 (file)
@@ -25,7 +25,7 @@ limitations under the License.
        <parent>
                <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
                <artifactId>ric-dash-parent</artifactId>
-               <version>1.2.2-SNAPSHOT</version>
+               <version>1.2.3-SNAPSHOT</version>
        </parent>
        <!-- This groupId will NOT allow deployment in LF -->
        <groupId>org.o-ran-sc.ric.plt.e2mgr.client</groupId>
diff --git a/pom.xml b/pom.xml
index 4109bdc..8c394b3 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -26,14 +26,14 @@ limitations under the License.
                <!-- this group Id must match LF gerrit repository -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
-               <version>2.1.6.RELEASE</version>
+               <version>2.1.9.RELEASE</version>
                <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
        <artifactId>ric-dash-parent</artifactId>
        <name>RIC Dashboard project</name>
        <packaging>pom</packaging>
-       <version>1.2.2-SNAPSHOT</version>
+       <version>1.2.3-SNAPSHOT</version>
        <properties>
                <java.version>11</java.version>
                <!-- Properties for the license-maven-plugin in child POMs -->
index e008f8b..6976b00 100644 (file)
@@ -25,7 +25,7 @@ limitations under the License.
        <parent>
                <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
                <artifactId>ric-dash-parent</artifactId>
-               <version>1.2.2-SNAPSHOT</version>
+               <version>1.2.3-SNAPSHOT</version>
        </parent>
        <artifactId>ric-dash-be</artifactId>
        <name>RIC Dashboard Webapp backend</name>
index c441c17..f3352f6 100644 (file)
@@ -26,7 +26,6 @@ public abstract class DashboardConstants {
        }
 
        public static final String ENDPOINT_PREFIX = "/api";
-       public static final String LOGIN_PAGE = "/login.html";
        // Factor out method names used in multiple controllers
        public static final String VERSION_METHOD = "version";
        public static final String APP_NAME_AC = "AC";
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/LoginServlet.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/LoginServlet.java
deleted file mode 100644 (file)
index fe58e93..0000000
+++ /dev/null
@@ -1,116 +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;
-
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.net.URLEncoder;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
-import org.onap.portalsdk.core.onboarding.util.PortalApiProperties;
-import org.oransc.ric.portal.dashboard.portalapi.PortalAuthenticationFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.MediaType;
-
-/**
- * Serves a login page that contains a link from configuration to ONAP Portal.
- * This avoids the immediate redirect to Portal that is confusing to users and
- * infuriating to developers.
- * 
- * Basically this is do-it-yourself JSP :)
- */
-public class LoginServlet extends HttpServlet {
-
-       private static final long serialVersionUID = 1191385178190976568L;
-
-       private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-       @Override
-       public void init(ServletConfig servletConfig) throws ServletException {
-               logger.debug("init");
-               super.init(servletConfig);
-               final String portalURL = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
-               if (portalURL == null || portalURL.length() == 0)
-                       throw new ServletException("Failed to get property " + PortalApiConstants.ECOMP_REDIRECT_URL);
-       }
-
-       @Override
-       protected void doGet(HttpServletRequest request, HttpServletResponse response)
-                       throws IOException, ServletException {
-               logger.debug("doGet {}", request.getRequestURI());
-               // The original page URL should arrive as a query parameter
-               String appUrl = request.getParameter(PortalAuthenticationFilter.REDIRECT_URL_KEY);
-               // If a user bookmarks the login page, then nothing arrives;
-               // use the original URL without the login suffix.
-               if (appUrl == null || appUrl.isEmpty()) {
-                       String loginUrl = request.getRequestURL().toString();
-                       int indexOfLogin = loginUrl.indexOf(DashboardConstants.LOGIN_PAGE);
-                       appUrl = loginUrl.substring(0, indexOfLogin);
-               }
-               String encodedAppUrl = URLEncoder.encode(appUrl, "UTF-8");
-               String portalBaseUrl = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
-               String redirectUrl = portalBaseUrl + "?" + PortalAuthenticationFilter.REDIRECT_URL_KEY + "=" + encodedAppUrl;
-               String aHref = "<a href=\"" + redirectUrl + "\">";
-               // If only Java had "here" documents.
-               String body = String.join(//
-                               System.getProperty("line.separator"), //
-                               "<html>", //
-                               "<head>", //
-                               "<title>RIC Dashboard</title>", //
-                               "<style>", //
-                               "html, body { ", //
-                               "  font-family: Helvetica, Arial, sans-serif;", //
-                               "}", //
-                               "</style>", //
-                               "</head>", //
-                               "<body>", //
-                               "<h2>RIC Dashboard</h2>", //
-                               "<h4>Please log in.</h4>", //
-                               "<p>", //
-                               aHref, "Click here to authenticate at the ONAP Portal</a>", //
-                               "</p>", //
-                               "</body>", //
-                               "</html>");
-               writeAndFlush(response, MediaType.TEXT_HTML_VALUE, body);
-       }
-
-       /**
-        * Sets the content type and writes the response.
-        * 
-        * @param response
-        * @param contentType
-        * @param responseBody
-        * @throws IOException
-        */
-       private void writeAndFlush(HttpServletResponse response, String contentType, String responseBody)
-                       throws IOException {
-               response.setContentType(contentType);
-               response.getWriter().print(responseBody);
-               response.getWriter().flush();
-       }
-
-}
index edb80c8..20a1502 100644 (file)
@@ -24,8 +24,6 @@ import java.lang.invoke.MethodHandles;
 import java.lang.reflect.InvocationTargetException;
 
 import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
-import org.oransc.ric.portal.dashboard.DashboardConstants;
-import org.oransc.ric.portal.dashboard.LoginServlet;
 import org.oransc.ric.portal.dashboard.controller.A1MediatorController;
 import org.oransc.ric.portal.dashboard.controller.AdminController;
 import org.oransc.ric.portal.dashboard.controller.AnrXappController;
@@ -38,7 +36,6 @@ import org.oransc.ric.portal.dashboard.portalapi.PortalAuthenticationFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
-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;
@@ -105,8 +102,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
                        AppManagerController.CONTROLLER_PATH + "/" + AppManagerController.VERSION_METHOD, //
                        E2ManagerController.CONTROLLER_PATH + "/" + E2ManagerController.HEALTH_METHOD, //
                        E2ManagerController.CONTROLLER_PATH + "/" + E2ManagerController.VERSION_METHOD, //
-                       SimpleErrorController.ERROR_PATH, //
-                       DashboardConstants.LOGIN_PAGE //
+                       SimpleErrorController.ERROR_PATH
        };
 
        @Override
@@ -144,20 +140,4 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
                return portalAuthenticationFilter;
        }
 
-       /**
-        * 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
-        * Portal.
-        * 
-        * @return Servlet registration bean for the Dashboard login servlet.
-        */
-       @Bean
-       public ServletRegistrationBean<LoginServlet> loginServletBean() {
-               LoginServlet servlet = new LoginServlet();
-               final ServletRegistrationBean<LoginServlet> servletBean = new ServletRegistrationBean<>(servlet,
-                               DashboardConstants.LOGIN_PAGE);
-               servletBean.setName("LoginServlet");
-               return servletBean;
-       }
-
 }
index 58dab29..7ad509a 100644 (file)
@@ -67,6 +67,7 @@ public class AdminController {
 
        @Value("${metrics.url.mc}")
        private String mcAppMetricsUrl;
+
        public AdminController() {
                // Mock data
                users = new DashboardUser[] { //
index a5e3b52..f164734 100644 (file)
@@ -74,7 +74,7 @@ public class E2ManagerController {
        public static final String HEALTH_METHOD = "health";
        public static final String VERSION_METHOD = DashboardConstants.VERSION_METHOD;
        // Keep these consistent with the E2M implementation
-       /*package*/ static final String NODEB_PREFIX = "/nodeb";
+       /* package */ static final String NODEB_PREFIX = "/nodeb";
        public static final String RAN_METHOD = NODEB_PREFIX + "/ran";
        public static final String NODEB_SHUTDOWN_METHOD = NODEB_PREFIX + "/shutdown";
        public static final String NODEB_LIST_METHOD = NODEB_PREFIX + "/ids";
@@ -181,7 +181,7 @@ public class E2ManagerController {
        }
 
        @ApiOperation(value = "Abort any other ongoing procedures over X2 between the RIC and the RAN.")
-       @PutMapping(NODEB_PREFIX  + "/{" + PP_RANNAME + "}"+ RESET_METHOD)
+       @PutMapping(NODEB_PREFIX + "/{" + PP_RANNAME + "}" + RESET_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN })
        public void reset(@PathVariable(PP_RANNAME) String ranName, @RequestBody ResetRequest resetRequest,
                        HttpServletResponse response) {
index abe3b16..ac64c87 100644 (file)
  */
 package org.oransc.ric.portal.dashboard.controller;
 
+import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.net.URL;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,14 +49,19 @@ public class Html5PathsController {
         * https://stackoverflow.com/questions/44692781/configure-spring-boot-to-redirect-404-to-a-single-page-app
         * 
         * @param request
-        *                    HttpServletRequest
-        * @return Forward directive to index.html
+        *                     HttpServletRequest
+        * @param response
+        *                     HttpServletResponse
+        * @throws IOException
+        *                         On error
         */
        @RequestMapping(method = { RequestMethod.OPTIONS, RequestMethod.GET }, //
                        path = { "/catalog", "/control", "/stats", "/user" })
-       public String forwardAngularRoutes(HttpServletRequest request) {
-               logger.debug("forwardAngularRoutes: {}", request.getRequestURI());
-               return "forward:/index.html";
+       public void forwardAngularRoutes(HttpServletRequest request, HttpServletResponse response) throws IOException {
+               URL url = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), "/index.html");
+               if (logger.isDebugEnabled())
+                       logger.debug("forwardAngularRoutes: {} redirected to {}", request.getRequestURI(), url);
+               response.sendRedirect(url.toString());
        }
 
 }
index b02d026..6b92a30 100644 (file)
@@ -23,10 +23,14 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.onap.portalsdk.core.onboarding.exception.PortalAPIException;
+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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,16 +42,47 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 /**
  * Provides user-management services.
  * 
- * This first implementation serializes user details to a file. TODO: migrate to
- * a database.
+ * This first implementation serializes user details to a file.
+ * 
+ * TODO: migrate to a database.
  */
 public class DashboardUserManager {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+       public static final String USER_FILE_PATH = "/tmp/dashboard-users.json";
+
        private final File userFile;
        private final List<EcompUser> users;
 
+       /**
+        * convenience constructor that uses default file path
+        * 
+        * @param clear
+        *                  If true, start empty and remove any existing file.
+        * 
+        * @throws IOException
+        *                         On file error
+        */
+       public DashboardUserManager(boolean clear) throws IOException {
+               this(USER_FILE_PATH);
+               if (clear) {
+                       logger.debug("ctor: removing file {}", userFile.getAbsolutePath());
+                       File f = new File(DashboardUserManager.USER_FILE_PATH);
+                       if (f.exists())
+                               f.delete();
+                       users.clear();
+               }
+       }
+
+       /**
+        * Uses specified file path
+        * 
+        * @param userFilePath
+        *                         File path
+        * @throws IOException
+        *                         If file cannot be read
+        */
        public DashboardUserManager(final String userFilePath) throws IOException {
                logger.debug("ctor: userfile {}", userFilePath);
                if (userFilePath == null)
@@ -119,4 +154,22 @@ public class DashboardUserManager {
                }
        }
 
+       // Test infrastructure
+       public static void main(String[] args) throws Exception {
+               DashboardUserManager dum = new DashboardUserManager(false);
+               EcompUser user = new EcompUser();
+               user.setActive(true);
+               user.setLoginId("demo");
+               user.setFirstName("First");
+               user.setLastName("Last");
+               EcompRole role = new EcompRole();
+               role.setId(1L);
+               role.setName(DashboardConstants.ROLE_NAME_ADMIN);
+               Set<EcompRole> roles = new HashSet<>();
+               roles.add(role);
+               user.setRoles(roles);
+               dum.createUser(user);
+               logger.debug("Created user {}", user);
+       }
+
 }
index 18668f3..50f5b89 100644 (file)
@@ -44,6 +44,7 @@ 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.http.MediaType;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
@@ -147,7 +148,10 @@ public class PortalAuthenticationFilter implements Filter {
                        throws IOException, ServletException {
                Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                if (auth == null || auth.getAuthorities().isEmpty()) {
-                       logger.debug("doFilter adding auth to request {}", req);
+                       if (logger.isDebugEnabled()) {
+                               logger.debug("doFilter adding auth to request URI {}",
+                                               (req instanceof HttpServletRequest) ? ((HttpServletRequest) req).getRequestURL() : req);
+                       }
                        EcompRole admin = new EcompRole();
                        admin.setId(1L);
                        admin.setName(DashboardConstants.ROLE_ADMIN);
@@ -173,16 +177,21 @@ public class PortalAuthenticationFilter implements Filter {
         */
        private void doFilterEPSDKFW(ServletRequest req, ServletResponse res, FilterChain chain)
                        throws IOException, ServletException {
-               logger.debug("doFilter {}", req);
                HttpServletRequest request = (HttpServletRequest) req;
                HttpServletResponse response = (HttpServletResponse) res;
+               if (logger.isTraceEnabled())
+                       logger.trace("doFilter: req {}", request.getRequestURI());
                // Need to authenticate the request
                final String userId = authManager.valdiateEcompSso(request);
                final EcompUser ecompUser = (userId == null ? null : userManager.getUser(userId));
                if (userId == null || ecompUser == null) {
-                       String redirectURL = buildLoginPageUrl(request);
-                       logger.trace("doFilter: unauthorized, redirecting to {}", redirectURL);
-                       response.sendRedirect(redirectURL);
+                       logger.debug("doFilter: unauthorized user requests URI {}, serving login page", request.getRequestURI());
+                       StringBuffer sb = request.getRequestURL();
+                       sb.append(request.getQueryString() == null ? "" : "?" + request.getQueryString());
+                       String body = generateLoginRedirectPage(sb.toString());
+                       response.setContentType(MediaType.TEXT_HTML_VALUE);
+                       response.getWriter().print(body);
+                       response.getWriter().flush();
                } else {
                        EcompUserDetails userDetails = new EcompUserDetails(ecompUser);
                        // Using portal session as credentials is a hack
@@ -194,19 +203,44 @@ public class PortalAuthenticationFilter implements Filter {
                }
        }
 
-       private String buildLoginPageUrl(HttpServletRequest request) {
-               logger.trace("buildLoginPageUrl");
-               // Why so much work to recover the original request?
-               final StringBuffer sb = request.getRequestURL();
-               sb.append(request.getQueryString() == null ? "" : "?" + request.getQueryString());
-               final String requestedUrl = sb.toString();
-               String encodedUrl = null;
-               try {
-                       encodedUrl = URLEncoder.encode(requestedUrl, "UTF-8");
-               } catch (UnsupportedEncodingException ex) {
-                       logger.error("buildLoginPageUrl: Failed to encode {}", requestedUrl);
-               }
-               return DashboardConstants.LOGIN_PAGE + "?" + REDIRECT_URL_KEY + "=" + encodedUrl;
+       /**
+        * Generates a page with text only, absolutely no references to any webapp
+        * resources, so this can be served to an unauthenticated user without
+        * triggering a new authentication attempt. The page has a link to the Portal
+        * URL from configuration, with a return URL that is the original request.
+        * 
+        * @param appUrl
+        *                   Original requested URL
+        * @return HTML
+        * @throws UnsupportedEncodingException
+        *                                          On error
+        */
+       private static String generateLoginRedirectPage(String appUrl) throws UnsupportedEncodingException {
+               String encodedAppUrl = URLEncoder.encode(appUrl, "UTF-8");
+               String portalBaseUrl = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
+               String redirectUrl = portalBaseUrl + "?" + PortalAuthenticationFilter.REDIRECT_URL_KEY + "=" + encodedAppUrl;
+               String aHref = "<a href=\"" + redirectUrl + "\">";
+               // If only Java had "here" documents.
+               String body = String.join(//
+                               System.getProperty("line.separator"), //
+                               "<html>", //
+                               "<head>", //
+                               "<title>RIC Dashboard</title>", //
+                               "<style>", //
+                               "html, body { ", //
+                               "  font-family: Helvetica, Arial, sans-serif;", //
+                               "}", //
+                               "</style>", //
+                               "</head>", //
+                               "<body>", //
+                               "<h2>RIC Dashboard</h2>", //
+                               "<h4>Please log in.</h4>", //
+                               "<p>", //
+                               aHref, "Click here to authenticate at the ONAP Portal</a>", //
+                               "</p>", //
+                               "</body>", //
+                               "</html>");
+               return body;
        }
 
        /**
index 45eb669..bcc6cbc 100644 (file)
@@ -29,7 +29,7 @@ server.port = 8080
 userfile = users.json
 
 # boolean flag whether to enforce Portal user and roles on requests
-portalapi.security = false
+portalapi.security = true
 # class that decrypts ciphertext from Portal
 portalapi.decryptor = org.oransc.ric.portal.dashboard.portalapi.PortalSdkDecryptorAes
 # name of request cookie with user ID
index 8d06693..de2ee55 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.oransc.ric.portal.dashboard.config;
 
-import java.io.File;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.HashSet;
@@ -29,12 +28,10 @@ import org.onap.portalsdk.core.onboarding.exception.PortalAPIException;
 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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
-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;
@@ -92,22 +89,10 @@ public class WebSecurityMockConfiguration extends WebSecurityConfigurerAdapter {
                web.ignoring().antMatchers("/", "/csrf"); // allow swagger-ui to load
        }
 
-       @Bean
-       public ServletRegistrationBean<LoginServlet> loginServlet() {
-               LoginServlet servlet = new LoginServlet();
-               final ServletRegistrationBean<LoginServlet> servletBean = new ServletRegistrationBean<>(servlet,
-                               DashboardConstants.LOGIN_PAGE);
-               servletBean.setName("LoginServlet");
-               return servletBean;
-       }
-
        // This implementation is so light it can be used during tests.
        @Bean
        public DashboardUserManager dashboardUserManager() throws IOException, PortalAPIException {
-               File f = new File("/tmp/users.json");
-               if (f.exists())
-                       f.delete();
-               DashboardUserManager um = new DashboardUserManager(f.getAbsolutePath());
+               DashboardUserManager dum = new DashboardUserManager(true);
                // Mock user for convenience in testing
                EcompUser demo = new EcompUser();
                demo.setLoginId("demo");
@@ -119,8 +104,8 @@ public class WebSecurityMockConfiguration extends WebSecurityConfigurerAdapter {
                Set<EcompRole> roles = new HashSet<>();
                roles.add(role);
                demo.setRoles(roles);
-               um.createUser(demo);
-               return um;
+               dum.createUser(demo);
+               return dum;
        }
 
 }
index bb31028..4f24101 100644 (file)
@@ -26,7 +26,6 @@ import org.junit.jupiter.api.Assertions;
 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.PortalApIMockConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,8 +38,6 @@ public class PortalRestCentralServiceTest extends AbstractControllerTest {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-       // paths are hardcoded here exactly like the EPSDK-FW library :(
-
        @Test
        public void getAnalyticsTest() {
                // paths are hardcoded here exactly like the EPSDK-FW library :(
@@ -52,12 +49,13 @@ public class PortalRestCentralServiceTest extends AbstractControllerTest {
        }
 
        @Test
-       public void getLoginPageTest() {
-               URI uri = buildUri(null, DashboardConstants.LOGIN_PAGE);
+       public void getErrorPageTest() {
+               // Send unauthorized request
+               URI uri = buildUri(null, "/favicon.ico");
                logger.info("Invoking {}", uri);
                ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, null, String.class);
-               Assertions.assertTrue(response.getStatusCode().is2xxSuccessful());
-               Assertions.assertTrue(response.getBody().contains("Please log in"));
+               Assertions.assertTrue(response.getStatusCode().is4xxClientError());
+               Assertions.assertTrue(response.getBody().contains("Static error page"));
        }
 
        private HttpEntity<Object> getEntityWithHeaders(Object body) {
index 8080a0f..dfd36b0 100644 (file)
@@ -25,7 +25,7 @@ limitations under the License.
        <parent>
                <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
                <artifactId>ric-dash-parent</artifactId>
-               <version>1.2.2-SNAPSHOT</version>
+               <version>1.2.3-SNAPSHOT</version>
        </parent>
        <artifactId>ric-dash-fe</artifactId>
        <name>RIC Dashboard Webapp frontend</name>