2011-08-19 113 views
2

我正在用Java编写一个使用Spring-LDAP的程序。我需要实现一个方法,它应该通过SID搜索用户。出于这个原因,我使用了像"&((objectClass=User)(objectSid="+sid+"))"这样的过滤器。搜索不适用于字符串格式的sid,如"S-1-12-345677-5676743-223344-..."如何在Java中将SID转换为字符串,反之亦然?

使用Apache Directory Studio,我可以使用如下过滤器成功查询我的AD LDAP数据库:(objectSid=\ff\01\03\04\1a\2b\...)。这是十六进制格式的objectSid。

现在,如何将Java中的SID从String转换为十六进制,反之亦然?

回答

5

有一个在Advapi32UtilconvertSidToStringSidconvertStringSidToSid方法。

我不确定这是否是您需要的确切格式,但希望能让您更接近。

这里是一个blog post,它描述了可能有用的SID格式。

+0

完全正确,感谢名单!我以另一种方式做了它,但你对convertSidToStringSid和convertStringSidToSid的提示真的很有帮助!博客也很有帮助。 – mtm

2

由HO1建议(使用Advapi32Util)类的解决方案具有两个限制:

  1. 它needes的JNA库。
  2. 它只适用于在Windows平台上运行,因为它使用Windows-API。

因此,我写了一个纯Java的类,没有外部依赖关系,可以在所有平台上工作。这个类可以将安全标识符从二进制转换为文本表示,反之亦然。

如果您使用Spring-LDAP,也可以使用LdapUtils类提供的方法,但是这些方法不会对SID的格式进行任何检查,因此可能会产生不正确的结果或意外的异常。从InPlaceMsAdObjectSidValueEditor.java

import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 

public class SidConverter { 

    private final static int MASK_8_BIT = 0xff; 
    private final static long MASK_32_BIT = 0xffffffffL; 
    private final static long MASK_48_BIT = 0xffffffffffffL; 

    public static String bytesToString(byte[] bytes) { 
     if (bytes.length < 8) { 
      throw new IllegalArgumentException(
        "Binary SID representation must have at least 8 bytes but passed byte array has only " 
          + bytes.length + " bytes."); 
     } 
     // The revision number is an unsigned 8-bit unsigned integer. 
     int revision = bytes[0] & MASK_8_BIT; 
     // The number of sub-authority parts is specified as an 8-bit unsigned 
     // integer. 
     int numberOfSubAuthorityParts = bytes[1] & MASK_8_BIT; 
     if (bytes.length != 8 + numberOfSubAuthorityParts * 4) { 
      throw new IllegalArgumentException(
        "According to byte 1 of the SID it total length should be " 
          + (8 + 4 * numberOfSubAuthorityParts) 
          + " bytes, however its actual length is " 
          + bytes.length + " bytes."); 
     } 
     // The authority is a 48-bit unsigned integer stored in big-endian 
     // format. 
     long authority = ByteBuffer.wrap(bytes).getLong() & MASK_48_BIT; 
     // The sub-authority consists of up to 255 32-bit unsigned integers in 
     // little-endian format. The number of integers is specified by 
     // numberOfSubAuthorityParts. 
     int[] subAuthority = new int[numberOfSubAuthorityParts]; 
     ByteBuffer.wrap(bytes, 8, bytes.length - 8) 
       .order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put(subAuthority); 
     StringBuilder sb = new StringBuilder(); 
     sb.append("S-"); 
     sb.append(revision); 
     sb.append("-"); 
     sb.append(authority); 
     for (int subAuthorityPart : subAuthority) { 
      sb.append("-"); 
      sb.append(subAuthorityPart & MASK_32_BIT); 
     } 
     return sb.toString(); 
    } 

