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.Logger; 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 }