View Javadoc
1   /*
2    * Copyright 2013–2024 Michael Osipov
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.michaelo.tomcat.realm;
17  
18  import java.nio.ByteBuffer;
19  import java.nio.ByteOrder;
20  import java.util.Arrays;
21  
22  /**
23   * An immutable class representing a
24   * <a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/f992ad60-0fe4-4b87-9fed-beb478836861">security identifier</a>
25   * from Active Directory.
26   */
27  public class Sid {
28  
29  	public static final Sid NULL_SID = new Sid(new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00,
30  			(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
31  			(byte) 0x00, (byte) 0x00, (byte) 0x00 });
32  
33  	public static final Sid ANONYMOUS_SID = new Sid(new byte[] { (byte) 0x01, (byte) 0x01,
34  			(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
35  			(byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00 });
36  
37  	private byte[] bytes;
38  
39  	private int revision;
40  	private int subAuthorityCount;
41  	private byte[] identifierAuthority;
42  	private long[] subAuthorities;
43  
44  	private String sidString;
45  
46  	public Sid(byte[] sidBytes) {
47  		if (sidBytes == null)
48  			throw new NullPointerException("sidBytes cannot be null");
49  		if (sidBytes.length < 12)
50  			throw new IllegalArgumentException(
51  				"SID must be at least 12 bytes long but is " + sidBytes.length);
52  
53  		ByteBuffer buf = ByteBuffer.wrap(sidBytes);
54  		buf.order(ByteOrder.LITTLE_ENDIAN);
55  
56  		// Always 0x01
57  		this.revision = buf.get() & 0xFF;
58  		if (this.revision != 0x01)
59  			throw new IllegalArgumentException(
60  					"SID revision must be 1 but is " + this.revision);
61  
62  		// At most 15 subauthorities
63  		this.subAuthorityCount = buf.get() & 0xFF;
64  		if (this.subAuthorityCount > 15)
65  			throw new IllegalArgumentException(
66  					"SID subauthority count must be at most 15 but is " + this.subAuthorityCount);
67  
68  		this.identifierAuthority = new byte[6];
69  		buf.get(this.identifierAuthority);
70  
71  		StringBuilder sidStringBuilder = new StringBuilder("S");
72  
73  		sidStringBuilder.append('-').append(this.revision);
74  
75  		ByteBuffer iaBuf = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
76  		iaBuf.position(2);
77  		iaBuf.put(this.identifierAuthority);
78  		iaBuf.flip();
79  
80  		sidStringBuilder.append('-').append(iaBuf.getLong());
81  
82  		this.subAuthorities = new long[this.subAuthorityCount];
83  		for (byte b = 0; b < this.subAuthorityCount; b++) {
84  			this.subAuthorities[b] = buf.getInt() & 0xffffffffL;
85  
86  			sidStringBuilder.append('-').append(this.subAuthorities[b]);
87  		}
88  
89  		this.bytes = Arrays.copyOf(sidBytes, sidBytes.length);
90  		this.sidString = sidStringBuilder.toString();
91  	}
92  
93  	public byte[] getBytes() {
94  		return Arrays.copyOf(bytes, bytes.length);
95  	}
96  
97  	@Override
98  	public boolean equals(Object obj) {
99  		if (obj == null)
100 			return false;
101 
102 		if (!(obj instanceof Sid))
103 			return false;
104 
105 		Sid that = (Sid) obj;
106 
107 		if (this == that)
108 			return true;
109 
110 		return Arrays.equals(this.bytes, that.bytes);
111 	}
112 
113 	@Override
114 	public int hashCode() {
115 		return Arrays.hashCode(this.bytes);
116 	}
117 
118 	@Override
119 	public String toString() {
120 		return sidString;
121 	}
122 
123 }