View Javadoc
1   /*
2    * MIT License
3    *
4    * Copyright (c) 2010-2024 The Waffle Project Contributors: https://github.com/Waffle/waffle/graphs/contributors
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy
7    * of this software and associated documentation files (the "Software"), to deal
8    * in the Software without restriction, including without limitation the rights
9    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10   * copies of the Software, and to permit persons to whom the Software is
11   * furnished to do so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  package waffle.servlet;
25  
26  import java.io.Serializable;
27  import java.security.Principal;
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  import waffle.windows.auth.IWindowsAccount;
34  import waffle.windows.auth.IWindowsIdentity;
35  import waffle.windows.auth.PrincipalFormat;
36  import waffle.windows.auth.WindowsAccount;
37  
38  /**
39   * A Windows Principal.
40   */
41  public class WindowsPrincipal implements Principal, Serializable {
42  
43      /** The Constant serialVersionUID. */
44      private static final long serialVersionUID = 1L;
45  
46      /** The fqn. */
47      private final String fqn;
48  
49      /** The sid. */
50      private final byte[] sid;
51  
52      /** The sid string. */
53      private final String sidString;
54  
55      /** The roles. */
56      private final List<String> roles;
57  
58      /** The identity. */
59      private transient IWindowsIdentity identity;
60  
61      /** The groups. */
62      private final Map<String, WindowsAccount> groups;
63  
64      /**
65       * A windows principal.
66       *
67       * @param windowsIdentity
68       *            Windows identity.
69       */
70      public WindowsPrincipal(final IWindowsIdentity windowsIdentity) {
71          this(windowsIdentity, PrincipalFormat.FQN, PrincipalFormat.FQN);
72      }
73  
74      /**
75       * A windows principal.
76       *
77       * @param windowsIdentity
78       *            Windows identity.
79       * @param principalFormat
80       *            Principal format.
81       * @param roleFormat
82       *            Role format.
83       */
84      public WindowsPrincipal(final IWindowsIdentity windowsIdentity, final PrincipalFormat principalFormat,
85              final PrincipalFormat roleFormat) {
86          this.identity = windowsIdentity;
87          this.fqn = windowsIdentity.getFqn();
88          this.sid = windowsIdentity.getSid();
89          this.sidString = windowsIdentity.getSidString();
90          this.groups = WindowsPrincipal.getGroups(windowsIdentity.getGroups());
91          this.roles = WindowsPrincipal.getRoles(windowsIdentity, principalFormat, roleFormat);
92      }
93  
94      /**
95       * Gets the roles.
96       *
97       * @param windowsIdentity
98       *            the windows identity
99       * @param principalFormat
100      *            the principal format
101      * @param roleFormat
102      *            the role format
103      *
104      * @return the roles
105      */
106     private static List<String> getRoles(final IWindowsIdentity windowsIdentity, final PrincipalFormat principalFormat,
107             final PrincipalFormat roleFormat) {
108         final List<String> roles = new ArrayList<>();
109         roles.addAll(WindowsPrincipal.getPrincipalNames(windowsIdentity, principalFormat));
110         for (final IWindowsAccount group : windowsIdentity.getGroups()) {
111             roles.addAll(WindowsPrincipal.getRoleNames(group, roleFormat));
112         }
113         return roles;
114     }
115 
116     /**
117      * Gets the groups.
118      *
119      * @param groups
120      *            the groups
121      *
122      * @return the groups
123      */
124     private static Map<String, WindowsAccount> getGroups(final IWindowsAccount[] groups) {
125         final Map<String, WindowsAccount> groupMap = new HashMap<>();
126         for (final IWindowsAccount group : groups) {
127             groupMap.put(group.getFqn(), new WindowsAccount(group));
128         }
129         return groupMap;
130     }
131 
132     /**
133      * Byte representation of the SID.
134      *
135      * @return Array of bytes.
136      */
137     public byte[] getSid() {
138         return this.sid.clone();
139     }
140 
141     /**
142      * String representation of the SID.
143      *
144      * @return String.
145      */
146     public String getSidString() {
147         return this.sidString;
148     }
149 
150     /**
151      * Windows groups that the user is a member of.
152      *
153      * @return A map of group names to groups.
154      */
155     public Map<String, WindowsAccount> getGroups() {
156         return this.groups;
157     }
158 
159     /**
160      * Returns a list of role principal objects.
161      *
162      * @param group
163      *            Windows group.
164      * @param principalFormat
165      *            Principal format.
166      *
167      * @return List of role principal objects.
168      */
169     private static List<String> getRoleNames(final IWindowsAccount group, final PrincipalFormat principalFormat) {
170         final List<String> principals = new ArrayList<>();
171         switch (principalFormat) {
172             case FQN:
173                 principals.add(group.getFqn());
174                 break;
175             case SID:
176                 principals.add(group.getSidString());
177                 break;
178             case BOTH:
179                 principals.add(group.getFqn());
180                 principals.add(group.getSidString());
181                 break;
182             case NONE:
183             default:
184                 break;
185         }
186         return principals;
187     }
188 
189     /**
190      * Returns a list of user principal objects.
191      *
192      * @param windowsIdentity
193      *            Windows identity.
194      * @param principalFormat
195      *            Principal format.
196      *
197      * @return A list of user principal objects.
198      */
199     private static List<String> getPrincipalNames(final IWindowsIdentity windowsIdentity,
200             final PrincipalFormat principalFormat) {
201         final List<String> principals = new ArrayList<>();
202         switch (principalFormat) {
203             case FQN:
204                 principals.add(windowsIdentity.getFqn());
205                 break;
206             case SID:
207                 principals.add(windowsIdentity.getSidString());
208                 break;
209             case BOTH:
210                 principals.add(windowsIdentity.getFqn());
211                 principals.add(windowsIdentity.getSidString());
212                 break;
213             case NONE:
214             default:
215                 break;
216         }
217         return principals;
218     }
219 
220     /**
221      * Get an array of roles as a string.
222      *
223      * @return Role1, Role2, ...
224      */
225     public String getRolesString() {
226         return String.join(", ", this.roles);
227     }
228 
229     /**
230      * Checks whether the principal has a given role.
231      *
232      * @param role
233      *            Role name.
234      *
235      * @return True if the principal has a role, false otherwise.
236      */
237     public boolean hasRole(final String role) {
238         return this.roles.contains(role);
239     }
240 
241     /**
242      * Fully qualified name.
243      *
244      * @return String.
245      */
246     @Override
247     public String getName() {
248         return this.fqn;
249     }
250 
251     /**
252      * Underlying identity.
253      *
254      * @return String.
255      */
256     public IWindowsIdentity getIdentity() {
257         return this.identity;
258     }
259 
260     @Override
261     public String toString() {
262         return this.getName();
263     }
264 
265     @Override
266     public boolean equals(final Object o) {
267         if (this == o) {
268             return true;
269         }
270 
271         if (o instanceof WindowsPrincipal) {
272             return this.getName().equals(((WindowsPrincipal) o).getName());
273         }
274 
275         return false;
276     }
277 
278     @Override
279     public int hashCode() {
280         return this.getName().hashCode();
281     }
282 
283 }