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
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:
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 \
### 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:
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;
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
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);
}
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 {
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;
*
* 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
* 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
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);
- }
-
}
+++ /dev/null
-/*-
- * ========================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);
- }
-
-}
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;
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;
// 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;
<!-- Report request URLs -->
<logger name="org.springframework.web.client.RestTemplate" level="DEBUG" />
+ <!-- for debugging security
+ <logger name="org.springframework.security" level="DEBUG" />
+ -->
+
</configuration>