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