1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 module hunt.shiro.authc.SimpleAccount;
20 
21 import hunt.shiro.authc.Account;
22 import hunt.shiro.authc.AuthenticationInfo;
23 import hunt.shiro.authc.MergableAuthenticationInfo;
24 import hunt.shiro.authc.SaltedAuthenticationInfo;
25 import hunt.shiro.authc.SimpleAuthenticationInfo;
26 
27 import hunt.shiro.authz.permission.Permission;
28 import hunt.shiro.authz.SimpleAuthorizationInfo;
29 import hunt.shiro.subject.PrincipalCollection;
30 import hunt.shiro.subject.SimplePrincipalCollection;
31 import hunt.shiro.util.ByteSource;
32 
33 import hunt.collection;
34 
35 
36 /**
37  * Simple implementation of the {@link hunt.shiro.authc.Account} interface that
38  * contains principal and credential and authorization information (roles and permissions) as instance variables and
39  * exposes them via getters and setters using standard JavaBean notation.
40  *
41  */
42 class SimpleAccount : Account, MergableAuthenticationInfo, SaltedAuthenticationInfo {
43 
44     /*--------------------------------------------
45     |    I N S T A N C E   V A R I A B L E S    |
46     ============================================*/
47     /**
48      * The authentication information (principals and credentials) for this account.
49      */
50     private SimpleAuthenticationInfo authcInfo;
51 
52     /**
53      * The authorization information for this account.
54      */
55     private SimpleAuthorizationInfo authzInfo;
56 
57     /**
58      * Indicates this account is locked.  This isn't honored by all <tt>Realms</tt> but is honored by
59      * {@link hunt.shiro.realm.SimpleAccountRealm}.
60      */
61     private bool locked;
62 
63     /**
64      * Indicates credentials on this account are expired.  This isn't honored by all <tt>Realms</tt> but is honored by
65      * {@link hunt.shiro.realm.SimpleAccountRealm}.
66      */
67     private bool credentialsExpired;
68 
69     /*--------------------------------------------
70     |         C O N S T R U C T O R S           |
71     ============================================*/
72 
73     /**
74      * Default no-argument constructor.
75      */
76     this() {
77     }
78 
79     /**
80      * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials.
81      *
82      * @param principal   the 'primary' identifying attribute of the account, for example, a user id or username.
83      * @param credentials the credentials that verify identity for the account
84      * @param realmName   the name of the realm that accesses this account data
85      */
86      this(Object principal, Object credentials, string realmName) {
87         auto principalCast = cast(PrincipalCollection)principal;
88         this(principalCast !is null ? principalCast : new SimplePrincipalCollection(principal, realmName), credentials);
89     }
90 
91     /**
92      * Constructs a SimpleAccount instance for the specified realm with the given principals, hashedCredentials and
93      * credentials salt used when hashing the credentials.
94      *
95      * @param principal         the 'primary' identifying attribute of the account, for example, a user id or username.
96      * @param hashedCredentials the credentials that verify identity for the account
97      * @param credentialsSalt   the salt used when hashing the credentials
98      * @param realmName         the name of the realm that accesses this account data
99      * @see hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
100      */
101      this(Object principal, Object hashedCredentials, ByteSource credentialsSalt, string realmName) {
102         auto principalCast = cast(PrincipalCollection)principal;
103         this(principalCast !is null ? principalCast : new SimplePrincipalCollection(principal, realmName),
104                 hashedCredentials, credentialsSalt);
105     }
106 
107     /**
108      * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials.
109      *
110      * @param principals  the identifying attributes of the account, at least one of which should be considered the
111      *                    account's 'primary' identifying attribute, for example, a user id or username.
112      * @param credentials the credentials that verify identity for the account
113      * @param realmName   the name of the realm that accesses this account data
114      */
115     this(Collection!Object principals, Object credentials, string realmName) {
116         this(new SimplePrincipalCollection(principals, realmName), credentials);
117     }
118 
119     /**
120      * Constructs a SimpleAccount instance for the specified principals and credentials.
121      *
122      * @param principals  the identifying attributes of the account, at least one of which should be considered the
123      *                    account's 'primary' identifying attribute, for example, a user id or username.
124      * @param credentials the credentials that verify identity for the account
125      */
126      this(PrincipalCollection principals, Object credentials) {
127         this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
128         this.authzInfo = new SimpleAuthorizationInfo();
129     }
130 
131     /**
132      * Constructs a SimpleAccount instance for the specified principals and credentials.
133      *
134      * @param principals        the identifying attributes of the account, at least one of which should be considered the
135      *                          account's 'primary' identifying attribute, for example, a user id or username.
136      * @param hashedCredentials the hashed credentials that verify identity for the account
137      * @param credentialsSalt   the salt used when hashing the credentials
138      * @see hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
139      */
140      this(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) {
141         this.authcInfo = new SimpleAuthenticationInfo(principals, hashedCredentials, credentialsSalt);
142         this.authzInfo = new SimpleAuthorizationInfo();
143     }
144 
145     /**
146      * Constructs a SimpleAccount instance for the specified principals and credentials, with the assigned roles.
147      *
148      * @param principals  the identifying attributes of the account, at least one of which should be considered the
149      *                    account's 'primary' identifying attribute, for example, a user id or username.
150      * @param credentials the credentials that verify identity for the account
151      * @param roles       the names of the roles assigned to this account.
152      */
153      this(PrincipalCollection principals, Object credentials, Set!(string) roles) {
154         this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
155         this.authzInfo = new SimpleAuthorizationInfo(roles);
156     }
157 
158     /**
159      * Constructs a SimpleAccount instance for the specified realm with the given principal and credentials, with the
160      * the assigned roles and permissions.
161      *
162      * @param principal   the 'primary' identifying attributes of the account, for example, a user id or username.
163      * @param credentials the credentials that verify identity for the account
164      * @param realmName   the name of the realm that accesses this account data
165      * @param roleNames   the names of the roles assigned to this account.
166      * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
167      */
168      this(Object principal, Object credentials, string realmName, Set!(string) roleNames, Set!(Permission) permissions) {
169         this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principal, realmName), credentials);
170         this.authzInfo = new SimpleAuthorizationInfo(roleNames);
171         this.authzInfo.setObjectPermissions(permissions);
172     }
173 
174     /**
175      * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials, with the
176      * the assigned roles and permissions.
177      *
178      * @param principals  the identifying attributes of the account, at least one of which should be considered the
179      *                    account's 'primary' identifying attribute, for example, a user id or username.
180      * @param credentials the credentials that verify identity for the account
181      * @param realmName   the name of the realm that accesses this account data
182      * @param roleNames   the names of the roles assigned to this account.
183      * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
184      */
185      this(Collection!Object principals, Object credentials, string realmName, Set!(string) roleNames, 
186             Set!(Permission) permissions) {
187         this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principals, realmName), credentials);
188         this.authzInfo = new SimpleAuthorizationInfo(roleNames);
189         this.authzInfo.setObjectPermissions(permissions);
190     }
191 
192     /**
193      * Constructs a SimpleAccount instance from the given principals and credentials, with the
194      * the assigned roles and permissions.
195      *
196      * @param principals  the identifying attributes of the account, at least one of which should be considered the
197      *                    account's 'primary' identifying attribute, for example, a user id or username.
198      * @param credentials the credentials that verify identity for the account
199      * @param roleNames   the names of the roles assigned to this account.
200      * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
201      */
202      this(PrincipalCollection principals, Object credentials, Set!(string) roleNames, Set!(Permission) permissions) {
203         this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
204         this.authzInfo = new SimpleAuthorizationInfo(roleNames);
205         this.authzInfo.setObjectPermissions(permissions);
206     }
207 
208     /*--------------------------------------------
209     |  A C C E S S O R S / M O D I F I E R S    |
210     ============================================*/
211 
212     /**
213      * Returns the principals, aka the identifying attributes (username, user id, first name, last name, etc) of this
214      * Account.
215      *
216      * @return all the principals, aka the identifying attributes, of this Account.
217      */
218     PrincipalCollection getPrincipals() @trusted nothrow {
219         return authcInfo.getPrincipals();
220     }
221 
222     /**
223      * Sets the principals, aka the identifying attributes (username, user id, first name, last name, etc) of this
224      * Account.
225      *
226      * @param principals all the principals, aka the identifying attributes, of this Account.
227      * @see Account#getPrincipals()
228      */
229      void setPrincipals(PrincipalCollection principals) {
230         this.authcInfo.setPrincipals(principals);
231     }
232 
233 
234     /**
235      * Simply returns <code>this.authcInfo.getCredentials</code>.  The <code>authcInfo</code> attribute is constructed
236      * via the constructors to wrap the input arguments.
237      *
238      * @return this Account's credentials.
239      */
240      Object getCredentials() {
241         return authcInfo.getCredentials();
242     }
243 
244     /**
245      * Sets this Account's credentials that verify one or more of the Account's
246      * {@link #getPrincipals() principals}, such as a password or private key.
247      *
248      * @param credentials the credentials associated with this Account that verify one or more of the Account principals.
249      * @see hunt.shiro.authc.Account#getCredentials()
250      */
251      void setCredentials(Object credentials) {
252         this.authcInfo.setCredentials(credentials);
253     }
254 
255     /**
256      * Returns the salt used to hash this Account's credentials (eg for password hashing), or {@code null} if no salt
257      * was used or credentials were not hashed at all.
258      *
259      * @return the salt used to hash this Account's credentials (eg for password hashing), or {@code null} if no salt
260      *         was used or credentials were not hashed at all.
261      */
262      ByteSource getCredentialsSalt() {
263         return this.authcInfo.getCredentialsSalt();
264     }
265 
266     /**
267      * Sets the salt to use to hash this Account's credentials (eg for password hashing), or {@code null} if no salt
268      * is used or credentials are not hashed at all.
269      *
270      * @param salt the salt to use to hash this Account's credentials (eg for password hashing), or {@code null} if no
271      *             salt is used or credentials are not hashed at all.
272      */
273      void setCredentialsSalt(ByteSource salt) {
274         this.authcInfo.setCredentialsSalt(salt);
275     }
276 
277     /**
278      * Returns <code>this.authzInfo.getRoles();</code>
279      *
280      * @return the Account's assigned roles.
281      */
282      Collection!(string) getRoles() {
283         return authzInfo.getRoles();
284     }
285 
286     /**
287      * Sets the Account's assigned roles.  Simply calls <code>this.authzInfo.setRoles(roles)</code>.
288      *
289      * @param roles the Account's assigned roles.
290      * @see Account#getRoles()
291      */
292      void setRoles(Set!(string) roles) {
293         this.authzInfo.setRoles(roles);
294     }
295 
296     /**
297      * Adds a role to this Account's set of assigned roles.  Simply delegates to
298      * <code>this.authzInfo.addRole(role)</code>.
299      *
300      * @param role a role to assign to this Account.
301      */
302      void addRole(string role) {
303         this.authzInfo.addRole(role);
304     }
305 
306     /**
307      * Adds one or more roles to this Account's set of assigned roles. Simply delegates to
308      * <code>this.authzInfo.addRoles(roles)</code>.
309      *
310      * @param roles one or more roles to assign to this Account.
311      */
312      void addRole(Collection!(string) roles) {
313         this.authzInfo.addRoles(roles);
314     }
315 
316     /**
317      * Returns all string-based permissions assigned to this Account.  Simply delegates to
318      * <code>this.authzInfo.getStringPermissions()</code>.
319      *
320      * @return all string-based permissions assigned to this Account.
321      */
322      Collection!(string) getStringPermissions() {
323         return authzInfo.getStringPermissions();
324     }
325 
326     /**
327      * Sets the string-based permissions assigned to this Account.  Simply delegates to
328      * <code>this.authzInfo.setStringPermissions(permissions)</code>.
329      *
330      * @param permissions all string-based permissions assigned to this Account.
331      * @see hunt.shiro.authc.Account#getStringPermissions()
332      */
333      void setStringPermissions(Set!(string) permissions) {
334         this.authzInfo.setStringPermissions(permissions);
335     }
336 
337     /**
338      * Assigns a string-based permission directly to this Account (not to any of its realms).
339      *
340      * @param permission the string-based permission to assign.
341      */
342      void addStringPermission(string permission) {
343         this.authzInfo.addStringPermission(permission);
344     }
345 
346     /**
347      * Assigns one or more string-based permissions directly to this Account (not to any of its realms).
348      *
349      * @param permissions one or more string-based permissions to assign.
350      */
351      void addStringPermissions(Collection!(string) permissions) {
352         this.authzInfo.addStringPermissions(permissions);
353     }
354 
355     /**
356      * Returns all object-based permissions assigned directly to this Account (not any of its realms).
357      *
358      * @return all object-based permissions assigned directly to this Account (not any of its realms).
359      */
360      Collection!(Permission) getObjectPermissions() {
361         return authzInfo.getObjectPermissions();
362     }
363 
364     /**
365      * Sets all object-based permissions assigned directly to this Account (not any of its realms).
366      *
367      * @param permissions the object-based permissions to assign directly to this Account.
368      */
369      void setObjectPermissions(Set!(Permission) permissions) {
370         this.authzInfo.setObjectPermissions(permissions);
371     }
372 
373     /**
374      * Assigns an object-based permission directly to this Account (not any of its realms).
375      *
376      * @param permission the object-based permission to assign directly to this Account (not any of its realms).
377      */
378      void addObjectPermission(Permission permission) {
379         this.authzInfo.addObjectPermission(permission);
380     }
381 
382     /**
383      * Assigns one or more object-based permissions directly to this Account (not any of its realms).
384      *
385      * @param permissions one or more object-based permissions to assign directly to this Account (not any of its realms).
386      */
387      void addObjectPermissions(Collection!(Permission) permissions) {
388         this.authzInfo.addObjectPermissions(permissions);
389     }
390 
391     /**
392      * Returns <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
393      *
394      * @return <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
395      */
396      bool isLocked() {
397         return locked;
398     }
399 
400     /**
401      * Sets whether or not the account is locked and can be used to login.
402      *
403      * @param locked <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
404      */
405      void setLocked(bool locked) {
406         this.locked = locked;
407     }
408 
409     /**
410      * Returns whether or not the Account's credentials are expired.  This usually indicates that the Subject or an application
411      * administrator would need to change the credentials before the account could be used.
412      *
413      * @return whether or not the Account's credentials are expired.
414      */
415      bool isCredentialsExpired() {
416         return credentialsExpired;
417     }
418 
419     /**
420      * Sets whether or not the Account's credentials are expired.  A <code>true</code> value indicates that the Subject
421      * or application administrator would need to change their credentials before the account could be used.
422      *
423      * @param credentialsExpired <code>true</code> if this Account's credentials are expired and need to be changed,
424      *                           <code>false</code> otherwise.
425      */
426      void setCredentialsExpired(bool credentialsExpired) {
427         this.credentialsExpired = credentialsExpired;
428     }
429 
430 
431     /**
432      * Merges the specified <code>AuthenticationInfo</code> into this <code>Account</code>.
433      * <p/>
434      * If the specified argument is also an instance of {@link SimpleAccount SimpleAccount}, the
435      * {@link #isLocked()} and {@link #isCredentialsExpired()} attributes are merged (set on this instance) as well
436      * (only if their values are <code>true</code>).
437      *
438      * @param info the <code>AuthenticationInfo</code> to merge into this account.
439      */
440      void merge(AuthenticationInfo info) {
441         authcInfo.merge(info);
442 
443         // Merge SimpleAccount specific info\
444         SimpleAccount infoCast = cast(SimpleAccount)info;
445         if (infoCast !is null) {
446             SimpleAccount otherAccount = infoCast;
447             if (otherAccount.isLocked()) {
448                 setLocked(true);
449             }
450 
451             if (otherAccount.isCredentialsExpired()) {
452                 setCredentialsExpired(true);
453             }
454         }
455     }
456 
457     /**
458      * If the {@link #getPrincipals() principals} are not null, returns <code>principals.hashCode()</code>, otherwise
459      * returns 0 (zero).
460      *
461      * @return <code>principals.hashCode()</code> if they are not null, 0 (zero) otherwise.
462      */
463     override size_t toHash() @trusted nothrow {
464         PrincipalCollection pc = getPrincipals();
465         return (pc !is null ? (cast(Object)pc).toHash() : 0);
466     }
467 
468     /**
469      * Returns <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its
470      * {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise.
471      *
472      * @param o the object to test for equality.
473      * @return <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its
474      *         {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise.
475      */
476     override bool opEquals(Object o) {
477         if (o == this) {
478             return true;
479         }
480         auto oCast = cast(SimpleAccount)o;
481         if (oCast !is null) {
482             SimpleAccount sa = oCast;
483             //principal should be unique across the application, so only check this for equality:
484             return (getPrincipals() !is null ? getPrincipals() == sa.getPrincipals() : sa.getPrincipals()  is null);
485         }
486         return false;
487     }
488 
489     /**
490      * Returns {@link #getPrincipals() principals}.toString() if they are not null, otherwise prints out the string
491      * &quot;empty&quot;
492      *
493      * @return the string representation of this Account object.
494      */
495     override string toString() {
496         PrincipalCollection pc = getPrincipals();
497         return pc !is null ? (cast(Object)pc).toString() : "empty";
498     }
499 
500 }