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 package org.apache.shiro.authc;
20
21 import org.apache.shiro.lang.util.ByteSource;
22 import org.apache.shiro.lang.util.SimpleByteSource;
23 import org.apache.shiro.subject.MutablePrincipalCollection;
24 import org.apache.shiro.subject.PrincipalCollection;
25 import org.apache.shiro.subject.SimplePrincipalCollection;
26
27 import java.util.Collection;
28 import java.util.HashSet;
29 import java.util.Objects;
30 import java.util.Set;
31
32
33 /**
34 * Simple implementation of the {@link org.apache.shiro.authc.MergableAuthenticationInfo} interface that holds the principals and
35 * credentials.
36 *
37 * @see org.apache.shiro.realm.AuthenticatingRealm
38 * @since 0.9
39 */
40 public class SimpleAuthenticationInfo implements MergableAuthenticationInfo, SaltedAuthenticationInfo {
41
42 private static final long serialVersionUID = 5390456512469696779L;
43 /**
44 * The principals identifying the account associated with this AuthenticationInfo instance.
45 */
46 protected PrincipalCollection principals;
47 /**
48 * The credentials verifying the account principals.
49 */
50 protected Object credentials;
51
52 /**
53 * Any salt used in hashing the credentials.
54 *
55 * @since 1.1
56 */
57 protected ByteSource credentialsSalt = SimpleByteSource.empty();
58
59 /**
60 * Default no-argument constructor.
61 */
62 public SimpleAuthenticationInfo() {
63 }
64
65 /**
66 * Constructor that takes in a single 'primary' principal of the account and its corresponding credentials,
67 * associated with the specified realm.
68 * <p/>
69 * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based
70 * on the {@code principal} and {@code realmName} argument.
71 *
72 * @param principal the 'primary' principal associated with the specified realm.
73 * @param credentials the credentials that verify the given principal.
74 * @param realmName the realm from where the principal and credentials were acquired.
75 */
76 public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {
77 this.principals = new SimplePrincipalCollection(principal, realmName);
78 this.credentials = credentials;
79 }
80
81 /**
82 * Constructor that takes in a single 'primary' principal of the account, its corresponding hashed credentials,
83 * the salt used to hash the credentials, and the name of the realm to associate with the principals.
84 * <p/>
85 * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based
86 * on the <code>principal</code> and <code>realmName</code> argument.
87 *
88 * @param principal the 'primary' principal associated with the specified realm.
89 * @param hashedCredentials the hashed credentials that verify the given principal.
90 * @param credentialsSalt the salt used when hashing the given hashedCredentials
91 * @param realmName the realm from where the principal and credentials were acquired.
92 * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
93 * @since 1.1
94 */
95 public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
96 this.principals = new SimplePrincipalCollection(principal, realmName);
97 this.credentials = hashedCredentials;
98 this.credentialsSalt = credentialsSalt;
99 }
100
101 /**
102 * Constructor that takes in an account's identifying principal(s) and its corresponding credentials that verify
103 * the principals.
104 *
105 * @param principals a Realm's account's identifying principal(s)
106 * @param credentials the accounts corresponding principals that verify the principals.
107 */
108 public SimpleAuthenticationInfo(PrincipalCollection principals, Object credentials) {
109 this.principals = new SimplePrincipalCollection(principals);
110 this.credentials = credentials;
111 }
112
113 /**
114 * Constructor that takes in an account's identifying principal(s), hashed credentials used to verify the
115 * principals, and the salt used when hashing the credentials.
116 *
117 * @param principals a Realm's account's identifying principal(s)
118 * @param hashedCredentials the hashed credentials that verify the principals.
119 * @param credentialsSalt the salt used when hashing the hashedCredentials.
120 * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
121 * @since 1.1
122 */
123 public SimpleAuthenticationInfo(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) {
124 this.principals = new SimplePrincipalCollection(principals);
125 this.credentials = hashedCredentials;
126 this.credentialsSalt = credentialsSalt;
127 }
128
129
130 @Override
131 public PrincipalCollection getPrincipals() {
132 return principals;
133 }
134
135 /**
136 * Sets the identifying principal(s) represented by this instance.
137 *
138 * @param principals the identifying attributes of the corresponding Realm account.
139 */
140 public void setPrincipals(PrincipalCollection principals) {
141 this.principals = principals;
142 }
143
144 @Override
145 public Object getCredentials() {
146 return credentials;
147 }
148
149 /**
150 * Sets the credentials that verify the principals/identity of the associated Realm account.
151 *
152 * @param credentials attribute(s) that verify the account's identity/principals, such as a password or private key.
153 */
154 public void setCredentials(Object credentials) {
155 this.credentials = credentials;
156 }
157
158 /**
159 * Returns the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
160 * hashed at all.
161 * <p/>
162 * Note that this attribute is <em>NOT</em> handled in the
163 * {@link #merge(AuthenticationInfo) merge} method - a hash salt is only useful within a single realm (as each
164 * realm will perform it's own Credentials Matching logic), and once finished in that realm, Shiro has no further
165 * use for salts. Therefore it doesn't make sense to 'merge' salts in a multi-realm scenario.
166 *
167 * @return the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
168 * hashed at all.
169 * @since 1.1
170 */
171 @Override
172 public ByteSource getCredentialsSalt() {
173 return credentialsSalt;
174 }
175
176 /**
177 * Sets the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
178 * hashed at all.
179 * <p/>
180 * Note that this attribute is <em>NOT</em> handled in the
181 * {@link #merge(AuthenticationInfo) merge} method - a hash salt is only useful within a single realm (as each
182 * realm will perform it's own Credentials Matching logic), and once finished in that realm, Shiro has no further
183 * use for salts. Therefore it doesn't make sense to 'merge' salts in a multi-realm scenario.
184 *
185 * @param salt the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
186 * hashed at all.
187 * @since 1.1
188 */
189 public void setCredentialsSalt(ByteSource salt) {
190 this.credentialsSalt = salt;
191 }
192
193 /**
194 * Takes the specified <code>info</code> argument and adds its principals and credentials into this instance.
195 *
196 * @param info the <code>AuthenticationInfo</code> to add into this instance.
197 */
198 @Override
199 @SuppressWarnings({"unchecked", "checkstyle:NPathComplexity"})
200 public void merge(AuthenticationInfo info) {
201 if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty()) {
202 return;
203 }
204
205 if (this.principals == null) {
206 this.principals = info.getPrincipals();
207 } else {
208 if (!(this.principals instanceof MutablePrincipalCollection)) {
209 this.principals = new SimplePrincipalCollection(this.principals);
210 }
211 ((MutablePrincipalCollection) this.principals).addAll(info.getPrincipals());
212 }
213
214 //only mess with a salt value if we don't have one yet. It doesn't make sense
215 //to merge salt values from different realms because a salt is used only within
216 //the realm's credential matching process. But if the current instance's salt
217 //is null, then it can't hurt to pull in a non-null value if one exists.
218 //
219 //since 1.1:
220 if (this.credentialsSalt == null && info instanceof SaltedAuthenticationInfo) {
221 this.credentialsSalt = ((SaltedAuthenticationInfo) info).getCredentialsSalt();
222 }
223
224 Object thisCredentials = getCredentials();
225 Object otherCredentials = info.getCredentials();
226
227 if (otherCredentials == null) {
228 return;
229 }
230
231 if (thisCredentials == null) {
232 this.credentials = otherCredentials;
233 return;
234 }
235
236 if (!(thisCredentials instanceof Collection)) {
237 Set newSet = new HashSet();
238 newSet.add(thisCredentials);
239 setCredentials(newSet);
240 }
241
242 // At this point, the credentials should be a collection
243 Collection credentialCollection = (Collection) getCredentials();
244 if (otherCredentials instanceof Collection) {
245 credentialCollection.addAll((Collection) otherCredentials);
246 } else {
247 credentialCollection.add(otherCredentials);
248 }
249 }
250
251 /**
252 * Returns <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and
253 * its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise.
254 *
255 * @param o the object to compare for equality.
256 * @return <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and
257 * its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise.
258 */
259 @Override
260 public boolean equals(Object o) {
261 if (this == o) {
262 return true;
263 }
264 if (!(o instanceof SimpleAuthenticationInfo)) {
265 return false;
266 }
267
268 SimpleAuthenticationInfo that = (SimpleAuthenticationInfo) o;
269
270 //noinspection RedundantIfStatement
271 if (!Objects.equals(principals, that.principals)) {
272 return false;
273 }
274
275 return true;
276 }
277
278 /**
279 * Returns the hashcode of the internal {@link #getPrincipals() principals} instance.
280 *
281 * @return the hashcode of the internal {@link #getPrincipals() principals} instance.
282 */
283 @Override
284 public int hashCode() {
285 return (principals != null ? principals.hashCode() : 0);
286 }
287
288 /**
289 * Simple implementation that merely returns <code>{@link #getPrincipals() principals}.toString()</code>
290 *
291 * @return <code>{@link #getPrincipals() principals}.toString()</code>
292 */
293 @Override
294 public String toString() {
295 return principals.toString();
296 }
297
298 }