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.credential.SimpleCredentialsMatcher;
20 
21 import hunt.shiro.authc.credential.CredentialsMatcher;
22 
23 import hunt.shiro.authc.AuthenticationInfo;
24 import hunt.shiro.authc.AuthenticationToken;
25 import hunt.shiro.codec.CodecSupport;
26 
27 import hunt.Exceptions;
28 import hunt.logging.ConsoleLogger;
29 
30 import hunt.String;
31 //import java.security.MessageDigest;
32 //import hunt.util.ArrayHelper;
33 
34 
35 /**
36  * Simple CredentialsMatcher implementation.  Supports direct (plain) comparison for credentials of type
37  * byte[], char[], and Strings, and if the arguments do not match these types, then reverts back to simple
38  * <code>Object.equals</code> comparison.
39  * <p/>
40  * <p>Hashing comparisons (the most common technique used in secure applications) are not supported by this class, but
41  * instead by the {@link hunt.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher}.
42  *
43  * @see hunt.shiro.authc.credential.HashedCredentialsMatcher
44  */
45 class SimpleCredentialsMatcher : CodecSupport, CredentialsMatcher {
46 
47 
48 
49     /**
50      * Returns the {@code token}'s credentials.
51      * <p/>
52      * <p>This default implementation merely returns
53      * {@link AuthenticationToken#getCredentials() authenticationToken.getCredentials()} and exists as a template hook
54      * if subclasses wish to obtain the credentials in a different way or convert them to a different format before
55      * returning.
56      *
57      * @param token the {@code AuthenticationToken} submitted during the authentication attempt.
58      * @return the {@code token}'s associated credentials.
59      */
60     protected char[] getCredentials(AuthenticationToken token) {
61         return token.getCredentials();
62     }
63 
64     /**
65      * Returns the {@code account}'s credentials.
66      * <p/>
67      * <p>This default implementation merely returns
68      * {@link AuthenticationInfo#getCredentials() account.getCredentials()} and exists as a template hook if subclasses
69      * wish to obtain the credentials in a different way or convert them to a different format before
70      * returning.
71      *
72      * @param info the {@code AuthenticationInfo} stored in the data store to be compared against the submitted authentication
73      *             token's credentials.
74      * @return the {@code account}'s associated credentials.
75      */
76     protected Object getCredentials(AuthenticationInfo info) {
77         return info.getCredentials();
78     }
79 
80     /**
81      * Returns {@code true} if the {@code tokenCredentials} argument is logically equal to the
82      * {@code accountCredentials} argument.
83      * <p/>
84      * <p>If both arguments are either a byte array (byte[]), char array (char[]) or string, they will be both be
85      * converted to raw byte arrays via the {@link #toBytes toBytes} method first, and then resulting byte arrays
86      * are compared via {@link Arrays#equals(byte[], byte[]) ArrayHelper.equals(byte[],byte[])}.</p>
87      * <p/>
88      * <p>If either argument cannot be converted to a byte array as described, a simple Object <code>equals</code>
89      * comparison is made.</p>
90      * <p/>
91      * <p>Subclasses should override this method for more explicit equality checks.
92      *
93      * @param tokenCredentials   the {@code AuthenticationToken}'s associated credentials.
94      * @param accountCredentials the {@code AuthenticationInfo}'s stored credentials.
95      * @return {@code true} if the {@code tokenCredentials} are equal to the {@code accountCredentials}.
96      */
97     protected bool equals(Object tokenCredentials, Object accountCredentials) {
98         version(HUNT_DEBUG) {
99             tracef("Performing credentials equality check for tokenCredentials of type [" ~
100                     typeid(tokenCredentials).name ~ " and accountCredentials of type [" ~
101                     typeid(accountCredentials).name ~ "]");
102         }
103         
104         implementationMissing(false);
105         return false;
106         // if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) {
107         //     version(HUNT_DEBUG) {
108         //         tracef("Both credentials arguments can be easily converted to byte ArrayHelper.  Performing " ~
109         //                 "array equals comparison");
110         //     }
111         //     byte[] tokenBytes = toBytes(tokenCredentials);
112         //     byte[] accountBytes = toBytes(accountCredentials);
113         //     //return MessageDigest.isEqual(tokenBytes, accountBytes);
114         //     return tokenBytes == accountBytes;
115         // } else {
116         //     return accountCredentials == tokenCredentials;
117         // }
118     }
119 
120     /**
121      * This implementation acquires the {@code token}'s credentials
122      * (via {@link #getCredentials(AuthenticationToken) getCredentials(token)})
123      * and then the {@code account}'s credentials
124      * (via {@link #getCredentials(hunt.shiro.authc.AuthenticationInfo) getCredentials(account)}) and then passes both of
125      * them to the {@link #equals(Object,Object) equals(tokenCredentials, accountCredentials)} method for equality
126      * comparison.
127      *
128      * @param token the {@code AuthenticationToken} submitted during the authentication attempt.
129      * @param info  the {@code AuthenticationInfo} stored in the system matching the token principal.
130      * @return {@code true} if the provided token credentials are equal to the stored account credentials,
131      *         {@code false} otherwise
132      */
133      bool doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
134         char[] tokenCredentials = getCredentials(token);
135         Object accountCredentials = getCredentials(info);
136 
137         String str = cast(String)accountCredentials;
138         if(str is null) {
139             warning("accountCredentials: ", typeid(accountCredentials));
140             return false;
141         }
142 
143         return cast(string)tokenCredentials == str.value;
144     }
145 
146 }