Path: blob/master/test/jdk/com/sun/jndi/ldap/lib/LdapMessage.java
41155 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.math.BigInteger;24import java.util.Arrays;25import java.util.Optional;26import java.util.stream.Stream;2728/**29* An LDAP message.30*/31public class LdapMessage {3233private final byte[] message;34private int messageID;35private Operation operation;3637public enum Operation {38BIND_REQUEST(0x60, "BindRequest"), // [APPLICATION 0]39BIND_RESPONSE(0x61, "BindResponse"), // [APPLICATION 1]40UNBIND_REQUEST(0x42, "UnbindRequest"), // [APPLICATION 2]41SEARCH_REQUEST(0x63, "SearchRequest"), // [APPLICATION 3]42SEARCH_RESULT_ENTRY(0x64, "SearchResultEntry"), // [APPLICATION 4]43SEARCH_RESULT_DONE(0x65, "SearchResultDone"), // [APPLICATION 5]44MODIFY_REQUEST(0x66, "ModifyRequest"), // [APPLICATION 6]45MODIFY_RESPONSE(0x67, "ModifyResponse"), // [APPLICATION 7]46ADD_REQUEST(0x68, "AddRequest"), // [APPLICATION 8]47ADD_RESPONSE(0x69, "AddResponse"), // [APPLICATION 9]48DELETE_REQUEST(0x4A, "DeleteRequest"), // [APPLICATION 10]49DELETE_RESPONSE(0x6B, "DeleteResponse"), // [APPLICATION 11]50MODIFY_DN_REQUEST(0x6C, "ModifyDNRequest"), // [APPLICATION 12]51MODIFY_DN_RESPONSE(0x6D, "ModifyDNResponse"), // [APPLICATION 13]52COMPARE_REQUEST(0x6E, "CompareRequest"), // [APPLICATION 14]53COMPARE_RESPONSE(0x6F, "CompareResponse"), // [APPLICATION 15]54ABANDON_REQUEST(0x50, "AbandonRequest"), // [APPLICATION 16]55SEARCH_RESULT_REFERENCE(0x73, "SearchResultReference"), // [APPLICATION 19]56EXTENDED_REQUEST(0x77, "ExtendedRequest"), // [APPLICATION 23]57EXTENDED_RESPONSE(0x78, "ExtendedResponse"), // [APPLICATION 24]58INTERMEDIATE_RESPONSE(0x79, "IntermediateResponse"); // [APPLICATION 25]5960private final int id;61private final String name;6263Operation(int id, String name) {64this.id = id;65this.name = name;66}6768public int getId() {69return id;70}7172@Override73public String toString() {74return name;75}7677private static Operation fromId(int id) {78Optional<Operation> optional = Stream.of(Operation.values())79.filter(o -> o.id == id).findFirst();80if (optional.isPresent()) {81return optional.get();82} else {83throw new RuntimeException(84"Unknown id " + id + " for enum Operation.");85}86}87}8889public LdapMessage(byte[] message) {90this.message = message;91parse();92}9394public LdapMessage(String hexString) {95this(parseHexBinary(hexString));96}9798// Extracts the message ID and operation ID from an LDAP protocol encoding99private void parse() {100if (message == null || message.length < 2) {101throw new RuntimeException(102"Invalid ldap message: " + Arrays.toString(message));103}104105if (message[0] != 0x30) {106throw new RuntimeException("Bad LDAP encoding in message, "107+ "expected ASN.1 SEQUENCE tag (0x30), encountered "108+ message[0]);109}110111int index = 2;112if ((message[1] & 0x80) == 0x80) {113index += (message[1] & 0x0F);114}115116if (message[index] != 0x02) {117throw new RuntimeException("Bad LDAP encoding in message, "118+ "expected ASN.1 INTEGER tag (0x02), encountered "119+ message[index]);120}121int length = message[index + 1];122index += 2;123messageID = new BigInteger(1,124Arrays.copyOfRange(message, index, index + length)).intValue();125index += length;126int operationID = message[index];127operation = Operation.fromId(operationID);128}129130/**131* Return original ldap message in byte array.132*133* @return original ldap message134*/135public byte[] getMessage() {136return Arrays.copyOf(message, message.length);137}138139/**140* Return ldap message id.141*142* @return ldap message id.143*/144public int getMessageID() {145return messageID;146}147148/**149* Return ldap message's operation.150*151* @return ldap message's operation.152*/153public Operation getOperation() {154return operation;155}156157private static byte[] parseHexBinary(String s) {158159final int len = s.length();160161// "111" is not a valid hex encoding.162if (len % 2 != 0) {163throw new IllegalArgumentException(164"hexBinary needs to be even-length: " + s);165}166167byte[] out = new byte[len / 2];168169for (int i = 0; i < len; i += 2) {170int h = Character.digit(s.charAt(i), 16);171int l = Character.digit(s.charAt(i + 1), 16);172if (h == -1 || l == -1) {173throw new IllegalArgumentException(174"contains illegal character for hexBinary: " + s);175}176177out[i / 2] = (byte) (h * 16 + l);178}179180return out;181}182183public static int getMessageLength(byte[] encoding) {184if (encoding.length < 2) {185// not enough data to extract msg len, just return -1186return -1;187}188189if (encoding[0] != 0x30) {190throw new RuntimeException("Error: bad LDAP encoding message: "191+ "expected ASN.1 SEQUENCE tag (0x30), encountered "192+ encoding[0]);193}194195int len;196int index = 1;197int payloadLen = 0;198199if ((encoding[1] & 0x80) == 0x80) {200len = (encoding[1] & 0x0F);201index++;202} else {203len = 1;204}205206if (len > 4) {207throw new RuntimeException(208"Error: LDAP encoding message payload too large");209}210211if (encoding.length < index + len) {212// additional data required to extract payload len, return -1213return -1;214}215216for (byte b : Arrays.copyOfRange(encoding, index, index + len)) {217payloadLen = payloadLen << 8 | (b & 0xFF);218}219220if (payloadLen <= 0) {221throw new RuntimeException(222"Error: invalid LDAP encoding message length or payload too large");223}224225return index + len + payloadLen;226}227}228229230