diff --git a/dev-tools/checkstyle_suppressions.xml b/dev-tools/checkstyle_suppressions.xml index 3e774029d18..4748436a849 100644 --- a/dev-tools/checkstyle_suppressions.xml +++ b/dev-tools/checkstyle_suppressions.xml @@ -13,6 +13,7 @@ + diff --git a/plugin/security/build.gradle b/plugin/security/build.gradle index 4dfe7b27d13..12533a389b5 100644 --- a/plugin/security/build.gradle +++ b/plugin/security/build.gradle @@ -84,6 +84,11 @@ dependencyLicenses { mapping from: /http.*/, to: 'httpclient' } +licenseHeaders { + // This class was sourced from apache directory studio for some microsoft-specific logic + excludes << 'org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtil.java' +} + forbiddenPatterns { exclude '**/*.key' exclude '**/*.p12' diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java index f43e1768267..8e009154cad 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryGroupsResolver.java @@ -30,7 +30,7 @@ import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.OBJE import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.search; import static org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.searchForEntry; import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING; - +import static org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySIDUtil.convertToString; class ActiveDirectoryGroupsResolver implements GroupsResolver { @@ -84,7 +84,7 @@ class ActiveDirectoryGroupsResolver implements GroupsResolver { } else { final byte[][] tokenGroupSIDBytes = entry.getAttributeValueByteArrays(TOKEN_GROUPS); List orFilters = Arrays.stream(tokenGroupSIDBytes) - .map((sidBytes) -> Filter.createEqualityFilter("objectSid", binarySidToStringSid(sidBytes))) + .map((sidBytes) -> Filter.createEqualityFilter("objectSid", convertToString(sidBytes))) .collect(Collectors.toList()); listener.onResponse(Filter.createORFilter(orFilters)); } @@ -92,46 +92,4 @@ class ActiveDirectoryGroupsResolver implements GroupsResolver { TOKEN_GROUPS); } - /** - * To better understand what the sid is and how its string representation looks like, see - * http://blogs.msdn.com/b/alextch/archive/2007/06/18/sample-java-application-that-retrieves-group-membership-of-an-active-directory - * -user-account.aspx - * - * @param SID byte encoded security ID - */ - private static String binarySidToStringSid(byte[] SID) { - String strSID; - - //convert the SID into string format - - long version; - long authority; - long count; - long rid; - - strSID = "S"; - version = SID[0]; - strSID = strSID + "-" + Long.toString(version); - authority = SID[4]; - - for (int i = 0; i < 4; i++) { - authority <<= 8; - authority += SID[4 + i] & 0xFF; - } - - strSID = strSID + "-" + Long.toString(authority); - count = SID[2]; - count <<= 8; - count += SID[1] & 0xFF; - for (int j = 0; j < count; j++) { - rid = SID[11 + (j * 4)] & 0xFF; - for (int k = 1; k < 4; k++) { - rid <<= 8; - rid += SID[11 - k + (j * 4)] & 0xFF; - } - strSID = strSID + "-" + Long.toString(rid); - } - return strSID; - } - } diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtil.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtil.java new file mode 100644 index 00000000000..8cb6e128d17 --- /dev/null +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtil.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* + * This code sourced from:http://svn.apache.org/repos/asf/directory/studio/tags/2.0.0.v20170904-M13/plugins/valueeditors/src/main/java/org/apache/directory/studio/valueeditors/msad/InPlaceMsAdObjectSidValueEditor.java + */ + +package org.elasticsearch.xpack.security.authc.ldap; + +import org.apache.commons.codec.binary.Hex; + +class ActiveDirectorySIDUtil { + + static 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 ) ) + { + throw new IllegalArgumentException("Invalid SID"); + } + + 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 ) ) + { + throw new IllegalArgumentException("Invalid SID"); + } + + // 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(); + } +} diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtilTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtilTests.java new file mode 100644 index 00000000000..a3bda896bd3 --- /dev/null +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySIDUtilTests.java @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.authc.ldap; + +import org.apache.commons.codec.binary.Hex; +import org.elasticsearch.test.ESTestCase; + +import static org.hamcrest.Matchers.equalTo; + +public class ActiveDirectorySIDUtilTests extends ESTestCase { + + private static final String USER_SID_HEX ="01050000000000051500000050bd51b583ef8ebc4c75521ae9030000"; + private static final String USER_STRING_SID = "S-1-5-21-3042032976-3163484035-441611596-1001"; + + public void testSidConversion() throws Exception { + assertThat(USER_STRING_SID, equalTo(ActiveDirectorySIDUtil.convertToString(Hex.decodeHex(USER_SID_HEX.toCharArray())))); + } +}