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}