View Javadoc
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 }