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.workplace;
029
030import org.opencms.db.CmsLoginMessage;
031import org.opencms.db.CmsUserSettings;
032import org.opencms.file.CmsObject;
033import org.opencms.file.CmsProject;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.i18n.CmsAcceptLanguageHeaderParser;
037import org.opencms.i18n.CmsEncoder;
038import org.opencms.i18n.CmsMessageContainer;
039import org.opencms.json.JSONArray;
040import org.opencms.json.JSONException;
041import org.opencms.json.JSONObject;
042import org.opencms.jsp.CmsJspLoginBean;
043import org.opencms.main.CmsException;
044import org.opencms.main.CmsLog;
045import org.opencms.main.OpenCms;
046import org.opencms.security.CmsCustomLoginException;
047import org.opencms.security.CmsOrganizationalUnit;
048import org.opencms.ui.CmsVaadinUtils;
049import org.opencms.ui.apps.CmsPageEditorConfiguration;
050import org.opencms.ui.login.CmsLoginUI;
051import org.opencms.util.CmsRequestUtil;
052import org.opencms.util.CmsStringUtil;
053import org.opencms.util.CmsUriSplitter;
054
055import java.io.IOException;
056import java.util.ArrayList;
057import java.util.Calendar;
058import java.util.Date;
059import java.util.GregorianCalendar;
060import java.util.Iterator;
061import java.util.List;
062import java.util.Locale;
063
064import javax.servlet.http.Cookie;
065import javax.servlet.http.HttpServletRequest;
066import javax.servlet.http.HttpServletResponse;
067import javax.servlet.http.HttpSession;
068import javax.servlet.jsp.PageContext;
069
070import org.apache.commons.logging.Log;
071
072/**
073 * Handles the login of Users to the OpenCms workplace.<p>
074 *
075 * @since 6.0.0
076 */
077public class CmsLogin extends CmsJspLoginBean {
078
079    /** Action constant: Default action, display the dialog. */
080    public static final int ACTION_DISPLAY = 0;
081
082    /** Action constant: Login successful. */
083    public static final int ACTION_LOGIN = 1;
084
085    /** Action constant: Logout. */
086    public static final int ACTION_LOGOUT = 2;
087
088    /** The parameter name for the "getoulist" action. */
089    public static final String PARAM_ACTION_GETOULIST = "getoulist";
090
091    /** The parameter name for the "login" action. */
092    public static final String PARAM_ACTION_LOGIN = "login";
093
094    /** The parameter name for the "logout" action. */
095    public static final String PARAM_ACTION_LOGOUT = "logout";
096
097    /** The html id for the login form. */
098    public static final String PARAM_FORM = "ocLoginForm";
099
100    /** The parameter name for the organizational unit. */
101    public static final String PARAM_OUFQN = "ocOuFqn";
102
103    /** The parameter name for the search organizational unit. */
104    public static final String PARAM_OUSEARCH = "ocOuSearch";
105
106    /** The parameter name for the password. */
107    public static final String PARAM_PASSWORD = "ocPword";
108
109    /** The parameter name for the PC type. */
110    public static final String PARAM_PCTYPE = "ocPcType";
111
112    /** The parameter name for the organizational unit. */
113    public static final String PARAM_PREDEF_OUFQN = "ocPredefOuFqn";
114
115    /** The parameter name for the user name. */
116    public static final String PARAM_USERNAME = "ocUname";
117
118    /** The parameter name for the workplace data. */
119    public static final String PARAM_WPDATA = "ocWpData";
120
121    /** PC type constant: private PC. */
122    public static final String PCTYPE_PRIVATE = "private";
123
124    /** PC type constant: public PC. */
125    public static final String PCTYPE_PUBLIC = "public";
126
127    /** The oufqn cookie name. */
128    private static final String COOKIE_OUFQN = "OpenCmsOuFqn";
129
130    /** The PC type cookie name. */
131    private static final String COOKIE_PCTYPE = "OpenCmsPcType";
132
133    /** The username cookie name. */
134    private static final String COOKIE_USERNAME = "OpenCmsUserName";
135
136    /** The workplace data cookie name, value stores following information: ${left},${top},${width},${height}. */
137    private static final String COOKIE_WP_DATA = "OpenCmsWpData";
138
139    /** The log object for this class. */
140    private static final Log LOG = CmsLog.getLog(CmsLogin.class);
141
142    /** The action to perform. */
143    private int m_action;
144
145    /** The value of the "login" action parameter. */
146    private String m_actionLogin;
147
148    /** The value of the "logout" action parameter. */
149    private String m_actionLogout;
150
151    /** The path to open if direct edit is selected as start view. */
152    private String m_directEditPath;
153
154    /** The locale to use for display, this will not be the workplace locale, but the browser locale. */
155    private Locale m_locale;
156
157    /** The message to display with the dialog in a JavaScrip alert. */
158    private CmsMessageContainer m_message;
159
160    /** The selected organizational unit. */
161    private CmsOrganizationalUnit m_ou;
162
163    /** The value of the organizational unit parameter. */
164    private String m_oufqn;
165
166    /** The list of all organizational units. */
167    private List<CmsOrganizationalUnit> m_ous;
168
169    /** The value of the password parameter. */
170    private String m_password;
171
172    /** The value of the PC type parameter. */
173    private String m_pcType;
174
175    /** The redirect URL after a successful login. */
176    private String m_requestedResource;
177
178    /** The value of the user name parameter. */
179    private String m_username;
180
181    /**
182     * Public constructor for login page.<p>
183     *
184     * @param context the JSP page context object
185     * @param req the JSP request
186     * @param res the JSP response
187     */
188    public CmsLogin(PageContext context, HttpServletRequest req, HttpServletResponse res) {
189
190        super(context, req, res);
191
192        // this page must never be cached
193        res.setDateHeader(CmsRequestUtil.HEADER_LAST_MODIFIED, System.currentTimeMillis());
194        CmsRequestUtil.setNoCacheHeaders(res);
195        m_locale = getLocaleForRequest(req);
196    }
197
198    /**
199     * Gets the copyright information HTML.<p>
200     *
201     * @param locale the locale for which to get the copyright info
202     *
203     * @return the copyright info HTML
204     */
205    public static String getCopyrightHtml(Locale locale) {
206
207        StringBuffer html = new StringBuffer();
208        html.append("<div style=\"text-align: center; font-size: 10px; white-space: nowrap;\">");
209        html.append("<a href=\"http://www.opencms.org\" target=\"_blank\">OpenCms</a> ");
210        html.append(Messages.get().getBundle(locale).key(Messages.GUI_LOGIN_OPENCMS_IS_FREE_SOFTWARE_0));
211        html.append("</div>\n");
212        html.append("<div style=\"text-align: center; font-size: 10px; white-space: nowrap;\">");
213        html.append(Messages.get().getBundle(locale).key(Messages.GUI_LOGIN_TRADEMARKS_0));
214        html.append("</div>\n");
215        html.append("<div style=\"text-align: center; font-size: 10px; white-space: nowrap;\">");
216        html.append("&copy; 2002 - 2015 Alkacon Software GmbH &amp; Co. KG. ");
217        html.append(Messages.get().getBundle(locale).key(Messages.GUI_LOGIN_RIGHTS_RESERVED_0));
218        html.append("</div>\n");
219        return html.toString();
220    }
221
222    /**
223     * Returns the direct edit path from the user settings, or <code>null</code> if not set.<p>
224     *
225     * @param cms the CMS context to use
226     * @param userSettings the user settings
227     *
228     * @return the direct edit path
229     */
230    public static String getDirectEditPath(CmsObject cms, CmsUserSettings userSettings) {
231
232        if (userSettings.getStartView().equals(CmsWorkplace.VIEW_DIRECT_EDIT)
233            | userSettings.getStartView().equals(CmsPageEditorConfiguration.APP_ID)) {
234
235            try {
236                CmsObject cloneCms = OpenCms.initCmsObject(cms);
237                String startSite = CmsWorkplace.getStartSiteRoot(cloneCms, userSettings);
238                cloneCms.getRequestContext().setSiteRoot(startSite);
239                String projectName = userSettings.getStartProject();
240                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(projectName)) {
241                    cloneCms.getRequestContext().setCurrentProject(cloneCms.readProject(projectName));
242                }
243                String folder = userSettings.getStartFolder();
244                CmsResource targetRes = cloneCms.readDefaultFile(folder);
245                if (targetRes != null) {
246                    return cloneCms.getSitePath(targetRes);
247                }
248            } catch (Exception e) {
249                LOG.debug(e.getLocalizedMessage(), e);
250            }
251        }
252        return null;
253    }
254
255    /**
256     * Gets the list of OUs which should be selectable in the login dialog.<p>
257     *
258     * @param cms the CMS context to use
259     * @param predefOu the predefined OU
260     *
261     * @return the list of organizational units for the OU selector
262     */
263    public static List<CmsOrganizationalUnit> getOrgUnitsForLoginDialog(CmsObject cms, String predefOu) {
264
265        List<CmsOrganizationalUnit> result = new ArrayList<CmsOrganizationalUnit>();
266        try {
267            if (predefOu == null) {
268                result.add(OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, ""));
269                result.addAll(OpenCms.getOrgUnitManager().getOrganizationalUnits(cms, "", true));
270                Iterator<CmsOrganizationalUnit> itOus = result.iterator();
271                while (itOus.hasNext()) {
272                    CmsOrganizationalUnit ou = itOus.next();
273                    if (ou.hasFlagHideLogin() || ou.hasFlagWebuser()) {
274                        itOus.remove();
275                    }
276                }
277            } else {
278                result.add(OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, predefOu));
279            }
280        } catch (CmsException e) {
281            LOG.error(e.getLocalizedMessage(), e);
282        }
283        return result;
284
285    }
286
287    /**
288     * Gets the window title for a given locale.<p>
289     *
290     * @param locale the locale
291     * @return the window title
292     */
293    public static String getTitle(Locale locale) {
294
295        return Messages.get().getBundle(locale).key(Messages.GUI_LOGIN_TITLE_0);
296    }
297
298    /**
299     * Initializes the site and project for a CMS context after login, and returns the workplace settings for the corresponding user.<p>
300     *
301     * @param cms the CMS context which should be initialized
302     * @return the workplace set
303     */
304    public static CmsWorkplaceSettings initSiteAndProject(CmsObject cms) {
305
306        CmsWorkplaceSettings workplaceSettings = CmsWorkplace.initWorkplaceSettings(cms, null, false);
307        String startSite = CmsWorkplace.getStartSiteRoot(cms, workplaceSettings);
308        // switch to the preferred site
309        workplaceSettings.setSite(startSite);
310        cms.getRequestContext().setSiteRoot(startSite);
311        // store the workplace settings
312        CmsUserSettings settings = workplaceSettings.getUserSettings();
313        // get the direct edit path
314
315        try {
316            CmsProject project = cms.readProject(settings.getStartProject());
317            if (OpenCms.getOrgUnitManager().getAllAccessibleProjects(cms, project.getOuFqn(), false).contains(
318                project)) {
319                // user has access to the project, set this as current project
320                workplaceSettings.setProject(project.getUuid());
321                cms.getRequestContext().setCurrentProject(project);
322            }
323        } catch (CmsException e) {
324            // unable to set the startup project, bad but not critical
325            LOG.warn(
326                Messages.get().getBundle().key(
327                    Messages.LOG_LOGIN_NO_STARTUP_PROJECT_2,
328                    cms.getRequestContext().getCurrentUser().getName(),
329                    settings.getStartProject()),
330                e);
331        }
332        return workplaceSettings;
333    }
334
335    /**
336     * Sets the cookie data.<p>
337     *
338     * @param pcType the pctype value
339     * @param username the username value
340     * @param oufqn the oufqn value
341     *
342     * @param request the current request
343     * @param response the current response
344     */
345    public static void setCookieData(
346        String pcType,
347        String username,
348        String oufqn,
349        HttpServletRequest request,
350        HttpServletResponse response) {
351
352        // set the PC type cookie only if security dialog is enabled
353        if (OpenCms.getLoginManager().isEnableSecurity() && CmsStringUtil.isNotEmpty(pcType)) {
354            Cookie pcTypeCookie = getCookie(request, COOKIE_PCTYPE);
355            pcTypeCookie.setValue(pcType);
356            setCookie(pcTypeCookie, false, request, response);
357        }
358
359        // only store user name and OU cookies on private PC types
360        if (PCTYPE_PRIVATE.equals(pcType)) {
361            // set the user name cookie
362            Cookie userNameCookie = getCookie(request, COOKIE_USERNAME);
363            userNameCookie.setValue(username);
364            setCookie(userNameCookie, false, request, response);
365
366            // set the organizational unit cookie
367            Cookie ouFqnCookie = getCookie(request, COOKIE_OUFQN);
368            ouFqnCookie.setValue(oufqn);
369            setCookie(ouFqnCookie, false, request, response);
370        } else if (OpenCms.getLoginManager().isEnableSecurity() && PCTYPE_PUBLIC.equals(pcType)) {
371            // delete user name and organizational unit cookies
372            Cookie userNameCookie = getCookie(request, COOKIE_USERNAME);
373            setCookie(userNameCookie, true, request, response);
374            Cookie ouFqnCookie = getCookie(request, COOKIE_OUFQN);
375            setCookie(ouFqnCookie, true, request, response);
376
377        }
378    }
379
380    /**
381     * Checks that the user name and password are not empty, and returns an error message if they are.<p>
382     *
383     * @param username the user name
384     * @param password the password
385     *
386     * @return the error message, or null if the user name and password are OK
387     */
388    public static CmsMessageContainer validateUserAndPasswordNotEmpty(String username, String password) {
389
390        boolean userEmpty = CmsStringUtil.isEmpty(username);
391        boolean passwordEmpty = CmsStringUtil.isEmpty(password);
392
393        // login was requested
394        if (userEmpty && passwordEmpty) {
395            return Messages.get().container(Messages.GUI_LOGIN_NO_DATA_0);
396        } else if (userEmpty) {
397            return Messages.get().container(Messages.GUI_LOGIN_NO_NAME_0);
398        } else if (passwordEmpty) {
399            return Messages.get().container(Messages.GUI_LOGIN_NO_PASSWORD_0);
400        }
401        return null;
402    }
403
404    /**
405     * Returns the cookie with the given name, if not cookie is found a new one is created.<p>
406     *
407     * @param request the current request
408     * @param name the name of the cookie
409     *
410     * @return the cookie
411     */
412    protected static Cookie getCookie(HttpServletRequest request, String name) {
413
414        Cookie[] cookies = request.getCookies();
415        for (int i = 0; (cookies != null) && (i < cookies.length); i++) {
416            if (name.equalsIgnoreCase(cookies[i].getName())) {
417                return cookies[i];
418            }
419        }
420        return new Cookie(name, "");
421    }
422
423    /**
424     * Sets the cookie in the response.<p>
425     *
426     * @param cookie the cookie to set
427     * @param delete flag to determine if the cookir should be deleted
428     * @param request the current request
429     * @param response the current response
430     */
431    protected static void setCookie(
432        Cookie cookie,
433        boolean delete,
434        HttpServletRequest request,
435        HttpServletResponse response) {
436
437        if (request.getAttribute(PARAM_PREDEF_OUFQN) != null) {
438            // prevent the use of cookies if using a direct ou login url
439            return;
440        }
441        int maxAge = 0;
442        if (!delete) {
443            // set the expiration date of the cookie to six months from today
444            GregorianCalendar cal = new GregorianCalendar();
445            cal.add(Calendar.MONTH, 6);
446            maxAge = (int)((cal.getTimeInMillis() - System.currentTimeMillis()) / 1000);
447        }
448        cookie.setMaxAge(maxAge);
449        // set the path
450        cookie.setPath(CmsStringUtil.joinPaths(OpenCms.getStaticExportManager().getVfsPrefix(), "/system/login"));
451        // set the cookie
452        response.addCookie(cookie);
453    }
454
455    /**
456     * Returns the best matching locale for the given request.<p>
457     *
458     * @param req the request
459     *
460     * @return the locale
461     */
462    private static Locale getLocaleForRequest(HttpServletRequest req) {
463
464        CmsAcceptLanguageHeaderParser parser = new CmsAcceptLanguageHeaderParser(
465            req,
466            OpenCms.getWorkplaceManager().getDefaultLocale());
467        List<Locale> acceptedLocales = parser.getAcceptedLocales();
468        List<Locale> workplaceLocales = OpenCms.getWorkplaceManager().getLocales();
469        Locale locale = OpenCms.getLocaleManager().getFirstMatchingLocale(acceptedLocales, workplaceLocales);
470        if (locale == null) {
471            // no match found - use OpenCms default locale
472            locale = OpenCms.getWorkplaceManager().getDefaultLocale();
473        }
474        return locale;
475    }
476
477    /**
478     * Returns the HTML code for selecting an organizational unit.<p>
479     *
480     * @return the HTML code for selecting an organizational unit
481     */
482    public String buildOrgUnitSelector() {
483
484        StringBuffer html = new StringBuffer();
485        html.append("<select style='width: 100%;' size='1' ");
486        appendId(html, PARAM_OUFQN);
487        html.append(">\n");
488        for (CmsOrganizationalUnit ou : getOus()) {
489            String selected = "";
490            if (ou.getName().equals(m_oufqn)
491                || (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_oufqn) && ou.getName().equals(m_oufqn.substring(1)))) {
492                selected = " selected='selected'";
493            }
494            html.append("<option value='").append(ou.getName()).append("'").append(selected).append(">");
495            html.append(ou.getDisplayName(m_locale));
496            html.append("</option>\n");
497        }
498        html.append("</select>\n");
499        return html.toString();
500    }
501
502    /**
503     * Returns the HTML for the login dialog in it's current state.<p>
504     *
505     * @return the HTML for the login dialog
506     *
507     * @throws IOException in case a redirect fails
508     * @throws CmsException in case displaying the login dialog fails
509     */
510    public String displayDialog() throws IOException, CmsException {
511
512        if ((OpenCms.getSiteManager().getSites().size() > 1)
513            && !OpenCms.getSiteManager().isWorkplaceRequest(getRequest())) {
514
515            // this is a multi site-configuration, but not a request to the configured Workplace site
516            // do not send any redirects to the workplace site for security reasons
517            getResponse().sendError(HttpServletResponse.SC_NOT_FOUND);
518            return null;
519        }
520
521        CmsObject cms = getCmsObject();
522        if (shouldUseNewLogin() && (cms.getRequestContext().getCurrentUser().isGuestUser())) {
523            if (getRequest().getParameter(PARAM_ACTION_LOGOUT) != null) {
524                getResponse().sendRedirect(OpenCms.getLinkManager().substituteLink(cms, "/system/login"));
525                return "";
526            } else {
527                return CmsLoginUI.displayVaadinLoginDialog(getRequest(), getResponse());
528            }
529        }
530
531        m_message = null;
532        if (cms.getRequestContext().getCurrentUser().isGuestUser()) {
533            // user is not currently logged in
534            m_action = ACTION_DISPLAY;
535            m_username = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_USERNAME);
536            if (m_username != null) {
537                // remove white spaces, can only lead to confusion on user name
538                m_username = m_username.trim();
539            }
540            m_password = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_PASSWORD);
541            m_actionLogin = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_ACTION_LOGIN);
542            m_oufqn = getRequest().getParameter(PARAM_OUFQN);
543            if (m_oufqn == null) {
544                m_oufqn = getPreDefOuFqn();
545            }
546            if (OpenCms.getLoginManager().isEnableSecurity()) {
547                // security option is enabled, try to get PC type from request parameter
548                m_pcType = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_PCTYPE);
549            } else {
550                // if security option is disabled, just set PC type to "private" to get common login dialog
551                m_pcType = PCTYPE_PRIVATE;
552            }
553
554            // try to get some info from a cookie
555            getCookieData();
556
557            // set PC type to "public" as default if not already set by cookie, request or if security option is disabled
558            if (m_pcType == null) {
559                m_pcType = PCTYPE_PUBLIC;
560            }
561        } else {
562            // user is already logged in
563            m_oufqn = cms.getRequestContext().getOuFqn();
564            m_action = ACTION_LOGIN;
565            m_actionLogout = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_ACTION_LOGOUT);
566        }
567
568        if (m_oufqn == null) {
569            m_oufqn = CmsOrganizationalUnit.SEPARATOR;
570        }
571
572        String actionGetOus = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_ACTION_GETOULIST);
573        if (Boolean.TRUE.toString().equals(actionGetOus)) {
574            return getJsonOrgUnitList();
575        }
576
577        // initialize the right ou
578        m_ou = null;
579        try {
580            m_ou = OpenCms.getOrgUnitManager().readOrganizationalUnit(getCmsObject(), m_oufqn);
581        } catch (CmsException e) {
582            m_oufqn = CmsOrganizationalUnit.SEPARATOR;
583            try {
584                m_ou = OpenCms.getOrgUnitManager().readOrganizationalUnit(getCmsObject(), m_oufqn);
585            } catch (CmsException exc) {
586                LOG.error(exc.getLocalizedMessage(), exc);
587            }
588        }
589
590        // initialize the requested resource
591        m_requestedResource = CmsRequestUtil.getNotEmptyParameter(
592            getRequest(),
593            CmsWorkplaceManager.PARAM_LOGIN_REQUESTED_RESOURCE);
594        if (m_requestedResource == null) {
595            // no resource was requested, use default workplace URI
596            m_requestedResource = CmsVaadinUtils.getWorkplaceLink();
597        }
598
599        if (Boolean.valueOf(m_actionLogin).booleanValue()) {
600            CmsMessageContainer emptyValidation = validateUserAndPasswordNotEmpty(m_username, m_password);
601            if (emptyValidation != null) {
602                m_message = emptyValidation;
603            } else {
604
605                // try to login with the given user information
606                login((m_oufqn == null ? CmsOrganizationalUnit.SEPARATOR : m_oufqn) + m_username, m_password);
607
608                if (getLoginException() == null) {
609                    // the login was successful
610                    m_action = ACTION_LOGIN;
611
612                    CmsWorkplaceSettings settings = initSiteAndProject(cms);
613                    getRequest().getSession().setAttribute(CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS, settings);
614                    m_directEditPath = getDirectEditPath(cms, settings.getUserSettings());
615                } else {
616                    // there was an error during login
617                    CmsException loginException = getLoginException();
618
619                    if (org.opencms.security.Messages.ERR_LOGIN_FAILED_DISABLED_2 == loginException.getMessageContainer().getKey()) {
620                        // the user account is disabled
621                        m_message = Messages.get().container(Messages.GUI_LOGIN_FAILED_DISABLED_0);
622                    } else if (org.opencms.security.Messages.ERR_LOGIN_FAILED_TEMP_DISABLED_4 == loginException.getMessageContainer().getKey()) {
623                        // the user account is temporarily disabled because of too many login failures
624                        m_message = Messages.get().container(Messages.GUI_LOGIN_FAILED_TEMP_DISABLED_0);
625                    } else if (org.opencms.security.Messages.ERR_LOGIN_FAILED_WITH_MESSAGE_1 == loginException.getMessageContainer().getKey()) {
626                        // all logins have been disabled be the Administration
627                        CmsLoginMessage loginMessage = OpenCms.getLoginManager().getLoginMessage();
628                        if (loginMessage != null) {
629                            m_message = Messages.get().container(
630                                Messages.GUI_LOGIN_FAILED_WITH_MESSAGE_1,
631                                loginMessage.getMessage());
632                        }
633                    }
634                    if (m_message == null) {
635                        if (loginException instanceof CmsCustomLoginException) {
636                            m_message = loginException.getMessageContainer();
637                        } else {
638                            // any other error - display default message
639                            m_message = Messages.get().container(Messages.GUI_LOGIN_FAILED_0);
640                        }
641                    }
642                }
643            }
644        } else if (Boolean.valueOf(m_actionLogout).booleanValue()) {
645            m_action = ACTION_LOGOUT;
646            // store the workplace window data
647            Cookie wpDataCookie = getCookie(getRequest(), COOKIE_WP_DATA);
648            String wpData = CmsRequestUtil.getNotEmptyParameter(getRequest(), PARAM_WPDATA);
649            if (wpData != null) {
650                wpData = CmsEncoder.escapeXml(wpData);
651                wpDataCookie.setValue(wpData);
652                setCookie(wpDataCookie, false, getRequest(), getResponse());
653            }
654            // after logout this will automatically redirect to the login form again
655            logout();
656            return null;
657        }
658
659        if (m_action == ACTION_LOGIN) {
660            // clear message
661            m_message = null;
662            // login is successful, check if the requested resource can be read
663            CmsUriSplitter splitter = new CmsUriSplitter(m_requestedResource, true);
664            String resource = splitter.getPrefix();
665            if (CmsStringUtil.isEmptyOrWhitespaceOnly(resource)) {
666                // bad resource name, use workplace as default
667                resource = CmsWorkplace.JSP_WORKPLACE_URI;
668            }
669            if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_directEditPath)
670                && !getCmsObject().existsResource(resource, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
671                // requested resource does either not exist or is not readable by user
672                if (CmsWorkplace.JSP_WORKPLACE_URI.equals(resource)) {
673                    // we know the Workplace exists, so the user does not have access to the Workplace
674                    // probably this is a "Guest" user in a default setup where "Guest" has no access to the Workplace
675                    m_message = Messages.get().container(Messages.GUI_LOGIN_FAILED_NO_WORKPLACE_PERMISSIONS_0);
676                    m_action = ACTION_DISPLAY;
677                } else if (getCmsObject().existsResource(CmsWorkplace.JSP_WORKPLACE_URI)) {
678                    // resource does either not exist or is not readable, but general workplace permissions are granted
679                    m_message = Messages.get().container(Messages.GUI_LOGIN_UNKNOWN_RESOURCE_1, m_requestedResource);
680                    m_requestedResource = CmsWorkplace.JSP_WORKPLACE_URI;
681                } else {
682                    // resource does not exist and no general workplace permissions granted
683                    m_message = Messages.get().container(
684                        Messages.GUI_LOGIN_FAILED_NO_TARGET_PERMISSIONS_1,
685                        m_requestedResource);
686                    m_action = ACTION_DISPLAY;
687                }
688            }
689            if (m_action == ACTION_DISPLAY) {
690                //the login was invalid
691                m_requestedResource = null;
692                // destroy the generated session
693                HttpSession session = getRequest().getSession(false);
694                if (session != null) {
695                    session.invalidate();
696                }
697                setCookieData(getRequest(), getResponse());
698            } else {
699                // successfully logged in, so set the cookie
700                setCookieData(getRequest(), getResponse());
701            }
702        }
703
704        return displayLoginForm();
705    }
706
707    /**
708     * Gets the login info from the cookies.<p>
709     */
710    public void getCookieData() {
711
712        // get the PC type cookie
713        Cookie pcTypeCookie = getCookie(getRequest(), COOKIE_PCTYPE);
714        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(pcTypeCookie.getValue())) {
715            // only set the data if needed
716            if (m_pcType == null) {
717                m_pcType = pcTypeCookie.getValue();
718            }
719        }
720        if ("null".equals(m_pcType)) {
721            m_pcType = null;
722        }
723        // get other cookies only on private PC types (or if security option is disabled)
724        if ((m_pcType == null) || PCTYPE_PRIVATE.equals(m_pcType)) {
725            // get the user name cookie
726            Cookie userNameCookie = getCookie(getRequest(), COOKIE_USERNAME);
727            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(userNameCookie.getValue())) {
728                // only set the data if needed
729                if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_username)) {
730                    m_username = userNameCookie.getValue();
731                }
732                if (m_pcType == null) {
733                    // set PC type to private PC if the user cookie is found
734                    m_pcType = PCTYPE_PRIVATE;
735                }
736            }
737            if ("null".equals(m_username)) {
738                m_username = null;
739            }
740            // get the organizational unit cookie
741            Cookie ouFqnCookie = getCookie(getRequest(), COOKIE_OUFQN);
742            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(ouFqnCookie.getValue())) {
743                // only set the data if needed
744                if (m_oufqn == null) {
745                    m_oufqn = ouFqnCookie.getValue();
746                }
747            }
748            if ("null".equals(m_oufqn)) {
749                m_oufqn = null;
750            }
751        }
752    }
753
754    /**
755     * @see org.opencms.jsp.CmsJspLoginBean#getFormLink()
756     */
757    @Override
758    public String getFormLink() {
759
760        if (getPreDefOuFqn() == null) {
761            return super.getFormLink();
762        }
763        String preDefOuFqn = (String)getRequest().getAttribute(PARAM_PREDEF_OUFQN);
764        try {
765            OpenCms.getOrgUnitManager().readOrganizationalUnit(getCmsObject(), preDefOuFqn);
766        } catch (CmsException e) {
767            // organizational unit does not exist
768            return super.getFormLink();
769        }
770        return link("/system/login" + CmsEncoder.escapeXml(preDefOuFqn));
771    }
772
773    /**
774     * Returns the available organizational units as JSON array string.<p>
775     *
776     * @return the available organizational units as JSON array string
777     */
778    public String getJsonOrgUnitList() {
779
780        List<CmsOrganizationalUnit> allOus = getOus();
781        List<JSONObject> jsonOus = new ArrayList<JSONObject>(allOus.size());
782        int index = 0;
783        for (CmsOrganizationalUnit ou : allOus) {
784            JSONObject jsonObj = new JSONObject();
785            try {
786                // 1: OU fully qualified name
787                jsonObj.put("name", ou.getName());
788                // 2: OU display name
789                jsonObj.put("displayname", ou.getDisplayName(m_locale));
790                // 3: OU simple name
791                jsonObj.put("simplename", ou.getSimpleName());
792                // 4: OU description
793                jsonObj.put("description", ou.getDescription(m_locale));
794                // 5: selection flag
795                boolean isSelected = false;
796                if (ou.getName().equals(m_oufqn)
797                    || (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_oufqn)
798                        && ou.getName().equals(m_oufqn.substring(1)))) {
799                    isSelected = true;
800                }
801                jsonObj.put("active", isSelected);
802                // 6: level of the OU
803                jsonObj.put("level", CmsResource.getPathLevel(ou.getName()));
804                // 7: OU index
805                jsonObj.put("index", index);
806                // add the generated JSON object to the result list
807                jsonOus.add(jsonObj);
808                index++;
809            } catch (JSONException e) {
810                // error creating JSON object, skip this OU
811            }
812        }
813        // generate a JSON array from the JSON object list
814        JSONArray jsonArr = new JSONArray(jsonOus);
815        return jsonArr.toString();
816    }
817
818    /**
819     * Sets the cookie data.<p>
820     *
821     * @param request the current request
822     * @param response the current response
823     */
824    public void setCookieData(HttpServletRequest request, HttpServletResponse response) {
825
826        setCookieData(m_pcType, m_username, m_oufqn, request, response);
827    }
828
829    /**
830     * Appends the JavaScript for the login screen to the given HTML buffer.<p>
831     *
832     * @param html the HTML buffer to append the script to
833     * @param message the message to display after an unsuccessful login
834     */
835    protected void appendDefaultLoginScript(StringBuffer html, CmsMessageContainer message) {
836
837        html.append("<script  src=\"");
838        html.append(CmsWorkplace.getSkinUri()).append("jquery/packed/jquery.js");
839        html.append("\"></script>\n");
840        html.append("<script >\n");
841        if (message != null) {
842            html.append("function showAlert() {\n");
843            html.append("\talert(\"");
844            html.append(CmsStringUtil.escapeJavaScript(message.key(m_locale)));
845            html.append("\");\n");
846            html.append("}\n");
847        }
848        html.append("var orgUnitShow = false;\n");
849        html.append("var orgUnits = null;\n");
850        html.append("var activeOu = -1;\n");
851        html.append("var searchTimeout;\n");
852        html.append("var searchDefaultValue = \"");
853        html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_SEARCH_0));
854        html.append("\";\n");
855
856        // triggers the options to select the OU to login to
857        html.append("function orgUnitSelection() {\n");
858        html.append("\tif (!orgUnitShow) {\n");
859        html.append("\t\tif (orgUnits == null) {\n");
860        html.append("\t\t\t$.post(\"");
861        html.append(getFormLink());
862        html.append("\", { ");
863        html.append(PARAM_ACTION_GETOULIST);
864        html.append(": \"true\" }");
865        html.append(", function(data){ fillOrgUnits(data); });\n");
866        html.append("\t\t}\n");
867        html.append("\t\tdocument.getElementById('ouSelId').style.display = 'block';\n");
868        html.append("\t\tdocument.getElementById('ouLabelId').style.display = 'block';\n");
869        html.append("\t\tdocument.getElementById('ouSearchId').style.display = 'block';\n");
870        html.append("\t\tdocument.getElementById('ouBtnId').value = '");
871        html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_SELECT_OFF_0));
872        html.append("';\n");
873        html.append("\t} else {\n");
874        html.append("\t\tdocument.getElementById('ouSelId').style.display = 'none';\n");
875        html.append("\t\tdocument.getElementById('ouLabelId').style.display = 'none';\n");
876        html.append("\t\tdocument.getElementById('ouSearchId').style.display = 'none';\n");
877        html.append("\t\tdocument.getElementById('ouBtnId').value = '");
878        html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_SELECT_ON_0));
879        html.append("';\n");
880        html.append("\t}\n");
881        html.append("\torgUnitShow = !orgUnitShow;\n");
882        html.append("\tdocument.getElementById('titleId').style.display = 'block';\n");
883        html.append("\tdocument.getElementById('titleIdOu').style.display = 'none';\n");
884        html.append("}\n");
885
886        // creates the HTML for the OUs to login to
887        html.append("function fillOrgUnits(data) {\n");
888        html.append("\torgUnits = eval(data);\n");
889        html.append("\tvar html = \"\";\n");
890        html.append("\tvar foundOu = false;\n");
891        html.append("\tvar activeIndex = -1;\n");
892        html.append("\tfor (var i = 0; i < orgUnits.length; i++) {\n");
893        html.append("\t\tvar currOu = orgUnits[i];\n");
894        html.append("\t\tvar actClass = \"\";\n");
895        html.append("\t\tif (currOu.active == true) {\n");
896        html.append("\t\t\t// this is the active OU\n");
897        html.append("\t\t\tactiveOu = currOu.index;\n");
898        html.append("\t\t\tactClass = \" class=\\\"active\\\"\";\n");
899        html.append("\t\t}\n");
900        html.append("\t\tvar actStyle = \"\";\n");
901        html.append("\t\tif (currOu.level > 0) {\n");
902        html.append("\t\t\tactStyle = \" style=\\\"margin-left: \" + (currOu.level * 20) + \"px;\\\"\";\n");
903        html.append("\t\t}\n");
904        html.append("\t\thtml += \"<div\";\n");
905        html.append("\t\thtml += actClass;\n");
906        html.append("\t\thtml += actStyle;\n");
907        html.append("\t\thtml += \" id=\\\"ou\" + currOu.index;\n");
908        html.append("\t\thtml += \"\\\" onclick=\\\"selectOu('\";\n");
909        html.append("\t\thtml += currOu.name;\n");
910        html.append("\t\thtml += \"', \" + currOu.index;\n");
911        html.append("\t\thtml += \");\\\"><span class=\\\"name\\\">\";\n");
912        html.append("\t\thtml += currOu.description;\n");
913        html.append("\t\thtml += \"</span>\";\n");
914        html.append("\t\tif (currOu.name != \"\") {\n");
915        html.append("\t\t\thtml += \"<span class=\\\"path\\\"\";\n");
916        html.append("\t\t\thtml += \" title=\\\"\";\n");
917        html.append("\t\t\thtml += currOu.name;\n");
918        html.append("\t\t\thtml += \"\\\">\";\n");
919        html.append("\t\t\thtml += currOu.simplename;\n");
920        html.append("\t\t\thtml += \"</span>\";\n");
921        html.append("\t\t}\n");
922        html.append("\t\thtml += \"</div>\";\n");
923        html.append("\t}\n");
924        html.append(
925            "\thtml += \"<div id=\\\"nooufound\\\" style=\\\"display: none;\\\"><span class=\\\"name\\\">\";\n");
926        html.append("\thtml += \"");
927        html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_SEARCH_NORESULTS_0));
928        html.append("\";\n");
929        html.append("\thtml += \"</span></div>\";\n");
930        html.append("\t$(\"#ouSelId\").append(html);\n");
931        html.append("\t$(\"#ouSelId\").slideDown();\n");
932        html.append("\tscrollToActiveOu();\n");
933        html.append("}\n");
934
935        // shows the list of OUs matching the search term or all OUs if the search term is empty
936        html.append("function showOrgUnits(searchTerm) {\n");
937        html.append("\tvar html = \"\";\n");
938        html.append("\tvar foundOu = false;\n");
939        html.append("\tfor (var i = 0; i < orgUnits.length; i++) {\n");
940        html.append("\t\tvar currOu = orgUnits[i];\n");
941        html.append("\t\tif (searchTerm != \"\") {\n");
942        html.append("\t\t\tvar stLower = searchTerm.toLowerCase();\n");
943        html.append(
944            "\t\t\tif (currOu.name.toLowerCase().indexOf(stLower )== -1 && currOu.description.toLowerCase().indexOf(stLower) == -1) {\n");
945        html.append("\t\t\t\t$(\"#ou\" + i + \":visible\").slideUp();\n");
946        html.append("\t\t\t} else {\n");
947        html.append("\t\t\t\t$(\"#ou\" + i + \":hidden\").slideDown();\n");
948        html.append("\t\t\t\t$(\"#ou\" + i).removeAttr(\"style\");\n");
949        html.append("\t\t\t\tfoundOu = true;\n");
950        html.append("\t\t\t}\n");
951        html.append("\t\t} else {\n");
952        html.append("\t\t\tfoundOu = true;\n");
953        html.append("\t\t\tvar actStyle = \"\";\n");
954        html.append("\t\t\tif (currOu.level > 0) {\n");
955        html.append("\t\t\t\tactStyle = \"margin-left: \" + (currOu.level * 20) + \"px;\";\n");
956        html.append("\t\t\t}\n");
957        html.append("\t\t\t$(\"#ou\" + i).attr(\"style\", actStyle);\n");
958        html.append("\t\t\t$(\"#ou\" + i + \":hidden\").slideDown();\n");
959        html.append("\t\t}\n");
960        html.append("\t}\n");
961        html.append("\tif (searchTerm != \"\" && foundOu == false) {\n");
962        html.append("\t\t$(\"#nooufound:hidden\").slideDown();\n");
963        html.append("\t} else {\n");
964        html.append("\t\t$(\"#nooufound:visible\").slideUp();\n");
965        html.append("\t}\n");
966        html.append("\tif (searchTerm == \"\") {\n");
967        html.append("\t\tscrollToActiveOu();\n");
968        html.append("\t}\n");
969        html.append("}\n");
970
971        // selects the OU to login to
972        html.append("function selectOu(ouPath, ouIndex) {\n");
973        html.append("\tif (ouIndex != -1 && ouIndex != activeOu) {\n");
974        html.append("\t\t$(\"#ou\" + ouIndex).addClass(\"active\");\n");
975        html.append("\t\torgUnits[ouIndex].active = true;\n");
976        html.append("\t\t$(\"#");
977        html.append(PARAM_OUFQN);
978        html.append("\").val(ouPath);\n");
979        html.append("\t\tif (activeOu != -1) {\n");
980        html.append("\t\t\torgUnits[activeOu].active = false;\n");
981        html.append("\t\t\t$(\"#ou\" + activeOu).removeClass();\n");
982        html.append("\t\t}\n");
983        html.append("\t\tactiveOu = ouIndex;\n");
984        html.append("\t}\n");
985        html.append("}\n");
986
987        // filters the OUs by the provided search term using a timeout, called by the onkeyup event of the search input field
988        html.append("function searchOu() {\n");
989        html.append("\tvar searchElem = $(\"#");
990        html.append(PARAM_OUSEARCH);
991        html.append("\");\n");
992        html.append("\tvar searchTerm = searchElem.val();\n");
993        html.append("\tif (searchTerm == searchDefaultValue) {");
994        html.append("\t\tsearchTerm = \"\";");
995        html.append("\t}");
996        html.append("\tclearTimeout(searchTimeout);\n");
997        html.append("\tsearchTimeout = setTimeout(\"showOrgUnits(\\\"\" + trim(searchTerm) + \"\\\");\", 750);\n");
998        html.append("}\n");
999
1000        // sets the value of the OU search input field, called by the onfocus and onblur event of the field
1001        html.append("function checkOuValue() {\n");
1002        html.append("\tvar searchElem = $(\"#");
1003        html.append(PARAM_OUSEARCH);
1004        html.append("\");\n");
1005        html.append("\tif (searchElem.val() == searchDefaultValue) {");
1006        html.append("\t\tsearchElem.val(\"\");");
1007        html.append("\t\tsearchElem.removeAttr(\"class\");");
1008        html.append("\t} else if (searchElem.val() == \"\") {");
1009        html.append("\t\tsearchElem.val(searchDefaultValue);");
1010        html.append("\t\tsearchElem.attr(\"class\", \"inactive\");");
1011        html.append("\t}");
1012        html.append("}\n");
1013
1014        // scrolls to the currently selected OU if it is out of visible range
1015        html.append("function scrollToActiveOu() {\n");
1016        html.append("\tif (activeOu != -1) {\n");
1017        html.append("\t\tvar activeOffset = $(\"#ou\" + activeOu).offset().top;\n");
1018        html.append("\t\tvar parentOffset = $(\"#ouSelId\").offset().top;\n");
1019        html.append("\t\tactiveOffset = activeOffset - parentOffset;\n");
1020        html.append("\t\tif (activeOffset > $(\"#ouSelId\").height()) {;\n");
1021        html.append("\t\t\t$(\"#ouSelId\").animate({scrollTop: activeOffset}, 500);\n");
1022        html.append("\t\t};\n");
1023        html.append("\t}\n");
1024        html.append("}\n");
1025
1026        // function to check IE version, in case of a version < IE8 login will be disabled and an error message shown.
1027        html.append("function checkBrowser(){\n ");
1028        html.append("var div = document.createElement(\"div\");\n");
1029        html.append("div.innerHTML = \"<!--[if lt IE 8]><i></i><![endif]-->\";\n");
1030        html.append("var isIeLessThan8 = (div.getElementsByTagName(\"i\").length == 1);\n");
1031        html.append("if (isIeLessThan8) {\n  $('#");
1032        html.append(PARAM_FORM);
1033        html.append(
1034            "').after('<div style=\"color: #B31B34; font-weight: bold; font-size: 14px; margin: 20px; text-align: center;\">");
1035        html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_UNSUPPORTED_BROWSER_0));
1036        html.append("</div>');\n $('#");
1037        html.append(PARAM_FORM);
1038        html.append(
1039            "').css(\"display\",\"none\"); /** $('input').attr('disabled', 'disabled');\n  alert('wrong browser'); */\n}\n}\n");
1040
1041        // called when the login form page is loaded
1042        html.append("function doOnload() {\n checkBrowser();\n");
1043        html.append("\tdocument.");
1044        html.append(PARAM_FORM);
1045        html.append(".");
1046        html.append(PARAM_USERNAME);
1047        html.append(".select();\n");
1048        html.append("\tdocument.");
1049        html.append(PARAM_FORM);
1050        html.append(".");
1051        html.append(PARAM_USERNAME);
1052        html.append(".focus();\n");
1053        if (message != null) {
1054            html.append("\tshowAlert();\n");
1055        }
1056        html.append("}\n");
1057
1058        // helper function to trim a given string
1059        html.append("function trim (myStr) {\n");
1060        html.append("\treturn myStr.replace(/^\\s+/, '').replace (/\\s+$/, '');\n");
1061        html.append("}\n");
1062
1063        html.append("</script>\n");
1064    }
1065
1066    /**
1067     * Appends the JavaScript that opens the Direct Edit window after a successful login
1068     * to the given HTML buffer.<p>
1069     *
1070     * @param html the html buffer to append the script to
1071     */
1072    protected void appendDirectEditOpenerScript(StringBuffer html) {
1073
1074        html.append("<script >\n");
1075        html.append("function doOnload() {\n");
1076
1077        // the window's name must be the same as in:
1078        // system/workplace/resources/commons/explorer.js
1079        html.append("window.name='preview';");
1080        html.append("window.location.replace('");
1081        html.append(link(m_directEditPath));
1082        html.append("');");
1083
1084        html.append("}\n");
1085        html.append("</script>\n");
1086    }
1087
1088    /**
1089     * Appends the HTML form name/id code for the given id to the given html.<p>
1090     *
1091     * @param html the html where to append the id to
1092     * @param id the id to append
1093     */
1094    protected void appendId(StringBuffer html, String id) {
1095
1096        html.append(" name=\"");
1097        html.append(id);
1098        html.append("\" id=\"");
1099        html.append(id);
1100        html.append("\" ");
1101    }
1102
1103    /**
1104     * Appends the JavaScript that opens the Workplace window after a successful login
1105     * to the given HTML buffer.<p>
1106     *
1107     * @param html the html buffer to append the script to
1108     * @param requestedResource the requested resource to open in a new window
1109     * @param message the message to display if the originally requested resource is not available
1110     */
1111    protected void appendWorkplaceOpenerScript(
1112        StringBuffer html,
1113        String requestedResource,
1114        CmsMessageContainer message) {
1115
1116        String winId = "OpenCms" + System.currentTimeMillis();
1117
1118        html.append("<script >\n");
1119
1120        html.append("function doOnload() {\n");
1121
1122        // display missing resource warning if required
1123        if (message != null) {
1124            html.append("\talert(\"");
1125            html.append(CmsStringUtil.escapeJavaScript(message.key(m_locale)));
1126            html.append("\");\n");
1127        }
1128
1129        // display login message if required
1130        CmsLoginMessage loginMessage = OpenCms.getLoginManager().getLoginMessage();
1131        if ((loginMessage != null) && (loginMessage.isActive())) {
1132            String msg;
1133            if (loginMessage.isLoginForbidden()) {
1134                // login forbidden for normal users, current user must be Administrator
1135                msg = Messages.get().container(
1136                    Messages.GUI_LOGIN_SUCCESS_WITH_MESSAGE_2,
1137                    loginMessage.getMessage(),
1138                    new Date(loginMessage.getTimeEnd())).key(m_locale);
1139            } else {
1140                // just display the message
1141                msg = loginMessage.getMessage();
1142            }
1143            html.append("\talert(\"");
1144            html.append(CmsStringUtil.escapeJavaScript(msg));
1145            html.append("\");\n");
1146        }
1147
1148        String openResource = requestedResource;
1149
1150        // check if user agreement should be shown
1151        CmsLoginUserAgreement agreementInfo = new CmsLoginUserAgreement(this);
1152        if (agreementInfo.isShowUserAgreement()) {
1153            openResource = agreementInfo.getConfigurationVfsPath()
1154                + "?"
1155                + CmsLoginUserAgreement.PARAM_WPRES
1156                + "="
1157                + requestedResource;
1158        }
1159
1160        html.append("\tvar openUri = \"");
1161        html.append(link(openResource));
1162        html.append("\";\n");
1163        html.append("\tvar workplaceWin = openWorkplace(openUri, \"");
1164        html.append(winId);
1165        html.append("\");\n");
1166        html.append("\tif (window.name != \"");
1167        html.append(winId);
1168        html.append("\") {\n");
1169        html.append("\t\twindow.opener = workplaceWin;\n");
1170        html.append("\t\tif (workplaceWin != null) {\n");
1171        html.append("\t\t\twindow.close();\n");
1172        html.append("\t\t}\n");
1173        html.append("\t}\n");
1174        html.append("}\n");
1175
1176        html.append("function openWorkplace(url, name) {\n");
1177
1178        Cookie wpDataCookie = getCookie(getRequest(), COOKIE_WP_DATA);
1179        boolean useCookieData = false;
1180        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(wpDataCookie.getValue())) {
1181            String[] winValues = CmsStringUtil.splitAsArray(wpDataCookie.getValue(), '|');
1182            if (winValues.length == 4) {
1183                useCookieData = true;
1184                html.append("\tvar winLeft = ").append(winValues[0]).append(";\n");
1185                html.append("\tvar winTop = ").append(winValues[1]).append(";\n");
1186                html.append("\tvar winWidth = ").append(winValues[2]).append(";\n");
1187                html.append("\tvar winHeight = ").append(winValues[3]).append(";\n");
1188            }
1189        }
1190
1191        if (!useCookieData) {
1192            html.append("\tvar isInWin = (window.name.match(/^OpenCms\\d+$/) != null);\n");
1193            html.append("\tvar winHeight = 0, winWidth = 0, winTop = 0, winLeft = 0;\n");
1194            html.append("\tif (window.innerHeight) {\n");
1195            // Mozilla
1196            html.append("\t\twinHeight = window.innerHeight;\n");
1197            html.append("\t\twinWidth = window.innerWidth;\n");
1198            html.append("\t} else if (document.documentElement && document.documentElement.clientHeight) {\n");
1199            // IE 6 "strict" mode
1200            html.append("\t\twinHeight = document.documentElement.clientHeight;\n");
1201            html.append("\t\twinWidth = document.documentElement.clientWidth;\n");
1202            html.append("\t} else if (document.body && document.body.clientHeight) {\n");
1203            // IE 5, IE 6 "relaxed" mode
1204            html.append("\t\twinHeight = document.body.clientWidth;\n");
1205            html.append("\t\twinWidth = document.body.clientHeight;\n");
1206            html.append("\t}\n");
1207            html.append("\tif (window.screenY) {\n");
1208            // Mozilla
1209            html.append("\t\twinTop = window.screenY;\n");
1210            html.append("\t\twinLeft = window.screenX;\n");
1211            html.append("\t\tif (! isInWin) {\n");
1212            html.append("\t\t\twinTop += 25;\n");
1213            html.append("\t\t\twinLeft += 25;\n");
1214            html.append("\t\t}\n");
1215            html.append("\t} else if (window.screenTop) {\n");
1216            // IE
1217            html.append("\t\twinTop = window.screenTop;\n");
1218            html.append("\t\twinLeft = window.screenLeft;\n");
1219            html.append("\t}\n");
1220            html.append("\n");
1221        }
1222
1223        if (requestedResource.startsWith(CmsWorkplace.VFS_PATH_WORKPLACE)) {
1224            html.append(
1225                "\tvar openerStr = \"width=\" + winWidth + \",height=\" + winHeight + \",left=\" + winLeft + \",top=\" + winTop + \",scrollbars=no,location=no,toolbar=no,menubar=no,directories=no,status=yes,resizable=yes\";\n");
1226        } else {
1227            html.append(
1228                "\tvar openerStr = \"width=\" + winWidth + \",height=\" + winHeight + \",left=\" + winLeft + \",top=\" + winTop + \",scrollbars=yes,location=yes,toolbar=yes,menubar=yes,directories=no,status=yes,resizable=yes\";\n");
1229        }
1230        html.append("\tvar OpenCmsWin = window.open(url, name, openerStr);\n");
1231        html.append("\n");
1232        html.append("\ttry{\n");
1233        html.append("\t\tif (! OpenCmsWin.opener) {\n");
1234        html.append("\t\t\tOpenCmsWin.opener = self;\n");
1235        html.append("\t\t}\n");
1236        html.append("\t\tif (OpenCmsWin.focus) {\n");
1237        html.append("\t\t\tOpenCmsWin.focus();\n");
1238        html.append("\t\t}\n");
1239        html.append("\t} catch (e) {}\n");
1240        html.append("\n");
1241        html.append("\treturn OpenCmsWin;\n");
1242        html.append("}\n");
1243
1244        html.append("</script>\n");
1245    }
1246
1247    /**
1248     * Returns the HTML for the login form.<p>
1249     *
1250     * @return the HTML for the login form
1251     */
1252    protected String displayLoginForm() {
1253
1254        StringBuffer html = new StringBuffer(8192);
1255
1256        html.append("<!DOCTYPE html>\n");
1257        html.append("<html><head>\n");
1258        html.append("<title>");
1259        html.append(getTitle(m_locale));
1260
1261        html.append("</title>\n");
1262
1263        String encoding = getRequestContext().getEncoding();
1264        html.append("<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=");
1265        html.append(encoding);
1266        html.append("\">\n");
1267
1268        // append workplace CSS
1269        html.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"");
1270        html.append(CmsWorkplace.getStyleUri(this, "workplace.css"));
1271        html.append("\">\n");
1272
1273        // append favicon relation
1274        html.append("<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"");
1275        html.append(CmsWorkplace.getSkinUri()).append("commons/favicon.ico");
1276        html.append("\">\n");
1277
1278        if (m_action == ACTION_DISPLAY) {
1279            // append default script
1280            appendDefaultLoginScript(html, m_message);
1281        } else if (m_action == ACTION_LOGIN) {
1282            // append window opener script
1283            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_directEditPath)) {
1284                appendDirectEditOpenerScript(html);
1285            } else {
1286                appendWorkplaceOpenerScript(html, m_requestedResource, m_message);
1287            }
1288        }
1289
1290        html.append("</head>\n");
1291
1292        html.append("<body class=\"dialog\" onload=\"doOnload();\">\n");
1293
1294        html.append("<div style=\"text-align: center; padding-top: 50px;\">");
1295        html.append("<img src=\"");
1296        html.append(CmsWorkplace.getResourceUri("commons/login_logo.png"));
1297        html.append("\" alt=\"OpenCms Logo\">");
1298        html.append("</div>\n");
1299
1300        html.append("<table class=\"logindialog\" cellpadding=\"0\" cellspacing=\"0\"><tr><td>\n");
1301        html.append("<table class=\"dialogbox\" cellpadding=\"0\" cellspacing=\"0\"><tr><td>\n");
1302        html.append("<div class=\"dialoghead\">");
1303
1304        if (m_oufqn == null) {
1305            m_oufqn = CmsOrganizationalUnit.SEPARATOR;
1306        }
1307        if (m_action == ACTION_DISPLAY) {
1308            html.append("<div id='titleId'");
1309            if (!m_oufqn.equals(CmsOrganizationalUnit.SEPARATOR)) {
1310                html.append(" style='display: none;'");
1311            }
1312            html.append(">\n");
1313            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_HEADLINE_0));
1314            html.append("</div>\n");
1315            html.append("<div id='titleIdOu'");
1316            if (m_oufqn.equals(CmsOrganizationalUnit.SEPARATOR)) {
1317                html.append(" style='display: none;'");
1318            }
1319            html.append(">\n");
1320            html.append(
1321                Messages.get().getBundle(m_locale).key(
1322                    Messages.GUI_LOGIN_HEADLINE_SELECTED_ORGUNIT_1,
1323                    m_ou.getDescription(getCmsObject().getRequestContext().getLocale())));
1324            html.append("</div>\n");
1325        } else if (m_action == ACTION_LOGIN) {
1326            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_HEADLINE_ALREADY_IN_0));
1327        }
1328
1329        html.append("</div>\n");
1330
1331        if (m_action == ACTION_DISPLAY) {
1332            // start form
1333            html.append("<form style=\"margin: 0px; padding: 0px;\" action=\"");
1334            html.append(getFormLink());
1335            html.append("\"");
1336            if (PCTYPE_PUBLIC.equals(m_pcType)) {
1337                html.append(" autocomplete=\"off\"");
1338            }
1339            appendId(html, PARAM_FORM);
1340            html.append("method=\"POST\">\n");
1341        }
1342
1343        html.append("<div class=\"dialogcontent\">\n");
1344        html.append("<table border=\"0\">\n");
1345
1346        // show security option box if enabled in configuration
1347        if ((m_action == ACTION_DISPLAY) && OpenCms.getLoginManager().isEnableSecurity()) {
1348            html.append("<tr>\n");
1349            html.append("<td rowspan=\"2\">\n");
1350            // security image should not be shown any more
1351            //html.append("<img src=\"");
1352            //html.append(CmsWorkplace.getResourceUri("commons/login_security.png"));
1353            //html.append("\" height=\"48\" width=\"48\" alt=\"\">");
1354            html.append("</td>\n");
1355            html.append("<td colspan=\"2\" style=\"white-space: nowrap;\">\n");
1356            html.append("<div style=\"padding-bottom: 5px;\"><b>");
1357            html.append(
1358                CmsStringUtil.escapeHtml(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_SECURITY_0)));
1359            html.append("</b></div>\n");
1360            html.append("</td>\n");
1361            html.append("</tr>\n");
1362            html.append("<tr>\n");
1363            html.append("<td colspan=\"2\" style=\"white-space: nowrap;\">");
1364            html.append("<div class=\"loginsecurity\">");
1365            html.append("<input type=\"radio\" value=\"");
1366            html.append(PCTYPE_PUBLIC);
1367            html.append("\" name=\"");
1368            html.append(PARAM_PCTYPE);
1369            html.append("\"");
1370            if (PCTYPE_PUBLIC.equals(m_pcType)) {
1371                html.append(" checked=\"checked\"");
1372            }
1373            html.append(">&nbsp;");
1374            html.append(
1375                CmsStringUtil.escapeHtml(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_PCTYPE_PUBLIC_0)));
1376            html.append("<br/>");
1377            html.append("<input type=\"radio\" value=\"");
1378            html.append(PCTYPE_PRIVATE);
1379            html.append("\" name=\"");
1380            html.append(PARAM_PCTYPE);
1381            html.append("\"");
1382            if (PCTYPE_PRIVATE.equals(m_pcType)) {
1383                html.append(" checked=\"checked\"");
1384            }
1385            html.append(">&nbsp;");
1386            html.append(
1387                CmsStringUtil.escapeHtml(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_PCTYPE_PRIVATE_0)));
1388            html.append("</div></td>\n");
1389            html.append("</tr>\n");
1390        }
1391
1392        html.append("<tr>\n");
1393        html.append("<td></td>\n<td colspan=\"2\" style=\"white-space: nowrap;\">\n");
1394        html.append("<div style=\"padding-bottom: 10px;\">");
1395
1396        if (m_action == ACTION_DISPLAY) {
1397            html.append(CmsStringUtil.escapeHtml(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_MESSAGE_0)));
1398        } else if (m_action == ACTION_LOGIN) {
1399            html.append(
1400                CmsStringUtil.escapeHtml(
1401                    Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_MESSAGE_ALREADY_IN_0)));
1402        }
1403
1404        html.append("</div>\n");
1405        html.append("</td>\n");
1406        html.append("</tr>\n");
1407
1408        html.append("<tr>\n");
1409
1410        html.append("<td style=\"width: 60px; text-align: center; vertical-align: top\" rowspan=\"5\">");
1411        html.append("<img src=\"");
1412        html.append(CmsWorkplace.getResourceUri("commons/login.png"));
1413        html.append("\" height=\"48\" width=\"48\" alt=\"\">");
1414        html.append("</td>\n");
1415
1416        html.append("<td style=\"white-space: nowrap;\"><b>");
1417        html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_USERNAME_0));
1418        html.append("</b>&nbsp;&nbsp;</td>\n");
1419        html.append("<td style=\"width: 300px; white-space: nowrap;\">");
1420
1421        if (m_action == ACTION_DISPLAY) {
1422            // append input for user name
1423            html.append("<input style=\"width: 300px;\" type=\"text\"");
1424            if (PCTYPE_PUBLIC.equals(m_pcType)) {
1425                html.append(" autocomplete=\"off\"");
1426            }
1427            appendId(html, PARAM_USERNAME);
1428            html.append("value=\"");
1429            html.append(
1430                (CmsStringUtil.isEmpty(m_username) || PCTYPE_PUBLIC.equals(m_pcType))
1431                ? ""
1432                : CmsEncoder.escapeXml(m_username));
1433            html.append("\">");
1434        } else if (m_action == ACTION_LOGIN) {
1435            // append name of user that has been logged in
1436            html.append(getRequestContext().getCurrentUser().getFullName());
1437        }
1438
1439        html.append("</td>\n");
1440        html.append("</tr>\n");
1441
1442        if (m_action == ACTION_DISPLAY) {
1443            // append 2 rows: input for user name and login button
1444            html.append("<tr>\n");
1445            html.append("<td style=\"white-space: nowrap;\"><b>");
1446            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_PASSWORD_0));
1447            html.append("</b>&nbsp;&nbsp;</td>\n");
1448            html.append("<td style=\"width: 300px; white-space: nowrap;\">");
1449            html.append("<input style=\"width: 300px;\" type=\"password\"");
1450            if (PCTYPE_PUBLIC.equals(m_pcType)) {
1451                html.append(" autocomplete=\"off\"");
1452            }
1453            appendId(html, PARAM_PASSWORD);
1454            html.append(">");
1455            html.append("</td>\n");
1456            html.append("</tr>\n");
1457
1458            html.append("<tr>\n");
1459            html.append("<td style=\"white-space: nowrap;\"><div id='ouLabelId' style='display: none;'><b>");
1460            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_0)).append(
1461                "</b>&nbsp;&nbsp;\n");
1462            html.append("</div></td>\n");
1463            html.append(
1464                "<td style=\"width: 300px; white-space: nowrap;\"><div id='ouSearchId' style='display: none;'><input class=\"inactive\" style=\"width: 300px;\" type=\"text\" value=\"");
1465            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_SEARCH_0));
1466            html.append("\"");
1467            appendId(html, PARAM_OUSEARCH);
1468            html.append(" onfocus=\"checkOuValue();\"");
1469            html.append(" onblur=\"checkOuValue();\"");
1470            html.append(" onkeyup=\"searchOu();\"");
1471            html.append("/>");
1472            html.append("<input type=\"hidden\" value=\"");
1473            html.append(m_oufqn == null ? "" : m_oufqn);
1474            html.append("\"");
1475            appendId(html, PARAM_OUFQN);
1476            html.append("/>");
1477            html.append("</div></td>\n");
1478            html.append("</tr>\n");
1479
1480            html.append("<tr>\n");
1481            html.append("<td colspan=\"2\"><div id='ouSelId' style='display: none;'>");
1482            html.append("</div></td>\n");
1483            html.append("</tr>\n");
1484
1485            html.append("<tr>\n");
1486            html.append("<td>\n");
1487            html.append("</td>\n");
1488            html.append("<td style=\"white-space: nowrap;\">\n");
1489            html.append("<input type=\"hidden\"");
1490            appendId(html, PARAM_ACTION_LOGIN);
1491            html.append("value=\"true\">\n");
1492
1493            if (m_requestedResource != null) {
1494                html.append("<input type=\"hidden\"");
1495                appendId(html, CmsWorkplaceManager.PARAM_LOGIN_REQUESTED_RESOURCE);
1496                html.append("value=\"");
1497                html.append(CmsEncoder.escapeXml(m_requestedResource));
1498                html.append("\">\n");
1499            }
1500
1501            html.append("<input class=\"loginbutton\" type=\"submit\" value=\"");
1502            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_BUTTON_0));
1503            html.append("\">\n");
1504
1505            if ((getOus().size() > 1)
1506                && ((getPreDefOuFqn() == null) || getPreDefOuFqn().equals(CmsOrganizationalUnit.SEPARATOR))) {
1507                // options
1508                html.append("&nbsp;<input id='ouBtnId' class='loginbutton' type='button' value='");
1509                html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_ORGUNIT_SELECT_ON_0));
1510                html.append("' onclick='javascript:orgUnitSelection();'>\n");
1511            }
1512            html.append("</td>\n");
1513            html.append("</tr>\n");
1514        } else if (m_action == ACTION_LOGIN) {
1515            // append 2 rows: one empty, other for button with re-open window script
1516            html.append("<tr><td></td><td></td></tr>\n");
1517
1518            html.append("<tr>\n");
1519            html.append("<td></td>\n");
1520            html.append("<td style=\"width:100%; white-space: nowrap;\">\n");
1521            html.append("<input class=\"loginbutton\" type=\"button\" value=\"");
1522            html.append(Messages.get().getBundle(m_locale).key(Messages.GUI_LOGIN_BUTTON_ALREADY_IN_0));
1523            html.append("\" onclick=\"doOnload()\">\n");
1524            html.append("</td>\n");
1525            html.append("</tr>\n");
1526        }
1527
1528        html.append("</table>\n");
1529        html.append("</div>");
1530
1531        if (m_action == ACTION_DISPLAY) {
1532            // end form
1533            html.append("</form>\n");
1534        }
1535
1536        html.append("</td></tr></table>\n");
1537        html.append("</td></tr></table>\n");
1538        html.append(getCopyrightHtml(m_locale));
1539
1540        html.append("<noscript>\n");
1541        html.append(
1542            "<div style=\"text-align: center; font-size: 14px; border: 2px solid black; margin: 50px; padding: 20px; background-color: red; color: white; white-space: nowrap;\"><b>");
1543        html.append(
1544            CmsStringUtil.escapeHtml(
1545                Messages.get().getBundle(m_locale).key(
1546                    Messages.GUI_LOGIN_NOSCRIPT_1,
1547                    OpenCms.getSiteManager().getWorkplaceSiteMatcher())));
1548        html.append("</b></div>\n");
1549        html.append("</noscript>\n");
1550
1551        html.append("</body></html>");
1552
1553        return html.toString();
1554    }
1555
1556    /**
1557     * Returns all organizational units in the system.<p>
1558     *
1559     * @return a list of {@link CmsOrganizationalUnit} objects
1560     */
1561    protected List<CmsOrganizationalUnit> getOus() {
1562
1563        if (m_ous == null) {
1564            m_ous = getOrgUnitsForLoginDialog(getCmsObject(), getPreDefOuFqn());
1565        }
1566        return m_ous;
1567    }
1568
1569    /**
1570     * Returns the predefined organizational unit fqn.<p>
1571     *
1572     * This is normally selected by url, and set by the {@link CmsWorkplaceLoginHandler}.<p>
1573     *
1574     * @return the predefined organizational unit fqn
1575     */
1576    protected String getPreDefOuFqn() {
1577
1578        if (Boolean.valueOf(m_actionLogout).booleanValue() && (getRequest().getAttribute(PARAM_PREDEF_OUFQN) == null)) {
1579            String oufqn = getCmsObject().getRequestContext().getOuFqn();
1580            if (!oufqn.startsWith(CmsOrganizationalUnit.SEPARATOR)) {
1581                oufqn = CmsOrganizationalUnit.SEPARATOR + oufqn;
1582            }
1583            getRequest().setAttribute(CmsLogin.PARAM_PREDEF_OUFQN, oufqn);
1584        }
1585        return (String)getRequest().getAttribute(PARAM_PREDEF_OUFQN);
1586    }
1587
1588    private boolean shouldUseNewLogin() {
1589
1590        return true;
1591    }
1592}