    public static byte[] stringToBytes(String sid) { 
     if (!sid.startsWith("S-") && !sid.startsWith("s-")) { 
      throw new IllegalArgumentException("Invalid SID \"" + sid 
        + "\": A valid SID must start with \"S-\"."); 
     } 
     String[] parts = sid.split("-"); 
     if (parts.length < 3) { 
      throw new IllegalArgumentException("Invalid SID \"" + sid 
        + "\": A valid SID must have at least two dashes."); 
     } 
     if (parts.length > MASK_8_BIT + 3) { 
      throw new IllegalArgumentException("Invalid SID \"" + sid 
        + "\": A valid SID must not have more than 257 dashes."); 
     } 
     int revision; 
     try { 
      revision = Integer.parseInt(parts[1]); 
     } catch (NumberFormatException e) { 
      throw new IllegalArgumentException(
        "Invalid revision part in SID \"" 
          + sid 
          + "\": The revision must be an integer number between 0 and 255."); 
     } 
     if (revision < 0 || revision > MASK_8_BIT) { 
      throw new IllegalArgumentException(
        "Invalid revision part in SID \"" 
          + sid 
          + "\": The revision must be an integer number between 0 and 255."); 
     } 
     int numberOfSubAuthorityParts = parts.length - 3; 
     long authority; 
     try { 
      authority = Long.parseLong(parts[2]); 
     } catch (NumberFormatException e) { 
      throw new IllegalArgumentException(
        "Invalid authority part in SID \"" 
          + sid 
          + "\": The authority must be an integer number between 0 and 281474976710655."); 
     } 
     if (authority < 0 || authority > MASK_48_BIT) { 
      throw new IllegalArgumentException(
        "Invalid authority part in SID \"" 
          + sid 
          + "\": The authority must be an integer number between 0 and 281474976710655."); 
     } 
     int[] subAuthority = new int[numberOfSubAuthorityParts]; 
     for (int i = 0; i < numberOfSubAuthorityParts; i++) { 
      long subAuthorityPart; 
      try { 
       subAuthorityPart = Long.parseLong(parts[3 + i]); 
      } catch (NumberFormatException e) { 
       throw new IllegalArgumentException(
         "Invalid sub-authority part in SID \"" 
           + sid 
           + "\": The sub-authority parts must be integer numbers between 0 and 4294967295."); 
      } 
      if (subAuthorityPart < 0 || subAuthorityPart > MASK_32_BIT) { 
       throw new IllegalArgumentException(
         "Invalid sub-authority part in SID \"" 
           + sid 
           + "\": The sub-authority parts must be integer numbers between 0 and 4294967295."); 
      } 
      subAuthority[i] = (int) subAuthorityPart; 
     } 
     byte[] bytes = new byte[8 + numberOfSubAuthorityParts * 4]; 
     // We have to write the authority first, otherwise it would overwrite 
     // the revision and length bytes. 
     ByteBuffer.wrap(bytes).putLong(authority); 
     bytes[0] = (byte) revision; 
     bytes[1] = (byte) numberOfSubAuthorityParts; 
     ByteBuffer.wrap(bytes, 8, bytes.length - 8) 
       .order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put(subAuthority); 
     return bytes; 
    } 

} 
+0

特别感谢您指出LdapUtils解决方案。错过了那个:) – Apokralipsa

1

使用convertToString:

protected String convertToString(byte[] bytes) 
{ 
    /* 
    * The binary data structure, from http://msdn.microsoft.com/en-us/library/cc230371(PROT.10).aspx: 
    * byte[0] - Revision (1 byte): An 8-bit unsigned integer that specifies the revision level of the SID structure. This value MUST be set to 0x01. 
    * byte[1] - SubAuthorityCount (1 byte): An 8-bit unsigned integer that specifies the number of elements in the SubAuthority array. The maximum number of elements allowed is 15. 
    * byte[2-7] - IdentifierAuthority (6 bytes): A SID_IDENTIFIER_AUTHORITY structure that contains information, which indicates the authority under which the SID was created. It describes the entity that created the SID and manages the account. 
    *    Six element arrays of 8-bit unsigned integers that specify the top-level authority 
    *    big-endian! 
    * and then - SubAuthority (variable): A variable length array of unsigned 32-bit integers that uniquely identifies a principal relative to the IdentifierAuthority. Its length is determined by SubAuthorityCount. 
    *    little-endian! 
    */ 

    if (bytes == null || bytes.length < 8) 
    { 
     return Messages.getString("InPlaceMsAdObjectSidValueEditor.InvalidSid"); //$NON-NLS-1$ 
    } 

    char[] hex = Hex.encodeHex(bytes); 
    StringBuffer sb = new StringBuffer(); 

    // start with 'S' 
    sb.append('S'); 

    // revision 
    int revision = Integer.parseInt(new String(hex, 0, 2), 16); 
    sb.append('-'); 
    sb.append(revision); 

    // get count 
    int count = Integer.parseInt(new String(hex, 2, 2), 16); 

    // check length 
    if (bytes.length != (8 + count * 4)) 
    { 
     return Messages.getString("InPlaceMsAdObjectSidValueEditor.InvalidSid"); //$NON-NLS-1$ 
    } 

    // get authority, big-endian 
    long authority = Long.parseLong(new String(hex, 4, 12), 16); 
    sb.append('-'); 
    sb.append(authority); 

    // sub-authorities, little-endian 
    for (int i = 0; i < count; i++) 
    { 
     StringBuffer rid = new StringBuffer(); 
     for (int k = 3; k >= 0; k--) 
     { 
      rid.append(hex[16 + (i * 8) + (k * 2)]); 
      rid.append(hex[16 + (i * 8) + (k * 2) + 1]); 
     } 

     long subAuthority = Long.parseLong(rid.toString(), 16); 
     sb.append('-'); 
     sb.append(subAuthority); 
    } 

    return sb.toString(); 
} 

