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