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