View Javadoc
1   /*
2    * Copyright 2013–2023 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.security.Principal;
19  import java.util.Arrays;
20  import java.util.Collections;
21  import java.util.Enumeration;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.catalina.TomcatPrincipal;
26  import org.ietf.jgss.GSSCredential;
27  import org.ietf.jgss.GSSName;
28  
29  /**
30   * Represents a principal from Active Directory with a list of roles.
31   * <p>
32   * An Active Directory principal is comprised of the following items:
33   * <ul>
34   * <li>the GSS name,</li>
35   * <li>the security identifier (SID),</li>
36   * <li>an optional GSS credential for credential delegation (impersonation),</li>
37   * <li>an array of security groups the user has been assigned to, stored according to the
38   * role format configured in the realm,</li>
39   * <li>and a map with additional attributes which are either a {@code String}, {@code byte[]} or a
40   * {@code List} of either one.</li>
41   * </ul>
42   */
43  public class ActiveDirectoryPrincipal implements TomcatPrincipal {
44  
45  	private final GSSName gssName;
46  	private final Sid sid;
47  	private final transient GSSCredential gssCredential;
48  	private final String[] roles;
49  	private final Map<String, Object> additionalAttributes;
50  
51  	/**
52  	 * Constructs a new principal for the given parameters.
53  	 */
54  	public ActiveDirectoryPrincipal(GSSName gssName, Sid sid, GSSCredential gssCredential) {
55  		this(gssName, sid, null, gssCredential, null);
56  	}
57  
58  	/**
59  	 * Constructs a new principal for the given parameters.
60  	 */
61  	public ActiveDirectoryPrincipal(GSSName gssName, Sid sid, List<String> roles,
62  			GSSCredential gssCredential, Map<String, Object> additionalAttributes) {
63  		this.gssName = gssName;
64  		this.sid = sid;
65  		if (roles == null || roles.isEmpty())
66  			this.roles = new String[0];
67  		else {
68  			this.roles = roles.toArray(new String[0]);
69  			Arrays.sort(this.roles);
70  		}
71  		this.gssCredential = gssCredential;
72  		if (additionalAttributes == null || additionalAttributes.isEmpty())
73  			this.additionalAttributes = Collections.emptyMap();
74  		else
75  			this.additionalAttributes = Collections.unmodifiableMap(additionalAttributes);
76  	}
77  
78  	@Override
79  	public Principal getUserPrincipal() {
80  		return this;
81  	}
82  
83  	@Override
84  	public String getName() {
85  		return gssName.toString();
86  	}
87  
88  	/**
89  	 * Returns the underlying GSS name.
90  	 *
91  	 * @return the underlying GSS name
92  	 */
93  	public GSSName getGssName() {
94  		return gssName;
95  	}
96  
97  	/**
98  	 * Returns the security identifier (SID) of the principal.
99  	 *
100 	 * @return the security identifier
101 	 */
102 	public Sid getSid() {
103 		return sid;
104 	}
105 
106 	@Override
107 	public GSSCredential getGssCredential() {
108 		return gssCredential;
109 	}
110 
111 	/**
112 	 * Grants access if supplied role is associated with this principal.
113 	 *
114 	 * @param role
115 	 *            the role to check
116 	 * @return true if principal is associated with the role, else false
117 	 */
118 	public boolean hasRole(String role) {
119 		if ("*".equals(role)) // Special 2.4 role meaning everyone
120 			return true;
121 		if (role == null)
122 			return false;
123 		return Arrays.binarySearch(roles, role) >= 0;
124 	}
125 
126 	/**
127 	 * Returns the sorted roles of the given principal.
128 	 *
129 	 * @return a sorted read-only view of the roles
130 	 */
131 	public String[] getRoles() {
132 		return Arrays.copyOf(roles, roles.length);
133 	}
134 
135 	@Override
136 	public Object getAttribute(String name) {
137 		return additionalAttributes.get(name);
138 	}
139 
140 	@Override
141 	public Enumeration<String> getAttributeNames() {
142 		return Collections.enumeration(additionalAttributes.keySet());
143 	}
144 
145 	/**
146 	 * Holds additional attributes for a given principal which may be stored in Active Directory.
147 	 *
148 	 * @return a read-only view of the additional attributes
149 	 */
150 	public Map<String, Object> getAdditionalAttributes() {
151 		return additionalAttributes;
152 	}
153 
154 	@Override
155 	public boolean equals(Object obj) {
156 		if (obj == null)
157 			return false;
158 
159 		if (!(obj instanceof ActiveDirectoryPrincipal))
160 			return false;
161 
162 		ActiveDirectoryPrincipal other = (ActiveDirectoryPrincipal) obj;
163 
164 		return gssName.equals((Object) other.gssName);
165 	}
166 
167 	@Override
168 	public int hashCode() {
169 		return gssName.hashCode();
170 	}
171 
172 	@Override
173 	public String toString() {
174 		return gssName.toString();
175 	}
176 
177 	@Override
178 	public void logout() throws Exception {
179 		if (gssCredential != null) {
180 			gssCredential.dispose();
181 		}
182 	}
183 
184 }