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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.protocols.ldap; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.ArrayList; 033 034 import org.opends.server.protocols.asn1.ASN1Boolean; 035 import org.opends.server.protocols.asn1.ASN1Element; 036 import org.opends.server.protocols.asn1.ASN1OctetString; 037 import org.opends.server.protocols.asn1.ASN1Sequence; 038 import org.opends.server.types.Control; 039 import org.opends.server.types.DebugLogLevel; 040 import org.opends.server.types.LDAPException; 041 042 import static org.opends.server.loggers.debug.DebugLogger.*; 043 import org.opends.server.loggers.debug.DebugTracer; 044 import static org.opends.messages.ProtocolMessages.*; 045 import static org.opends.server.protocols.asn1.ASN1Constants.*; 046 import static org.opends.server.protocols.ldap.LDAPConstants.*; 047 import static org.opends.server.protocols.ldap.LDAPResultCode.*; 048 import static org.opends.server.util.ServerConstants.*; 049 050 051 052 /** 053 * This class defines the data structures and methods to use when interacting 054 * with a generic LDAP control or set of controls. 055 */ 056 public class LDAPControl 057 { 058 /** 059 * The tracer object for the debug logger. 060 */ 061 private static final DebugTracer TRACER = getTracer(); 062 063 // The control wrapped by this LDAP control. 064 private Control control; 065 066 067 068 /** 069 * Creates a new LDAP control with the information in the provided control. 070 * 071 * @param control The control to use to create this LDAP control. 072 */ 073 public LDAPControl(Control control) 074 { 075 this.control = control; 076 } 077 078 079 080 /** 081 * Creates a new LDAP control with the specified OID. It will not be 082 * critical, and will not have a value. 083 * 084 * @param oid The OID for this LDAP control. 085 */ 086 public LDAPControl(String oid) 087 { 088 control = new Control(oid, false); 089 } 090 091 092 093 /** 094 * Creates a new LDAP control with the specified OID and criticality. It will 095 * not have a value. 096 * 097 * @param oid The OID for this LDAP control. 098 * @param isCritical Indicates whether this control should be considered 099 * critical. 100 */ 101 public LDAPControl(String oid, boolean isCritical) 102 { 103 control = new Control(oid, isCritical); 104 } 105 106 107 108 /** 109 * Creates a new LDAP control with the specified OID, criticality, and value. 110 * 111 * @param oid The OID for this LDAP control. 112 * @param isCritical Indicates whether this control should be considered 113 * critical. 114 * @param value The value for this LDAP control. 115 */ 116 public LDAPControl(String oid, boolean isCritical, ASN1OctetString value) 117 { 118 control = new Control(oid, isCritical, value); 119 } 120 121 122 123 /** 124 * Retrieves the control wrapped by this LDAP control. 125 * 126 * @return The control wrapped by this LDAP control. 127 */ 128 public Control getControl() 129 { 130 return control; 131 } 132 133 134 135 /** 136 * Encodes this control to an ASN.1 element. 137 * 138 * @return The ASN.1 element containing the encoded control. 139 */ 140 public ASN1Element encode() 141 { 142 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3); 143 elements.add(new ASN1OctetString(control.getOID())); 144 145 if (control.isCritical()) 146 { 147 elements.add(new ASN1Boolean(control.isCritical())); 148 } 149 150 ASN1OctetString value = control.getValue(); 151 if (value != null) 152 { 153 elements.add(value); 154 } 155 156 return new ASN1Sequence(elements); 157 } 158 159 160 161 /** 162 * Encodes the provided set of controls into an ASN.1 sequence. 163 * 164 * @param controls The set of controls to encode. 165 * 166 * @return The ASN.1 element containing the encoded set of controls. 167 */ 168 public static ASN1Element encodeControls(ArrayList<LDAPControl> controls) 169 { 170 ArrayList<ASN1Element> elements = 171 new ArrayList<ASN1Element>(controls.size()); 172 for (LDAPControl c : controls) 173 { 174 elements.add(c.encode()); 175 } 176 177 return new ASN1Sequence(TYPE_CONTROL_SEQUENCE, elements); 178 } 179 180 181 182 /** 183 * Decodes the provided ASN.1 element as an LDAP control. 184 * 185 * @param element The ASN.1 element to decode. 186 * 187 * @return The decoded LDAP control. 188 * 189 * @throws LDAPException If a problem occurs while attempting to decode the 190 * provided ASN.1 element as an LDAP control. 191 */ 192 public static LDAPControl decode(ASN1Element element) 193 throws LDAPException 194 { 195 if (element == null) 196 { 197 Message message = ERR_LDAP_CONTROL_DECODE_NULL.get(); 198 throw new LDAPException(PROTOCOL_ERROR, message); 199 } 200 201 202 ArrayList<ASN1Element> elements; 203 try 204 { 205 elements = element.decodeAsSequence().elements(); 206 } 207 catch (Exception e) 208 { 209 if (debugEnabled()) 210 { 211 TRACER.debugCaught(DebugLogLevel.ERROR, e); 212 } 213 214 Message message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(String.valueOf(e)); 215 throw new LDAPException(PROTOCOL_ERROR, message, e); 216 } 217 218 219 int numElements = elements.size(); 220 if ((numElements < 1) || (numElements > 3)) 221 { 222 Message message = 223 ERR_LDAP_CONTROL_DECODE_INVALID_ELEMENT_COUNT.get(numElements); 224 throw new LDAPException(PROTOCOL_ERROR, message); 225 } 226 227 228 String oid; 229 try 230 { 231 oid = elements.get(0).decodeAsOctetString().stringValue(); 232 } 233 catch (Exception e) 234 { 235 if (debugEnabled()) 236 { 237 TRACER.debugCaught(DebugLogLevel.ERROR, e); 238 } 239 240 Message message = ERR_LDAP_CONTROL_DECODE_OID.get(String.valueOf(e)); 241 throw new LDAPException(PROTOCOL_ERROR, message, e); 242 } 243 244 245 if (numElements == 1) 246 { 247 return new LDAPControl(oid); 248 } 249 else if (numElements == 2) 250 { 251 boolean isCritical; 252 ASN1OctetString value; 253 254 ASN1Element e = elements.get(1); 255 switch (e.getType()) 256 { 257 case UNIVERSAL_BOOLEAN_TYPE: 258 value = null; 259 260 try 261 { 262 isCritical = e.decodeAsBoolean().booleanValue(); 263 } 264 catch (Exception e2) 265 { 266 if (debugEnabled()) 267 { 268 TRACER.debugCaught(DebugLogLevel.ERROR, e2); 269 } 270 271 Message message = 272 ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e)); 273 throw new LDAPException(PROTOCOL_ERROR, message, e2); 274 } 275 break; 276 case UNIVERSAL_OCTET_STRING_TYPE: 277 isCritical = false; 278 279 try 280 { 281 value = e.decodeAsOctetString(); 282 } 283 catch (Exception e2) 284 { 285 if (debugEnabled()) 286 { 287 TRACER.debugCaught(DebugLogLevel.ERROR, e2); 288 } 289 290 Message message = 291 ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e)); 292 throw new LDAPException(PROTOCOL_ERROR, message, e2); 293 } 294 break; 295 default: 296 Message message = 297 ERR_LDAP_CONTROL_DECODE_INVALID_TYPE.get(e.getType()); 298 throw new LDAPException(PROTOCOL_ERROR, message); 299 } 300 301 return new LDAPControl(oid, isCritical, value); 302 } 303 else 304 { 305 boolean isCritical; 306 try 307 { 308 isCritical = elements.get(1).decodeAsBoolean().booleanValue(); 309 } 310 catch (Exception e) 311 { 312 if (debugEnabled()) 313 { 314 TRACER.debugCaught(DebugLogLevel.ERROR, e); 315 } 316 317 Message message = 318 ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e)); 319 throw new LDAPException(PROTOCOL_ERROR, message, e); 320 } 321 322 ASN1OctetString value; 323 try 324 { 325 value = elements.get(2).decodeAsOctetString(); 326 } 327 catch (Exception e) 328 { 329 if (debugEnabled()) 330 { 331 TRACER.debugCaught(DebugLogLevel.ERROR, e); 332 } 333 334 Message message = ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e)); 335 throw new LDAPException(PROTOCOL_ERROR, message, e); 336 } 337 338 return new LDAPControl(oid, isCritical, value); 339 } 340 } 341 342 343 344 /** 345 * Decodes the provided ASN.1 element as a set of controls. 346 * 347 * @param element The ASN.1 element containing the encoded set of controls. 348 * 349 * @return The decoded set of controls. 350 * 351 * @throws LDAPException If a problem occurs while attempting to decode the 352 * controls. 353 */ 354 public static ArrayList<LDAPControl> decodeControls(ASN1Element element) 355 throws LDAPException 356 { 357 if (element == null) 358 { 359 Message message = ERR_LDAP_CONTROL_DECODE_CONTROLS_NULL.get(); 360 throw new LDAPException(PROTOCOL_ERROR, message); 361 } 362 363 364 ArrayList<ASN1Element> elements; 365 try 366 { 367 elements = element.decodeAsSequence().elements(); 368 } 369 catch (Exception e) 370 { 371 Message message = 372 ERR_LDAP_CONTROL_DECODE_CONTROLS_SEQUENCE.get(String.valueOf(e)); 373 throw new LDAPException(PROTOCOL_ERROR, message, e); 374 } 375 376 377 ArrayList<LDAPControl> controls = 378 new ArrayList<LDAPControl>(elements.size()); 379 for (ASN1Element e : elements) 380 { 381 controls.add(decode(e)); 382 } 383 384 return controls; 385 } 386 387 388 389 /** 390 * Retrieves the OID for this control. 391 * 392 * @return The OID for this control. 393 */ 394 public String getOID() 395 { 396 return control.getOID(); 397 } 398 399 400 401 /** 402 * Indicates whether this control should be considered critical. 403 * 404 * @return <CODE>true</CODE> if this control should be considered critical, 405 * or <CODE>false</CODE> if not. 406 */ 407 public boolean isCritical() 408 { 409 return control.isCritical(); 410 } 411 412 413 414 /** 415 * Retrieves the value for this control. 416 * 417 * @return The value for this control, or <CODE>null</CODE> if there is none. 418 */ 419 public ASN1OctetString getValue() 420 { 421 return control.getValue(); 422 } 423 424 425 426 /** 427 * Retrieves a string representation of this LDAP control. 428 * 429 * @return A string representation of this LDAP control. 430 */ 431 public String toString() 432 { 433 StringBuilder buffer = new StringBuilder(); 434 toString(buffer); 435 return buffer.toString(); 436 } 437 438 439 440 /** 441 * Appends a string representation of this LDAP control to the provided 442 * buffer. 443 * 444 * @param buffer The buffer to which the information should be appended. 445 */ 446 public void toString(StringBuilder buffer) 447 { 448 buffer.append("LDAPControl(oid="); 449 buffer.append(control.getOID()); 450 buffer.append(", criticality="); 451 buffer.append(control.isCritical()); 452 453 ASN1OctetString value = control.getValue(); 454 if (value != null) 455 { 456 buffer.append(", value="); 457 buffer.append(String.valueOf(value)); 458 } 459 460 buffer.append(")"); 461 } 462 463 464 465 /** 466 * Appends a multi-line string representation of this LDAP control to the 467 * provided buffer. 468 * 469 * @param buffer The buffer to which the information should be appended. 470 * @param indent The number of spaces to indent the information. 471 */ 472 public void toString(StringBuilder buffer, int indent) 473 { 474 StringBuilder indentBuf = new StringBuilder(indent); 475 for (int i=0 ; i < indent; i++) 476 { 477 indentBuf.append(' '); 478 } 479 480 buffer.append(indentBuf); 481 buffer.append("LDAP Control"); 482 buffer.append(EOL); 483 484 buffer.append(indentBuf); 485 buffer.append(" OID: "); 486 buffer.append(control.getOID()); 487 buffer.append(EOL); 488 489 buffer.append(indentBuf); 490 buffer.append(" Criticality: "); 491 buffer.append(control.isCritical()); 492 buffer.append(EOL); 493 494 ASN1OctetString value = control.getValue(); 495 if (value != null) 496 { 497 buffer.append(indentBuf); 498 buffer.append(" Value:"); 499 value.toString(buffer, indent+4); 500 } 501 } 502 } 503