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