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 2007-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS 026 */ 027package org.opends.server.core; 028 029import java.util.ArrayList; 030import java.util.List; 031 032import org.forgerock.i18n.LocalizableMessage; 033import org.forgerock.i18n.slf4j.LocalizedLogger; 034import org.forgerock.opendj.ldap.ByteString; 035import org.forgerock.opendj.ldap.ResultCode; 036import org.opends.server.api.ClientConnection; 037import org.opends.server.types.*; 038import org.opends.server.types.operation.PreParseBindOperation; 039import org.opends.server.workflowelement.localbackend.LocalBackendBindOperation; 040 041import static org.forgerock.opendj.ldap.ResultCode.*; 042import static org.opends.messages.CoreMessages.*; 043import static org.opends.server.core.DirectoryServer.*; 044import static org.opends.server.loggers.AccessLogger.*; 045import static org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement.*; 046 047/** 048 * This class defines an operation that may be used to authenticate a user to 049 * the Directory Server. Note that for security restrictions, response messages 050 * that may be returned to the client must be carefully cleaned to ensure that 051 * they do not provide a malicious client with information that may be useful in 052 * an attack. This does impact the debuggability of the server, but that can 053 * be addressed by calling the <CODE>setAuthFailureReason</CODE> method, which 054 * can provide a reason for a failure in a form that will not be returned to the 055 * client but may be written to a log file. 056 */ 057public class BindOperationBasis 058 extends AbstractOperation 059 implements BindOperation, PreParseBindOperation 060{ 061 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 062 063 /** The credentials used for SASL authentication. */ 064 private ByteString saslCredentials; 065 066 /** The server SASL credentials provided to the client in the response. */ 067 private ByteString serverSASLCredentials; 068 069 /** The authentication info for this bind operation. */ 070 private AuthenticationInfo authInfo; 071 072 /** The authentication type used for this bind operation. */ 073 private AuthenticationType authType; 074 075 /** The raw, unprocessed bind DN as contained in the client request. */ 076 private ByteString rawBindDN; 077 078 /** The password used for simple authentication. */ 079 private ByteString simplePassword; 080 081 /** The bind DN used for this bind operation. */ 082 private DN bindDN; 083 084 /** The DN of the user entry that is attempting to authenticate. */ 085 private DN userEntryDN; 086 087 /** 088 * The DN of the user as whom a SASL authentication was attempted (regardless 089 * of whether the authentication was successful) for the purpose of updating 090 * password policy state information. 091 */ 092 private Entry saslAuthUserEntry; 093 094 /** The set of response controls for this bind operation. */ 095 private final List<Control> responseControls = new ArrayList<>(0); 096 097 /** A message explaining the reason for the authentication failure. */ 098 private LocalizableMessage authFailureReason; 099 100 /** The SASL mechanism used for SASL authentication. */ 101 private String saslMechanism; 102 103 /** 104 * A string representation of the protocol version for this bind operation. 105 */ 106 private String protocolVersion; 107 108 /** 109 * Creates a new simple bind operation with the provided information. 110 * 111 * @param clientConnection The client connection with which this operation 112 * is associated. 113 * @param operationID The operation ID for this operation. 114 * @param messageID The message ID of the request with which this 115 * operation is associated. 116 * @param requestControls The set of controls included in the request. 117 * @param protocolVersion The string representation of the protocol version 118 * associated with this bind request. 119 * @param rawBindDN The raw, unprocessed bind DN as provided in the 120 * request from the client. 121 * @param simplePassword The password to use for the simple 122 * authentication. 123 */ 124 public BindOperationBasis(ClientConnection clientConnection, long operationID, 125 int messageID, List<Control> requestControls, 126 String protocolVersion, ByteString rawBindDN, 127 ByteString simplePassword) 128 { 129 super(clientConnection, operationID, messageID, requestControls); 130 131 this.protocolVersion = protocolVersion; 132 133 setRawBindDN(rawBindDN); 134 setSimplePassword(simplePassword); 135 136 cancelResult = getBindCancelResult(); 137 } 138 139 140 141 /** 142 * Creates a new SASL bind operation with the provided information. 143 * 144 * @param clientConnection The client connection with which this operation 145 * is associated. 146 * @param operationID The operation ID for this operation. 147 * @param messageID The message ID of the request with which this 148 * operation is associated. 149 * @param requestControls The set of controls included in the request. 150 * @param protocolVersion The string representation of the protocol version 151 * associated with this bind request. 152 * @param rawBindDN The raw, unprocessed bind DN as provided in the 153 * request from the client. 154 * @param saslMechanism The SASL mechanism included in the request. 155 * @param saslCredentials The optional SASL credentials included in the 156 * request. 157 */ 158 public BindOperationBasis(ClientConnection clientConnection, long operationID, 159 int messageID, List<Control> requestControls, 160 String protocolVersion, ByteString rawBindDN, 161 String saslMechanism, ByteString saslCredentials) 162 { 163 super(clientConnection, operationID, messageID, requestControls); 164 165 this.protocolVersion = protocolVersion; 166 this.authType = AuthenticationType.SASL; 167 this.saslMechanism = saslMechanism; 168 this.saslCredentials = saslCredentials; 169 170 setRawBindDN(rawBindDN); 171 172 cancelResult = getBindCancelResult(); 173 } 174 175 /** 176 * Creates a new simple bind operation with the provided information. 177 * 178 * @param clientConnection The client connection with which this operation 179 * is associated. 180 * @param operationID The operation ID for this operation. 181 * @param messageID The message ID of the request with which this 182 * operation is associated. 183 * @param requestControls The set of controls included in the request. 184 * @param protocolVersion The string representation of the protocol version 185 * associated with this bind request. 186 * @param bindDN The bind DN for this bind operation. 187 * @param simplePassword The password to use for the simple 188 * authentication. 189 */ 190 public BindOperationBasis(ClientConnection clientConnection, long operationID, 191 int messageID, List<Control> requestControls, 192 String protocolVersion, DN bindDN, 193 ByteString simplePassword) 194 { 195 super(clientConnection, operationID, messageID, requestControls); 196 197 this.protocolVersion = protocolVersion; 198 this.bindDN = bindDN; 199 200 rawBindDN = computeRawBindDN(bindDN); 201 202 setSimplePassword(simplePassword); 203 204 cancelResult = getBindCancelResult(); 205 } 206 207 208 209 /** 210 * Creates a new SASL bind operation with the provided information. 211 * 212 * @param clientConnection The client connection with which this operation 213 * is associated. 214 * @param operationID The operation ID for this operation. 215 * @param messageID The message ID of the request with which this 216 * operation is associated. 217 * @param requestControls The set of controls included in the request. 218 * @param protocolVersion The string representation of the protocol version 219 * associated with this bind request. 220 * @param bindDN The bind DN for this bind operation. 221 * @param saslMechanism The SASL mechanism included in the request. 222 * @param saslCredentials The optional SASL credentials included in the 223 * request. 224 */ 225 public BindOperationBasis(ClientConnection clientConnection, long operationID, 226 int messageID, List<Control> requestControls, 227 String protocolVersion, DN bindDN, 228 String saslMechanism, ByteString saslCredentials) 229 { 230 super(clientConnection, operationID, messageID, requestControls); 231 232 this.protocolVersion = protocolVersion; 233 this.authType = AuthenticationType.SASL; 234 this.bindDN = bindDN; 235 this.saslMechanism = saslMechanism; 236 this.saslCredentials = saslCredentials; 237 238 rawBindDN = computeRawBindDN(bindDN); 239 240 cancelResult = getBindCancelResult(); 241 } 242 243 private ByteString computeRawBindDN(DN bindDN) 244 { 245 if (bindDN != null) 246 { 247 return ByteString.valueOfUtf8(bindDN.toString()); 248 } 249 return ByteString.empty(); 250 } 251 252 private CancelResult getBindCancelResult() 253 { 254 return new CancelResult(CANNOT_CANCEL, ERR_CANNOT_CANCEL_BIND.get()); 255 } 256 257 /** {@inheritDoc} */ 258 @Override 259 public DN getProxiedAuthorizationDN() 260 { 261 return null; 262 } 263 264 /** {@inheritDoc} */ 265 @Override 266 public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN) 267 { 268 } 269 270 /** {@inheritDoc} */ 271 @Override 272 public final AuthenticationType getAuthenticationType() 273 { 274 return authType; 275 } 276 277 /** {@inheritDoc} */ 278 @Override 279 public final ByteString getRawBindDN() 280 { 281 return rawBindDN; 282 } 283 284 /** {@inheritDoc} */ 285 @Override 286 public final void setRawBindDN(ByteString rawBindDN) 287 { 288 if (rawBindDN != null) 289 { 290 this.rawBindDN = rawBindDN; 291 } 292 else 293 { 294 this.rawBindDN = ByteString.empty(); 295 } 296 297 bindDN = null; 298 } 299 300 /** {@inheritDoc} */ 301 @Override 302 public final DN getBindDN() 303 { 304 try 305 { 306 if (bindDN == null) 307 { 308 bindDN = DN.decode(rawBindDN); 309 } 310 } 311 catch (DirectoryException de) 312 { 313 logger.traceException(de); 314 315 setResultCode(ResultCode.INVALID_CREDENTIALS); 316 setAuthFailureReason(de.getMessageObject()); 317 } 318 return bindDN; 319 } 320 321 /** {@inheritDoc} */ 322 @Override 323 public final ByteString getSimplePassword() 324 { 325 return simplePassword; 326 } 327 328 /** {@inheritDoc} */ 329 @Override 330 public final void setSimplePassword(ByteString simplePassword) 331 { 332 if (simplePassword != null) 333 { 334 this.simplePassword = simplePassword; 335 } 336 else 337 { 338 this.simplePassword = ByteString.empty(); 339 } 340 341 authType = AuthenticationType.SIMPLE; 342 saslMechanism = null; 343 saslCredentials = null; 344 } 345 346 /** {@inheritDoc} */ 347 @Override 348 public final String getSASLMechanism() 349 { 350 return saslMechanism; 351 } 352 353 /** {@inheritDoc} */ 354 @Override 355 public final ByteString getSASLCredentials() 356 { 357 return saslCredentials; 358 } 359 360 /** {@inheritDoc} */ 361 @Override 362 public final void setSASLCredentials(String saslMechanism, 363 ByteString saslCredentials) 364 { 365 this.saslMechanism = saslMechanism; 366 this.saslCredentials = saslCredentials; 367 368 authType = AuthenticationType.SASL; 369 simplePassword = null; 370 } 371 372 /** {@inheritDoc} */ 373 @Override 374 public final ByteString getServerSASLCredentials() 375 { 376 return serverSASLCredentials; 377 } 378 379 /** {@inheritDoc} */ 380 @Override 381 public final void setServerSASLCredentials(ByteString serverSASLCredentials) 382 { 383 this.serverSASLCredentials = serverSASLCredentials; 384 } 385 386 /** {@inheritDoc} */ 387 @Override 388 public final Entry getSASLAuthUserEntry() 389 { 390 return saslAuthUserEntry; 391 } 392 393 /** {@inheritDoc} */ 394 @Override 395 public final void setSASLAuthUserEntry(Entry saslAuthUserEntry) 396 { 397 this.saslAuthUserEntry = saslAuthUserEntry; 398 } 399 400 /** {@inheritDoc} */ 401 @Override 402 public final LocalizableMessage getAuthFailureReason() 403 { 404 return authFailureReason; 405 } 406 407 /** {@inheritDoc} */ 408 @Override 409 public final void setAuthFailureReason(LocalizableMessage message) 410 { 411 if (DirectoryServer.returnBindErrorMessages()) 412 { 413 appendErrorMessage(message); 414 } 415 else 416 { 417 authFailureReason = message; 418 } 419 } 420 421 /** {@inheritDoc} */ 422 @Override 423 public final DN getUserEntryDN() 424 { 425 return userEntryDN; 426 } 427 428 /** {@inheritDoc} */ 429 @Override 430 public final AuthenticationInfo getAuthenticationInfo() 431 { 432 return authInfo; 433 } 434 435 /** {@inheritDoc} */ 436 @Override 437 public final void setAuthenticationInfo(AuthenticationInfo authInfo) 438 { 439 this.authInfo = authInfo; 440 } 441 442 /** {@inheritDoc} */ 443 @Override 444 public final OperationType getOperationType() 445 { 446 // Note that no debugging will be done in this method because it is a likely 447 // candidate for being called by the logging subsystem. 448 return OperationType.BIND; 449 } 450 451 /** {@inheritDoc} */ 452 @Override 453 public final List<Control> getResponseControls() 454 { 455 return responseControls; 456 } 457 458 /** {@inheritDoc} */ 459 @Override 460 public final void addResponseControl(Control control) 461 { 462 responseControls.add(control); 463 } 464 465 /** {@inheritDoc} */ 466 @Override 467 public final void removeResponseControl(Control control) 468 { 469 responseControls.remove(control); 470 } 471 472 /** {@inheritDoc} */ 473 @Override 474 public final void toString(StringBuilder buffer) 475 { 476 buffer.append("BindOperation(connID="); 477 buffer.append(clientConnection.getConnectionID()); 478 buffer.append(", opID="); 479 buffer.append(operationID); 480 buffer.append(", protocol=\""); 481 buffer.append(clientConnection.getProtocol()); 482 buffer.append(" "); 483 buffer.append(protocolVersion); 484 buffer.append(", dn="); 485 buffer.append(rawBindDN); 486 buffer.append(", authType="); 487 buffer.append(authType); 488 buffer.append(")"); 489 } 490 491 /** {@inheritDoc} */ 492 @Override 493 public void setUserEntryDN(DN userEntryDN) 494 { 495 this.userEntryDN = userEntryDN; 496 } 497 498 /** {@inheritDoc} */ 499 @Override 500 public String getProtocolVersion() 501 { 502 return protocolVersion; 503 } 504 505 /** {@inheritDoc} */ 506 @Override 507 public void setProtocolVersion(String protocolVersion) 508 { 509 this.protocolVersion = protocolVersion; 510 } 511 512 /** {@inheritDoc} */ 513 @Override 514 public final void run() 515 { 516 // Start the processing timer and initially set the result to indicate that 517 // the result is unknown. 518 setResultCode(ResultCode.UNDEFINED); 519 setProcessingStartTime(); 520 521 logBindRequest(this); 522 523 // Wipe out any existing authentication for the client connection and create 524 // a placeholder that will be used if the bind is successful. 525 ClientConnection clientConnection = getClientConnection(); 526 clientConnection.setUnauthenticated(); 527 528 // Abandon any operations that may be in progress for the client. 529 LocalizableMessage cancelReason = INFO_CANCELED_BY_BIND_REQUEST.get(); 530 CancelRequest cancelRequest = new CancelRequest(true, cancelReason); 531 clientConnection.cancelAllOperationsExcept(cancelRequest, getMessageID()); 532 533 534 // This flag is set to true as soon as a workflow has been executed. 535 boolean workflowExecuted = false; 536 try 537 { 538 // Invoke the pre-parse bind plugins. 539 if (!processOperationResult(getPluginConfigManager().invokePreParseBindPlugins(this))) 540 { 541 return; 542 } 543 544 545 // Process the bind DN to convert it from the raw form as provided by the 546 // client into the form required for the rest of the bind processing. 547 DN bindDN = getBindDN(); 548 if (bindDN == null){ 549 return; 550 } 551 552 // If this is a simple bind 553 // Then check whether the bind DN is actually one of the alternate root DNs 554 // defined in the server. If so, then replace it with the actual DN 555 // for that user. 556 switch (getAuthenticationType()) 557 { 558 case SIMPLE: 559 DN actualRootDN = DirectoryServer.getActualRootBindDN(bindDN); 560 if (actualRootDN != null) 561 { 562 bindDN = actualRootDN; 563 } 564 } 565 566 workflowExecuted = execute(this, bindDN); 567 } 568 catch(CanceledOperationException coe) 569 { 570 // This shouldn't happen for bind operations. Just cancel anyways 571 logger.traceException(coe); 572 573 setResultCode(ResultCode.CANCELLED); 574 575 appendErrorMessage(cancelRequest.getCancelReason()); 576 } 577 finally 578 { 579 setProcessingStopTime(); 580 logBindResponse(this); 581 582 // Send the bind response to the client. 583 clientConnection.sendResponse(this); 584 585 // If the bind processing is finished, then unset the "bind in progress" 586 // flag to allow other operations to be processed on the connection. 587 if (getResultCode() != ResultCode.SASL_BIND_IN_PROGRESS) 588 { 589 clientConnection.finishSaslBind(); 590 } 591 clientConnection.finishBind(); 592 593 invokePostResponsePlugins(workflowExecuted); 594 } 595 } 596 597 /** 598 * Invokes the post response plugins. If a workflow has been executed 599 * then invoke the post response plugins provided by the workflow 600 * elements of the workflow, otherwise invoke the post response plugins 601 * that have been registered with the current operation. 602 * 603 * @param workflowExecuted <code>true</code> if a workflow has been executed 604 */ 605 private void invokePostResponsePlugins(boolean workflowExecuted) 606 { 607 // Invoke the post response plugins 608 if (workflowExecuted) 609 { 610 // The post responses are provided by the workflow elements of the workflow. 611 List localOperations = (List) getAttachment(Operation.LOCALBACKENDOPERATIONS); 612 if (localOperations != null) 613 { 614 for (Object localOp : localOperations) 615 { 616 LocalBackendBindOperation localOperation = (LocalBackendBindOperation) localOp; 617 // Invoke the post-response bind plugins. 618 getPluginConfigManager().invokePostResponseBindPlugins(localOperation); 619 } 620 } 621 else 622 { 623 // The current operation does not implement any bind post response 624 // interface so we cannot invoke any post-response plugin. 625 } 626 } 627 } 628 629 /** {@inheritDoc} */ 630 @Override 631 public void updateOperationErrMsgAndResCode() 632 { 633 LocalizableMessage message = ERR_BIND_OPERATION_UNKNOWN_USER.get(); 634 setResultCode(ResultCode.INVALID_CREDENTIALS); 635 setAuthFailureReason(message); 636 } 637}