| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.ofbiz.webapp.control; |
| |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.entity.DelegatorFactory; |
| import org.apache.ofbiz.entity.GenericValue; |
| import org.apache.ofbiz.service.LocalDispatcher; |
| import org.apache.ofbiz.webapp.WebAppUtil; |
| |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import javax.servlet.http.HttpSession; |
| import java.util.Map; |
| import java.util.UUID; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| /** |
| * This class manages the authentication tokens that provide single sign-on authentication to the OFBiz applications. |
| */ |
| public class ExternalLoginKeysManager { |
| private static final String module = ExternalLoginKeysManager.class.getName(); |
| private static final String EXTERNAL_LOGIN_KEY_ATTR = "externalLoginKey"; |
| // This Map is keyed by the randomly generated externalLoginKey and the value is a UserLogin GenericValue object |
| private static final Map<String, GenericValue> externalLoginKeys = new ConcurrentHashMap<>(); |
| |
| /** |
| * Gets (and creates if necessary) an authentication token to be used for an external login parameter. |
| * When a new token is created, it is persisted in the web session and in the web request and map entry keyed by the |
| * token and valued by a userLogin object is added to a map that is looked up for subsequent requests. |
| * |
| * @param request - the http request in which the authentication token is searched and stored |
| * @return the authentication token as persisted in the session and request objects |
| */ |
| public static String getExternalLoginKey(HttpServletRequest request) { |
| String externalKey = (String) request.getAttribute(EXTERNAL_LOGIN_KEY_ATTR); |
| if (externalKey != null) return externalKey; |
| |
| HttpSession session = request.getSession(); |
| synchronized (session) { |
| // if the session has a previous key in place, remove it from the master list |
| String sesExtKey = (String) session.getAttribute(EXTERNAL_LOGIN_KEY_ATTR); |
| |
| if (sesExtKey != null) { |
| if (isAjax(request)) return sesExtKey; |
| |
| externalLoginKeys.remove(sesExtKey); |
| } |
| |
| GenericValue userLogin = (GenericValue) request.getAttribute("userLogin"); |
| //check the userLogin here, after the old session setting is set so that it will always be cleared |
| if (userLogin == null) return ""; |
| |
| //no key made yet for this request, create one |
| while (externalKey == null || externalLoginKeys.containsKey(externalKey)) { |
| UUID uuid = UUID.randomUUID(); |
| externalKey = "EL" + uuid.toString(); |
| } |
| |
| request.setAttribute(EXTERNAL_LOGIN_KEY_ATTR, externalKey); |
| session.setAttribute(EXTERNAL_LOGIN_KEY_ATTR, externalKey); |
| externalLoginKeys.put(externalKey, userLogin); |
| return externalKey; |
| } |
| } |
| |
| /** |
| * Removes the authentication token, if any, from the session. |
| * |
| * @param session - the http session from which the authentication token is removed |
| */ |
| static void cleanupExternalLoginKey(HttpSession session) { |
| String sesExtKey = (String) session.getAttribute(EXTERNAL_LOGIN_KEY_ATTR); |
| if (sesExtKey != null) { |
| externalLoginKeys.remove(sesExtKey); |
| } |
| } |
| |
| /** |
| * OFBiz controller event that performs the user authentication using the authentication token. |
| * The methods is designed to be used in a chain of controller preprocessor event: it always return &success& |
| * even when the authentication token is missing or the authentication fails in order to move the processing to the |
| * next event in the chain. |
| * |
| * @param request - the http request object |
| * @param response - the http response object |
| * @return - &success& in all the cases |
| */ |
| public static String checkExternalLoginKey(HttpServletRequest request, HttpServletResponse response) { |
| String externalKey = request.getParameter(EXTERNAL_LOGIN_KEY_ATTR); |
| if (externalKey == null) return "success"; |
| |
| GenericValue userLogin = externalLoginKeys.get(externalKey); |
| if (userLogin != null) { |
| //to check it's the right tenant |
| //in case username and password are the same in different tenants |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| String oldDelegatorName = delegator.getDelegatorName(); |
| if (!oldDelegatorName.equals(userLogin.getDelegator().getDelegatorName())) { |
| delegator = DelegatorFactory.getDelegator(userLogin.getDelegator().getDelegatorName()); |
| LocalDispatcher dispatcher = WebAppUtil.makeWebappDispatcher(request.getServletContext(), delegator); |
| LoginWorker.setWebContextObjects(request, response, delegator, dispatcher); |
| } |
| // found userLogin, do the external login... |
| |
| // if the user is already logged in and the login is different, logout the other user |
| HttpSession session = request.getSession(); |
| GenericValue currentUserLogin = (GenericValue) session.getAttribute("userLogin"); |
| if (currentUserLogin != null) { |
| if (currentUserLogin.getString("userLoginId").equals(userLogin.getString("userLoginId"))) { |
| // is the same user, just carry on... |
| return "success"; |
| } |
| |
| // logout the current user and login the new user... |
| LoginWorker.logout(request, response); |
| // ignore the return value; even if the operation failed we want to set the new UserLogin |
| } |
| |
| LoginWorker.doBasicLogin(userLogin, request); |
| } else { |
| Debug.logWarning("Could not find userLogin for external login key: " + externalKey, module); |
| } |
| |
| return "success"; |
| } |
| |
| private static boolean isAjax(HttpServletRequest request) { |
| return "XMLHttpRequest".equals(request.getHeader("X-Requested-With")); |
| } |
| |
| } |