(从Apache目录工作室)

0

例无JNA

这里有一个转换的SID不使用JNA一些不错的紧凑的代码。它甚至通过返回NULL,EMPTY或一个零长度的数组构建一些“错误检查”,如果事情不是很正确的话。

对于SID为String:

/** 
* Converts Windows SID to a String. NULL input returns NULL. 
* Invalid byte array returns EMPTY. 
* @param sid SID as byte array. 
* @return SID as String. 
*/ 
public static String convertSidToStr(byte[] sid) { 
    if (sid==null) return null; 
    if (sid.length<8 || sid.length % 4 != 0) return ""; 
    StringBuilder sb = new StringBuilder(); 
    sb.append("S-").append(sid[0]); 
    int c = sid[1]; // Init with Subauthority Count. 
    ByteBuffer bb = ByteBuffer.wrap(sid); 
    // bb.order(ByteOrder.BIG_ENDIAN); // Not needed, default big endian. 
    sb.append("-").append((long)bb.getLong() & 0XFFFFFFFFFFFFL); 
    bb.order(ByteOrder.LITTLE_ENDIAN); // Now switch. 
    for (int i=0; i<c; i++) { // Create Subauthorities. 
     sb.append("-").append((long)bb.getInt() & 0xFFFFFFFFL); 
    }   
    return sb.toString();  
} 

对于字符串SID:

/** 
* Converts Windows SID String to byte array. NULL input returns NULL. 
* Invalid String returns zero-length byte array. 
* @param sid SID as String. 
* @return SID as byte array. 
*/ 
public static byte[] convertStrToSid(String sid) { 
    if (sid==null) return null; 
    if (!sid.matches("^[sS]-\\d-\\d{1,13})" 
      + "(?:-\\d{1,10})*$")) return new byte[0]; 
    String[] ss = sid.split("-"); 
    int c=ss.length-3; // Init with Subauthority Count. 
    byte[] b=new byte[2+6+(c*4)]; 
    ByteBuffer bb = ByteBuffer.wrap(b); 
    // bb.order(ByteOrder.BIG_ENDIAN); // Not needed, default big endian. 
    bb.putLong(Long.parseLong(ss[2])); 
    // Overlay bytes 0 and 1 with Revision and Identifier Authority. 
    b[0]=(byte)Short.parseShort(ss[1]); 
    b[1]=(byte)c; 
    bb.order(ByteOrder.LITTLE_ENDIAN); // Now switch. 
    for (int i=0; i<c; i++) { // Create Subauthorities. 
     bb.putInt((int)Long.parseLong(ss[i+3])); 
    } 
    return b;  
} 

仅供参考,请参阅的TechNet的Security Identifier Structure

1

http://miromannino.com/blog/convert-a-sid-to-string-with-java/

public static String convertSidToStringSid(byte[] sid) { 
    int offset, size; 

    // sid[0] is the Revision, we allow only version 1, because it's the 
    // only that exists right now. 
    if (sid[0] != 1) 
     throw new IllegalArgumentException("SID revision must be 1"); 

    StringBuilder stringSidBuilder = new StringBuilder("S-1-"); 

    // The next byte specifies the numbers of sub authorities (number of 
    // dashes minus two) 
    int subAuthorityCount = sid[1] & 0xFF; 

    // IdentifierAuthority (6 bytes starting from the second) (big endian) 
    long identifierAuthority = 0; 
    offset = 2; 
    size = 6; 
    for (int i = 0; i < size; i++) { 
     identifierAuthority |= (long) (sid[offset + i] & 0xFF) << (8 * (size - 1 - i)); 
     // The & 0xFF is necessary because byte is signed in Java 
    } 
    if (identifierAuthority < Math.pow(2, 32)) { 
     stringSidBuilder.append(Long.toString(identifierAuthority)); 
    } else { 
     stringSidBuilder.append("0x").append(
       Long.toHexString(identifierAuthority).toUpperCase()); 
    } 

    // Iterate all the SubAuthority (little-endian) 
    offset = 8; 
    size = 4; // 32-bits (4 bytes) for each SubAuthority 
    for (int i = 0; i < subAuthorityCount; i++, offset += size) { 
     long subAuthority = 0; 
     for (int j = 0; j < size; j++) { 
      subAuthority |= (long) (sid[offset + j] & 0xFF) << (8 * j); 
      // The & 0xFF is necessary because byte is signed in Java 
     } 
     stringSidBuilder.append("-").append(subAuthority); 
    } 

    return stringSidBuilder.toString(); 
} 
相关问题