001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.login.util;
016    
017    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
018    import com.liferay.portal.kernel.cluster.ClusterNode;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.messaging.DestinationNames;
026    import com.liferay.portal.kernel.messaging.MessageBusUtil;
027    import com.liferay.portal.kernel.servlet.SessionMessages;
028    import com.liferay.portal.kernel.util.CookieKeys;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.Http;
031    import com.liferay.portal.kernel.util.MapUtil;
032    import com.liferay.portal.kernel.util.ParamUtil;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.StringUtil;
035    import com.liferay.portal.kernel.util.Validator;
036    import com.liferay.portal.liveusers.LiveUsers;
037    import com.liferay.portal.model.Company;
038    import com.liferay.portal.model.CompanyConstants;
039    import com.liferay.portal.model.User;
040    import com.liferay.portal.model.UserTracker;
041    import com.liferay.portal.security.auth.AuthException;
042    import com.liferay.portal.security.auth.AuthenticatedUserUUIDStoreUtil;
043    import com.liferay.portal.security.auth.Authenticator;
044    import com.liferay.portal.service.CompanyLocalServiceUtil;
045    import com.liferay.portal.service.ServiceContext;
046    import com.liferay.portal.service.ServiceContextFactory;
047    import com.liferay.portal.service.UserLocalServiceUtil;
048    import com.liferay.portal.theme.ThemeDisplay;
049    import com.liferay.portal.util.PortalUtil;
050    import com.liferay.portal.util.PortletKeys;
051    import com.liferay.portal.util.PropsValues;
052    import com.liferay.portal.util.WebKeys;
053    import com.liferay.portlet.PortletURLFactoryUtil;
054    import com.liferay.util.Encryptor;
055    
056    import java.util.ArrayList;
057    import java.util.Enumeration;
058    import java.util.HashMap;
059    import java.util.List;
060    import java.util.Map;
061    
062    import javax.portlet.ActionRequest;
063    import javax.portlet.PortletMode;
064    import javax.portlet.PortletModeException;
065    import javax.portlet.PortletPreferences;
066    import javax.portlet.PortletRequest;
067    import javax.portlet.PortletURL;
068    import javax.portlet.WindowState;
069    import javax.portlet.WindowStateException;
070    
071    import javax.servlet.http.Cookie;
072    import javax.servlet.http.HttpServletRequest;
073    import javax.servlet.http.HttpServletResponse;
074    import javax.servlet.http.HttpSession;
075    
076    /**
077     * @author Brian Wing Shun Chan
078     * @author Scott Lee
079     */
080    public class LoginUtil {
081    
082            public static long getAuthenticatedUserId(
083                            HttpServletRequest request, String login, String password,
084                            String authType)
085                    throws PortalException, SystemException {
086    
087                    long userId = GetterUtil.getLong(login);
088    
089                    Company company = PortalUtil.getCompany(request);
090    
091                    String requestURI = request.getRequestURI();
092    
093                    String contextPath = PortalUtil.getPathContext();
094    
095                    if (requestURI.startsWith(contextPath.concat("/api/liferay"))) {
096                            throw new AuthException();
097                    }
098                    else {
099                            Map<String, String[]> headerMap = new HashMap<String, String[]>();
100    
101                            Enumeration<String> enu1 = request.getHeaderNames();
102    
103                            while (enu1.hasMoreElements()) {
104                                    String name = enu1.nextElement();
105    
106                                    Enumeration<String> enu2 = request.getHeaders(name);
107    
108                                    List<String> headers = new ArrayList<String>();
109    
110                                    while (enu2.hasMoreElements()) {
111                                            String value = enu2.nextElement();
112    
113                                            headers.add(value);
114                                    }
115    
116                                    headerMap.put(
117                                            name, headers.toArray(new String[headers.size()]));
118                            }
119    
120                            Map<String, String[]> parameterMap = request.getParameterMap();
121                            Map<String, Object> resultsMap = new HashMap<String, Object>();
122    
123                            if (Validator.isNull(authType)) {
124                                    authType = company.getAuthType();
125                            }
126    
127                            int authResult = Authenticator.FAILURE;
128    
129                            if (authType.equals(CompanyConstants.AUTH_TYPE_EA)) {
130                                    authResult = UserLocalServiceUtil.authenticateByEmailAddress(
131                                            company.getCompanyId(), login, password, headerMap,
132                                            parameterMap, resultsMap);
133    
134                                    userId = MapUtil.getLong(resultsMap, "userId", userId);
135                            }
136                            else if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
137                                    authResult = UserLocalServiceUtil.authenticateByScreenName(
138                                            company.getCompanyId(), login, password, headerMap,
139                                            parameterMap, resultsMap);
140    
141                                    userId = MapUtil.getLong(resultsMap, "userId", userId);
142                            }
143                            else if (authType.equals(CompanyConstants.AUTH_TYPE_ID)) {
144                                    authResult = UserLocalServiceUtil.authenticateByUserId(
145                                            company.getCompanyId(), userId, password, headerMap,
146                                            parameterMap, resultsMap);
147                            }
148    
149                            if (authResult != Authenticator.SUCCESS) {
150                                    User user = UserLocalServiceUtil.fetchUser(userId);
151    
152                                    if (user != null) {
153                                            UserLocalServiceUtil.checkLockout(user);
154                                    }
155    
156                                    throw new AuthException();
157                            }
158                    }
159    
160                    return userId;
161            }
162    
163            public static String getEmailFromAddress(
164                            PortletPreferences preferences, long companyId)
165                    throws SystemException {
166    
167                    return PortalUtil.getEmailFromAddress(
168                            preferences, companyId, PropsValues.LOGIN_EMAIL_FROM_ADDRESS);
169            }
170    
171            public static String getEmailFromName(
172                            PortletPreferences preferences, long companyId)
173                    throws SystemException {
174    
175                    return PortalUtil.getEmailFromName(
176                            preferences, companyId, PropsValues.LOGIN_EMAIL_FROM_NAME);
177            }
178    
179            public static String getLogin(
180                            HttpServletRequest request, String paramName, Company company)
181                    throws SystemException {
182    
183                    String login = request.getParameter(paramName);
184    
185                    if ((login == null) || login.equals(StringPool.NULL)) {
186                            login = GetterUtil.getString(
187                                    CookieKeys.getCookie(request, CookieKeys.LOGIN, false));
188    
189                            if (PropsValues.COMPANY_LOGIN_PREPOPULATE_DOMAIN &&
190                                    Validator.isNull(login) &&
191                                    company.getAuthType().equals(CompanyConstants.AUTH_TYPE_EA)) {
192    
193                                    login = "@" + company.getMx();
194                            }
195                    }
196    
197                    return login;
198            }
199    
200            public static PortletURL getLoginURL(HttpServletRequest request, long plid)
201                    throws PortletModeException, WindowStateException {
202    
203                    PortletURL portletURL = PortletURLFactoryUtil.create(
204                            request, PortletKeys.LOGIN, plid, PortletRequest.RENDER_PHASE);
205    
206                    portletURL.setParameter("saveLastPath", Boolean.FALSE.toString());
207                    portletURL.setParameter("struts_action", "/login/login");
208                    portletURL.setPortletMode(PortletMode.VIEW);
209                    portletURL.setWindowState(WindowState.MAXIMIZED);
210    
211                    return portletURL;
212            }
213    
214            public static void login(
215                            HttpServletRequest request, HttpServletResponse response,
216                            String login, String password, boolean rememberMe, String authType)
217                    throws Exception {
218    
219                    CookieKeys.validateSupportCookie(request);
220    
221                    HttpSession session = request.getSession();
222    
223                    Company company = PortalUtil.getCompany(request);
224    
225                    long userId = getAuthenticatedUserId(
226                            request, login, password, authType);
227    
228                    if (!PropsValues.AUTH_SIMULTANEOUS_LOGINS) {
229                            signOutSimultaneousLogins(userId);
230                    }
231    
232                    if (PropsValues.SESSION_ENABLE_PHISHING_PROTECTION) {
233                            session = renewSession(request, session);
234                    }
235    
236                    // Set cookies
237    
238                    String domain = CookieKeys.getDomain(request);
239    
240                    User user = UserLocalServiceUtil.getUserById(userId);
241    
242                    String userIdString = String.valueOf(userId);
243    
244                    session.setAttribute("j_username", userIdString);
245    
246                    if (PropsValues.PORTAL_JAAS_PLAIN_PASSWORD) {
247                            session.setAttribute("j_password", password);
248                    }
249                    else {
250                            session.setAttribute("j_password", user.getPassword());
251                    }
252    
253                    session.setAttribute("j_remoteuser", userIdString);
254    
255                    if (PropsValues.SESSION_STORE_PASSWORD) {
256                            session.setAttribute(WebKeys.USER_PASSWORD, password);
257                    }
258    
259                    Cookie companyIdCookie = new Cookie(
260                            CookieKeys.COMPANY_ID, String.valueOf(company.getCompanyId()));
261    
262                    if (Validator.isNotNull(domain)) {
263                            companyIdCookie.setDomain(domain);
264                    }
265    
266                    companyIdCookie.setPath(StringPool.SLASH);
267    
268                    Cookie idCookie = new Cookie(
269                            CookieKeys.ID,
270                            Encryptor.encrypt(company.getKeyObj(), userIdString));
271    
272                    if (Validator.isNotNull(domain)) {
273                            idCookie.setDomain(domain);
274                    }
275    
276                    idCookie.setPath(StringPool.SLASH);
277    
278                    Cookie passwordCookie = new Cookie(
279                            CookieKeys.PASSWORD,
280                            Encryptor.encrypt(company.getKeyObj(), password));
281    
282                    if (Validator.isNotNull(domain)) {
283                            passwordCookie.setDomain(domain);
284                    }
285    
286                    passwordCookie.setPath(StringPool.SLASH);
287    
288                    Cookie rememberMeCookie = new Cookie(
289                            CookieKeys.REMEMBER_ME, Boolean.TRUE.toString());
290    
291                    if (Validator.isNotNull(domain)) {
292                            rememberMeCookie.setDomain(domain);
293                    }
294    
295                    rememberMeCookie.setPath(StringPool.SLASH);
296    
297                    int loginMaxAge = PropsValues.COMPANY_SECURITY_AUTO_LOGIN_MAX_AGE;
298    
299                    String userUUID = userIdString.concat(StringPool.PERIOD).concat(
300                            String.valueOf(System.nanoTime()));
301    
302                    Cookie userUUIDCookie = new Cookie(
303                            CookieKeys.USER_UUID,
304                            Encryptor.encrypt(company.getKeyObj(), userUUID));
305    
306                    userUUIDCookie.setPath(StringPool.SLASH);
307    
308                    session.setAttribute(WebKeys.USER_UUID, userUUID);
309    
310                    if (PropsValues.SESSION_DISABLED) {
311                            rememberMe = true;
312                    }
313    
314                    if (rememberMe) {
315                            companyIdCookie.setMaxAge(loginMaxAge);
316                            idCookie.setMaxAge(loginMaxAge);
317                            passwordCookie.setMaxAge(loginMaxAge);
318                            rememberMeCookie.setMaxAge(loginMaxAge);
319                            userUUIDCookie.setMaxAge(loginMaxAge);
320                    }
321                    else {
322    
323                            // This was explicitly changed from 0 to -1 so that the cookie lasts
324                            // as long as the browser. This allows an external servlet wrapped
325                            // in AutoLoginFilter to work throughout the client connection. The
326                            // cookies ARE removed on an actual logout, so there is no security
327                            // issue. See LEP-4678 and LEP-5177.
328    
329                            companyIdCookie.setMaxAge(-1);
330                            idCookie.setMaxAge(-1);
331                            passwordCookie.setMaxAge(-1);
332                            rememberMeCookie.setMaxAge(0);
333                            userUUIDCookie.setMaxAge(-1);
334                    }
335    
336                    Cookie loginCookie = new Cookie(CookieKeys.LOGIN, login);
337    
338                    if (Validator.isNotNull(domain)) {
339                            loginCookie.setDomain(domain);
340                    }
341    
342                    loginCookie.setMaxAge(loginMaxAge);
343                    loginCookie.setPath(StringPool.SLASH);
344    
345                    Cookie screenNameCookie = new Cookie(
346                            CookieKeys.SCREEN_NAME,
347                            Encryptor.encrypt(company.getKeyObj(), user.getScreenName()));
348    
349                    if (Validator.isNotNull(domain)) {
350                            screenNameCookie.setDomain(domain);
351                    }
352    
353                    screenNameCookie.setMaxAge(loginMaxAge);
354                    screenNameCookie.setPath(StringPool.SLASH);
355    
356                    boolean secure = request.isSecure();
357    
358                    if (secure && !PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
359                            !StringUtil.equalsIgnoreCase(
360                                    Http.HTTPS, PropsValues.WEB_SERVER_PROTOCOL)) {
361    
362                            Boolean httpsInitial = (Boolean)session.getAttribute(
363                                    WebKeys.HTTPS_INITIAL);
364    
365                            if ((httpsInitial == null) || !httpsInitial.booleanValue()) {
366                                    secure = false;
367                            }
368                    }
369    
370                    CookieKeys.addCookie(request, response, companyIdCookie, secure);
371                    CookieKeys.addCookie(request, response, idCookie, secure);
372                    CookieKeys.addCookie(request, response, userUUIDCookie, secure);
373    
374                    if (rememberMe) {
375                            CookieKeys.addCookie(request, response, loginCookie, secure);
376                            CookieKeys.addCookie(request, response, passwordCookie, secure);
377                            CookieKeys.addCookie(request, response, rememberMeCookie, secure);
378                            CookieKeys.addCookie(request, response, screenNameCookie, secure);
379                    }
380    
381                    AuthenticatedUserUUIDStoreUtil.register(userUUID);
382            }
383    
384            public static HttpSession renewSession(
385                            HttpServletRequest request, HttpSession session)
386                    throws Exception {
387    
388                    // Invalidate the previous session to prevent phishing
389    
390                    String[] protectedAttributeNames =
391                            PropsValues.SESSION_PHISHING_PROTECTED_ATTRIBUTES;
392    
393                    Map<String, Object> protectedAttributes = new HashMap<String, Object>();
394    
395                    for (String protectedAttributeName : protectedAttributeNames) {
396                            Object protectedAttributeValue = session.getAttribute(
397                                    protectedAttributeName);
398    
399                            if (protectedAttributeValue == null) {
400                                    continue;
401                            }
402    
403                            protectedAttributes.put(
404                                    protectedAttributeName, protectedAttributeValue);
405                    }
406    
407                    try {
408                            session.invalidate();
409                    }
410                    catch (IllegalStateException ise) {
411    
412                            // This only happens in Geronimo
413    
414                            if (_log.isWarnEnabled()) {
415                                    _log.warn(ise.getMessage());
416                            }
417                    }
418    
419                    session = request.getSession(true);
420    
421                    for (String protectedAttributeName : protectedAttributeNames) {
422                            Object protectedAttributeValue = protectedAttributes.get(
423                                    protectedAttributeName);
424    
425                            if (protectedAttributeValue == null) {
426                                    continue;
427                            }
428    
429                            session.setAttribute(
430                                    protectedAttributeName, protectedAttributeValue);
431                    }
432    
433                    return session;
434            }
435    
436            public static void sendPassword(ActionRequest actionRequest)
437                    throws Exception {
438    
439                    String toAddress = ParamUtil.getString(actionRequest, "emailAddress");
440    
441                    sendPassword(actionRequest, null, null, toAddress, null, null);
442            }
443    
444            public static void sendPassword(
445                            ActionRequest actionRequest, String fromName, String fromAddress,
446                            String toAddress, String subject, String body)
447                    throws Exception {
448    
449                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
450                            actionRequest);
451    
452                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
453                            WebKeys.THEME_DISPLAY);
454    
455                    Company company = themeDisplay.getCompany();
456    
457                    if (!company.isSendPassword() && !company.isSendPasswordResetLink()) {
458                            return;
459                    }
460    
461                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
462                            User.class.getName(), actionRequest);
463    
464                    UserLocalServiceUtil.sendPassword(
465                            company.getCompanyId(), toAddress, fromName, fromAddress, subject,
466                            body, serviceContext);
467    
468                    SessionMessages.add(actionRequest, "requestProcessed", toAddress);
469            }
470    
471            public static void signOutSimultaneousLogins(long userId) throws Exception {
472                    long companyId = CompanyLocalServiceUtil.getCompanyIdByUserId(userId);
473    
474                    Map<String, UserTracker> sessionUsers = LiveUsers.getSessionUsers(
475                            companyId);
476    
477                    List<UserTracker> userTrackers = new ArrayList<UserTracker>(
478                            sessionUsers.values());
479    
480                    for (UserTracker userTracker : userTrackers) {
481                            if (userId != userTracker.getUserId()) {
482                                    continue;
483                            }
484    
485                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
486    
487                            ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
488    
489                            if (clusterNode != null) {
490                                    jsonObject.put("clusterNodeId", clusterNode.getClusterNodeId());
491                            }
492    
493                            jsonObject.put("command", "signOut");
494                            jsonObject.put("companyId", companyId);
495                            jsonObject.put("sessionId", userTracker.getSessionId());
496                            jsonObject.put("userId", userId);
497    
498                            MessageBusUtil.sendMessage(
499                                    DestinationNames.LIVE_USERS, jsonObject.toString());
500                    }
501            }
502    
503            private static Log _log = LogFactoryUtil.getLog(LoginUtil.class);
504    
505    }