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.crypto.CmsEncryptionException; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsUser; 033import org.opencms.flex.CmsFlexController; 034import org.opencms.gwt.shared.CmsGwtConstants; 035import org.opencms.i18n.CmsEncoder; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.main.CmsRuntimeException; 039import org.opencms.main.OpenCms; 040import org.opencms.security.CmsOrganizationalUnit; 041import org.opencms.ui.A_CmsUI; 042import org.opencms.ui.CmsVaadinErrorHandler; 043import org.opencms.ui.CmsVaadinUtils; 044import org.opencms.ui.Messages; 045import org.opencms.ui.apps.CmsAppWorkplaceUi; 046import org.opencms.ui.components.CmsBasicDialog; 047import org.opencms.ui.components.CmsBasicDialog.DialogWidth; 048import org.opencms.ui.components.extensions.CmsPollServerExtension; 049import org.opencms.ui.login.CmsLoginHelper.LoginParameters; 050import org.opencms.ui.shared.CmsVaadinConstants; 051import org.opencms.util.CmsFileUtil; 052import org.opencms.util.CmsMacroResolver; 053import org.opencms.util.CmsRequestUtil; 054import org.opencms.util.CmsStringUtil; 055import org.opencms.workplace.CmsWorkplace; 056import org.opencms.workplace.CmsWorkplaceManager; 057import org.opencms.workplace.CmsWorkplaceSettings; 058 059import java.io.IOException; 060import java.io.Serializable; 061import java.util.List; 062import java.util.Locale; 063 064import javax.servlet.http.HttpServletRequest; 065import javax.servlet.http.HttpServletResponse; 066import javax.servlet.http.HttpSession; 067 068import org.apache.commons.logging.Log; 069 070import com.vaadin.annotations.Theme; 071import com.vaadin.server.VaadinRequest; 072import com.vaadin.server.VaadinService; 073import com.vaadin.server.VaadinServletRequest; 074import com.vaadin.server.VaadinSession; 075import com.vaadin.shared.Version; 076import com.vaadin.ui.Alignment; 077import com.vaadin.ui.Button; 078import com.vaadin.ui.Notification; 079import com.vaadin.ui.Notification.Type; 080import com.vaadin.ui.Window; 081import com.vaadin.ui.Window.CloseEvent; 082import com.vaadin.ui.Window.CloseListener; 083import com.vaadin.v7.ui.Label; 084import com.vaadin.v7.ui.VerticalLayout; 085 086/** 087 * The UI class for the Vaadin-based login dialog.<p> 088 */ 089@Theme("opencms") 090public class CmsLoginUI extends A_CmsUI { 091 092 /** 093 * Parameters which are initialized during the initial page load of the login dialog.<p> 094 */ 095 public static class Parameters implements Serializable { 096 097 /** The serial version id. */ 098 private static final long serialVersionUID = -4885232184680664315L; 099 100 /** The locale. */ 101 public Locale m_locale; 102 103 /** The PC type (public or private). */ 104 public String m_pcType; 105 106 /** The preselected OU. */ 107 public String m_preselectedOu; 108 109 /** The requested resource. */ 110 public String m_requestedResource; 111 112 /** The requested workplace app path. */ 113 public String m_requestedWorkplaceApp; 114 115 /** 116 * Creates a new instance.<p> 117 * 118 * @param pcType the PC type 119 * @param preselectedOu the preselected OU 120 * @param locale the locale 121 * @param requestedResource the requested resource 122 * @param requestedWorkplaceApp the requested workplace app path 123 */ 124 public Parameters( 125 String pcType, 126 String preselectedOu, 127 Locale locale, 128 String requestedResource, 129 String requestedWorkplaceApp) { 130 131 m_pcType = pcType; 132 m_preselectedOu = preselectedOu; 133 m_locale = locale; 134 m_requestedResource = requestedResource; 135 m_requestedWorkplaceApp = requestedWorkplaceApp; 136 } 137 138 /** 139 * Gets the locale.<p> 140 * 141 * @return the locale 142 */ 143 public Locale getLocale() { 144 145 return m_locale; 146 } 147 148 /** 149 * Gets the PC type (private or public).<p> 150 * 151 * @return the pc type 152 */ 153 public String getPcType() { 154 155 return m_pcType; 156 157 } 158 159 /** 160 * Gets the preselected OU.<p> 161 * 162 * @return the preselected OU 163 */ 164 public String getPreselectedOu() { 165 166 return m_preselectedOu; 167 } 168 169 /** 170 * Gets the requested resource path.<p> 171 * 172 * @return the requested resource path 173 */ 174 public String getRequestedResource() { 175 176 return m_requestedResource; 177 } 178 179 /** 180 * Returns the requested workplace app path.<p> 181 * 182 * @return the requested workplace app path 183 */ 184 public String getRequestedWorkplaceApp() { 185 186 return m_requestedWorkplaceApp; 187 } 188 189 } 190 191 /** 192 * Attribute used to store initialization data when the UI is first loaded. 193 */ 194 public static final String INIT_DATA_SESSION_ATTR = "CmsLoginUI_initData"; 195 196 /** The admin CMS context. */ 197 static CmsObject m_adminCms; 198 199 /** Logger instance for this class. */ 200 private static final Log LOG = CmsLog.getLog(CmsLoginUI.class); 201 202 /** Serial version id. */ 203 private static final long serialVersionUID = 1L; 204 205 /** The login controller. */ 206 private CmsLoginController m_controller; 207 208 /** The login form. */ 209 private CmsLoginForm m_loginForm; 210 211 /** The widget used to open the login target. */ 212 private CmsLoginTargetOpener m_targetOpener; 213 214 /** 215 * Returns the initial HTML for the Vaadin based login dialog.<p> 216 * 217 * @param request the request 218 * @param response the response 219 * 220 * @return the initial page HTML for the Vaadin login dialog 221 * 222 * @throws IOException in case writing to the response fails 223 * @throws CmsException in case the user has not the required role 224 */ 225 public static String displayVaadinLoginDialog(HttpServletRequest request, HttpServletResponse response) 226 throws IOException, CmsException { 227 228 CmsFlexController controller = CmsFlexController.getController(request); 229 if (controller == null) { 230 // controller not found - this request was not initialized properly 231 throw new CmsRuntimeException( 232 org.opencms.jsp.Messages.get().container( 233 org.opencms.jsp.Messages.ERR_MISSING_CMS_CONTROLLER_1, 234 CmsLoginUI.class.getName())); 235 } 236 CmsRequestUtil.disableCrossSiteFrameEmbedding(response); 237 CmsObject cms = controller.getCmsObject(); 238 if ((OpenCms.getSiteManager().getSites().size() > 1) && !OpenCms.getSiteManager().isWorkplaceRequest(request)) { 239 // do not send any redirects to the workplace site for security reasons 240 response.sendError(HttpServletResponse.SC_NOT_FOUND); 241 return null; 242 } 243 String logout = request.getParameter(CmsLoginHelper.PARAM_ACTION_LOGOUT); 244 if (Boolean.valueOf(logout).booleanValue()) { 245 CmsLoginController.logout(cms, request, response); 246 return null; 247 } 248 if (!cms.getRequestContext().getCurrentUser().isGuestUser()) { 249 if (CmsLoginHelper.shouldAutoLogout(cms)) { 250 LOG.info("Auto logout for current user"); 251 // the dialog does the actual logout, so here we do nothing 252 } else { 253 String encryptedTarget = request.getParameter(CmsGwtConstants.PARAM_LOGIN_REDIRECT); 254 String target = null; 255 if (CmsStringUtil.isEmptyOrWhitespaceOnly(encryptedTarget)) { 256 target = CmsLoginController.getLoginTarget( 257 cms, 258 getWorkplaceSettings(cms, request.getSession()), 259 null); 260 } else { 261 try { 262 target = OpenCms.getDefaultTextEncryption().decrypt(encryptedTarget); 263 } catch (CmsEncryptionException e) { 264 LOG.error(e.getLocalizedMessage(), e); 265 return null; 266 } 267 } 268 response.sendRedirect(target); 269 return null; 270 } 271 } 272 CmsLoginHelper.LoginParameters params = CmsLoginHelper.getLoginParameters(cms, request, false); 273 request.getSession().setAttribute(CmsLoginUI.INIT_DATA_SESSION_ATTR, params); 274 try { 275 byte[] pageBytes = CmsFileUtil.readFully( 276 Thread.currentThread().getContextClassLoader().getResourceAsStream( 277 "org/opencms/ui/login/login-page.html")); 278 String page = new String(pageBytes, "UTF-8"); 279 CmsMacroResolver resolver = new CmsMacroResolver(); 280 String context = OpenCms.getSystemInfo().getContextPath(); 281 String vaadinDir = CmsStringUtil.joinPaths(context, "VAADIN/"); 282 String vaadinVersion = Version.getFullVersion(); 283 String vaadinServlet = CmsStringUtil.joinPaths(context, "workplace/dialogs/"); 284 String vaadinBootstrap = CmsStringUtil.joinPaths( 285 context, 286 "VAADIN/vaadinBootstrap.js?v=" + OpenCms.getSystemInfo().getVersionNumber()); 287 String autocomplete = params.isPrivatePc() ? "on" : "off"; 288 StringBuffer workplaceCssBuffer = null; 289 if (!OpenCms.getWorkplaceAppManager().getWorkplaceCssUris().isEmpty()) { 290 workplaceCssBuffer = new StringBuffer(); 291 workplaceCssBuffer.append("\n<style type=\"text/css\">\n"); 292 for (String cssURI : OpenCms.getWorkplaceAppManager().getWorkplaceCssUris()) { 293 workplaceCssBuffer.append("@import url(\"").append(CmsWorkplace.getResourceUri(cssURI)).append( 294 "\");\n"); 295 } 296 workplaceCssBuffer.append("</style>\n"); 297 } 298 String cmsLogo = OpenCms.getSystemInfo().getContextPath() 299 + CmsWorkplace.RFS_PATH_RESOURCES 300 + "commons/login_logo.png"; 301 resolver.addMacro("workplaceCss", workplaceCssBuffer != null ? workplaceCssBuffer.toString() : ""); 302 resolver.addMacro("loadingHtml", CmsVaadinConstants.LOADING_INDICATOR_HTML); 303 resolver.addMacro("vaadinDir", vaadinDir); 304 resolver.addMacro("vaadinVersion", vaadinVersion); 305 resolver.addMacro("vaadinServlet", vaadinServlet); 306 resolver.addMacro("vaadinBootstrap", vaadinBootstrap); 307 resolver.addMacro("cmsLogo", cmsLogo); 308 resolver.addMacro("autocomplete", autocomplete); 309 resolver.addMacro("title", CmsLoginHelper.getTitle(params.getLocale())); 310 if (params.isPrivatePc()) { 311 resolver.addMacro( 312 "hiddenPasswordField", 313 " <input type=\"password\" id=\"hidden-password\" name=\"ocPword\" autocomplete=\"%(autocomplete)\" >"); 314 } 315 if (params.getUsername() != null) { 316 resolver.addMacro("predefUser", "value=\"" + CmsEncoder.escapeXml(params.getUsername()) + "\""); 317 } 318 page = resolver.resolveMacros(page); 319 return page; 320 } catch (Exception e) { 321 LOG.error("Failed to display login dialog.", e); 322 return "<!--Error-->"; 323 } 324 } 325 326 /** 327 * Returns the bootstrap html fragment required to display the login dialog.<p> 328 * 329 * @param cms the cms context 330 * @param request the request 331 * 332 * @return the html fragment 333 * 334 * @throws IOException in case reading the html template fails 335 */ 336 public static String generateLoginHtmlFragment(CmsObject cms, VaadinRequest request) throws IOException { 337 338 LoginParameters parameters = CmsLoginHelper.getLoginParameters(cms, (HttpServletRequest)request, true); 339 request.getWrappedSession().setAttribute(CmsLoginUI.INIT_DATA_SESSION_ATTR, parameters); 340 byte[] pageBytes; 341 342 pageBytes = CmsFileUtil.readFully( 343 Thread.currentThread().getContextClassLoader().getResourceAsStream( 344 "org/opencms/ui/login/login-fragment.html")); 345 346 String html = new String(pageBytes, "UTF-8"); 347 String autocomplete = ((parameters.getPcType() == null) 348 || parameters.getPcType().equals(CmsLoginHelper.PCTYPE_PRIVATE)) ? "on" : "off"; 349 CmsMacroResolver resolver = new CmsMacroResolver(); 350 resolver.addMacro("autocompplete", autocomplete); 351 if ((parameters.getPcType() == null) || parameters.getPcType().equals(CmsLoginHelper.PCTYPE_PRIVATE)) { 352 resolver.addMacro( 353 "hiddenPasswordField", 354 " <input type=\"password\" id=\"hidden-password\" name=\"ocPword\" autocomplete=\"%(autocomplete)\" >"); 355 } 356 if (parameters.getUsername() != null) { 357 resolver.addMacro("predefUser", "value=\"" + CmsEncoder.escapeXml(parameters.getUsername()) + "\""); 358 } 359 html = resolver.resolveMacros(html); 360 return html; 361 } 362 363 /** 364 * Sets the admin CMS object.<p> 365 * 366 * @param cms the admin cms object 367 */ 368 public static void setAdminCmsObject(CmsObject cms) { 369 370 m_adminCms = cms; 371 } 372 373 /** 374 * Returns the current users workplace settings.<p> 375 * 376 * @param cms the CMS context 377 * @param session the session 378 * 379 * @return the settings 380 */ 381 private static CmsWorkplaceSettings getWorkplaceSettings(CmsObject cms, HttpSession session) { 382 383 CmsWorkplaceSettings settings = (CmsWorkplaceSettings)session.getAttribute( 384 CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS); 385 if (settings == null) { 386 settings = CmsLoginHelper.initSiteAndProject(cms); 387 if (VaadinService.getCurrentRequest() != null) { 388 VaadinService.getCurrentRequest().getWrappedSession().setAttribute( 389 CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS, 390 settings); 391 } else { 392 session.setAttribute(CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS, settings); 393 } 394 } 395 return settings; 396 } 397 398 public void clearError() { 399 400 m_loginForm.clearError(); 401 } 402 403 /** 404 * Gets the selected org unit.<p> 405 * 406 * @return the selected org unit 407 */ 408 public String getOrgUnit() { 409 410 String result = m_loginForm.getOrgUnit(); 411 if (result == null) { 412 result = ""; 413 } 414 return result; 415 416 } 417 418 /** 419 * Gets the password.<p> 420 * 421 * @return the password 422 */ 423 public String getPassword() { 424 425 return m_loginForm.getPassword(); 426 } 427 428 /** 429 * Gets the selected PC type.<p> 430 * 431 * @return the PC type 432 */ 433 public String getPcType() { 434 435 String result = m_loginForm.getPcType(); 436 if (result == null) { 437 result = CmsLoginForm.PC_TYPE_PUBLIC; 438 } 439 return result; 440 } 441 442 /** 443 * Gets the user name.<p> 444 * 445 * @return the user name 446 */ 447 public String getUser() { 448 449 return m_loginForm.getUser(); 450 } 451 452 /** 453 * Opens the login target for a logged in user.<p> 454 * 455 * @param loginTarget the login target 456 * @param isPublicPC the public PC flag 457 */ 458 public void openLoginTarget(String loginTarget, boolean isPublicPC) { 459 460 // login was successful, remove login init data from session 461 VaadinService.getCurrentRequest().getWrappedSession().removeAttribute(INIT_DATA_SESSION_ATTR); 462 m_targetOpener.openTarget(loginTarget, isPublicPC); 463 } 464 465 /** 466 * Sets the org units which should be selectable by the user.<p> 467 * 468 * @param ous the selectable org units 469 */ 470 public void setSelectableOrgUnits(List<CmsOrganizationalUnit> ous) { 471 472 m_loginForm.setSelectableOrgUnits(ous); 473 } 474 475 /** 476 * Show notification that the user is already loogged in.<p> 477 */ 478 public void showAlreadyLoggedIn() { 479 480 // TODO: do something useful 481 Notification.show("You are already logged in"); 482 } 483 484 /** 485 * Shows the 'forgot password view'.<p> 486 * 487 * @param authToken the authorization token given as a request parameter 488 */ 489 public void showForgotPasswordView(String authToken) { 490 491 try { 492 CmsTokenValidator validator = new CmsTokenValidator(); 493 String validationResult = validator.validateToken( 494 A_CmsUI.getCmsObject(), 495 authToken, 496 OpenCms.getLoginManager().getTokenLifetime()); 497 if (validationResult == null) { 498 CmsUser user = validator.getUser(); 499 if (!user.isManaged()) { 500 CmsSetPasswordDialog dlg = new CmsSetPasswordDialog(m_adminCms, user, getLocale()); 501 A_CmsUI.get().setContentToDialog( 502 Messages.get().getBundle(A_CmsUI.get().getLocale()).key(Messages.GUI_PWCHANGE_HEADER_0) 503 + user.getName(), 504 dlg); 505 } else { 506 Notification.show( 507 CmsVaadinUtils.getMessageText(Messages.ERR_USER_NOT_SELF_MANAGED_1, user.getName()), 508 Type.ERROR_MESSAGE); 509 } 510 } else { 511 A_CmsUI.get().setError( 512 Messages.get().getBundle(A_CmsUI.get().getLocale()).key(Messages.GUI_PWCHANGE_INVALID_TOKEN_0)); 513 LOG.info("Invalid authorization token: " + authToken + " / " + validationResult); 514 } 515 } catch (Exception e) { 516 LOG.error(e.getLocalizedMessage(), e); 517 } 518 } 519 520 /** 521 * Shows the given login error message.<p> 522 * 523 * @param messageHtml the message HTML 524 */ 525 public void showLoginError(String messageHtml) { 526 527 m_loginForm.displayError(messageHtml); 528 m_loginForm.resetPassword(); 529 } 530 531 /** 532 * Initializes the login view.<p> 533 * 534 * @param preselectedOu a potential preselected OU 535 * @param isAutoLogout true if user was automatically logged out 536 */ 537 public void showLoginView(String preselectedOu, boolean isAutoLogout) { 538 539 VerticalLayout content = new VerticalLayout(); 540 content.setSizeFull(); 541 542 m_targetOpener = new CmsLoginTargetOpener(A_CmsUI.get()); 543 //content.setExpandRatio(m_targetOpener, 0f); 544 content.addComponent(m_loginForm); 545 content.setComponentAlignment(m_loginForm, Alignment.MIDDLE_CENTER); 546 content.setExpandRatio(m_loginForm, 1); 547 548 setContent(content); 549 550 m_loginForm.selectOrgUnit(preselectedOu); 551 if (isAutoLogout) { 552 String text = CmsVaadinUtils.getMessageText(Messages.GUI_AUTO_LOGOUT_0); 553 m_loginForm.displayError(text); 554 } 555 556 } 557 558 /** 559 * Shows the password reset dialog.<p> 560 * 561 * @param orgUnit the OU that should be preselected 562 */ 563 public void showPasswordResetDialog(String orgUnit) { 564 565 String caption = CmsVaadinUtils.getMessageText(Messages.GUI_PWCHANGE_FORGOT_PASSWORD_0); 566 A_CmsUI r = A_CmsUI.get(); 567 r.setContent(new Label()); 568 Window window = CmsBasicDialog.prepareWindow(DialogWidth.narrow); 569 CmsBasicDialog dialog = new CmsBasicDialog(); 570 VerticalLayout result = new VerticalLayout(); 571 dialog.setContent(result); 572 window.setContent(dialog); 573 window.setCaption(caption); 574 window.setClosable(true); 575 final CmsForgotPasswordDialog forgotPassword = new CmsForgotPasswordDialog(orgUnit); 576 window.addCloseListener(new CloseListener() { 577 578 /** Serial version id. */ 579 private static final long serialVersionUID = 1L; 580 581 public void windowClose(CloseEvent e) { 582 583 forgotPassword.cancel(); 584 } 585 586 }); 587 for (Button button : forgotPassword.getButtons()) { 588 dialog.addButton(button); 589 } 590 591 r.addWindow(window); 592 window.center(); 593 VerticalLayout vl = result; 594 vl.addComponent(forgotPassword); 595 } 596 597 /** 598 * @see com.vaadin.ui.UI#init(com.vaadin.server.VaadinRequest) 599 */ 600 @Override 601 protected void init(VaadinRequest request) { 602 603 addStyleName("login-dialog"); 604 LoginParameters params = (LoginParameters)(request.getWrappedSession().getAttribute(INIT_DATA_SESSION_ATTR)); 605 if (params == null) { 606 params = CmsLoginHelper.getLoginParameters(getCmsObject(), (HttpServletRequest)request, true); 607 request.getWrappedSession().setAttribute(CmsLoginUI.INIT_DATA_SESSION_ATTR, params); 608 } 609 VaadinSession.getCurrent().setErrorHandler(new CmsVaadinErrorHandler()); 610 m_controller = new CmsLoginController(m_adminCms, params); 611 m_controller.setUi(this); 612 setLocale(params.getLocale()); 613 m_loginForm = new CmsLoginForm(m_controller, params.getLocale()); 614 VaadinServletRequest r1 = ((VaadinServletRequest)request); 615 r1.getLocale(); 616 m_controller.onInit(); 617 getPage().setTitle( 618 CmsAppWorkplaceUi.WINDOW_TITLE_PREFIX 619 + CmsVaadinUtils.getMessageText(org.opencms.workplace.Messages.GUI_LOGIN_HEADLINE_0)); 620 new CmsPollServerExtension(this); 621 } 622}