001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2008-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027 028package org.opends.guitools.controlpanel.ui; 029 030import java.awt.Component; 031import java.awt.GridBagConstraints; 032import java.net.URI; 033import java.security.cert.X509Certificate; 034import java.util.Iterator; 035import java.util.LinkedHashSet; 036 037import javax.naming.NamingException; 038import javax.naming.ldap.InitialLdapContext; 039import javax.swing.JLabel; 040import javax.swing.JPasswordField; 041import javax.swing.JTextField; 042import javax.swing.SwingUtilities; 043 044import org.forgerock.i18n.LocalizableMessage; 045import org.forgerock.i18n.slf4j.LocalizedLogger; 046import org.opends.admin.ads.util.ApplicationTrustManager; 047import org.opends.guitools.controlpanel.datamodel.ConfigReadException; 048import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 049import org.opends.guitools.controlpanel.util.BackgroundTask; 050import org.opends.guitools.controlpanel.util.Utilities; 051import org.opends.quicksetup.UserDataCertificateException; 052import org.opends.quicksetup.ui.CertificateDialog; 053import org.opends.quicksetup.util.UIKeyStore; 054import org.opends.quicksetup.util.Utils; 055import org.opends.server.types.DN; 056import org.opends.server.util.StaticUtils; 057 058import static com.forgerock.opendj.cli.Utils.*; 059 060import static org.opends.messages.AdminToolMessages.*; 061import static org.opends.messages.QuickSetupMessages.*; 062 063/** 064 * The panel that appears when the user is asked to provide authentication. 065 */ 066public class LoginPanel extends StatusGenericPanel 067{ 068 private static final long serialVersionUID = 5051556513294844797L; 069 private JPasswordField pwd; 070 private JTextField dn; 071 private JLabel pwdLabel; 072 private JLabel dnLabel; 073 private String usedUrl; 074 075 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 076 077 /** 078 * Default constructor. 079 * 080 */ 081 public LoginPanel() 082 { 083 super(); 084 createLayout(); 085 } 086 087 /** {@inheritDoc} */ 088 @Override 089 public LocalizableMessage getTitle() 090 { 091 return INFO_CTRL_PANEL_LOGIN_PANEL_TITLE.get(); 092 } 093 094 /** 095 * Creates the layout of the panel (but the contents are not populated here). 096 */ 097 private void createLayout() 098 { 099 GridBagConstraints gbc = new GridBagConstraints(); 100 gbc.anchor = GridBagConstraints.WEST; 101 gbc.gridx = 0; 102 gbc.gridy = 0; 103 104 gbc.weightx = 0.0; 105 gbc.gridwidth = 1; 106 gbc.fill = GridBagConstraints.NONE; 107 dnLabel = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BIND_DN_LABEL.get()); 108 add(dnLabel, gbc); 109 gbc.insets.left = 10; 110 gbc.gridx = 1; 111 dn = Utilities.createTextField("cn=Directory Manager", 20); 112 gbc.weightx = 1.0; 113 gbc.fill = GridBagConstraints.HORIZONTAL; 114 add(dn, gbc); 115 gbc.insets.top = 10; 116 gbc.insets.left = 0; 117 118 gbc.gridx = 0; 119 gbc.gridy ++; 120 gbc.weightx = 0.0; 121 gbc.gridwidth = 1; 122 gbc.fill = GridBagConstraints.NONE; 123 pwdLabel = Utilities.createPrimaryLabel( 124 INFO_CTRL_PANEL_BIND_PASSWORD_LABEL.get()); 125 add(pwdLabel, gbc); 126 gbc.insets.left = 10; 127 gbc.gridx = 1; 128 pwd = Utilities.createPasswordField(); 129 gbc.weightx = 1.0; 130 gbc.fill = GridBagConstraints.HORIZONTAL; 131 add(pwd, gbc); 132 133 addBottomGlue(gbc); 134 } 135 136 /** {@inheritDoc} */ 137 @Override 138 public Component getPreferredFocusComponent() 139 { 140 return pwd; 141 } 142 143 /** {@inheritDoc} */ 144 @Override 145 public void configurationChanged(ConfigurationChangeEvent ev) 146 { 147 } 148 149 /** {@inheritDoc} */ 150 @Override 151 public void toBeDisplayed(boolean visible) 152 { 153 super.toBeDisplayed(visible); 154 if (visible) 155 { 156 pwd.setText(""); 157 } 158 } 159 160 /** {@inheritDoc} */ 161 @Override 162 public void okClicked() 163 { 164 setPrimaryValid(dnLabel); 165 setPrimaryValid(pwdLabel); 166 final LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>(); 167 168 boolean dnInvalid = false; 169 boolean pwdInvalid = false; 170 171 if ("".equals(dn.getText().trim())) 172 { 173 dnInvalid = true; 174 errors.add(INFO_EMPTY_DIRECTORY_MANAGER_DN.get()); 175 } 176 else if (!isDN(dn.getText())) 177 { 178 dnInvalid = true; 179 errors.add(INFO_NOT_A_DIRECTORY_MANAGER_DN.get()); 180 } 181 182 if (pwd.getPassword().length == 0) 183 { 184 pwdInvalid = true; 185 errors.add(INFO_EMPTY_PWD.get()); 186 } 187 if (dnInvalid) 188 { 189 setPrimaryInvalid(dnLabel); 190 } 191 192 if (pwdInvalid) 193 { 194 setPrimaryInvalid(pwdLabel); 195 } 196 197 if (errors.isEmpty()) 198 { 199 setEnabledOK(false); 200 setEnabledCancel(false); 201 displayMessage(INFO_CTRL_PANEL_VERIFYING_AUTHENTICATION_SUMMARY.get()); 202 203 BackgroundTask<InitialLdapContext> worker = 204 new BackgroundTask<InitialLdapContext>() 205 { 206 /** {@inheritDoc} */ 207 @Override 208 public InitialLdapContext processBackgroundTask() throws Throwable 209 { 210 InitialLdapContext ctx = null; 211 try 212 { 213 usedUrl = getInfo().getAdminConnectorURL(); 214 ctx = Utilities.getAdminDirContext(getInfo(), dn.getText(), 215 String.valueOf(pwd.getPassword())); 216 217 if (getInfo().getDirContext() != null) 218 { 219 try 220 { 221 getInfo().getDirContext().close(); 222 } 223 catch (Throwable t) 224 { 225 } 226 } 227 if (getInfo().getUserDataDirContext() != null) 228 { 229 try 230 { 231 getInfo().getUserDataDirContext().close(); 232 } 233 catch (Throwable t) 234 { 235 } 236 } 237 try 238 { 239 Thread.sleep(500); 240 } 241 catch (Throwable t) 242 { 243 } 244 SwingUtilities.invokeLater(new Runnable() 245 { 246 @Override 247 public void run() 248 { 249 displayMessage( 250 INFO_CTRL_PANEL_READING_CONFIGURATION_SUMMARY.get()); 251 } 252 }); 253 getInfo().setDirContext(ctx); 254 getInfo().setUserDataDirContext(null); 255 getInfo().regenerateDescriptor(); 256 return ctx; 257 } catch (Throwable t) 258 { 259 StaticUtils.close(ctx); 260 throw t; 261 } 262 } 263 264 /** {@inheritDoc} */ 265 @Override 266 public void backgroundTaskCompleted(InitialLdapContext ctx, 267 Throwable throwable) 268 { 269 boolean handleCertificateException = false; 270 if (throwable != null) 271 { 272 logger.info(LocalizableMessage.raw("Error connecting: " + throwable, throwable)); 273 274 if (isCertificateException(throwable)) 275 { 276 ApplicationTrustManager.Cause cause = 277 getInfo().getTrustManager().getLastRefusedCause(); 278 279 logger.info(LocalizableMessage.raw("Certificate exception cause: "+cause)); 280 UserDataCertificateException.Type excType = null; 281 if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED) 282 { 283 excType = UserDataCertificateException.Type.NOT_TRUSTED; 284 } 285 else if (cause == 286 ApplicationTrustManager.Cause.HOST_NAME_MISMATCH) 287 { 288 excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH; 289 } 290 else 291 { 292 LocalizableMessage msg = getThrowableMsg( 293 INFO_ERROR_CONNECTING_TO_LOCAL.get(), throwable); 294 errors.add(msg); 295 } 296 297 if (excType != null) 298 { 299 String h; 300 int p; 301 try 302 { 303 URI uri = new URI(usedUrl); 304 h = uri.getHost(); 305 p = uri.getPort(); 306 } 307 catch (Throwable t) 308 { 309 logger.warn(LocalizableMessage.raw( 310 "Error parsing ldap url of ldap url.", t)); 311 h = INFO_NOT_AVAILABLE_LABEL.get().toString(); 312 p = -1; 313 } 314 UserDataCertificateException udce = 315 new UserDataCertificateException(null, 316 INFO_CERTIFICATE_EXCEPTION.get(h, p), 317 throwable, h, p, 318 getInfo().getTrustManager().getLastRefusedChain(), 319 getInfo().getTrustManager().getLastRefusedAuthType(), 320 excType); 321 322 handleCertificateException(udce); 323 handleCertificateException = true; 324 } 325 } 326 else if (throwable instanceof NamingException) 327 { 328 boolean found = false; 329 String providedDn = dn.getText(); 330 Iterator<DN> it = getInfo().getServerDescriptor(). 331 getAdministrativeUsers().iterator(); 332 while (it.hasNext() && !found) 333 { 334 found = Utils.areDnsEqual(providedDn, it.next().toString()); 335 } 336 if (!found) 337 { 338 errors.add(INFO_NOT_A_DIRECTORY_MANAGER_IN_CONFIG.get()); 339 } 340 else 341 { 342 errors.add(Utils.getMessageForException( 343 (NamingException)throwable)); 344 } 345 346 setPrimaryInvalid(dnLabel); 347 setPrimaryInvalid(pwdLabel); 348 } 349 else if (throwable instanceof ConfigReadException) 350 { 351 errors.add(((ConfigReadException)throwable).getMessageObject()); 352 } 353 else 354 { 355 // This is a bug 356 throwable.printStackTrace(); 357 errors.add(getThrowableMsg(INFO_BUG_MSG.get(), throwable)); 358 } 359 } 360 displayMainPanel(); 361 setEnabledCancel(true); 362 setEnabledOK(true); 363 if (!errors.isEmpty()) 364 { 365 displayErrorDialog(errors); 366 pwd.setSelectionStart(0); 367 pwd.setSelectionEnd(pwd.getPassword().length); 368 pwd.requestFocusInWindow(); 369 } 370 else if (!handleCertificateException) 371 { 372 Utilities.getParentDialog(LoginPanel.this).setVisible(false); 373 } 374 } 375 }; 376 worker.startBackgroundTask(); 377 } 378 else 379 { 380 displayErrorDialog(errors); 381 if (dnInvalid) 382 { 383 dn.setSelectionStart(0); 384 dn.setSelectionEnd(dn.getText().length()); 385 dn.requestFocusInWindow(); 386 } 387 if (pwdInvalid) 388 { 389 pwd.setSelectionStart(0); 390 pwd.setSelectionEnd(pwd.getPassword().length); 391 pwd.requestFocusInWindow(); 392 } 393 394 } 395 } 396 397 /** {@inheritDoc} */ 398 @Override 399 public void cancelClicked() 400 { 401 setPrimaryValid(dnLabel); 402 setPrimaryValid(pwdLabel); 403 pwd.setText(null); 404 super.cancelClicked(); 405 } 406 407 /** 408 * Displays a dialog asking the user to accept a certificate if the user 409 * accepts it, we update the trust manager and simulate a click on "OK" to 410 * re-check the authentication. 411 * This method assumes that we are being called from the event thread. 412 */ 413 private void handleCertificateException(UserDataCertificateException ce) 414 { 415 CertificateDialog dlg = new CertificateDialog(null, ce); 416 dlg.pack(); 417 Utilities.centerGoldenMean(dlg, Utilities.getParentDialog(this)); 418 dlg.setVisible(true); 419 if (dlg.getUserAnswer() != 420 CertificateDialog.ReturnType.NOT_ACCEPTED) 421 { 422 X509Certificate[] chain = ce.getChain(); 423 String authType = ce.getAuthType(); 424 String host = ce.getHost(); 425 426 if (chain != null && authType != null && host != null) 427 { 428 logger.info(LocalizableMessage.raw("Accepting certificate presented by host "+host)); 429 getInfo().getTrustManager().acceptCertificate(chain, authType, host); 430 /* Simulate a click on the OK by calling in the okClicked method. */ 431 SwingUtilities.invokeLater(new Runnable() 432 { 433 @Override 434 public void run() 435 { 436 okClicked(); 437 } 438 }); 439 } 440 else 441 { 442 if (chain == null) 443 { 444 logger.warn(LocalizableMessage.raw( 445 "The chain is null for the UserDataCertificateException")); 446 } 447 if (authType == null) 448 { 449 logger.warn(LocalizableMessage.raw( 450 "The auth type is null for the UserDataCertificateException")); 451 } 452 if (host == null) 453 { 454 logger.warn(LocalizableMessage.raw( 455 "The host is null for the UserDataCertificateException")); 456 } 457 } 458 } 459 if (dlg.getUserAnswer() == 460 CertificateDialog.ReturnType.ACCEPTED_PERMANENTLY) 461 { 462 X509Certificate[] chain = ce.getChain(); 463 if (chain != null) 464 { 465 try 466 { 467 UIKeyStore.acceptCertificate(chain); 468 } 469 catch (Throwable t) 470 { 471 logger.warn(LocalizableMessage.raw("Error accepting certificate: "+t, t)); 472 } 473 } 474 } 475 } 476}