View Javadoc

1   /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.springframework.security.userdetails;
17  
18  import java.util.SortedSet;
19  import java.util.TreeSet;
20  
21  import org.springframework.security.GrantedAuthority;
22  import org.springframework.util.Assert;
23  
24  
25  /**
26   * Models core user information retieved by an {@link UserDetailsService}.<p>Implemented with value object
27   * semantics (immutable after construction, like a <code>String</code>). Developers may use this class directly,
28   * subclass it, or write their own {@link UserDetails} implementation from scratch.</p>
29   *
30   * @author Ben Alex
31   * @version $Id: User.java 2780 2008-03-22 11:44:28Z luke_t $
32   */
33  public class User implements UserDetails {
34      //~ Instance fields ================================================================================================
35  
36      private static final long serialVersionUID = 1L;
37      private String password;
38      private String username;
39      private GrantedAuthority[] authorities;
40      private boolean accountNonExpired;
41      private boolean accountNonLocked;
42      private boolean credentialsNonExpired;
43      private boolean enabled;
44  
45      //~ Constructors ===================================================================================================
46  
47      /**
48       * Construct the <code>User</code> with the details required by
49       * {@link org.springframework.security.providers.dao.DaoAuthenticationProvider}.
50       *
51       * @param username the username presented to the
52       *        <code>DaoAuthenticationProvider</code>
53       * @param password the password that should be presented to the
54       *        <code>DaoAuthenticationProvider</code>
55       * @param enabled set to <code>true</code> if the user is enabled
56       * @param authorities the authorities that should be granted to the caller
57       *        if they presented the correct username and password and the user
58       *        is enabled
59       *
60       * @throws IllegalArgumentException if a <code>null</code> value was passed
61       *         either as a parameter or as an element in the
62       *         <code>GrantedAuthority[]</code> array
63       *
64       * @deprecated use new constructor with extended properties (this
65       *             constructor will be removed from release 1.0.0)
66       */
67      public User(String username, String password, boolean enabled, GrantedAuthority[] authorities)
68          throws IllegalArgumentException {
69          this(username, password, enabled, true, true, authorities);
70      }
71  
72      /**
73       * Construct the <code>User</code> with the details required by
74       * {@link org.springframework.security.providers.dao.DaoAuthenticationProvider}.
75       *
76       * @param username the username presented to the
77       *        <code>DaoAuthenticationProvider</code>
78       * @param password the password that should be presented to the
79       *        <code>DaoAuthenticationProvider</code>
80       * @param enabled set to <code>true</code> if the user is enabled
81       * @param accountNonExpired set to <code>true</code> if the account has not
82       *        expired
83       * @param credentialsNonExpired set to <code>true</code> if the credentials
84       *        have not expired
85       * @param authorities the authorities that should be granted to the caller
86       *        if they presented the correct username and password and the user
87       *        is enabled
88       *
89       * @throws IllegalArgumentException if a <code>null</code> value was passed
90       *         either as a parameter or as an element in the
91       *         <code>GrantedAuthority[]</code> array
92       *
93       * @deprecated use new constructor with extended properties (this
94       *             constructor will be removed from release 1.0.0)
95       */
96      public User(String username, String password, boolean enabled, boolean accountNonExpired,
97          boolean credentialsNonExpired, GrantedAuthority[] authorities)
98          throws IllegalArgumentException {
99          this(username, password, enabled, accountNonExpired, credentialsNonExpired, true, authorities);
100     }
101 
102     /**
103      * Construct the <code>User</code> with the details required by
104      * {@link org.springframework.security.providers.dao.DaoAuthenticationProvider}.
105      *
106      * @param username the username presented to the
107      *        <code>DaoAuthenticationProvider</code>
108      * @param password the password that should be presented to the
109      *        <code>DaoAuthenticationProvider</code>
110      * @param enabled set to <code>true</code> if the user is enabled
111      * @param accountNonExpired set to <code>true</code> if the account has not
112      *        expired
113      * @param credentialsNonExpired set to <code>true</code> if the credentials
114      *        have not expired
115      * @param accountNonLocked set to <code>true</code> if the account is not
116      *        locked
117      * @param authorities the authorities that should be granted to the caller
118      *        if they presented the correct username and password and the user
119      *        is enabled
120      *
121      * @throws IllegalArgumentException if a <code>null</code> value was passed
122      *         either as a parameter or as an element in the
123      *         <code>GrantedAuthority[]</code> array
124      */
125     public User(String username, String password, boolean enabled, boolean accountNonExpired,
126         boolean credentialsNonExpired, boolean accountNonLocked, GrantedAuthority[] authorities)
127         throws IllegalArgumentException {
128         if (((username == null) || "".equals(username)) || (password == null)) {
129             throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
130         }
131 
132         this.username = username;
133         this.password = password;
134         this.enabled = enabled;
135         this.accountNonExpired = accountNonExpired;
136         this.credentialsNonExpired = credentialsNonExpired;
137         this.accountNonLocked = accountNonLocked;
138         setAuthorities(authorities);
139     }
140 
141     //~ Methods ========================================================================================================
142 
143     public boolean equals(Object rhs) {
144         if (!(rhs instanceof User) || (rhs == null)) {
145             return false;
146         }
147 
148         User user = (User) rhs;
149 
150         // We rely on constructor to guarantee any User has non-null and >0
151         // authorities
152         if (user.getAuthorities().length != this.getAuthorities().length) {
153             return false;
154         }
155 
156         for (int i = 0; i < this.getAuthorities().length; i++) {
157             if (!this.getAuthorities()[i].equals(user.getAuthorities()[i])) {
158                 return false;
159             }
160         }
161 
162         // We rely on constructor to guarantee non-null username and password
163         return (this.getPassword().equals(user.getPassword()) && this.getUsername().equals(user.getUsername())
164                 && (this.isAccountNonExpired() == user.isAccountNonExpired())
165                 && (this.isAccountNonLocked() == user.isAccountNonLocked())
166                 && (this.isCredentialsNonExpired() == user.isCredentialsNonExpired())
167                 && (this.isEnabled() == user.isEnabled()));
168     }
169 
170     public GrantedAuthority[] getAuthorities() {
171         return authorities;
172     }
173 
174     public String getPassword() {
175         return password;
176     }
177 
178     public String getUsername() {
179         return username;
180     }
181 
182     public int hashCode() {
183         int code = 9792;
184 
185         if (this.getAuthorities() != null) {
186             for (int i = 0; i < this.getAuthorities().length; i++) {
187                 code = code * (this.getAuthorities()[i].hashCode() % 7);
188             }
189         }
190 
191         if (this.getPassword() != null) {
192             code = code * (this.getPassword().hashCode() % 7);
193         }
194 
195         if (this.getUsername() != null) {
196             code = code * (this.getUsername().hashCode() % 7);
197         }
198 
199         if (this.isAccountNonExpired()) {
200             code = code * -2;
201         }
202 
203         if (this.isAccountNonLocked()) {
204             code = code * -3;
205         }
206 
207         if (this.isCredentialsNonExpired()) {
208             code = code * -5;
209         }
210 
211         if (this.isEnabled()) {
212             code = code * -7;
213         }
214 
215         return code;
216     }
217 
218     public boolean isAccountNonExpired() {
219         return accountNonExpired;
220     }
221 
222     public boolean isAccountNonLocked() {
223         return this.accountNonLocked;
224     }
225 
226     public boolean isCredentialsNonExpired() {
227         return credentialsNonExpired;
228     }
229 
230     public boolean isEnabled() {
231         return enabled;
232     }
233 
234     protected void setAuthorities(GrantedAuthority[] authorities) {
235         Assert.notNull(authorities, "Cannot pass a null GrantedAuthority array");
236         // Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-xxx)
237         SortedSet sorter = new TreeSet();
238         for (int i = 0; i < authorities.length; i++) {
239             Assert.notNull(authorities[i],
240                 "Granted authority element " + i + " is null - GrantedAuthority[] cannot contain any null elements");
241             sorter.add(authorities[i]);
242         }
243         
244         this.authorities = (GrantedAuthority[]) sorter.toArray(new GrantedAuthority[sorter.size()]);
245     }
246 
247     public String toString() {
248         StringBuffer sb = new StringBuffer();
249         sb.append(super.toString()).append(": ");
250         sb.append("Username: ").append(this.username).append("; ");
251         sb.append("Password: [PROTECTED]; ");
252         sb.append("Enabled: ").append(this.enabled).append("; ");
253         sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
254         sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
255         sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
256 
257         if (this.getAuthorities() != null) {
258             sb.append("Granted Authorities: ");
259 
260             for (int i = 0; i < this.getAuthorities().length; i++) {
261                 if (i > 0) {
262                     sb.append(", ");
263                 }
264 
265                 sb.append(this.getAuthorities()[i].toString());
266             }
267         } else {
268             sb.append("Not granted any authorities");
269         }
270 
271         return sb.toString();
272     }
273 }