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 module hunt.shiro.authc.SimpleAuthenticationInfo;
20 
21 import hunt.shiro.authc.AuthenticationInfo;
22 import hunt.shiro.authc.MergableAuthenticationInfo;
23 import hunt.shiro.authc.SaltedAuthenticationInfo;
24 import hunt.shiro.subject.MutablePrincipalCollection;
25 import hunt.shiro.subject.PrincipalCollection;
26 import hunt.shiro.subject.SimplePrincipalCollection;
27 import hunt.shiro.util.ByteSource;
28 
29 
30 import hunt.collection;
31 import hunt.collection.HashSet;
32 import hunt.collection.Set;
33 
34 
35 /**
36  * Simple implementation of the {@link hunt.shiro.authc.MergableAuthenticationInfo} interface that holds the principals and
37  * credentials.
38  *
39  * @see hunt.shiro.realm.AuthenticatingRealm
40  */
41 class SimpleAuthenticationInfo : MergableAuthenticationInfo, SaltedAuthenticationInfo {
42 
43     /**
44      * The principals identifying the account associated with this AuthenticationInfo instance.
45      */
46     protected PrincipalCollection principals;
47     
48     /**
49      * The credentials verifying the account principals.
50      */
51     protected Object credentials;
52 
53     /**
54      * Any salt used in hashing the credentials.
55      *
56      */
57     protected ByteSource credentialsSalt;
58 
59     /**
60      * Default no-argument constructor.
61      */
62     this() {
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      this(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 hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
93      */
94      this(Object principal, Object hashedCredentials, ByteSource credentialsSalt, string realmName) {
95         this.principals = new SimplePrincipalCollection(principal, realmName);
96         this.credentials = hashedCredentials;
97         this.credentialsSalt = credentialsSalt;
98     }
99 
100     /**
101      * Constructor that takes in an account's identifying principal(s) and its corresponding credentials that verify
102      * the principals.
103      *
104      * @param principals  a Realm's account's identifying principal(s)
105      * @param credentials the accounts corresponding principals that verify the principals.
106      */
107      this(PrincipalCollection principals, Object credentials) {
108         this.principals = new SimplePrincipalCollection(principals);
109         this.credentials = credentials;
110     }
111 
112     /**
113      * Constructor that takes in an account's identifying principal(s), hashed credentials used to verify the
114      * principals, and the salt used when hashing the credentials.
115      *
116      * @param principals        a Realm's account's identifying principal(s)
117      * @param hashedCredentials the hashed credentials that verify the principals.
118      * @param credentialsSalt   the salt used when hashing the hashedCredentials.
119      * @see hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher
120      */
121      this(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) {
122         this.principals = new SimplePrincipalCollection(principals);
123         this.credentials = hashedCredentials;
124         this.credentialsSalt = credentialsSalt;
125     }
126 
127 
128     PrincipalCollection getPrincipals() @trusted nothrow {
129         return principals;
130     }
131 
132     /**
133      * Sets the identifying principal(s) represented by this instance.
134      *
135      * @param principals the indentifying attributes of the corresponding Realm account.
136      */
137      void setPrincipals(PrincipalCollection principals) {
138         this.principals = principals;
139     }
140 
141      Object getCredentials() {
142         return credentials;
143     }
144 
145     /**
146      * Sets the credentials that verify the principals/identity of the associated Realm account.
147      *
148      * @param credentials attribute(s) that verify the account's identity/principals, such as a password or private key.
149      */
150      void setCredentials(Object credentials) {
151         this.credentials = credentials;
152     }
153 
154     /**
155      * Returns the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
156      * hashed at all.
157      * <p/>
158      * Note that this attribute is <em>NOT</em> handled in the
159      * {@link #merge(AuthenticationInfo) merge} method - a hash salt is only useful within a single realm (as each
160      * realm will perform it's own Credentials Matching logic), and once finished in that realm, Shiro has no further
161      * use for salts.  Therefore it doesn't make sense to 'merge' salts in a multi-realm scenario.
162      *
163      * @return the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
164      *         hashed at all.
165      */
166      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      */
182      void setCredentialsSalt(ByteSource salt) {
183         this.credentialsSalt = salt;
184     }
185 
186     /**
187      * Takes the specified <code>info</code> argument and adds its principals and credentials into this instance.
188      *
189      * @param info the <code>AuthenticationInfo</code> to add into this instance.
190      */
191 
192      void merge(AuthenticationInfo info) {
193         if (info  is null || info.getPrincipals()  is null || info.getPrincipals().isEmpty()) {
194             return;
195         }
196 
197         if (this.principals  is null) {
198             this.principals = info.getPrincipals();
199         } else {
200             auto principalsCast = cast(MutablePrincipalCollection)this.principals;
201             if (principalsCast is null) {
202                 this.principals = new SimplePrincipalCollection(this.principals);
203             }
204             principalsCast.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         auto infoCast = cast(SaltedAuthenticationInfo)info;
214         if (this.credentialsSalt  is null && infoCast !is null) {
215             this.credentialsSalt = infoCast.getCredentialsSalt();
216         }
217 
218         Object thisCredentials = getCredentials();
219         Object otherCredentials = info.getCredentials();
220 
221         if (otherCredentials  is null) {
222             return;
223         }
224 
225         if (thisCredentials  is null) {
226             this.credentials = otherCredentials;
227             return;
228         }
229         auto thisCredentialsCast = cast(Collection!Object) thisCredentials;
230         if (thisCredentialsCast is null) {
231             Set!Object newSet = new HashSet!Object();
232             newSet.add(thisCredentials);
233             setCredentials(cast(Object)newSet);
234         }
235 
236         // At this point, the credentials should be a collection
237         Collection!Object credentialCollection = cast(Collection!Object)getCredentials();
238         auto otherCredentialsCast = cast(Collection!Object)otherCredentials;
239         if (otherCredentialsCast !is null) {
240             credentialCollection.addAll(otherCredentialsCast);
241         } else {
242             credentialCollection.add(otherCredentials);
243         }
244     }
245 
246     /**
247      * Returns <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and
248      * its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise.
249      *
250      * @param o the object to compare for equality.
251      * @return <code>true</code> if the Object argument is an <code>instanceof SimpleAuthenticationInfo</code> and
252      *         its {@link #getPrincipals() principals} are equal to this instance's principals, <code>false</code> otherwise.
253      */
254     override bool opEquals(Object o) {
255         if (this == o) return true;
256         auto oCast = cast(SimpleAuthenticationInfo)o;
257         if (oCast is null) return false;
258 
259         SimpleAuthenticationInfo that = oCast;
260 
261         //noinspection RedundantIfStatement
262         if (principals !is null ? principals != that.principals : that.principals !is null) return false;
263 
264         return true;
265     }
266 
267     /**
268      * Returns the hashcode of the internal {@link #getPrincipals() principals} instance.
269      *
270      * @return the hashcode of the internal {@link #getPrincipals() principals} instance.
271      */
272     override size_t toHash() @trusted nothrow {
273         return (principals !is null ? (cast(Object)principals).toHash() : 0);
274     }
275 
276     /**
277      * Simple implementation that merely returns <code>{@link #getPrincipals() principals}.toString()</code>
278      *
279      * @return <code>{@link #getPrincipals() principals}.toString()</code>
280      */
281     override string toString() {
282         return (cast(Object) principals).toString();
283     }
284 
285 }