Added converters for Active Directory SID.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.ldap.support;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.naming.CompositeName;
|
||||
@@ -24,6 +25,7 @@ import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.NamingException;
|
||||
@@ -310,4 +312,171 @@ public final class LdapUtils {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a binary SID to its String representation, according to the
|
||||
* algorithm described <a
|
||||
* href="http://blogs.msdn.com/oldnewthing/archive/2004/03/15/89753.aspx"
|
||||
* >here</a>. Thanks to <a href=
|
||||
* "http://www.jroller.com/eyallupu/entry/java_jndi_how_to_convert">Eyal
|
||||
* Lupu</a> for algorithmic inspiration.
|
||||
*
|
||||
* <pre>
|
||||
* If you have a SID like S-a-b-c-d-e-f-g-...
|
||||
*
|
||||
* Then the bytes are
|
||||
* a (revision)
|
||||
* N (number of dashes minus two)
|
||||
* bbbbbb (six bytes of "b" treated as a 48-bit number in big-endian format)
|
||||
* cccc (four bytes of "c" treated as a 32-bit number in little-endian format)
|
||||
* dddd (four bytes of "d" treated as a 32-bit number in little-endian format)
|
||||
* eeee (four bytes of "e" treated as a 32-bit number in little-endian format)
|
||||
* ffff (four bytes of "f" treated as a 32-bit number in little-endian format)
|
||||
* etc.
|
||||
*
|
||||
* So for example, if your SID is S-1-5-21-2127521184-1604012920-1887927527-72713, then your raw hex SID is
|
||||
*
|
||||
* 010500000000000515000000A065CF7E784B9B5FE77C8770091C0100
|
||||
*
|
||||
* This breaks down as follows:
|
||||
* 01 S-1
|
||||
* 05 (seven dashes, seven minus two = 5)
|
||||
* 000000000005 (5 = 0x000000000005, big-endian)
|
||||
* 15000000 (21 = 0x00000015, little-endian)
|
||||
* A065CF7E (2127521184 = 0x7ECF65A0, little-endian)
|
||||
* 784B9B5F (1604012920 = 0x5F9B4B78, little-endian)
|
||||
* E77C8770 (1887927527 = 0X70877CE7, little-endian)
|
||||
* 091C0100 (72713 = 0x00011c09, little-endian)
|
||||
*
|
||||
* S-1- version number (SID_REVISION)
|
||||
* -5- SECURITY_NT_AUTHORITY
|
||||
* -21- SECURITY_NT_NON_UNIQUE
|
||||
* -...-...-...- these identify the machine that issued the SID
|
||||
* 72713 unique user id on the machine
|
||||
* </pre>
|
||||
*
|
||||
* @param sid binary SID in byte array format
|
||||
* @return String version of the given sid
|
||||
* @since 1.3.1
|
||||
*/
|
||||
public static String convertBinarySidToString(byte[] sid) {
|
||||
// Add the 'S' prefix
|
||||
StringBuffer sidAsString = new StringBuffer("S-");
|
||||
|
||||
// bytes[0] : in the array is the version (must be 1 but might
|
||||
// change in the future)
|
||||
sidAsString.append(sid[0]).append('-');
|
||||
|
||||
// bytes[2..7] : the Authority
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int t = 2; t <= 7; t++) {
|
||||
String hexString = Integer.toHexString(sid[t] & 0xFF);
|
||||
sb.append(hexString);
|
||||
}
|
||||
sidAsString.append(Long.parseLong(sb.toString(), 16));
|
||||
|
||||
// bytes[1] : the sub authorities count
|
||||
int count = sid[1];
|
||||
|
||||
// bytes[8..end] : the sub authorities (these are Integers - notice
|
||||
// the endian)
|
||||
for (int i = 0; i < count; i++) {
|
||||
int currSubAuthOffset = i * 4;
|
||||
sb.setLength(0);
|
||||
sb.append(toHexString((byte) (sid[11 + currSubAuthOffset] & 0xFF)));
|
||||
sb.append(toHexString((byte) (sid[10 + currSubAuthOffset] & 0xFF)));
|
||||
sb.append(toHexString((byte) (sid[9 + currSubAuthOffset] & 0xFF)));
|
||||
sb.append(toHexString((byte) (sid[8 + currSubAuthOffset] & 0xFF)));
|
||||
|
||||
sidAsString.append('-').append(Long.parseLong(sb.toString(), 16));
|
||||
}
|
||||
|
||||
// That's it - we have the SID
|
||||
return sidAsString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String SID to its binary representation, according to the
|
||||
* algorithm described <a
|
||||
* href="http://blogs.msdn.com/oldnewthing/archive/2004/03/15/89753.aspx"
|
||||
* >here</a>.
|
||||
*
|
||||
* @param sid SID in readable format
|
||||
* @return Binary version of the given sid
|
||||
* @see LdapUtils#convertBinarySidToString(byte[])
|
||||
* @since 1.3.1
|
||||
*/
|
||||
public static byte[] convertStringSidToBinary(String string) {
|
||||
String[] parts = string.split("-");
|
||||
byte sidRevision = (byte) Integer.parseInt(parts[1]);
|
||||
int subAuthCount = parts.length - 3;
|
||||
|
||||
byte[] sid = new byte[] {sidRevision, (byte) subAuthCount};
|
||||
sid = ArrayUtils.addAll(sid, numberToBytes(parts[2], 6, true));
|
||||
for (int i = 0; i < subAuthCount; i++) {
|
||||
sid = ArrayUtils.addAll(sid, numberToBytes(parts[3 + i], 4, false));
|
||||
}
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given number to a binary representation of the specified
|
||||
* length and "endian-ness".
|
||||
*
|
||||
* @param number String with number to convert
|
||||
* @param length How long the resulting binary array should be
|
||||
* @param bigEndian <code>true</code> if big endian (5=0005), or
|
||||
* <code>false</code> if little endian (5=5000)
|
||||
* @return byte array containing the binary result in the given order
|
||||
*/
|
||||
static byte[] numberToBytes(String number, int length, boolean bigEndian) {
|
||||
BigInteger bi = new BigInteger(number);
|
||||
byte[] bytes = bi.toByteArray();
|
||||
int remaining = length - bytes.length;
|
||||
if (remaining < 0) {
|
||||
bytes = ArrayUtils.subarray(bytes, -remaining, bytes.length);
|
||||
} else {
|
||||
byte[] fill = new byte[remaining];
|
||||
bytes = ArrayUtils.addAll(fill, bytes);
|
||||
}
|
||||
if (!bigEndian) {
|
||||
ArrayUtils.reverse(bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte into its hexadecimal representation, padding with a
|
||||
* leading zero to get an even number of characters.
|
||||
*
|
||||
* @param b value to convert
|
||||
* @return hex string, possibly padded with a zero
|
||||
*/
|
||||
static String toHexString(final byte b) {
|
||||
String hexString = Integer.toHexString(b & 0xFF);
|
||||
if (hexString.length() % 2 != 0) {
|
||||
// Pad with 0
|
||||
hexString = "0" + hexString;
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array into its hexadecimal representation, padding each
|
||||
* with a leading zero to get an even number of characters.
|
||||
*
|
||||
* @param b values to convert
|
||||
* @return hex string, possibly with elements padded with a zero
|
||||
*/
|
||||
static String toHexString(final byte[] b) {
|
||||
StringBuffer sb = new StringBuffer("{");
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
sb.append(toHexString(b[i]));
|
||||
if (i < b.length - 1) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import javax.naming.directory.BasicAttributes;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.easymock.MockControl;
|
||||
import org.springframework.ldap.NoSuchAttributeException;
|
||||
|
||||
@@ -89,4 +90,125 @@ public class LdapUtilsTest extends TestCase {
|
||||
|
||||
handlerControl.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Example SID from "http://www.pcreview.co.uk/forums/thread-1458615.php".
|
||||
*/
|
||||
public void testConvertBinarySidToString() throws Exception {
|
||||
byte[] sid = { (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
|
||||
(byte) 0x15, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0xe9, (byte) 0x67, (byte) 0xbb, (byte) 0x98,
|
||||
(byte) 0xd6, (byte) 0xb7, (byte) 0xd7, (byte) 0xbf,
|
||||
(byte) 0x82, (byte) 0x05, (byte) 0x1e, (byte) 0x6c,
|
||||
(byte) 0x28, (byte) 0x06, (byte) 0x00, (byte) 0x00 };
|
||||
String result = LdapUtils.convertBinarySidToString(sid);
|
||||
assertEquals("S-1-5-21-2562418665-3218585558-1813906818-1576", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example SID from "http://blogs.msdn.com/oldnewthing/archive/2004/03/15/89753.aspx".
|
||||
*/
|
||||
public void testConvertAnotherBinarySidToString() throws Exception {
|
||||
byte[] sid = { (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
|
||||
(byte) 0x15, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0xa0, (byte) 0x65, (byte) 0xcf, (byte) 0x7e,
|
||||
(byte) 0x78, (byte) 0x4b, (byte) 0x9b, (byte) 0x5f,
|
||||
(byte) 0xe7, (byte) 0x7c, (byte) 0x87, (byte) 0x70,
|
||||
(byte) 0x09, (byte) 0x1c, (byte) 0x01, (byte) 0x00 };
|
||||
String result = LdapUtils.convertBinarySidToString(sid);
|
||||
assertEquals("S-1-5-21-2127521184-1604012920-1887927527-72713", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hand-crafted SID.
|
||||
*/
|
||||
public void testConvertHandCraftedBinarySidToString() throws Exception {
|
||||
byte[] sid = { (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
|
||||
(byte) 0x15, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
|
||||
String result = LdapUtils.convertBinarySidToString(sid);
|
||||
assertEquals("S-1-5-21-1-2-3-4", result);
|
||||
}
|
||||
|
||||
public void testSmallNumberToBytesBigEndian() throws Exception {
|
||||
byte[] result = LdapUtils.numberToBytes("5", 6, true);
|
||||
assertEquals(6, result.length);
|
||||
assertEquals(0, result[0]);
|
||||
assertEquals(0, result[1]);
|
||||
assertEquals(0, result[2]);
|
||||
assertEquals(0, result[3]);
|
||||
assertEquals(0, result[4]);
|
||||
assertEquals(5, result[5]);
|
||||
}
|
||||
|
||||
public void testLargeNumberToBytesBigEndian() throws Exception {
|
||||
byte[] result = LdapUtils.numberToBytes("1183728", 6, true);
|
||||
assertEquals(6, result.length);
|
||||
assertEquals(0, result[0]);
|
||||
assertEquals(0, result[1]);
|
||||
assertEquals(0, result[2]);
|
||||
assertEquals(18, result[3]);
|
||||
assertEquals(15, result[4]);
|
||||
assertEquals(-16, result[5]);
|
||||
}
|
||||
|
||||
public void testSmallNumberToBytesLittleEndian() throws Exception {
|
||||
byte[] result = LdapUtils.numberToBytes("21", 4, false);
|
||||
assertEquals(4, result.length);
|
||||
assertEquals(21, result[0]);
|
||||
assertEquals(0, result[1]);
|
||||
assertEquals(0, result[2]);
|
||||
assertEquals(0, result[3]);
|
||||
}
|
||||
|
||||
public void testLargeNumberToBytesLittleEndian() throws Exception {
|
||||
byte[] result = LdapUtils.numberToBytes("2127521184", 4, false);
|
||||
assertEquals(4, result.length);
|
||||
assertEquals(-96, result[0]);
|
||||
assertEquals(101, result[1]);
|
||||
assertEquals(-49, result[2]);
|
||||
assertEquals(126, result[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hand-crafted SID.
|
||||
*/
|
||||
public void testConvertHandCraftedStringSidToBinary() throws Exception {
|
||||
byte[] expectedSid = { (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
|
||||
(byte) 0x15, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
|
||||
byte[] result = LdapUtils.convertStringSidToBinary("S-1-5-21-1-2-3-4");
|
||||
assertTrue("incorrect length of array", ArrayUtils.isSameLength(expectedSid, result));
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
assertEquals("i=" + i + ",", expectedSid[i], result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example SID from "http://www.pcreview.co.uk/forums/thread-1458615.php".
|
||||
*/
|
||||
public void testConvertStringSidToBinary() throws Exception {
|
||||
byte[] expectedSid = { (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
|
||||
(byte) 0x15, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0xe9, (byte) 0x67, (byte) 0xbb, (byte) 0x98,
|
||||
(byte) 0xd6, (byte) 0xb7, (byte) 0xd7, (byte) 0xbf,
|
||||
(byte) 0x82, (byte) 0x05, (byte) 0x1e, (byte) 0x6c,
|
||||
(byte) 0x28, (byte) 0x06, (byte) 0x00, (byte) 0x00 };
|
||||
byte[] result = LdapUtils.convertStringSidToBinary("S-1-5-21-2562418665-3218585558-1813906818-1576");
|
||||
assertTrue("incorrect length of array", ArrayUtils.isSameLength(expectedSid, result));
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
assertEquals("i=" + i + ",", expectedSid[i], result[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user