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.PasswordService;
20 
21 import hunt.shiro.util.ByteSource;
22 
23 /**
24  * A {@code PasswordService} supports common use cases when using passwords as a credentials mechanism.
25  * <p/>
26  * Most importantly, implementations of this interface are expected to employ best-practices to ensure that
27  * passwords remain as safe as possible in application environments.
28  * <h2>Usage</h2>
29  * A {@code PasswordService} is used at two different times during an application's lifecycle:
30  * <ul>
31  * <li>When creating a user account or resetting their password</li>
32  * <li>When a user logs in, when passwords must be compared</li>
33  * </ul>
34  * <h3>Account Creation or Password Reset</h3>
35  * Whenever you create a new user account or reset that account's password, we must translate the end-user submitted
36  * raw/plaintext password value to a string format that is much safer to store.  You do that by calling the
37  * {@link #encryptPassword(Object)} method to create the safer value.  For
38  * example:
39  * <pre>
40  * string submittedPlaintextPassword = ...
41  * string encryptedValue = passwordService.encryptPassword(submittedPlaintextPassword);
42  * ...
43  * userAccount.setPassword(encryptedValue);
44  * userAccount.save(); //create or update to your data store
45  * </pre>
46  * Be sure to save this encrypted password in your data store and never the original/raw submitted password.
47  * <h3>Login Password Comparison</h3>
48  * Shiro performs the comparison during login automatically.  Along with your {@code PasswordService}, you just
49  * have to configure a {@link PasswordMatcher} on a realm that has password-based accounts.   During a login attempt,
50  * shiro will use the {@code PasswordMatcher} and the {@code PasswordService} to automatically compare submitted
51  * passwords.
52  * <p/>
53  * For example, if using Shiro's INI, here is how you might configure the PasswordMatcher and PasswordService:
54  * <pre>
55  * [main]
56  * ...
57  * passwordService = hunt.shiro.authc.credential.DefaultPasswordService
58  * # configure the passwordService to use the settings you desire
59  * ...
60  * passwordMatcher = hunt.shiro.authc.credential.PasswordMatcher
61  * passwordMatcher.passwordService = $passwordService
62  * ...
63  * # Finally, set the matcher on a realm that requires password matching for account authentication:
64  * myRealm = ...
65  * myRealm.credentialsMatcher = $passwordMatcher
66  * </pre>
67  *
68  * @see DefaultPasswordService
69  * @see PasswordMatcher
70  */
71 interface PasswordService {
72 
73     /**
74      * Converts the specified plaintext password (usually acquired from your application's 'new user' or 'password reset'
75      * workflow) into a formatted string safe for storage.  The returned string can be safely saved with the
76      * corresponding user account record (e.g. as a 'password' attribute).
77      * <p/>
78      * It is expected that the string returned from this method will be presented to the
79      * {@link #passwordsMatch(Object, string) passwordsMatch(plaintext,encrypted)} method when performing a
80      * password comparison check.
81      * <h3>Usage</h3>
82      * The input argument type can be any 'byte backed' {@code Object} - almost always either a
83      * string or character array representing passwords (character arrays are often a safer way to represent passwords
84      * as they can be cleared/nulled-out after use.  Any argument type supported by
85      * {@link ByteSourceUtil#isCompatible(Object)} is valid.
86      * <p/>
87      * For example:
88      * <pre>
89      * string rawPassword = ...
90      * string encryptedValue = passwordService.encryptPassword(rawPassword);
91      * </pre>
92      * or, identically:
93      * <pre>
94      * char[] rawPasswordChars = ...
95      * string encryptedValue = passwordService.encryptPassword(rawPasswordChars);
96      * </pre>
97      * <p/>
98      * The resulting {@code encryptedValue} should be stored with the account to be retrieved later during a
99      * login attempt.  For example:
100      * <pre>
101      * string encryptedValue = passwordService.encryptPassword(rawPassword);
102      * ...
103      * userAccount.setPassword(encryptedValue);
104      * userAccount.save(); //create or update to your data store
105      * </pre>
106      *
107      * @param plaintextPassword the raw password as 'byte-backed' object (string, character array, {@link ByteSource},
108      *                          etc) usually acquired from your application's 'new user' or 'password reset' workflow.
109      * @return the encrypted password, formatted for storage.
110      * @throws IllegalArgumentException if the argument cannot be easily converted to bytes as defined by
111      *                                  {@link ByteSourceUtil#isCompatible(Object)}.
112      * @see ByteSourceUtil#isCompatible(Object)
113      */
114     string encryptPassword(Object plaintextPassword);
115 
116     /**
117      * Returns {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password,
118      * {@code false} otherwise.
119      * <h3>Usage</h3>
120      * The {@code submittedPlaintext} argument type can be any 'byte backed' {@code Object} - almost always either a
121      * string or character array representing passwords (character arrays are often a safer way to represent passwords
122      * as they can be cleared/nulled-out after use.  Any argument type supported by
123      * {@link ByteSourceUtil#isCompatible(Object)} is valid.
124      * <p/>
125      * For example:
126      * <pre>
127      * string submittedPassword = ...
128      * passwordService.passwordsMatch(submittedPassword, encryptedPassword);
129      * </pre>
130      * or similarly:
131      * <pre>
132      * char[] submittedPasswordCharacters = ...
133      * passwordService.passwordsMatch(submittedPasswordCharacters, encryptedPassword);
134      * </pre>
135      *
136      * @param submittedPlaintext a raw/plaintext password submitted by an end user/Subject.
137      * @param encrypted          the previously encrypted password known to be associated with an account.
138      *                           This value is expected to have been previously generated from the
139      *                           {@link #encryptPassword(Object) encryptPassword} method (typically
140      *                           when the account is created or the account's password is reset).
141      * @return {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password,
142      *         {@code false} otherwise.
143      * @see ByteSourceUtil#isCompatible(Object)
144      */
145     bool passwordsMatch(Object submittedPlaintext, string encrypted);
146 }