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.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 ? (PrincipalCollection) principal : new SimplePrincipalCollection(principal, realmName), credentials);
085    }
086
087    /**
088     * Constructs a SimpleAccount instance for the specified realm with the given principals, hashedCredentials and
089     * credentials salt used when hashing the credentials.
090     *
091     * @param principal         the 'primary' identifying attribute of the account, for example, a user id or username.
092     * @param hashedCredentials the credentials that verify identity for the account
093     * @param credentialsSalt   the salt used when hashing the credentials
094     * @param realmName         the name of the realm that accesses this account data
095     * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
096     * @since 1.1
097     */
098    public SimpleAccount(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
099        this(principal instanceof PrincipalCollection ? (PrincipalCollection) principal : new SimplePrincipalCollection(principal, realmName),
100                hashedCredentials, credentialsSalt);
101    }
102
103    /**
104     * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials.
105     *
106     * @param principals  the identifying attributes of the account, at least one of which should be considered the
107     *                    account's 'primary' identifying attribute, for example, a user id or username.
108     * @param credentials the credentials that verify identity for the account
109     * @param realmName   the name of the realm that accesses this account data
110     */
111    public SimpleAccount(Collection principals, Object credentials, String realmName) {
112        this(new SimplePrincipalCollection(principals, realmName), credentials);
113    }
114
115    /**
116     * Constructs a SimpleAccount instance for the specified principals and credentials.
117     *
118     * @param principals  the identifying attributes of the account, at least one of which should be considered the
119     *                    account's 'primary' identifying attribute, for example, a user id or username.
120     * @param credentials the credentials that verify identity for the account
121     */
122    public SimpleAccount(PrincipalCollection principals, Object credentials) {
123        this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
124        this.authzInfo = new SimpleAuthorizationInfo();
125    }
126
127    /**
128     * Constructs a SimpleAccount instance for the specified principals and credentials.
129     *
130     * @param principals        the identifying attributes of the account, at least one of which should be considered the
131     *                          account's 'primary' identifying attribute, for example, a user id or username.
132     * @param hashedCredentials the hashed credentials that verify identity for the account
133     * @param credentialsSalt   the salt used when hashing the credentials
134     * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
135     * @since 1.1
136     */
137    public SimpleAccount(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) {
138        this.authcInfo = new SimpleAuthenticationInfo(principals, hashedCredentials, credentialsSalt);
139        this.authzInfo = new SimpleAuthorizationInfo();
140    }
141
142    /**
143     * Constructs a SimpleAccount instance for the specified principals and credentials, with the assigned roles.
144     *
145     * @param principals  the identifying attributes of the account, at least one of which should be considered the
146     *                    account's 'primary' identifying attribute, for example, a user id or username.
147     * @param credentials the credentials that verify identity for the account
148     * @param roles       the names of the roles assigned to this account.
149     */
150    public SimpleAccount(PrincipalCollection principals, Object credentials, Set<String> roles) {
151        this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
152        this.authzInfo = new SimpleAuthorizationInfo(roles);
153    }
154
155    /**
156     * Constructs a SimpleAccount instance for the specified realm with the given principal and credentials, with the
157     * the assigned roles and permissions.
158     *
159     * @param principal   the 'primary' identifying attributes of the account, for example, a user id or username.
160     * @param credentials the credentials that verify identity for the account
161     * @param realmName   the name of the realm that accesses this account data
162     * @param roleNames   the names of the roles assigned to this account.
163     * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
164     */
165    public SimpleAccount(Object principal, Object credentials, String realmName, Set<String> roleNames, Set<Permission> permissions) {
166        this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principal, realmName), credentials);
167        this.authzInfo = new SimpleAuthorizationInfo(roleNames);
168        this.authzInfo.setObjectPermissions(permissions);
169    }
170
171    /**
172     * Constructs a SimpleAccount instance for the specified realm with the given principals and credentials, with the
173     * the assigned roles and permissions.
174     *
175     * @param principals  the identifying attributes of the account, at least one of which should be considered the
176     *                    account's 'primary' identifying attribute, for example, a user id or username.
177     * @param credentials the credentials that verify identity for the account
178     * @param realmName   the name of the realm that accesses this account data
179     * @param roleNames   the names of the roles assigned to this account.
180     * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
181     */
182    public SimpleAccount(Collection principals, Object credentials, String realmName, Set<String> roleNames, Set<Permission> permissions) {
183        this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principals, realmName), credentials);
184        this.authzInfo = new SimpleAuthorizationInfo(roleNames);
185        this.authzInfo.setObjectPermissions(permissions);
186    }
187
188    /**
189     * Constructs a SimpleAccount instance from the given principals and credentials, with the
190     * the assigned roles and permissions.
191     *
192     * @param principals  the identifying attributes of the account, at least one of which should be considered the
193     *                    account's 'primary' identifying attribute, for example, a user id or username.
194     * @param credentials the credentials that verify identity for the account
195     * @param roleNames   the names of the roles assigned to this account.
196     * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms).
197     */
198    public SimpleAccount(PrincipalCollection principals, Object credentials, Set<String> roleNames, Set<Permission> permissions) {
199        this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
200        this.authzInfo = new SimpleAuthorizationInfo(roleNames);
201        this.authzInfo.setObjectPermissions(permissions);
202    }
203
204    /*--------------------------------------------
205    |  A C C E S S O R S / M O D I F I E R S    |
206    ============================================*/
207
208    /**
209     * Returns the principals, aka the identifying attributes (username, user id, first name, last name, etc) of this
210     * Account.
211     *
212     * @return all the principals, aka the identifying attributes, of this Account.
213     */
214    public PrincipalCollection getPrincipals() {
215        return authcInfo.getPrincipals();
216    }
217
218    /**
219     * Sets the principals, aka the identifying attributes (username, user id, first name, last name, etc) of this
220     * Account.
221     *
222     * @param principals all the principals, aka the identifying attributes, of this Account.
223     * @see Account#getPrincipals()
224     */
225    public void setPrincipals(PrincipalCollection principals) {
226        this.authcInfo.setPrincipals(principals);
227    }
228
229
230    /**
231     * Simply returns <code>this.authcInfo.getCredentials</code>.  The <code>authcInfo</code> attribute is constructed
232     * via the constructors to wrap the input arguments.
233     *
234     * @return this Account's credentials.
235     */
236    public Object getCredentials() {
237        return authcInfo.getCredentials();
238    }
239
240    /**
241     * Sets this Account's credentials that verify one or more of the Account's
242     * {@link #getPrincipals() principals}, such as a password or private key.
243     *
244     * @param credentials the credentials associated with this Account that verify one or more of the Account principals.
245     * @see org.apache.shiro.authc.Account#getCredentials()
246     */
247    public void setCredentials(Object credentials) {
248        this.authcInfo.setCredentials(credentials);
249    }
250
251    /**
252     * Returns the salt used to hash this Account's credentials (eg for password hashing), or {@code null} if no salt
253     * was used or credentials were not hashed at all.
254     *
255     * @return the salt used to hash this Account's credentials (eg for password hashing), or {@code null} if no salt
256     *         was used or credentials were not hashed at all.
257     * @since 1.1
258     */
259    public ByteSource getCredentialsSalt() {
260        return this.authcInfo.getCredentialsSalt();
261    }
262
263    /**
264     * Sets the salt to use to hash this Account's credentials (eg for password hashing), or {@code null} if no salt
265     * is used or credentials are not hashed at all.
266     *
267     * @param salt the salt to use to hash this Account's credentials (eg for password hashing), or {@code null} if no
268     *             salt is used or credentials are not hashed at all.
269     * @since 1.1
270     */
271    public void setCredentialsSalt(ByteSource salt) {
272        this.authcInfo.setCredentialsSalt(salt);
273    }
274
275    /**
276     * Returns <code>this.authzInfo.getRoles();</code>
277     *
278     * @return the Account's assigned roles.
279     */
280    public Collection<String> getRoles() {
281        return authzInfo.getRoles();
282    }
283
284    /**
285     * Sets the Account's assigned roles.  Simply calls <code>this.authzInfo.setRoles(roles)</code>.
286     *
287     * @param roles the Account's assigned roles.
288     * @see Account#getRoles()
289     */
290    public void setRoles(Set<String> roles) {
291        this.authzInfo.setRoles(roles);
292    }
293
294    /**
295     * Adds a role to this Account's set of assigned roles.  Simply delegates to
296     * <code>this.authzInfo.addRole(role)</code>.
297     *
298     * @param role a role to assign to this Account.
299     */
300    public void addRole(String role) {
301        this.authzInfo.addRole(role);
302    }
303
304    /**
305     * Adds one or more roles to this Account's set of assigned roles. Simply delegates to
306     * <code>this.authzInfo.addRoles(roles)</code>.
307     *
308     * @param roles one or more roles to assign to this Account.
309     */
310    public void addRole(Collection<String> roles) {
311        this.authzInfo.addRoles(roles);
312    }
313
314    /**
315     * Returns all String-based permissions assigned to this Account.  Simply delegates to
316     * <code>this.authzInfo.getStringPermissions()</code>.
317     *
318     * @return all String-based permissions assigned to this Account.
319     */
320    public Collection<String> getStringPermissions() {
321        return authzInfo.getStringPermissions();
322    }
323
324    /**
325     * Sets the String-based permissions assigned to this Account.  Simply delegates to
326     * <code>this.authzInfo.setStringPermissions(permissions)</code>.
327     *
328     * @param permissions all String-based permissions assigned to this Account.
329     * @see org.apache.shiro.authc.Account#getStringPermissions()
330     */
331    public void setStringPermissions(Set<String> permissions) {
332        this.authzInfo.setStringPermissions(permissions);
333    }
334
335    /**
336     * Assigns a String-based permission directly to this Account (not to any of its realms).
337     *
338     * @param permission the String-based permission to assign.
339     */
340    public void addStringPermission(String permission) {
341        this.authzInfo.addStringPermission(permission);
342    }
343
344    /**
345     * Assigns one or more string-based permissions directly to this Account (not to any of its realms).
346     *
347     * @param permissions one or more String-based permissions to assign.
348     */
349    public void addStringPermissions(Collection<String> permissions) {
350        this.authzInfo.addStringPermissions(permissions);
351    }
352
353    /**
354     * Returns all object-based permissions assigned directly to this Account (not any of its realms).
355     *
356     * @return all object-based permissions assigned directly to this Account (not any of its realms).
357     */
358    public Collection<Permission> getObjectPermissions() {
359        return authzInfo.getObjectPermissions();
360    }
361
362    /**
363     * Sets all object-based permissions assigned directly to this Account (not any of its realms).
364     *
365     * @param permissions the object-based permissions to assign directly to this Account.
366     */
367    public void setObjectPermissions(Set<Permission> permissions) {
368        this.authzInfo.setObjectPermissions(permissions);
369    }
370
371    /**
372     * Assigns an object-based permission directly to this Account (not any of its realms).
373     *
374     * @param permission the object-based permission to assign directly to this Account (not any of its realms).
375     */
376    public void addObjectPermission(Permission permission) {
377        this.authzInfo.addObjectPermission(permission);
378    }
379
380    /**
381     * Assigns one or more object-based permissions directly to this Account (not any of its realms).
382     *
383     * @param permissions one or more object-based permissions to assign directly to this Account (not any of its realms).
384     */
385    public void addObjectPermissions(Collection<Permission> permissions) {
386        this.authzInfo.addObjectPermissions(permissions);
387    }
388
389    /**
390     * Returns <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
391     *
392     * @return <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
393     */
394    public boolean isLocked() {
395        return locked;
396    }
397
398    /**
399     * Sets whether or not the account is locked and can be used to login.
400     *
401     * @param locked <code>true</code> if this Account is locked and thus cannot be used to login, <code>false</code> otherwise.
402     */
403    public void setLocked(boolean locked) {
404        this.locked = locked;
405    }
406
407    /**
408     * Returns whether or not the Account's credentials are expired.  This usually indicates that the Subject or an application
409     * administrator would need to change the credentials before the account could be used.
410     *
411     * @return whether or not the Account's credentials are expired.
412     */
413    public boolean isCredentialsExpired() {
414        return credentialsExpired;
415    }
416
417    /**
418     * Sets whether or not the Account's credentials are expired.  A <code>true</code> value indicates that the Subject
419     * or application administrator would need to change their credentials before the account could be used.
420     *
421     * @param credentialsExpired <code>true</code> if this Account's credentials are expired and need to be changed,
422     *                           <code>false</code> otherwise.
423     */
424    public void setCredentialsExpired(boolean credentialsExpired) {
425        this.credentialsExpired = credentialsExpired;
426    }
427
428
429    /**
430     * Merges the specified <code>AuthenticationInfo</code> into this <code>Account</code>.
431     * <p/>
432     * If the specified argument is also an instance of {@link SimpleAccount SimpleAccount}, the
433     * {@link #isLocked()} and {@link #isCredentialsExpired()} attributes are merged (set on this instance) as well
434     * (only if their values are <code>true</code>).
435     *
436     * @param info the <code>AuthenticationInfo</code> to merge into this account.
437     */
438    public void merge(AuthenticationInfo info) {
439        authcInfo.merge(info);
440
441        // Merge SimpleAccount specific info
442        if (info instanceof SimpleAccount) {
443            SimpleAccount otherAccount = (SimpleAccount) info;
444            if (otherAccount.isLocked()) {
445                setLocked(true);
446            }
447
448            if (otherAccount.isCredentialsExpired()) {
449                setCredentialsExpired(true);
450            }
451        }
452    }
453
454    /**
455     * If the {@link #getPrincipals() principals} are not null, returns <code>principals.hashCode()</code>, otherwise
456     * returns 0 (zero).
457     *
458     * @return <code>principals.hashCode()</code> if they are not null, 0 (zero) otherwise.
459     */
460    public int hashCode() {
461        return (getPrincipals() != null ? getPrincipals().hashCode() : 0);
462    }
463
464    /**
465     * Returns <code>true</code> if the specified object is also a {@link SimpleAccount SimpleAccount} and its
466     * {@link #getPrincipals() principals} are equal to this object's <code>principals</code>, <code>false</code> otherwise.
467     *
468     * @param o the object to test for equality.
469     * @return <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    public boolean equals(Object o) {
473        if (o == this) {
474            return true;
475        }
476        if (o instanceof SimpleAccount) {
477            SimpleAccount sa = (SimpleAccount) o;
478            //principal should be unique across the application, so only check this for equality:
479            return (getPrincipals() != null ? getPrincipals().equals(sa.getPrincipals()) : sa.getPrincipals() == null);
480        }
481        return false;
482    }
483
484    /**
485     * Returns {@link #getPrincipals() principals}.toString() if they are not null, otherwise prints out the string
486     * &quot;empty&quot;
487     *
488     * @return the String representation of this Account object.
489     */
490    public String toString() {
491        return getPrincipals() != null ? getPrincipals().toString() : "empty";
492    }
493
494}