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.PasswordMatcher;
20 
21 import hunt.shiro.authc.credential.CredentialsMatcher;
22 import hunt.shiro.authc.credential.DefaultPasswordService;
23 import hunt.shiro.authc.credential.PasswordService;
24 import hunt.shiro.authc.credential.HashingPasswordService;
25 
26 import hunt.shiro.authc.AuthenticationInfo;
27 import hunt.shiro.authc.AuthenticationToken;
28 import hunt.shiro.crypto.hash.Hash;
29 
30 import hunt.Exceptions;
31 import hunt.String;
32 
33 
34 /**
35  * A {@link CredentialsMatcher} that employs best-practices comparisons for hashed text passwords.
36  * <p/>
37  * This implementation delegates to an internal {@link PasswordService} to perform the actual password
38  * comparison.  This class is essentially a bridge between the generic CredentialsMatcher interface and the
39  * more specific {@code PasswordService} component.
40  *
41  */
42 class PasswordMatcher : CredentialsMatcher {
43 
44     private PasswordService passwordService;
45 
46      this() {
47         this.passwordService = new DefaultPasswordService();
48     }
49 
50      bool doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
51 
52         // PasswordService service = ensurePasswordService();
53 
54         // Object submittedPassword = getSubmittedPassword(token);
55         // Object storedCredentials = getStoredPassword(info);
56         // assertStoredCredentialsType(storedCredentials);
57         // auto storedCredentialsCast = cast(Hash) storedCredentials;
58         // if (storedCredentialsCast !is null) {
59         //     Hash hashedPassword = storedCredentialsCast;
60         //     HashingPasswordService hashingService = assertHashingPasswordService(service);
61         //     return hashingService.passwordsMatch(submittedPassword, hashedPassword);
62         // }
63         // //otherwise they are a string (asserted in the 'assertStoredCredentialsType' method call above):
64         // string formatted = (cast(String)storedCredentials).value;
65         // return passwordService.passwordsMatch(submittedPassword, formatted);
66         implementationMissing(false);
67         return false;
68     }
69 
70     private HashingPasswordService assertHashingPasswordService(PasswordService service) {
71         auto serviceCast = cast(HashingPasswordService)service;
72         if (serviceCast !is null) {
73             return serviceCast;
74         }
75         string msg = "AuthenticationInfo's stored credentials are a Hash instance, but the " ~
76                 "configured passwordService is not a " ~
77                 "HashingPasswordService instance.  This is required to perform Hash " ~
78                 "object password comparisons.";
79         throw new IllegalStateException(msg);
80     }
81 
82     private PasswordService ensurePasswordService() {
83         PasswordService service = getPasswordService();
84         if (service  is null) {
85             string msg = "Required PasswordService has not been configured.";
86             throw new IllegalStateException(msg);
87         }
88         return service;
89     }
90 
91     protected char[] getSubmittedPassword(AuthenticationToken token) {
92         return token !is null ? token.getCredentials() : null;
93     }
94 
95     private void assertStoredCredentialsType(Object credentials) {
96         auto credentialsCast = cast(String)credentials;
97         auto credentialsCast2 = cast(Hash)credentials;
98         if (credentialsCast !is null || credentialsCast2 !is null) {
99             return;
100         }
101 
102         string msg = "Stored account credentials are expected to be either a " ~
103                      "Hash instance or a formatted hash string.";
104         throw new IllegalArgumentException(msg);
105     }
106 
107     protected Object getStoredPassword(AuthenticationInfo storedAccountInfo) {
108         Object stored = storedAccountInfo !is null ? storedAccountInfo.getCredentials() : null;
109         //fix for https://issues.apache.org/jira/browse/SHIRO-363
110         // if (stored instanceof[] char) {
111         //     stored = new string((char[])stored);
112         // }
113         return stored;
114     }
115 
116      PasswordService getPasswordService() {
117         return passwordService;
118     }
119 
120      void setPasswordService(PasswordService passwordService) {
121         this.passwordService = passwordService;
122     }
123 }