summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openecomp/sparky/security
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openecomp/sparky/security')
-rw-r--r--src/main/java/org/openecomp/sparky/security/EcompSso.java160
-rw-r--r--src/main/java/org/openecomp/sparky/security/SecurityContextFactory.java79
-rw-r--r--src/main/java/org/openecomp/sparky/security/SecurityContextFactoryImpl.java206
-rw-r--r--src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java271
-rw-r--r--src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java230
-rw-r--r--src/main/java/org/openecomp/sparky/security/portal/PortalRestAPIServiceImpl.java229
-rw-r--r--src/main/java/org/openecomp/sparky/security/portal/UserManager.java171
-rw-r--r--src/main/java/org/openecomp/sparky/security/portal/config/PortalAuthenticationConfig.java99
-rw-r--r--src/main/java/org/openecomp/sparky/security/portal/config/RolesConfig.java91
9 files changed, 1536 insertions, 0 deletions
diff --git a/src/main/java/org/openecomp/sparky/security/EcompSso.java b/src/main/java/org/openecomp/sparky/security/EcompSso.java
new file mode 100644
index 0000000..a008066
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/EcompSso.java
@@ -0,0 +1,160 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.openecomp.sparky.security;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties;
+import org.openecomp.sparky.logging.AaiUiMsgs;
+import org.openecomp.sparky.security.portal.config.PortalAuthenticationConfig;
+import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
+
+
+/**
+ * Provides authentication services for onboarded ECOMP applications.
+ */
+public class EcompSso {
+
+ public static final String EP_SERVICE = "EPService";
+ public static final String CSP_COOKIE_NAME = "csp_cookie_name";
+ public static final String CSP_GATE_KEEPER_PROD_KEY = "csp_gate_keeper_prod_key";
+ public static final String ONAP_ENABLED = "ONAP_ENABLED";
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(EcompSso.class);
+
+ /**
+ * Searches the request for a cookie with the specified name.
+ *
+ * @param request
+ * @param cookieName
+ * @return Cookie, or null if not found.
+ */
+ public static Cookie getCookie(HttpServletRequest request, String cookieName) {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null)
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals(cookieName)) {
+ return cookie;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Answers whether the ECOMP Portal service cookie is present in the specified request.
+ *
+ * @param request
+ * @return true if the cookie is found, else false.
+ */
+ private static boolean isEPServiceCookiePresent(HttpServletRequest request) {
+ Cookie ep = getCookie(request, EP_SERVICE);
+ return (ep != null);
+ }
+
+ /**
+ * Validates whether the ECOMP Portal sign-on process has completed, which relies the AT&T Global
+ * Log On single-sign on process. Checks for the ECOMP cookie (see {@link #EP_SERVICE}). If found,
+ * then searches for a CSP cookie; if not found, for a WebJunction header.
+ *
+ * @param request
+ * @return ATT UID if the ECOMP cookie is present and the sign-on process established an ATT UID;
+ * else null.
+ */
+ public static String validateEcompSso(HttpServletRequest request) {
+ boolean isOnapEnabled = PortalAuthenticationConfig.getInstance().getIsOnapEnabled();
+ if (isOnapEnabled) {
+ if (isEPServiceCookiePresent(request)) {
+ /* This is a "temporary" fix until proper separation
+ * between closed source and open source code is reached */
+ return ONAP_ENABLED;
+ }
+ return null;
+ } else {
+ return getLoginIdFromCookie(request);
+ }
+ }
+
+ /**
+ * Searches the specified request for the CSP cookie, decodes it and gets the ATT UID.
+ *
+ * @param request
+ * @return ATTUID if the cookie is present in the request and can be decoded successfully (expired
+ * cookies do not decode); else null.
+ */
+ private static String getLoginIdFromCookie(HttpServletRequest request) {
+ String attuid = null;
+ try {
+ String[] cspFields = getCspData(request);
+ if (cspFields != null && cspFields.length > 5)
+ attuid = cspFields[5];
+ } catch (Throwable t) {
+ LOG.info(AaiUiMsgs.LOGIN_FILTER_INFO,
+ "getLoginIdFromCookie failed " + t.getLocalizedMessage());
+ }
+ return attuid;
+ }
+
+ /**
+ * Searches the specified request for the CSP cookie, decodes it and parses it to a String array.
+ *
+ * @param request
+ * @return Array of String as parsed from the cookie; null if the cookie is not present; empty
+ * array if the cookie could not be decoded.
+ */
+ private static String[] getCspData(HttpServletRequest request) {
+ final String cookieName = PortalApiProperties.getProperty(CSP_COOKIE_NAME);
+ if (cookieName == null) {
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG,
+ "getCspData: Failed to get property " + CSP_COOKIE_NAME);
+ return null;
+ }
+ Cookie csp = getCookie(request, cookieName);
+ if (csp == null) {
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "getCspData failed to get cookie " + cookieName);
+ return null;
+ }
+ final String cspCookieEncrypted = csp.getValue();
+
+ String gateKeeperProdKey = PortalApiProperties.getProperty(CSP_GATE_KEEPER_PROD_KEY);
+ if (gateKeeperProdKey == null) {
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG,
+ "getCspData: failed to get property " + CSP_GATE_KEEPER_PROD_KEY);
+ }
+
+ String cspCookieDecrypted = "";
+ try {
+ cspCookieDecrypted = CipherUtil.decrypt(cspCookieEncrypted,"");
+ } catch (Exception e) {
+ LOG.info(AaiUiMsgs.LOGIN_FILTER_INFO,
+ "decrypting cookie failed " + e.getLocalizedMessage());
+ }
+
+ String[] cspData = cspCookieDecrypted.split("\\|");
+ return cspData;
+ }
+}
diff --git a/src/main/java/org/openecomp/sparky/security/SecurityContextFactory.java b/src/main/java/org/openecomp/sparky/security/SecurityContextFactory.java
new file mode 100644
index 0000000..3144dee
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/SecurityContextFactory.java
@@ -0,0 +1,79 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * A factory for creating SecurityContext objects.
+ */
+public interface SecurityContextFactory {
+
+ public String getSslAlgorithm();
+
+ public void setSslAlgorithm(String sslAlgorithm);
+
+ public String getKeyManagerAlgortihm();
+
+ public void setKeyManagerAlgortihm(String keyManagerAlgortihm);
+
+ public String getKeyStoreType();
+
+ public void setKeyStoreType(String keyStoreType);
+
+ public boolean isServerCertificationChainValidationEnabled();
+
+ public void setServerCertificationChainValidationEnabled(
+ boolean serverCertificationChainValidationEnabled);
+
+ public String getTrustStoreFileName();
+
+ public void setTrustStoreFileName(String filename);
+
+ public String getClientCertPassword();
+
+ public void setClientCertPassword(String password);
+
+ public void setClientCertFileInputStream(FileInputStream fis);
+
+ public void setClientCertFileName(String filename) throws IOException;
+
+ public FileInputStream getClientCertFileInputStream();
+
+ public SSLContext getSecureContext()
+ throws KeyManagementException, NoSuchAlgorithmException, FileNotFoundException,
+ KeyStoreException, CertificateException, IOException, UnrecoverableKeyException;
+
+}
diff --git a/src/main/java/org/openecomp/sparky/security/SecurityContextFactoryImpl.java b/src/main/java/org/openecomp/sparky/security/SecurityContextFactoryImpl.java
new file mode 100644
index 0000000..1fb03a7
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/SecurityContextFactoryImpl.java
@@ -0,0 +1,206 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * The Class SecurityContextFactoryImpl.
+ */
+public class SecurityContextFactoryImpl implements SecurityContextFactory {
+
+ protected String sslAlgorithm;
+ protected String keyManagerAlgortihm;
+ protected String keyStoreType;
+ protected boolean serverCertificationChainValidationEnabled;
+ protected String trustStoreFileName;
+ protected String clientCertPassword;
+ protected FileInputStream clientCertFileInputStream;
+ protected String clientCertFileName;
+ protected byte[] clientCertBytes;
+
+ /**
+ * Instantiates a new security context factory impl.
+ */
+ public SecurityContextFactoryImpl() {
+ this.sslAlgorithm = "TLS";
+ this.keyManagerAlgortihm = "SunX509";
+ this.keyStoreType = "PKCS12";
+ this.serverCertificationChainValidationEnabled = false;
+ this.clientCertFileInputStream = null;
+ this.clientCertFileName = null;
+ }
+
+ @Override
+ public String getSslAlgorithm() {
+ return sslAlgorithm;
+ }
+
+ @Override
+ public void setSslAlgorithm(String sslAlgorithm) {
+ this.sslAlgorithm = sslAlgorithm;
+ }
+
+ @Override
+ public String getKeyManagerAlgortihm() {
+ return keyManagerAlgortihm;
+ }
+
+ @Override
+ public void setKeyManagerAlgortihm(String keyManagerAlgortihm) {
+ this.keyManagerAlgortihm = keyManagerAlgortihm;
+ }
+
+ @Override
+ public String getKeyStoreType() {
+ return keyStoreType;
+ }
+
+ @Override
+ public void setKeyStoreType(String keyStoreType) {
+ this.keyStoreType = keyStoreType;
+ }
+
+ @Override
+ public boolean isServerCertificationChainValidationEnabled() {
+ return serverCertificationChainValidationEnabled;
+ }
+
+ @Override
+ public void setServerCertificationChainValidationEnabled(
+ boolean serverCertificationChainValidationEnabled) {
+ this.serverCertificationChainValidationEnabled = serverCertificationChainValidationEnabled;
+ }
+
+ @Override
+ public void setClientCertFileName(String filename) throws IOException {
+ this.clientCertFileName = filename;
+
+ if (filename == null) {
+ this.clientCertBytes = null;
+ } else {
+ this.clientCertBytes = Files.readAllBytes(new File(filename).toPath());
+ }
+ }
+
+ @Override
+ public void setClientCertFileInputStream(FileInputStream fis) {
+ this.clientCertFileInputStream = fis;
+ }
+
+ @Override
+ public FileInputStream getClientCertFileInputStream() {
+ return this.clientCertFileInputStream;
+ }
+
+ @Override
+ public SSLContext getSecureContext() throws KeyManagementException, NoSuchAlgorithmException,
+ KeyStoreException, CertificateException, IOException, UnrecoverableKeyException {
+
+ TrustManager[] trustAllCerts = null;
+
+ if (serverCertificationChainValidationEnabled) {
+
+ System.setProperty("javax.net.ssl.trustStore", trustStoreFileName);
+
+ } else {
+
+ // Create a trust manager that does not validate certificate chains
+ trustAllCerts = new TrustManager[] {new X509TrustManager() {
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
+ } };
+ }
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyManagerAlgortihm);
+
+ KeyStore ks = KeyStore.getInstance(keyStoreType);
+
+ char[] pwd = null;
+ if (clientCertPassword != null) {
+ pwd = clientCertPassword.toCharArray();
+ }
+
+ if (clientCertBytes != null) {
+ ks.load(new ByteArrayInputStream(clientCertBytes), pwd);
+ } else {
+ ks.load(null, pwd);
+ }
+
+ kmf.init(ks, pwd);
+
+ SSLContext ctx = SSLContext.getInstance(sslAlgorithm);
+ ctx.init(kmf.getKeyManagers(), trustAllCerts, null);
+
+ return ctx;
+
+ }
+
+ @Override
+ public String getTrustStoreFileName() {
+ return this.trustStoreFileName;
+ }
+
+ @Override
+ public void setTrustStoreFileName(String filename) {
+ this.trustStoreFileName = filename;
+ }
+
+ @Override
+ public String getClientCertPassword() {
+ return this.clientCertPassword;
+ }
+
+ @Override
+ public void setClientCertPassword(String password) {
+ this.clientCertPassword = password;
+ }
+
+}
diff --git a/src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java b/src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java
new file mode 100644
index 0000000..7140e96
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/filter/CspCookieFilter.java
@@ -0,0 +1,271 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.filter;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.sparky.logging.AaiUiMsgs;
+import org.openecomp.sparky.util.NodeUtils;
+import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
+
+import org.openecomp.cl.mdc.MdcContext;
+
+// import esGateKeeper.esGateKeeper;
+
+/**
+ * Redirects to the AT&T global login page if the user is not authenticated.<br>
+ * Filter properties need to be configured in: csp-cookie-filter.properties
+ */
+public class CspCookieFilter implements Filter {
+
+ /** Redirect URL for the login page. */
+ private String globalLoginUrl;
+
+ /** Application identifier. */
+ private String applicationId;
+
+ /** Gatekeeper environment setting (development or production). */
+ private String gateKeeperEnvironment;
+
+ private static final String FILTER_PARAMETER_CONFIG = "config";
+ private static final String PROPERTY_GLOBAL_LOGIN_URL = "global.login.url";
+ private static final String PROPERTY_APPLICATION_ID = "application.id";
+ private static final String PROPERTY_GATEKEEPER_ENVIRONMENT = "gatekeeper.environment";
+ // valid open redirect domains
+ private List<String> redirectDomains = new ArrayList<>();
+ private static final String PROPERTY_REDIRECT_DOMAINS = "redirect-domain";
+
+ /** Needed by esGateKeeper, does not accept any other value. */
+ private static final String GATEKEEPER_ACCOUNT_NAME = "CSP";
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(CspCookieFilter.class);
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+ */
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "CspCookieFilter", "", "Init", "");
+
+ try {
+ setConfigurationProperties(filterConfig);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_CSP_CONFIG_FILE);
+ throw new ServletException(exc);
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ Cookie[] cookies = request.getCookies();
+ if ((cookies == null) || (cookies.length == 0)) {
+ doLogin(request, response);
+ return;
+ }
+
+ /*
+ * String attEsSec = getSecurityCookie(cookies);
+ *
+ * if (attESSec == null || attESSec.length() == 0) { doLogin(request, response); return; }
+ *
+ * String attESSecUnEncrypted = esGateKeeper.esGateKeeper(attESSec, GATEKEEPER_ACCOUNT_NAME,
+ * gateKeeperEnvironment); if (attESSecUnEncrypted == null) { doLogin(request, response); } else
+ * {
+ */
+ // LOG.info("User has valid cookie");
+ chain.doFilter(request, response);
+ // }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#destroy()
+ */
+ @Override
+ public void destroy() {}
+
+ /**
+ * Sets all required properties needed by this filter.
+ *
+ * @param filterConfig the filter configuration defined in the application web.xml
+ * @throws IOException if the properties failed to load.
+ */
+ private void setConfigurationProperties(FilterConfig filterConfig) throws IOException {
+ InputStream inputStream = new FileInputStream(TierSupportUiConstants.STATIC_CONFIG_APP_LOCATION
+ + filterConfig.getInitParameter(FILTER_PARAMETER_CONFIG));
+ Properties cspProperties = new Properties();
+ cspProperties.load(inputStream);
+ globalLoginUrl = cspProperties.getProperty(PROPERTY_GLOBAL_LOGIN_URL);
+ applicationId = cspProperties.getProperty(PROPERTY_APPLICATION_ID);
+ gateKeeperEnvironment = cspProperties.getProperty(PROPERTY_GATEKEEPER_ENVIRONMENT);
+ redirectDomains = Arrays.asList(cspProperties.getProperty(PROPERTY_REDIRECT_DOMAINS).split(","));
+ }
+
+ /**
+ * Returns the attESSec cookie if found in the client.
+ *
+ * @param cookies the cookies available in the client
+ * @return the attESSec authentication cookie generated by the login page.
+ */
+ private String getSecurityCookie(Cookie[] cookies) {
+ String attEsSec = null;
+ for (int i = 0; i < cookies.length; i++) {
+ Cookie thisCookie = cookies[i];
+ String cookieName = thisCookie.getName();
+
+ if ("attESSec".equals(cookieName)) {
+ attEsSec = thisCookie.getValue();
+ break;
+ }
+ }
+ return attEsSec;
+ }
+
+ /**
+ * Redirects to the AT&T global login page. If this is an AJAX request it returns an unauthorized
+ * HTTP error in the response.
+ *
+ * @param request the filter request object
+ * @param response the filter response object
+ * @throws IOException if there is an error setting the error response
+ */
+ private void doLogin(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ if (isAjaxRequest(request)) {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+ "User is not authorized. Please login to application");
+ } else {
+ // Fix for Safari 7.0.2 onwards to avoid login page cache
+ response.addHeader("Cache-Control", "no-cache, no-store");
+ String redirectURL = createRedirectUrl(request);
+ if (this.isValidRedirectURL(redirectURL)){
+ response.sendRedirect(redirectURL);
+ LOG.debug(AaiUiMsgs.VALID_REDIRECT_URL, redirectURL);
+ } else{
+ response.sendError(400, "Bad redirect URL: " + redirectURL);
+ LOG.error(AaiUiMsgs.INVALID_REDIRECT_URL, redirectURL);
+ }
+ }
+ }
+
+ /**
+ * Checks if a redirect url is valid
+ * @param url URL to validate
+ * @return true if URL is a valid redirect URL, false otherwise
+ */
+ private boolean isValidRedirectURL (String url){
+ String redirectTo = url.substring(url.indexOf("?retURL=")+ "?retURL=".length());
+ try {
+ redirectTo = URLDecoder.decode(redirectTo, StandardCharsets.UTF_8.toString());
+ } catch (UnsupportedEncodingException e) {
+ LOG.error(AaiUiMsgs.UNSUPPORTED_URL_ENCODING, e.getLocalizedMessage());
+ return false;
+ }
+ for (String domain: this.redirectDomains){
+ if (redirectTo.endsWith(domain))
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns <code>true</code> if the request is an AJAX request.
+ *
+ * @param request the filter request object
+ * @return <code>true</code> if the request is an AJAX request.
+ */
+ private boolean isAjaxRequest(HttpServletRequest request) {
+ String headerValue = request.getHeader("X-Requested-With");
+ if ("XMLHttpRequest".equals(headerValue)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the redirection URL to the AT&T Global login page.
+ *
+ * @param request the request
+ * @return the string
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private String createRedirectUrl(HttpServletRequest request) throws UnsupportedEncodingException {
+ String returnUrl = getReturnUrl(request);
+
+ return globalLoginUrl + "?retURL=" + returnUrl + "&sysName=" + applicationId;
+ }
+
+ /**
+ * Gets the URL encoded return URL.
+ *
+ * @param request the HTTP request
+ * @return an encoded URL to return to following login
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private String getReturnUrl(HttpServletRequest request) throws UnsupportedEncodingException {
+ StringBuffer retUrl = request.getRequestURL();
+ String urlParams = request.getQueryString();
+ if (urlParams != null) {
+ retUrl.append("?" + urlParams);
+ }
+ return URLEncoder.encode(retUrl.toString(), StandardCharsets.UTF_8.toString());
+ }
+}
diff --git a/src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java b/src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java
new file mode 100644
index 0000000..3ab8990
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/filter/LoginFilter.java
@@ -0,0 +1,230 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiConstants;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties;
+import org.openecomp.portalsdk.core.onboarding.util.SSOUtil;
+import org.openecomp.sparky.logging.AaiUiMsgs;
+import org.openecomp.sparky.security.EcompSso;
+import org.openecomp.sparky.security.portal.config.PortalAuthenticationConfig;
+
+/**
+ * This filter checks every request for proper ECOMP Portal single sign on initialization. The
+ * possible paths and actions:
+ * <OL>
+ * <LI>User starts at an app page via a bookmark. No ECOMP portal cookie is set. Redirect there to
+ * get one; then continue as below.
+ * <LI>User starts at ECOMP Portal and goes to app. Alternately, the user's session times out and
+ * the user hits refresh. The ECOMP Portal cookie is set, but there is no valid session. Create one
+ * and publish info.
+ * <LI>User has valid ECOMP Portal cookie and session. Reset the max idle in that session.
+ * </OL>
+ * <P>
+ * Notes:
+ * <UL>
+ * <LI>Portal Session should be up prior to App Session</LI>
+ * <LI>If App Session Expires or if EPService cookie is unavailable, we need to redirect to Portal.
+ * <LI>Method {@link #initiateSessionMgtHandler(HttpServletRequest)} should be called for Session
+ * management when the initial session is created
+ * <LI>While redirecting, the cookie "redirectUrl" should also be set so that Portal knows where to
+ * forward the request to once the Portal Session is created and EPService cookie is set.
+ * <LI>Method {@link #resetSessionMaxIdleTimeOut(HttpServletRequest)} should be called for every
+ * request to reset the MaxInactiveInterval to the right value.
+ * </UL>
+ * <P>
+ * This filter incorporates most features of the SDK application's SessionTimeoutInterceptor and
+ * SingleSignOnController classes
+ */
+public class LoginFilter implements Filter {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(LoginFilter.class);
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Validate that app has provided useful portal properties
+ if (PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL) == null) {
+ throw new ServletException("Failed to find URL in portal.properties");
+ }
+
+ PortalAuthenticationConfig appProperties;
+ try {
+ appProperties = PortalAuthenticationConfig.getInstance();
+ } catch (Exception ex) {
+ throw new ServletException("Failed to get properties", ex);
+ }
+
+ String restUser = appProperties.getUsername();
+ String restPassword = appProperties.getPassword();
+ if (restUser == null || restPassword == null) {
+ throw new ServletException("Failed to find user and/or password from properties");
+ }
+ }
+
+ @Override
+ public void destroy() {
+ // No resources to release
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
+ * javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws ServletException, IOException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ // Choose authentication appropriate for the request.
+ final String restApiURI = request.getContextPath() + PortalApiConstants.API_PREFIX;
+ if (request.getRequestURI().startsWith(restApiURI)) {
+ // REST servlet checks credentials
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: delegating auth to REST servlet for request " + request.getRequestURI());
+ chain.doFilter(request, response);
+ } else {
+ // All other requests require ECOMP Portal authentication
+ if (EcompSso.validateEcompSso(request) == null) {
+ String redirectURL, logMessage;
+
+ // Redirect to Portal UI
+ redirectURL = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
+ logMessage = "Unauthorized login attempt.";
+
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG,
+ logMessage +
+ " | Remote IP: " + request.getRemoteAddr() +
+ " | User agent: " + request.getHeader(HttpHeaders.USER_AGENT) +
+ " | Request URL: " + request.getRequestURL() +
+ " | Redirecting to: " + redirectURL);
+
+ response.sendRedirect(redirectURL);
+ } else {
+ HttpSession session = request.getSession(false);
+ if (session == null) {
+ // New session
+ session = request.getSession(true);
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: created new session " + session.getId());
+ initiateSessionMgtHandler(request);
+ } else {
+ // Existing session
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: resetting idle in existing session " + session.getId());
+ resetSessionMaxIdleTimeOut(request);
+ }
+ // Pass request back down the filter chain
+ chain.doFilter(request, response);
+ }
+ }
+ }
+
+ /**
+ * Publishes information about the session.
+ *
+ * @param request
+ */
+ private void initiateSessionMgtHandler(HttpServletRequest request) {
+ String portalJSessionId = getPortalJSessionId(request);
+ String jSessionId = getJessionId(request);
+ storeMaxInactiveTime(request);
+ PortalTimeoutHandler.sessionCreated(portalJSessionId, jSessionId, request.getSession(false));
+ }
+
+ /**
+ * Gets the ECOMP Portal service cookie value.
+ *
+ * @param request
+ * @return Cookie value, or null if not found.
+ */
+ private String getPortalJSessionId(HttpServletRequest request) {
+ Cookie ep = EcompSso.getCookie(request, EcompSso.EP_SERVICE);
+ return ep == null ? null : ep.getValue();
+ }
+
+ /**
+ * Gets the container session ID.
+ *
+ * @param request
+ * @return Session ID, or null if no session.
+ */
+ private String getJessionId(HttpServletRequest request) {
+ HttpSession session = request.getSession();
+ return session == null ? null : session.getId();
+ }
+
+ /**
+ * Sets the global session's max idle time to the session's max inactive interval.
+ *
+ * @param request
+ */
+ private void storeMaxInactiveTime(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+ if (session != null
+ && session.getAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME) == null) {
+ session.setAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME,
+ session.getMaxInactiveInterval());
+ }
+ }
+
+ /**
+ * Sets the session's max inactive interval.
+ *
+ * @param request
+ */
+ private void resetSessionMaxIdleTimeOut(HttpServletRequest request) {
+ try {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ final Object maxIdleAttribute = session
+ .getAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME);
+ if (maxIdleAttribute != null) {
+ session.setMaxInactiveInterval(Integer.parseInt(maxIdleAttribute.toString()));
+ }
+ }
+ } catch (Exception e) {
+ LOG.info(AaiUiMsgs.LOGIN_FILTER_INFO, "resetSessionMaxIdleTimeOut: failed to set session max inactive interval - " + e.getLocalizedMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/org/openecomp/sparky/security/portal/PortalRestAPIServiceImpl.java b/src/main/java/org/openecomp/sparky/security/portal/PortalRestAPIServiceImpl.java
new file mode 100644
index 0000000..ce43ea2
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/portal/PortalRestAPIServiceImpl.java
@@ -0,0 +1,229 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.portal;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.openecomp.portalsdk.core.onboarding.crossapi.IPortalRestAPIService;
+import org.openecomp.portalsdk.core.onboarding.exception.PortalAPIException;
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+import org.openecomp.portalsdk.core.restful.domain.EcompUser;
+import org.openecomp.sparky.security.EcompSso;
+import org.openecomp.sparky.security.portal.config.PortalAuthenticationConfig;
+import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responds to ECOMP Portal's REST queries for user and role information and management.
+ */
+public class PortalRestAPIServiceImpl implements IPortalRestAPIService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PortalRestAPIServiceImpl.class);
+ private static final String ERROR_MESSAGE = "Failed to {0} user [loginId:{1}]";
+
+ private UserManager userManager;
+
+ /**
+ * Initialise user manager.
+ */
+ public PortalRestAPIServiceImpl() {
+ userManager = new UserManager(new File(TierSupportUiConstants.USERS_FILE_LOCATION));
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // User interface
+ /////////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#pushUser(com.att.fusion.core.
+ * restful.domain.EcompUser)
+ */
+ @Override
+ public void pushUser(EcompUser user) throws PortalAPIException {
+ LOG.debug("Push user [loginId:" + user.getLoginId() + "]");
+
+ if (userManager.getUser(user.getLoginId()).isPresent()) {
+ String message = getMessage(ERROR_MESSAGE, "push", user.getLoginId())
+ + ", user is already stored";
+ LOG.error(message);
+ throw new PortalAPIException(message);
+ }
+
+ try {
+ userManager.pushUser(user);
+ } catch (IOException e) {
+ String message = getMessage(ERROR_MESSAGE, "push", user.getLoginId());
+ LOG.error(message, e);
+ throw new PortalAPIException(message, e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#editUser(java.lang.String,
+ * com.att.fusion.core.restful.domain.EcompUser)
+ */
+ @Override
+ public void editUser(String loginId, EcompUser user) throws PortalAPIException {
+ LOG.debug("Edit user [loginId:" + loginId + "]");
+
+ userManager.getUser(loginId).orElseThrow(() -> {
+ String message = getMessage(ERROR_MESSAGE, "edit", loginId) + ", unknown user";
+ LOG.error(message);
+ return new PortalAPIException(message);
+ });
+
+ try {
+ userManager.editUser(loginId, user);
+ } catch (IOException e) {
+ String message = getMessage(ERROR_MESSAGE, "edit", loginId);
+ LOG.error(message, e);
+ throw new PortalAPIException(message, e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#getUser(java.lang.String)
+ */
+ @Override
+ public EcompUser getUser(String loginId) throws PortalAPIException {
+ LOG.debug("Get user [loginId:" + loginId + "]");
+ return userManager.getUser(loginId).orElseThrow(() -> {
+ String message = getMessage(ERROR_MESSAGE, "get", loginId) + ", unknown user";
+ LOG.error(message);
+ return new PortalAPIException(message);
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#getUsers()
+ */
+ @Override
+ public List<EcompUser> getUsers() throws PortalAPIException {
+ LOG.debug("Get users");
+ return userManager.getUsers();
+ }
+
+ @Override
+ public String getUserId(HttpServletRequest request) throws PortalAPIException {
+ return EcompSso.validateEcompSso(request);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Role interface
+ /////////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#getAvailableRoles()
+ */
+ @Override
+ public List<EcompRole> getAvailableRoles() throws PortalAPIException {
+ LOG.debug("Get available roles");
+ return UserManager.getRoles();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#getUserRoles(java.lang.String)
+ */
+ @Override
+ public List<EcompRole> getUserRoles(String loginId) throws PortalAPIException {
+ LOG.debug("Get user roles");
+ return userManager.getUserRoles(loginId);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#pushUserRole(java.lang.String,
+ * java.util.List)
+ */
+ @Override
+ public void pushUserRole(String loginId, List<EcompRole> roles) throws PortalAPIException {
+ LOG.debug("Push user role [loginId:" + loginId + "]");
+ try {
+ EcompUser user = getUser(loginId);
+ if (roles != null) {
+ user.setRoles(new LinkedHashSet<EcompRole>(roles));
+ } else {
+ user.setRoles(new LinkedHashSet<EcompRole>());
+ }
+ editUser(loginId, user);
+ } catch (PortalAPIException e) {
+ String message = getMessage(ERROR_MESSAGE, "push role", loginId);
+ LOG.error(message);
+ throw new PortalAPIException(message, e);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Security interface
+ /////////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.att.fusion.core.onboarding.crossapi.IPortalRestAPIService#isAppAuthenticated(javax.servlet.
+ * http.HttpServletRequest)
+ */
+ @Override
+ public boolean isAppAuthenticated(HttpServletRequest request) throws PortalAPIException {
+ LOG.debug("Authentication request");
+ PortalAuthenticationConfig config = PortalAuthenticationConfig.getInstance();
+ String restUsername = request.getHeader(PortalAuthenticationConfig.PROP_USERNAME);
+ String restPassword = request.getHeader(PortalAuthenticationConfig.PROP_PASSWORD);
+ return restUsername != null && restPassword != null && restUsername.equals(config.getUsername())
+ && restPassword.equals(config.getPassword());
+ }
+
+ private String getMessage(String message, Object... args) {
+ MessageFormat formatter = new MessageFormat("");
+ formatter.applyPattern(message);
+ return formatter.format(args);
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/openecomp/sparky/security/portal/UserManager.java b/src/main/java/org/openecomp/sparky/security/portal/UserManager.java
new file mode 100644
index 0000000..bbc4ee3
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/portal/UserManager.java
@@ -0,0 +1,171 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.portal;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+import org.openecomp.portalsdk.core.restful.domain.EcompUser;
+import org.openecomp.sparky.security.portal.config.RolesConfig;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ * Basic file based user storage.
+ */
+public class UserManager {
+
+ private File usersFile;
+
+ private static final ReadWriteLock LOCK = new ReentrantReadWriteLock(true);
+ private static final Lock READ_LOCK = LOCK.readLock();
+ private static final Lock WRITE_LOCK = LOCK.writeLock();
+
+ private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
+
+ /**
+ *
+ * @param usersFile a file to store the users
+ */
+ public UserManager(File usersFile) {
+ this.usersFile = usersFile;
+ }
+
+ /**
+ * Returns all users stored.
+ *
+ * @return a list of users.
+ */
+ public List<EcompUser> getUsers() {
+ Type collectionType = new TypeToken<List<EcompUser>>() {
+ }.getType();
+
+ Optional<String> users = read(usersFile);
+ if (users.isPresent()) {
+ return GSON.fromJson(users.get(), collectionType);
+ }
+
+ return new ArrayList<>();
+ }
+
+ /**
+ * Returns a stored user.
+ *
+ * @param loginId the identifier of the user
+ * @return an optional user.
+ */
+ public Optional<EcompUser> getUser(String loginId) {
+ if (!getUsers().isEmpty()) {
+ return getUsers().stream().filter(u -> loginId.equals(u.getLoginId())).findFirst();
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Stores a user if not already stored.
+ *
+ * @param user the user to be stored
+ * @throws IOException
+ */
+ public void pushUser(EcompUser user) throws IOException {
+ WRITE_LOCK.lock();
+ try {
+ if (!getUser(user.getLoginId()).isPresent()) {
+ addUser(getUsers(), user);
+ }
+ } finally {
+ WRITE_LOCK.unlock();
+ }
+ }
+
+ /**
+ * Replaces an existing user.
+ *
+ * @param loginId the id of the user
+ * @param user the new user details
+ * @throws IOException
+ */
+ public void editUser(String loginId, EcompUser user) throws IOException {
+ WRITE_LOCK.lock();
+ try {
+ if (getUser(loginId).isPresent()) {
+ List<EcompUser> users = getUsers().stream().filter(u -> !u.getLoginId().equals(loginId))
+ .collect(Collectors.toList());
+ addUser(users, user);
+ }
+ } finally {
+ WRITE_LOCK.unlock();
+ }
+ }
+
+ /**
+ * Gets the roles assigned to a user.
+ *
+ * @param loginId the id of the user
+ * @return the assigned roles
+ */
+ public List<EcompRole> getUserRoles(String loginId) {
+ List<EcompRole> roles = new ArrayList<>();
+ roles.addAll(getUser(loginId).orElseGet(EcompUser::new).getRoles());
+ return roles;
+ }
+
+ public static List<EcompRole> getRoles() {
+ return RolesConfig.getInstance().getRoles();
+ }
+
+ private void addUser(List<EcompUser> users, EcompUser user) throws IOException {
+ users.add(user);
+ write(users);
+ }
+
+ private void write(List<EcompUser> users) throws IOException {
+ Files.write(usersFile.toPath(), GSON.toJson(users).getBytes());
+ }
+
+ private Optional<String> read(File file) {
+ READ_LOCK.lock();
+ try {
+ return Optional.of(new String(Files.readAllBytes(file.toPath())));
+ } catch (IOException e) { // NOSONAR
+ return Optional.empty();
+ } finally {
+ READ_LOCK.unlock();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/openecomp/sparky/security/portal/config/PortalAuthenticationConfig.java b/src/main/java/org/openecomp/sparky/security/portal/config/PortalAuthenticationConfig.java
new file mode 100644
index 0000000..c217615
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/portal/config/PortalAuthenticationConfig.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.portal.config;
+
+import java.util.Properties;
+
+import org.openecomp.sparky.util.ConfigHelper;
+import org.openecomp.sparky.util.Encryptor;
+import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
+
+/**
+ * Provides Portal authentication configuration.
+ */
+public class PortalAuthenticationConfig {
+
+ private String username;
+ private String password;
+ private boolean isOnapEnabled;
+
+ public static final String PROP_USERNAME = "username";
+ public static final String PROP_PASSWORD = "password"; // NOSONAR
+ public static final String PROP_IS_ONAP_ENABLED = "onap_enabled"; // NOSONAR
+ private static final String AUTHENTICATION_CONFIG_FILE = TierSupportUiConstants.PORTAL_AUTHENTICATION_FILE_LOCATION;
+
+ private PortalAuthenticationConfig() {
+ // Prevent instantiation
+ }
+
+ private static class PortalAuthenticationConfigHelper {
+ private static final PortalAuthenticationConfig INSTANCE = new PortalAuthenticationConfig();
+
+ private PortalAuthenticationConfigHelper() {
+ // Deliberately empty
+ }
+ }
+
+ /**
+ * Get a singleton instance of the configuration.
+ *
+ * @return
+ */
+ public static PortalAuthenticationConfig getInstance() {
+ PortalAuthenticationConfigHelper.INSTANCE.load();
+ return PortalAuthenticationConfigHelper.INSTANCE;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ Encryptor encryptor = new Encryptor();
+ return encryptor.decryptValue(password);
+ }
+
+ public boolean getIsOnapEnabled() {
+ return isOnapEnabled;
+ }
+
+ /**
+ * Reload the Portal authentication properties from the classpath.
+ */
+ public void reload() {
+ load();
+ }
+
+ /**
+ * Load the Portal authentication properties from the classpath.
+ */
+ private void load() {
+ Properties props = ConfigHelper.loadConfigFromExplicitPath(AUTHENTICATION_CONFIG_FILE);
+ username = props.getProperty(PROP_USERNAME);
+ password = props.getProperty(PROP_PASSWORD);
+ isOnapEnabled = Boolean.parseBoolean(props.getProperty(PROP_IS_ONAP_ENABLED, "true"));
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/openecomp/sparky/security/portal/config/RolesConfig.java b/src/main/java/org/openecomp/sparky/security/portal/config/RolesConfig.java
new file mode 100644
index 0000000..18753a4
--- /dev/null
+++ b/src/main/java/org/openecomp/sparky/security/portal/config/RolesConfig.java
@@ -0,0 +1,91 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.security.portal.config;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ * Provides roles configuration.
+ */
+public class RolesConfig {
+
+ private List<EcompRole> roles;
+
+ private static final Gson GSON = new Gson();
+ private static final String ROLES_CONFIG_FILE = TierSupportUiConstants.ROLES_FILE_LOCATION;
+
+ private RolesConfig() {
+ // Prevent instantiation
+ }
+
+ private static class RolesConfigHelper {
+ private static final RolesConfig INSTANCE = new RolesConfig();
+
+ private RolesConfigHelper() {
+ // Deliberately empty
+ }
+ }
+
+ /**
+ * Get a singleton instance of the configuration.
+ *
+ * @return
+ */
+ public static RolesConfig getInstance() {
+ try {
+ RolesConfigHelper.INSTANCE.load();
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+
+ return RolesConfigHelper.INSTANCE;
+ }
+
+ public List<EcompRole> getRoles() {
+ return roles;
+ }
+
+ private void load() throws JsonSyntaxException, IOException, URISyntaxException {
+ Type collectionType = new TypeToken<List<EcompRole>>() {
+ }.getType();
+
+ roles = Collections.unmodifiableList(GSON
+ .fromJson(new String(Files.readAllBytes(Paths.get(ROLES_CONFIG_FILE))), collectionType));
+ }
+} \ No newline at end of file