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