001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.authc;
020
021import org.apache.shiro.authz.Permission;
022import org.apache.shiro.authz.SimpleAuthorizationInfo;
023import org.apache.shiro.subject.PrincipalCollection;
024import org.apache.shiro.subject.SimplePrincipalCollection;
025import org.apache.shiro.lang.util.ByteSource;
026
027import java.io.Serializable;
028import java.util.Collection;
029import java.util.Set;
030
031
032/**
033 * Simple implementation of the {@link org.apache.shiro.authc.Account} interface that
034 * contains principal and credential and authorization information (roles and permissions) as instance variables and
035 * exposes them via getters and setters using standard JavaBean notation.
036 *
037 * @since 0.1
038 */
039public class SimpleAccount implements Account, MergableAuthenticationInfo, SaltedAuthenticationInfo, Serializable {
040
041    /*--------------------------------------------
042    |    I N S T A N C E   V A R I A B L E S    |
043    ============================================*/
044    /**
045     * The authentication information (principals and credentials) for this account.
046     */
047    private SimpleAuthenticationInfo authcInfo;
048
049    /**
050     * The authorization information for this account.
051     */
052    private SimpleAuthorizationInfo authzInfo;
053
054    /**
055     * Indicates this account is locked.  This isn't honored by all <tt>Realms</tt> but is honored by
056     * {@link org.apache.shiro.realm.SimpleAccountRealm}.
057     */
058    private boolean locked;
059
060    /**
061     * Indicates credentials on this account are expired.  This isn't honored by all <tt>Realms</tt> but is honored by
062     * {@link org.apache.shiro.realm.SimpleAccountRealm}.
063     */
064    private boolean credentialsExpired;
065
066    /*--------------------------------------------
067    |         C O N S T R U C T O R S           |
068    ============================================*/
069
070    /**
071     * Default no-argument constructor.
072     */
073    public SimpleAccount() {
074    }
075
076    /**
077     * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials.
078     *
079     * @param principal   the 'primary' identifying attribute of the account, for example, a user id or username.
080     * @param credentials the credentials that verify identity for the account
081     * @param realmName   the name of the realm that accesses this account data
082     */
083    public SimpleAccount(Object principal, Object credentials, String realmName) {
084        this(principal instanceof PrincipalCollection
085                ? (PrincipalCollection) principal : new SimplePrincipalCollection(principal, realmName), credentials);
086    }
087
088    /**
089     * Constructs a SimpleAccount instance for the specified realm with the given principals, hashedCredentials and
090     * credentials salt used when hashing the credentials.
091     *
092     * @param principal         the 'primary' identifying attribute of the account, for example, a user id or username.
093     * @param hashedCredentials the credentials that verify identity for the account
094     * @param credentialsSalt   the salt used when hashing the credentials
095     * @param realmName         the name of the realm that accesses this account data
096     * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
097     * @since 1.1
098     */
099    public SimpleAccount(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
100        this(principal instanceof PrincipalCollection ? (PrincipalCollection) principal
101                        : new SimplePrincipalCollection(principal, realmName),
102                hashedCredentials, credentialsSalt);
103    }
104
105    /**
106     * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials.
107     *
108     * @param principals  the identifying attributes of the account, at least one of which should be considered the
109     *                    account's 'primary' identifying attribute, for example, a user id or username.
110     * @param credentials the credentials that verify identity for the account
111     * @param realmName   the name of the realm that accesses this account data
112     */
113    public SimpleAccount(Collection principals, Object credentials, String realmName) {
114        this(new SimplePrincipalCollection(principals, realmName), credentials);
115    }
116
117    /**
118     * Constructs a SimpleAccount instance for the specified principals and credentials.
119     *
120     * @param principals  the identifying attributes of the account, at least one of which should be considered the
121     *                    account's 'primary' identifying attribute, for example, a user id or username.
122     * @param credentials the credentials that verify identity for the account
123     */
124    public SimpleAccount(PrincipalCollection principals, Object credentials) {
125        this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
126        this.authzInfo = new SimpleAuthorizationInfo();
127    }
128
129    /**
130     * Constructs a SimpleAccount instance for the specified principals and credentials.
131     *
132     * @param principals        the identifying attributes of the account, at least one of which should be considered the
133     *                          account's 'primary' identifying attribute, for example, a user id or username.
134     * @param hashedCredentials the hashed credentials that verify identity for the account
135     * @param credentialsSalt   the salt used when hashing the credentials
136     * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
137     * @since 1.1
138     */
139    public SimpleAccount(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) {
140        this.authcInfo = new SimpleAuthenticationInfo(principals, hashedCredentials, credentialsSalt);
141        this.authzInfo = new SimpleAuthorizationInfo();
142    }
143
144    /**
145     * Constructs a SimpleAccount instance for the specified principals and credentials, with the assigned roles.
146     *
147     * @param principals  the identifying attributes of the account, at least one of which should be considered the
148     *                    account's 'primary' identifying attribute, for example, a user id or username.
149     * @param credentials the credentials that verify identity for the account
150     * @param roles       the names of the roles assigned to this account.
151     */
152    public SimpleAccount(PrincipalCollection principals, Object credentials, Set<String> roles) {
153        this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
154        this.authzInfo = new SimpleAuthorizationInfo(roles);
155    }
156
157    /**
158     * Constructs a SimpleAccount instance for the specified realm with the given principal and credentials, with the
159     * the assigned roles and permissions.
160     *
161     * @param principal   the 'primary' identifying attributes of the account, for example, a user id or username.
162     * @param credentials the credentials that verify identity for the account
163     * @param realmName   the name of the realm that accesses this account data
164     * @param roleNames   the names of the roles assigned to this account.
165     * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
166     */
167    public SimpleAccount(Object principal, Object credentials, String realmName,
168                         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
186    public SimpleAccount(Collection principals, Object credentials, String realmName,
187                         Set<String> roleNames, Set<Permission> permissions) {
188        this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principals, realmName), credentials);
189        this.authzInfo = new SimpleAuthorizationInfo(roleNames);
190        this.authzInfo.setObjectPermissions(permissions);
191    }
192
193    /**
194     * Constructs a SimpleAccount instance from the given principals and credentials, with the
195     * the assigned roles and permissions.
196     *
197     * @param principals  the identifying attributes of the account, at least one of which should be considered the
198     *                    account's 'primary' identifying attribute, for example, a user id or username.
199     * @param credentials the credentials that verify identity for the account
200     * @param roleNames   the names of the roles assigned to this account.
201     * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
202     */
203    public SimpleAccount(PrincipalCollection principals, Object credentials, Set<String> roleNames, Set<Permission> permissions) {
204        this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
205        this.authzInfo = new SimpleAuthorizationInfo(roleNames);
206        this.authzInfo.setObjectPermissions(permissions);
207    }
208
209    /*--------------------------------------------
210    |  A C C E S S O R S / M O D I F I E R S    |
211    ============================================*/
212
213    /**
214     * Returns the principals, aka the identifying attributes (username, user id, first name, last name, etc.) of this
215     * Account.
216     *
217     * @return all the principals, aka the identifying attributes, of this Account.
218     */
219    public PrincipalCollection getPrincipals() {
220        return authcInfo.getPrincipals();
221    }
222
223    /**
224     * Sets the principals, aka the identifying attributes (username, user id, first name, last name, etc.) of this
225     * Account.
226     *
227     * @param principals all the principals, aka the identifying attributes, of this Account.
228     * @see Account#getPrincipals()
229     */
230    public void setPrincipals(PrincipalCollection principals) {
231        this.authcInfo.setPrincipals(principals);
232    }
233
234
235    /**
236     * Simply returns <code>this.authcInfo.getCredentials</code>.  The <code>authcInfo</code> attribute is constructed
237     * via the constructors to wrap the input arguments.
238     *
239     * @return this Account's credentials.
240     */
241    public Object getCredentials() {
242        return authcInfo.getCredentials();
243    }
244
245    /**
246     * Sets this Account's credentials that verify one or more of the Account's
247     * {@link #getPrincipals() principals}, such as a password or private key.
248     *
249     * @param credentials the credentials associated with this Account that verify one or more of the Account principals.
250     * @see org.apache.shiro.authc.Account#getCredentials()
251     */
252    public void setCredentials(Object credentials) {
253        this.authcInfo.setCredentials(credentials);
254    }
255
256    /**
257     * Returns the salt used to hash this Account's credentials (e.g. for password hashing), or {@code null} if no salt
258     * was used or credentials were not hashed at all.
259     *
260     * @return the salt used to hash this Account's credentials (e.g. for password hashing), or {@code null} if no salt
261     * was used or credentials were not hashed at all.
262     * @since 1.1
263     */
264    public ByteSource getCredentialsSalt() {
265        return this.authcInfo.getCredentialsSalt();
266    }
267
268    /**
269     * Sets the salt to use to hash this Account's credentials (e.g. for password hashing), or {@code null} if no salt
270     * is used or credentials are not hashed at all.
271     *
272     * @param salt the salt to use to hash this Account's credentials (e.g. for password hashing), or {@code null} if no
273     *             salt is used or credentials are not hashed at all.
274     * @since 1.1
275     */
276    public void setCredentialsSalt(ByteSource salt) {
277        this.authcInfo.setCredentialsSalt(salt);
278    }
279
280    /**
281     * Returns <code>this.authzInfo.getRoles();</code>
282     *
283     * @return the Account's assigned roles.
284     */
285    public Collection<String> getRoles() {
286        return authzInfo.getRoles();
287    }
288
289    /**
290     * Sets the Account's assigned roles.  Simply calls <code>this.authzInfo.setRoles(roles)</code>.
291     *
292     * @param roles the Account's assigned roles.
293     * @see Account#getRoles()
294     */
295    public void setRoles(Set<String> roles) {
296        this.authzInfo.setRoles(roles);
297    }
298
299    /**
300     * Adds a role to this Account's set of assigned roles.  Simply delegates to
301     * <code>this.authzInfo.addRole(role)</code>.
302     *
303     * @param role a role to assign to this Account.
304     */
305    public void addRole(String role) {
306        this.authzInfo.addRole(role);
307    }
308
309    /**
310     * Adds one or more roles to this Account's set of assigned roles. Simply delegates to
311     * <code>this.authzInfo.addRoles(roles)</code>.
312     *
313     * @param roles one or more roles to assign to this Account.
314     */
315    public void addRole(Collection<String> roles) {
316        this.authzInfo.addRoles(roles);
317    }
318
319    /**
320     * Returns all String-based permissions assigned to this Account.  Simply delegates to
321     * <code>this.authzInfo.getStringPermissions()</code>.
322     *
323     * @return all String-based permissions assigned to this Account.
324     */
325    public Collection<String> getStringPermissions() {
326        return authzInfo.getStringPermissions();
327    }
328
329    /**
330     * Sets the String-based permissions assigned to this Account.  Simply delegates to
331     * <code>this.authzInfo.setStringPermissions(permissions)</code>.
332     *
333     * @param permissions all String-based permissions assigned to this Account.
334     * @see org.apache.shiro.authc.Account#getStringPermissions()
335     */
336    public void setStringPermissions(Set<String> permissions) {
337        this.authzInfo.setStringPermissions(permissions);
338    }
339
340    /**
341     * Assigns a String-based permission directly to this Account (not to any of its realms).
342     *
343     * @param permission the String-based permission to assign.
344     */
345    public void addStringPermission(String permission) {
346        this.authzInfo.addStringPermission(permission);
347    }
348
349    /**
350     * Assigns one or more string-based permissions directly to this Account (not to any of its realms).
351     *
352     * @param permissions one or more String-based permissions to assign.
353     */
354    public void addStringPermissions(Collection<String> permissions) {
355        this.authzInfo.addStringPermissions(permissions);
356    }
357
358    /**
359     * Returns all object-based permissions assigned directly to this Account (not any of its realms).
360     *
361     * @return all object-based permissions assigned directly to this Account (not any of its realms).
362     */
363    public Collection<Permission> getObjectPermissions() {
364        return authzInfo.getObjectPermissions();
365    }
366
367    /**
368     * Set al. object-based permissions assigned directly to this Account (not any of its realms).
369     *
370     * @param permissions the object-based permissions to assign directly to this Account.
371     */
372    public void setObjectPermissions(Set<Permission> permissions) {
373        this.authzInfo.setObjectPermissions(permissions);
374    }
375
376    /**
377     * Assigns an object-based permission directly to this Account (not any of its realms).
378     *
379     * @param permission the object-based permission to assign directly to this Account (not any of its realms).
380     */
381    public void addObjectPermission(Permission permission) {
382        this.authzInfo.addObjectPermission(permission);
383    }
384
385    /**
386     * Assigns one or more object-based permissions directly to this Account (not any of its realms).
387     *
388     * @param permissions one or more object-based permissions to assign directly to this Account (not any of its realms).
389     */
390    public void addObjectPermissions(Collection<Permission> permissions) {
391        this.authzInfo.addObjectPermissions(permissions);
392    }
393
394    /**
395     * Returns <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
396     *
397     * @return <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
398     */
399    public boolean isLocked() {
400        return locked;
401    }
402
403    /**
404     * Sets whether or not the account is locked and can be used to login.
405     *
406     * @param locked <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
407     */
408    public void setLocked(boolean locked) {
409        this.locked = locked;
410    }
411
412    /**
413     * Returns whether or not the Account's credentials are expired.  This usually indicates that the Subject or an application
414     * administrator would need to change the credentials before the account could be used.
415     *
416     * @return whether or not the Account's credentials are expired.
417     */
418    public boolean isCredentialsExpired() {
419        return credentialsExpired;
420    }
421
422    /**
423     * Sets whether or not the Account's credentials are expired.  A <code>true</code> value indicates that the Subject
424     * or application administrator would need to change their credentials before the account could be used.
425     *
426     * @param credentialsExpired <code>true</code> if this Account's credentials are expired and need to be changed,
427     *                           <code>false</code> otherwise.
428     */
429    public void setCredentialsExpired(boolean credentialsExpired) {
430        this.credentialsExpired = credentialsExpired;
431    }
432
433
434    /**
435     * Merges the specified <code>AuthenticationInfo</code> into this <code>Account</code>.
436     * <p/>
437     * If the specified argument is also an instance of {@link SimpleAccount SimpleAccount}, the
438     * {@link #isLocked()} and {@link #isCredentialsExpired()} attributes are merged (set on this instance) as well
439     * (only if their values are <code>true</code>).
440     *
441     * @param info the <code>AuthenticationInfo</code> to merge into this account.
442     */
443    public void merge(AuthenticationInfo info) {
444        authcInfo.merge(info);
445
446        // Merge SimpleAccount specific info
447        if (info instanceof SimpleAccount) {
448            SimpleAccount otherAccount = (SimpleAccount) info;
449            if (otherAccount.isLocked()) {
450                setLocked(true);
451            }
452
453            if (otherAccount.isCredentialsExpired()) {
454                setCredentialsExpired(true);
455            }
456        }
457    }
458
459    /**
460     * If the {@link #getPrincipals() principals} are not null, returns <code>principals.hashCode()</code>, otherwise
461     * returns 0 (zero).
462     *
463     * @return <code>principals.hashCode()</code> if they are not null, 0 (zero) otherwise.
464     */
465    public int hashCode() {
466        return (getPrincipals() != null ? getPrincipals().hashCode() : 0);
467    }
468
469    /**
470     * Returns <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its
471     * {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise.
472     *
473     * @param o the object to test for equality.
474     * @return <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its
475     * {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise.
476     */
477    public boolean equals(Object o) {
478        if (o == this) {
479            return true;
480        }
481        if (o instanceof SimpleAccount) {
482            SimpleAccount sa = (SimpleAccount) o;
483            //principal should be unique across the application, so only check this for equality:
484            return (getPrincipals() != null ? getPrincipals().equals(sa.getPrincipals()) : sa.getPrincipals() == 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    public String toString() {
496        return getPrincipals() != null ? getPrincipals().toString() : "empty";
497    }
498
499}