001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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.ui.login;
029
030import org.opencms.db.CmsLoginMessage;
031import org.opencms.i18n.CmsMessages;
032import org.opencms.main.CmsLog;
033import org.opencms.main.OpenCms;
034import org.opencms.security.CmsOrganizationalUnit;
035import org.opencms.security.I_CmsCustomLogin;
036import org.opencms.security.I_CmsCustomLogin.Mode;
037import org.opencms.ui.A_CmsUI;
038import org.opencms.ui.CmsVaadinUtils;
039import org.opencms.ui.Messages;
040import org.opencms.ui.components.CmsFakeWindow;
041import org.opencms.ui.components.OpenCmsTheme;
042import org.opencms.util.CmsStringUtil;
043
044import java.util.List;
045import java.util.Locale;
046import java.util.Map;
047
048import org.apache.commons.logging.Log;
049
050import com.google.common.collect.Maps;
051import com.vaadin.annotations.DesignRoot;
052import com.vaadin.event.ShortcutAction.KeyCode;
053import com.vaadin.server.FontAwesome;
054import com.vaadin.server.Page;
055import com.vaadin.ui.Button;
056import com.vaadin.ui.Button.ClickEvent;
057import com.vaadin.ui.Button.ClickListener;
058import com.vaadin.ui.CssLayout;
059import com.vaadin.ui.FormLayout;
060import com.vaadin.ui.themes.ValoTheme;
061import com.vaadin.v7.shared.ui.label.ContentMode;
062import com.vaadin.v7.ui.Label;
063import com.vaadin.v7.ui.OptionGroup;
064import com.vaadin.v7.ui.TextField;
065import com.vaadin.v7.ui.VerticalLayout;
066
067/**
068 * Login form.<p>
069 */
070@DesignRoot
071public class CmsLoginForm extends VerticalLayout {
072
073    /** The private PC type constant. */
074    public static final String PC_TYPE_PRIVATE = "private";
075
076    /** The public PC type constant. */
077    public static final String PC_TYPE_PUBLIC = "public";
078
079    /** Logger instance for this class. */
080    private static final Log LOG = CmsLog.getLog(CmsLoginForm.class);
081
082    /** Version id. */
083    private static final long serialVersionUID = 1L;
084
085    /** The login controller. */
086    protected CmsLoginController m_controller;
087
088    /** Label showing an optional configurable message.*/
089    private Label m_additionalMessage;
090
091    /** The label showing the copyright information. */
092    private Label m_copyright;
093
094    private CssLayout m_customControls;
095
096    /** The error label. */
097    private Label m_error;
098
099    /**Fake window. */
100    private CmsFakeWindow m_fakeWindow;
101
102    /** Button for opening the "forgot password" dialog. */
103    private Button m_forgotPasswordButton;
104
105    /** Login button. */
106    private Button m_loginButton;
107
108    private FormLayout m_mainForm;
109
110    private Label m_mainFormLabel;
111
112    private boolean m_multipleOus;
113
114    /** Button to show / hide advanced options. */
115    private Button m_optionsButton;
116
117    /** Boolean which indicated whether the advanced options are currently visible. */
118    private boolean m_optionsVisible;
119
120    /** Widget for OU selection. */
121    private CmsLoginOuSelector m_ouSelect;
122
123    /** Widget for entering the password. */
124    private CmsLoginPasswordField m_passwordField;
125
126    /** The security field, which allows the user to choose between a private or public PC. */
127    private OptionGroup m_securityField;
128
129    private List<CmsOrganizationalUnit> m_selectableOus;
130
131    /** The password visibility toggle. */
132    private Button m_showPasswordButton;
133
134    /** Widget for entering the user name.  */
135    private TextField m_userField;
136
137    /**
138     * Creates a new instance.<p>
139     *
140     * @param controller the login controller
141     * @param locale the locale to use
142     */
143    public CmsLoginForm(CmsLoginController controller, Locale locale) {
144
145        m_controller = controller;
146        final CmsMessages messages = OpenCms.getWorkplaceManager().getMessages(locale);
147        Map<String, String> macros = Maps.newHashMap();
148        macros.put("showSecure", "" + controller.isShowSecure());
149        String pctype = controller.getPcType();
150        CmsVaadinUtils.readAndLocalizeDesign(this, messages, macros);
151        m_securityField.addItem(PC_TYPE_PUBLIC);
152        m_securityField.addItem(PC_TYPE_PRIVATE);
153        m_securityField.setValue(pctype);
154        m_copyright.setContentMode(ContentMode.HTML);
155        m_copyright.setValue(CmsLoginHelper.getCopyrightHtml(locale));
156        CmsLoginMessage beforeLoginMessage = OpenCms.getLoginManager().getBeforeLoginMessage();
157        if ((beforeLoginMessage != null) && beforeLoginMessage.isEnabled()) {
158            m_additionalMessage.setVisible(true);
159            m_additionalMessage.setContentMode(ContentMode.HTML);
160            m_additionalMessage.setValue(beforeLoginMessage.getMessage());
161        }
162        m_securityField.setItemCaption(
163            PC_TYPE_PRIVATE,
164            messages.key(org.opencms.workplace.Messages.GUI_LOGIN_PCTYPE_PRIVATE_0));
165        m_securityField.setItemCaption(
166            PC_TYPE_PUBLIC,
167            messages.key(org.opencms.workplace.Messages.GUI_LOGIN_PCTYPE_PUBLIC_0));
168        setWidth("600px");
169        m_loginButton.setClickShortcut(KeyCode.ENTER);
170        m_loginButton.addClickListener(new ClickListener() {
171
172            private static final long serialVersionUID = 1L;
173
174            public void buttonClick(ClickEvent event) {
175
176                m_controller.onClickLogin();
177            }
178        });
179        addAttachListener(new AttachListener() {
180
181            private static final long serialVersionUID = 1L;
182
183            @SuppressWarnings("synthetic-access")
184            public void attach(AttachEvent event) {
185
186                m_userField.focus();
187            }
188        });
189
190        ClickListener forgotPasswordListener = new ClickListener() {
191
192            private static final long serialVersionUID = 1L;
193
194            public void buttonClick(ClickEvent event) {
195
196                m_controller.onClickForgotPassword();
197            }
198        };
199
200        m_forgotPasswordButton.addClickListener(forgotPasswordListener);
201
202        m_optionsButton.addClickListener(
203
204            new ClickListener() {
205
206                private static final long serialVersionUID = 1L;
207
208                public void buttonClick(ClickEvent event) {
209
210                    toggleOptionsVisible();
211                }
212
213            });
214        m_error.setContentMode(ContentMode.HTML);
215        m_showPasswordButton.addStyleName("o-login-show-password");
216        m_showPasswordButton.addStyleName(ValoTheme.BUTTON_BORDERLESS);
217        m_showPasswordButton.addStyleName(OpenCmsTheme.BUTTON_UNPADDED);
218        m_showPasswordButton.setIcon(FontAwesome.EYE_SLASH);
219        m_showPasswordButton.addClickListener(evt -> togglePasswordVisible());
220        I_CmsCustomLogin customLogin = OpenCms.getLoginManager().getCustomLogin();
221        m_customControls.setVisible(false);
222        boolean loginAllowed = false;
223        try {
224            OpenCms.getLoginManager().checkLoginAllowed();
225            loginAllowed = true;
226        } catch (Exception e) {
227            // ignore
228        }
229        if ((customLogin != null) && customLogin.isEnabled() && loginAllowed) {
230            Button customButton = new Button();
231            customButton.addStyleName("o-custom-login-button");
232            customButton.setCaption(customLogin.getLoginButtonCaption(locale));
233            m_customControls.setVisible(true);
234            com.vaadin.ui.Label separator = new com.vaadin.ui.Label();
235            separator.setContentMode(com.vaadin.shared.ui.ContentMode.HTML);
236            String text = CmsVaadinUtils.getMessageText(Messages.GUI_LOGIN_CUSTOM_LOGIN_SEPARATOR_0);
237            String escapedText = CmsStringUtil.escapeHtml(text);
238            separator.setValue("<span>" + escapedText + "</span>");
239            separator.addStyleName("o-login-top-divider");
240            separator.setWidth("100%");
241            m_customControls.addComponent(separator);
242            m_customControls.addComponent(customButton);
243            CmsLoginOuSelector customLoginOuSelect = new CmsLoginOuSelector();
244            if (customLogin.needsOrgUnit()) {
245                List<CmsOrganizationalUnit> ouList = CmsLoginHelper.getOrgUnitsForLoginDialog(
246                    A_CmsUI.getCmsObject(),
247                    null);
248                customLoginOuSelect.initOrgUnits(ouList, false);
249                customLoginOuSelect.setValue(CmsLoginOuSelector.getId(ouList.get(0)));
250                customLoginOuSelect.addStyleName("o-custom-login-ou-select");
251                m_customControls.addComponent(customLoginOuSelect);
252            }
253            customButton.setCaption(customLogin.getLoginButtonCaption(locale));
254            customButton.addStyleName("o-custom-login-button");
255
256            customButton.setWidth("100%");
257            customButton.addClickListener(event -> {
258                String ou = null;
259                if (customLogin.needsOrgUnit()) {
260                    ou = customLoginOuSelect.getValue();
261                }
262                String redirect = customLogin.getRedirect(ou);
263                if (redirect != null) {
264                    Page.getCurrent().open(redirect, "_top", false);
265                } else {
266                    LOG.error("getRedirect() returned null for " + customLogin.getClass().getName());
267                }
268            });
269            if (customLogin.getMode() == Mode.replace) {
270                m_mainForm.setVisible(false);
271                m_mainFormLabel.setVisible(false);
272                m_securityField.setVisible(false);
273                m_loginButton.setVisible(false);
274                m_optionsButton.setVisible(false);
275                separator.setVisible(false);
276
277            }
278
279        }
280    }
281
282    /**
283     * Hides the error message.
284     */
285    public void clearError() {
286
287        m_error.setVisible(false);
288    }
289
290    /**
291     * Gets the OU.<p>
292     *
293     * @return the OU
294     */
295    public String getOrgUnit() {
296
297        return m_ouSelect.getValue();
298    }
299
300    /**
301     * Gets the password.<p>
302     *
303     * @return the password
304     */
305    public String getPassword() {
306
307        return m_passwordField.getValue();
308    }
309
310    /**
311     * Gets the PC type.<p>
312     *
313     * @return the PC type
314     */
315    public String getPcType() {
316
317        return "" + m_securityField.getValue();
318    }
319
320    /**
321     * Gets the user.<p>
322     *
323     * @return the user
324     */
325    public String getUser() {
326
327        return m_userField.getValue();
328    }
329
330    /**
331     * Resets the password field.<p>
332     */
333    public void resetPassword() {
334
335        m_passwordField.clear();
336
337    }
338
339    /**
340     * Selects a specific org unit.<p>
341     *
342     * @param preselectedOu the OU to select
343     */
344    public void selectOrgUnit(String preselectedOu) {
345
346        if (preselectedOu == null) {
347            if (OpenCms.getLoginManager().isOrgUnitRequired()) {
348                preselectedOu = CmsLoginOuSelector.OU_NONE;
349            } else {
350                preselectedOu = "/";
351            }
352        }
353        m_ouSelect.setValue(preselectedOu);
354
355    }
356
357    /**
358     * Sets visibility of 'advanced' options.<p>
359     *
360     * @param optionsVisible true if the options should be shown, false if not
361     */
362    public void setOptionsVisible(boolean optionsVisible) {
363
364        m_optionsVisible = optionsVisible;
365
366        boolean ousVisible = optionsVisible && !m_ouSelect.isAlwaysHidden();
367        m_ouSelect.setVisible(ousVisible);
368        m_forgotPasswordButton.setVisible(optionsVisible);
369        String optionsMessage = CmsVaadinUtils.getMessageText(
370            optionsVisible ? Messages.GUI_LOGIN_OPTIONS_HIDE_0 : Messages.GUI_LOGIN_OPTIONS_SHOW_0);
371        m_optionsButton.setCaption(optionsMessage);
372    }
373
374    /**
375     * Sets the org units available for selection.<p>
376     *
377     * @param ous the ous
378     */
379    public void setSelectableOrgUnits(List<CmsOrganizationalUnit> ous) {
380
381        m_selectableOus = ous;
382        boolean addEmptySelection = OpenCms.getLoginManager().isOrgUnitRequired() && (ous.size() > 1);
383        m_ouSelect.initOrgUnits(ous, addEmptySelection);
384
385        boolean optionsVisible = addEmptySelection && (ous.size() > 1);
386        setOptionsVisible(optionsVisible);
387    }
388
389    /**
390     * Toggles visibility of 'advanced' options.<p>
391     */
392    public void toggleOptionsVisible() {
393
394        setOptionsVisible(!m_optionsVisible);
395    }
396
397    /**
398     * Toggles the password visibility (also changes icon for the password visibility toggle button).
399     */
400    protected void togglePasswordVisible() {
401
402        boolean visible = !m_passwordField.isPasswordVisible();
403        m_showPasswordButton.setIcon(visible ? FontAwesome.EYE : FontAwesome.EYE_SLASH);
404        m_passwordField.setPasswordVisible(visible);
405
406    }
407
408    /**
409     * Displays the given login error.<p>
410     *
411     * @param messageHTML the error message
412     */
413    void displayError(String messageHTML) {
414
415        // m_fakeWindow.addStyleName("waggler");
416        m_error.setValue(messageHTML);
417        m_error.setVisible(true);
418        CmsVaadinUtils.waggleMeOnce(m_fakeWindow);
419        //
420        //Add JavaScript code, which adds the wiggle class and removes it after a short time.
421        //        JavaScript.getCurrent().execute(
422        //            "wiggleElement=document.querySelectorAll(\".waggler\")[0];\n"
423        //                + "wiggleElement.className=wiggleElement.className + \" waggle\";\n"
424        //                + "setTimeout(function () {\n"
425        //                + "element=document.querySelectorAll(\".waggle\")[0];\n"
426        //                + "element.className=element.className.replace(/\\bwaggle\\b/g, \"\");"
427        //                + "    }, 1500);");
428    }
429
430}