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