Как преобразовать SID в строку и наоборот в Java? - PullRequest
2 голосов
/ 19 августа 2011

Я пишу программу на Java, используя Spring-LDAP. Мне нужно реализовать метод, который должен искать пользователя по SID. По этой причине я использую фильтр типа "&((objectClass=User)(objectSid="+sid+"))". Поиск не работает с sid в формате String, например "S-1-12-345677-5676743-223344-...".

Используя Apache Directory Studio, я могу запросить свою базу данных AD LDAP регулярно, используя фильтр типа: (objectSid=\ff\01\03\04\1a\2b\...). Вот objectSid в шестнадцатеричном формате.

Теперь, как перевести SID из String в шестнадцатеричный и наоборот в программе на Java?

Ответы [ 5 ]

5 голосов
/ 19 августа 2011

В классе Advapi32Util есть методы convertSidToStringSid и convertStringSidToSid.

Я не уверен, что это будут именно те форматы, которые вам нужны, но, надеюсь, приблизит вас.

А вот сообщение в блоге , в котором описывается формат SID, который может оказаться полезным.

2 голосов
/ 17 февраля 2014

Решение, предложенное классом ho1 (с использованием Advapi32Util), имеет два ограничения:

  1. Это требует библиотеки JNA.
  2. Оно работает только при работе на платформе Windows, посколькуон использует Windows-API.

Поэтому я написал класс, который является чистой Java, не имеет внешних зависимостей и будет работать на всех платформах.Этот класс может преобразовывать идентификаторы безопасности из их двоичного файла в их текстовое представление и наоборот.

Если вы используете Spring-LDAP, вы также можете использовать методы, предоставляемые классом LdapUtils, однако эти методы не выполняются.любые проверки формата SID и, следовательно, могут привести к неправильным результатам или неожиданным исключениям.

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;
    }

}
1 голос
/ 20 июня 2017

С 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();
}
1 голос
/ 08 января 2017

Пример без JNA

Вот хороший компактный код для преобразования SID без использования JNA.В него даже встроена некоторая «проверка ошибок», возвращающая NULL, EMPTY или массив нулевой длины, если что-то не так.Для строки в 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 .

1 голос
/ 11 июля 2014

использовать convertToString из InPlaceMsAdObjectSidValueEditor.java :

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 Directory Studio)

...