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 }