001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.jsp;
029
030import org.opencms.db.CmsLoginMessage;
031import org.opencms.file.CmsRequestContext;
032import org.opencms.file.CmsUser;
033import org.opencms.i18n.CmsMessageContainer;
034import org.opencms.main.CmsException;
035import org.opencms.main.CmsLog;
036import org.opencms.main.OpenCms;
037import org.opencms.security.CmsAuthentificationException;
038
039import java.io.IOException;
040import java.util.Date;
041
042import javax.servlet.http.HttpServletRequest;
043import javax.servlet.http.HttpServletResponse;
044import javax.servlet.http.HttpSession;
045import javax.servlet.jsp.PageContext;
046
047import org.apache.commons.logging.Log;
048
049/**
050 * Provides convenient wrappers useful to create user login pages.<p>
051 *
052 * Initialize this bean at the beginning of your JSP like this:
053 * <pre>
054 * &lt;jsp:useBean id="cmslogin" class="org.opencms.jsp.CmsJspLoginBean"&gt;
055 * &lt% cmslogin.init(pageContext, request, response); %&gt;
056 * &lt;/jsp:useBean&gt;
057 * </pre>
058 * <p>
059 *
060 * @since 6.0.0
061 */
062public class CmsJspLoginBean extends CmsJspActionElement {
063
064    /** The log object for this class. */
065    private static final Log LOG = CmsLog.getLog(CmsJspLoginBean.class);
066
067    /** Flag to indicate if a login was successful. */
068    private CmsException m_loginException;
069
070    /**
071     * Empty constructor, required for every JavaBean.<p>
072     */
073    public CmsJspLoginBean() {
074
075        // noop, you must call the init() method after you create an instance
076    }
077
078    /**
079     * Constructor, with parameters.<p>
080     *
081     * @param context the JSP page context object
082     * @param req the JSP request
083     * @param res the JSP response
084     */
085    public CmsJspLoginBean(PageContext context, HttpServletRequest req, HttpServletResponse res) {
086
087        super();
088        init(context, req, res);
089    }
090
091    /**
092     * Logs any login exception.<p>
093     *
094     * @param requestContext the request context
095     * @param userName the user name
096     * @param currentLoginException the exception to log
097     */
098    public static void logLoginException(
099        CmsRequestContext requestContext,
100        String userName,
101        CmsException currentLoginException) {
102
103        if (currentLoginException instanceof CmsAuthentificationException) {
104
105            // the authentication of the user failed
106            if (org.opencms.security.Messages.ERR_LOGIN_FAILED_DISABLED_2 == currentLoginException.getMessageContainer().getKey()) {
107
108                // the user has been disabled
109                LOG.warn(
110                    Messages.get().getBundle().key(
111                        Messages.LOG_LOGIN_FAILED_DISABLED_3,
112                        userName,
113                        requestContext.addSiteRoot(requestContext.getUri()),
114                        requestContext.getRemoteAddress()));
115
116            } else if (org.opencms.security.Messages.ERR_LOGIN_FAILED_TEMP_DISABLED_4 == currentLoginException.getMessageContainer().getKey()) {
117
118                // the user has been disabled
119                LOG.warn(
120                    Messages.get().getBundle().key(
121                        Messages.LOG_LOGIN_FAILED_TEMP_DISABLED_5,
122                        new Object[] {
123                            userName,
124                            requestContext.addSiteRoot(requestContext.getUri()),
125                            requestContext.getRemoteAddress(),
126                            currentLoginException.getMessageContainer().getArgs()[2],
127                            currentLoginException.getMessageContainer().getArgs()[3]}));
128
129            } else if (org.opencms.security.Messages.ERR_LOGIN_FAILED_NO_USER_2 == currentLoginException.getMessageContainer().getKey()) {
130
131                // the requested user does not exist in the database
132                LOG.warn(
133                    Messages.get().getBundle().key(
134                        Messages.LOG_LOGIN_FAILED_NO_USER_3,
135                        userName,
136                        requestContext.addSiteRoot(requestContext.getUri()),
137                        requestContext.getRemoteAddress()));
138
139            } else if (org.opencms.security.Messages.ERR_LOGIN_FAILED_WITH_MESSAGE_1 == currentLoginException.getMessageContainer().getKey()) {
140
141                // logins have been disabled by the administration
142                long endTime = CmsLoginMessage.DEFAULT_TIME_END;
143                if (OpenCms.getLoginManager().getLoginMessage() != null) {
144                    endTime = OpenCms.getLoginManager().getLoginMessage().getTimeEnd();
145                }
146                LOG.info(
147                    Messages.get().getBundle().key(
148                        Messages.LOG_LOGIN_FAILED_WITH_MESSAGE_4,
149                        new Object[] {
150                            userName,
151                            requestContext.addSiteRoot(requestContext.getUri()),
152                            requestContext.getRemoteAddress(),
153                            new Date(endTime)}));
154
155            } else {
156
157                // the user exists, so the password must have been wrong
158                CmsMessageContainer message = Messages.get().container(
159                    Messages.LOG_LOGIN_FAILED_3,
160                    userName,
161                    requestContext.addSiteRoot(requestContext.getUri()),
162                    requestContext.getRemoteAddress());
163                if (OpenCms.getDefaultUsers().isUserAdmin(userName)) {
164                    // someone tried to log in as "Admin", log this in a higher channel
165                    LOG.error(message.key());
166                } else {
167                    LOG.warn(message.key());
168                }
169            }
170        } else {
171            // the error was database related, there may be an issue with the setup
172            // write the exception to the log as well
173            LOG.error(
174                Messages.get().getBundle().key(
175                    Messages.LOG_LOGIN_FAILED_DB_REASON_3,
176                    userName,
177                    requestContext.addSiteRoot(requestContext.getUri()),
178                    requestContext.getRemoteAddress()),
179                currentLoginException);
180        }
181    }
182
183    /**
184     * Returns the link to the form that contains the login element.<p>
185     *
186     * @return the link to the form that contains the login element
187     */
188    public String getFormLink() {
189
190        return link(getRequestContext().getUri());
191    }
192
193    /**
194     * Returns the exception that was thrown after login,
195     * or null if no Exception was thrown (i.e. login was successful
196     * or not attempted).<p>
197     *
198     * @return the exception thrown after login
199     */
200    public CmsException getLoginException() {
201
202        return m_loginException;
203    }
204
205    /**
206     * Returns the currently logged in user.<p>
207     *
208     * @return the currently logged in user
209     */
210    public CmsUser getUser() {
211
212        return getRequestContext().getCurrentUser();
213    }
214
215    /**
216     * Returns the user name of the currently logged in user.<p>
217     *
218     * @return the user name of the currently logged in user
219     */
220    public String getUserName() {
221
222        return getRequestContext().getCurrentUser().getName();
223    }
224
225    /**
226     * Returns true if the current user is not the guest user,
227     * i.e. if he already has logged in with some other user account.<p>
228     *
229     * @return true if the current user is already logged in
230     */
231    public boolean isLoggedIn() {
232
233        return !getCmsObject().getRequestContext().getCurrentUser().isGuestUser();
234    }
235
236    /**
237     * Indicates if a login was successful or not.<p>
238     *
239     * @return true if the login was successful
240     */
241    public boolean isLoginSuccess() {
242
243        return (m_loginException == null);
244    }
245
246    /**
247     * Logs a system user in to OpenCms.<p>
248     *
249     * @param userName the users name
250     * @param password the password
251     */
252    public void login(String userName, String password) {
253
254        login(userName, password, null);
255    }
256
257    /**
258     * Logs a system user into OpenCms.<p>
259     *
260     * Note that if a login project name is provided, this project must exist,
261     * otherwise the login is regarded as a failure even if the user data was correct.<p>
262     *
263     * @param userName the users name
264     * @param password the password
265     * @param projectName the project to switch to after login (if null project is not switched)
266     */
267    public void login(String userName, String password, String projectName) {
268
269        HttpSession session = null;
270        m_loginException = null;
271        try {
272
273            // login the user and create a new session
274            CmsUser user = getCmsObject().readUser(userName);
275            OpenCms.getSessionManager().checkCreateSessionForUser(user);
276            getCmsObject().loginUser(userName, password, getRequestContext().getRemoteAddress());
277
278            // make sure we have a new session after login for security reasons
279            session = getRequest().getSession(false);
280            if (session != null) {
281                session.invalidate();
282            }
283            session = getRequest().getSession(true);
284            if (projectName != null) {
285                // if this fails, the login is regarded as a failure as well
286                getCmsObject().getRequestContext().setCurrentProject(getCmsObject().readProject(projectName));
287            }
288            if (!getCmsObject().getRequestContext().getCurrentProject().isOnlineProject()) {
289                // in case the user is logged into an offline project, send any available login message
290                CmsLoginMessage loginMessage = OpenCms.getLoginManager().getLoginMessage();
291                if ((loginMessage != null) && loginMessage.isActive()) {
292                    OpenCms.getSessionManager().updateSessionInfo(getCmsObject(), getRequest());
293                    OpenCms.getSessionManager().sendBroadcast(null, loginMessage.getMessage(), user);
294                }
295            }
296
297        } catch (CmsException e) {
298            // the login has failed
299            m_loginException = e;
300        }
301        if (m_loginException == null) {
302            // login was successful
303            if (LOG.isInfoEnabled()) {
304                LOG.info(
305                    Messages.get().getBundle().key(
306                        Messages.LOG_LOGIN_SUCCESSFUL_3,
307                        userName,
308                        getRequestContext().addSiteRoot(getRequestContext().getUri()),
309                        getRequestContext().getRemoteAddress()));
310            }
311        } else {
312            // login was not successful
313            if (session != null) {
314                session.invalidate();
315            }
316            CmsException currentLoginException = m_loginException;
317            logLoginException(getRequestContext(), userName, currentLoginException);
318        }
319    }
320
321    /**
322     * Logs a system user in to OpenCms.<p>
323     *
324     * Note that if a login project name is provided, this project must exist,
325     * otherwise the login is regarded as a failure even if the user data was correct.<p>
326     *
327     * @param userName the users name
328     * @param password the password
329     * @param projectName the project to switch to after login (if null project is not switched)
330     * @param redirectUri the URI to redirect to after login (if null the current URI is used)
331     *
332     * @throws IOException in case redirect after login was not successful
333     */
334    public void login(String userName, String password, String projectName, String redirectUri) throws IOException {
335
336        login(userName, password, projectName);
337        if (m_loginException == null) {
338            if (redirectUri != null) {
339                getResponse().sendRedirect(
340                    OpenCms.getLinkManager().substituteLink(getCmsObject(), redirectUri, null, true));
341            } else {
342                getResponse().sendRedirect(getFormLink());
343            }
344        }
345    }
346
347    /**
348     * Logs a user out, i.e. destroys the current users session,
349     * after that the current page will be redirected to itself one time to ensure that
350     * the users session is truly destroyed.<p>
351     *
352     * @throws IOException if redirect after logout fails
353     */
354    public void logout() throws IOException {
355
356        String loggedInUserName = getRequestContext().getCurrentUser().getName();
357        HttpSession session = getRequest().getSession(false);
358        if (session != null) {
359            session.invalidate();
360            /* we need this because a new session might be created after this method,
361             but before the session info is updated in OpenCmsCore.showResource. */
362            getCmsObject().getRequestContext().setUpdateSessionEnabled(false);
363        }
364        // logout was successful
365        if (LOG.isInfoEnabled()) {
366            LOG.info(
367                Messages.get().getBundle().key(
368                    Messages.LOG_LOGOUT_SUCCESFUL_3,
369                    loggedInUserName,
370                    getRequestContext().addSiteRoot(getRequestContext().getUri()),
371                    getRequestContext().getRemoteAddress()));
372        }
373        getResponse().sendRedirect(getFormLink());
374    }
375}