View Javadoc
1   /*
2    * Copyright 2013–2019 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   * <p>
27   *
28   * @version $Id: Sid.java 336 2019-11-22 11:45:45Z michael-o $
29   */
30  public class Sid {
31  
32  	public static final Sidealm/Sid.html#Sid">Sid NULL_SID = new Sid(new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00,
33  			(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
34  			(byte) 0x00, (byte) 0x00, (byte) 0x00 });
35  
36  	public static final SidSid.html#Sid">Sid ANONYMOUS_SID = new Sid(new byte[] { (byte) 0x01, (byte) 0x01,
37  			(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
38  			(byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00 });
39  
40  	private byte[] bytes;
41  
42  	private int revision;
43  	private int subAuthorityCount;
44  	private byte[] identifierAuthority;
45  	private long[] subAuthorities;
46  
47  	private String sidString;
48  
49  	public Sid(byte[] sid) {
50  		if (sid == null)
51  			throw new NullPointerException("SID cannot be null");
52  
53  		if (sid.length < 12)
54  			throw new IllegalArgumentException(
55  					"SID must be at least 12 bytes long but is " + sid.length);
56  
57  		this.bytes = Arrays.copyOf(sid, sid.length);
58  
59  		ByteBuffer bb = ByteBuffer.wrap(this.bytes);
60  		bb.order(ByteOrder.LITTLE_ENDIAN);
61  
62  		// Always 0x01
63  		this.revision = bb.get() & 0xFF;
64  		if (this.revision != 0x01)
65  			throw new IllegalArgumentException(
66  					"SID revision must be 1 but is " + this.revision);
67  
68  		// At most 15 subauthorities
69  		this.subAuthorityCount = bb.get() & 0xFF;
70  		if (this.subAuthorityCount > 15)
71  			throw new IllegalArgumentException(
72  					"SID sub authority count must be at most 15 but is " + this.subAuthorityCount);
73  
74  		this.identifierAuthority = new byte[6];
75  		bb.get(this.identifierAuthority);
76  
77  		StringBuilder sidStringBuilder = new StringBuilder("S");
78  
79  		sidStringBuilder.append('-').append(this.revision);
80  
81  		ByteBuffer iaBb = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
82  		iaBb.position(2);
83  		iaBb.put(this.identifierAuthority);
84  		iaBb.flip();
85  
86  		sidStringBuilder.append('-').append(iaBb.getLong());
87  
88  		this.subAuthorities = new long[this.subAuthorityCount];
89  		for (byte b = 0; b < this.subAuthorityCount; b++) {
90  			this.subAuthorities[b] = bb.getInt() & 0xffffffffL;
91  
92  			sidStringBuilder.append('-').append(this.subAuthorities[b]);
93  		}
94  
95  		this.sidString = sidStringBuilder.toString();
96  	}
97  
98  	public byte[] getBytes() {
99  		return Arrays.copyOf(bytes, bytes.length);
100 	}
101 
102 	@Override
103 	public boolean equals(Object obj) {
104 		if (obj == null)
105 			return false;
106 
107 		if (!(obj instanceof Sid))
108 			return false;
109 
110 		Sid that = (Sid) obj;
111 
112 		if (this == that)
113 			return true;
114 
115 		return Arrays.equals(this.bytes, that.bytes);
116 	}
117 
118 	@Override
119 	public int hashCode() {
120 		return Arrays.hashCode(this.bytes);
121 	}
122 
123 	@Override
124 	public String toString() {
125 		return sidString;
126 	}
127 
128 }