2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * ===================================================================
8 * Unless otherwise specified, all software contained herein is licensed
9 * under the Apache License, Version 2.0 (the "License");
10 * you may not use this software except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * Unless otherwise specified, all documentation contained herein is licensed
22 * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
23 * you may not use this documentation except in compliance with the License.
24 * You may obtain a copy of the License at
26 * https://creativecommons.org/licenses/by/4.0/
28 * Unless required by applicable law or agreed to in writing, documentation
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
34 * ============LICENSE_END============================================
38 package org.onap.portalapp.controller.core;
40 import java.io.IOException;
41 import java.net.MalformedURLException;
43 import java.net.URLDecoder;
44 import java.net.URLEncoder;
45 import java.util.HashMap;
46 import java.util.List;
49 import javax.servlet.http.Cookie;
50 import javax.servlet.http.HttpServletRequest;
51 import javax.servlet.http.HttpSession;
53 import org.apache.commons.lang.StringUtils;
54 import org.onap.portalapp.model.EPServiceCookie;
55 import org.onap.portalsdk.core.auth.LoginStrategy;
56 import org.onap.portalsdk.core.command.LoginBean;
57 import org.onap.portalsdk.core.controller.UnRestrictedBaseController;
58 import org.onap.portalsdk.core.domain.RoleFunction;
59 import org.onap.portalsdk.core.domain.User;
60 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
61 import org.onap.portalsdk.core.menu.MenuProperties;
62 import org.onap.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
63 import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
64 import org.onap.portalsdk.core.onboarding.util.PortalApiProperties;
65 import org.onap.portalsdk.core.service.LoginService;
66 import org.onap.portalsdk.core.service.RoleService;
67 import org.onap.portalsdk.core.util.SystemProperties;
68 import org.onap.portalsdk.core.web.support.AppUtils;
69 import org.onap.portalsdk.core.web.support.UserUtils;
70 import org.springframework.beans.factory.annotation.Autowired;
71 import org.springframework.stereotype.Controller;
72 import org.springframework.web.bind.annotation.RequestMapping;
73 import org.springframework.web.bind.annotation.RequestMethod;
74 import org.springframework.web.client.RestTemplate;
75 import org.springframework.web.servlet.ModelAndView;
76 import org.springframework.web.util.WebUtils;
78 import com.fasterxml.jackson.core.JsonParseException;
79 import com.fasterxml.jackson.databind.JsonMappingException;
80 import com.fasterxml.jackson.databind.ObjectMapper;
84 public class SingleSignOnController extends UnRestrictedBaseController {
86 private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SingleSignOnController.class);
89 private LoginService loginService;
92 private LoginStrategy loginStrategy;
95 private RoleService roleService;
98 private RestTemplate restTemplate = new RestTemplate();
100 private String viewName;
101 private String welcomeView;
103 public String getWelcomeView() {
107 public void setWelcomeView(String welcomeView) {
108 this.welcomeView = welcomeView;
112 * Handles requests directed to the single sign-on page by the session timeout
116 * @return Redirect to an appropriate address
119 @RequestMapping(value = { "/single_signon.htm" }, method = RequestMethod.GET)
120 public ModelAndView singleSignOnLogin(HttpServletRequest request) throws Exception {
122 Map<String, String> model = new HashMap<>();
123 HashMap<String, String> additionalParamsMap = new HashMap<>();
124 LoginBean commandBean = new LoginBean();
126 // SessionTimeoutInterceptor sets these parameters
127 String forwardURL = URLDecoder.decode(request.getParameter("forwardURL"), "UTF-8");
128 String redirectToPortal = request.getParameter("redirectToPortal");
130 if (isLoginCookieExist(request) && redirectToPortal == null) {
131 HttpSession session = AppUtils.getSession(request);
132 User user = UserUtils.getUserSession(request);
133 if (session == null || user == null) {
135 final String authMech = SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM);
136 String userId = loginStrategy.getUserId(request);
137 commandBean.setUserid(userId);
138 commandBean = getLoginService().findUser(commandBean,
139 (String) request.getAttribute(MenuProperties.MENU_PROPERTIES_FILENAME_KEY),
140 additionalParamsMap);
141 List<RoleFunction> roleFunctionList = roleService.getRoleFunctions(userId);
142 if (commandBean.getUser() == null) {
143 String loginErrorMessage = (commandBean.getLoginErrorMessage() != null)
144 ? commandBean.getLoginErrorMessage()
145 : SystemProperties.MESSAGE_KEY_LOGIN_ERROR_USER_NOT_FOUND;
146 model.put(LoginStrategy.ERROR_MESSAGE_KEY, SystemProperties.getProperty(loginErrorMessage));
147 final String redirectUrl = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL)
148 + "?noUserError=Yes";
149 logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: user is null, redirect URL is {}",
151 return new ModelAndView("redirect:" + redirectUrl);
153 // store the user's information in the session
155 if (null == authMech || "".equals(authMech) || "BOTH".equals(authMech)) {
156 loginMethod = SystemProperties.getProperty(SystemProperties.LOGIN_METHOD_CSP);
157 } else if ("CSP".equals(authMech)) {
158 loginMethod = SystemProperties.getProperty(SystemProperties.LOGIN_METHOD_CSP);
160 loginMethod = SystemProperties.getProperty(SystemProperties.LOGIN_METHOD_WEB_JUNCTION);
162 UserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(),
163 commandBean.getBusinessDirectMenu(), loginMethod, roleFunctionList);
164 initateSessionMgtHandler(request);
165 logger.debug(EELFLoggerDelegate.debugLogger,
166 "singleSignOnLogin: create new user session for expired user {}; user {} exists in the system",
167 userId, commandBean.getUser().getOrgUserId());
168 return new ModelAndView("redirect:" + forwardURL);
170 } // user is null or session is null
172 // both user and session are non-null.
173 logger.info(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: redirecting to the forwardURL {}",
175 validateDomain(forwardURL);
176 return new ModelAndView("redirect:" + forwardURL);
181 * Login cookie not found, or redirect-to-portal parameter was found.
183 * Redirect the user to the portal with a suitable return URL. The forwardURL
184 * parameter that arrives as a parameter is a partial (not absolute) request
185 * path for a page in the application. The challenge here is to compute the
186 * correct absolute path for the original request so the portal can redirect the
187 * user back to the right place. If the application sits behind WebJunction, or
188 * if separate FE-BE hosts are used, then the URL yielded by the request has a
189 * host name that is not reachable by the user.
191 String returnToAppUrl;
192 if (SystemProperties.containsProperty(SystemProperties.APP_BASE_URL)) {
193 // New feature as of 1610, release 3.3.3:
194 // application can publish a base URL in system.properties
195 String appUrl = SystemProperties.getProperty(SystemProperties.APP_BASE_URL);
196 returnToAppUrl = appUrl + (appUrl.endsWith("/") ? "" : "/") + forwardURL;
197 validateDomain(returnToAppUrl);
198 logger.debug(EELFLoggerDelegate.debugLogger,
199 "singleSignOnLogin: using app base URL {} and redirectURL {}", appUrl, returnToAppUrl);
201 // Be backward compatible with applications that don't need this
203 // This is the controller for the single_signon.htm page, so the
205 // should always find the specified token.
206 returnToAppUrl = request.getRequestURL().toString().replace("single_signon.htm",
208 validateDomain(returnToAppUrl);
209 logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: computed redirectURL {}",
212 final String encodedReturnToAppUrl = URLEncoder.encode(returnToAppUrl, "UTF-8");
213 // Also send the application's UEB key so Portal can block URL
214 // reflection attacks.
215 final String uebAppKey = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
216 final String url = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
217 final String portalUrl = url.substring(0, url.lastIndexOf('/')) + "/process_csp";
218 final String redirectUrl = portalUrl + "?uebAppKey=" + uebAppKey + "&redirectUrl=" + encodedReturnToAppUrl;
219 logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: portal-bound redirect URL is {}",
221 // this line may not be necessary but jsessionid coockie is not getting created in all cases
222 // so force the cookie creation
223 request.getSession(true);
225 return new ModelAndView("redirect:" + redirectUrl);
229 private void validateDomain(String forwardURL) throws MalformedURLException {
230 if (StringUtils.isNotBlank(forwardURL)) {
231 String hostName = new URL(forwardURL).getHost();
232 if (StringUtils.isNotBlank(hostName) && !hostName.endsWith(SystemProperties.getProperty(SystemProperties.COOKIE_DOMAIN))) {
233 logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: accessing Unauthorized url",
235 throw new SecurityException("accessing Unauthorized url : " + hostName);
240 protected void initateSessionMgtHandler(HttpServletRequest request) {
241 String portalJSessionId = getPortalJSessionId(request);
242 String jSessionId = getJessionId(request);
243 PortalTimeoutHandler.sessionCreated(portalJSessionId, jSessionId, AppUtils.getSession(request));
246 public boolean isLoginCookieExist(HttpServletRequest request) throws JsonParseException, JsonMappingException, IOException {
247 Cookie ep = WebUtils.getCookie(request, LoginStrategy.EP_SERVICE);
249 return validateEPServiceCookie(ep.getValue());
254 //This method is validating EPService cookie in portal
255 public boolean validateEPServiceCookie(String cookieValue) throws JsonParseException, JsonMappingException, IOException{
256 Boolean result = false;
258 //Create json Request for REST call
259 final String uri = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REST_URL);
260 ObjectMapper mapper = new ObjectMapper();
261 Map<String,String> valueMap = mapper.readValue(URLDecoder.decode(cookieValue, "UTF-8"),HashMap.class);
263 EPServiceCookie epServiceCookie = new EPServiceCookie();
264 epServiceCookie.setValue(valueMap);
265 //Call portal service to validate
266 result = restTemplate.postForObject( uri+"/v3/validateCookie", epServiceCookie, Boolean.class);
267 logger.info(EELFLoggerDelegate.applicationLogger,"Epservice cookie validation result:: "+result);
269 logger.error(EELFLoggerDelegate.errorLogger,"Error in calling service :: "+e.getMessage());
275 public String getPortalJSessionId(HttpServletRequest request) {
276 Cookie ep = WebUtils.getCookie(request, LoginStrategy.EP_SERVICE);
277 return ep.getValue();
280 public String getJessionId(HttpServletRequest request) {
281 return request.getSession().getId();
285 public String getViewName() {
290 public void setViewName(String viewName) {
291 this.viewName = viewName;
294 public LoginService getLoginService() {
298 public void setLoginService(LoginService loginService) {
299 this.loginService = loginService;