001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.authc.credential;
020
021import org.apache.shiro.util.ByteSource;
022
023/**
024 * A {@code PasswordService} supports common use cases when using passwords as a credentials mechanism.
025 * <p/>
026 * Most importantly, implementations of this interface are expected to employ best-practices to ensure that
027 * passwords remain as safe as possible in application environments.
028 * <h2>Usage</h2>
029 * A {@code PasswordService} is used at two different times during an application's lifecycle:
030 * <ul>
031 * <li>When creating a user account or resetting their password</li>
032 * <li>When a user logs in, when passwords must be compared</li>
033 * </ul>
034 * <h3>Account Creation or Password Reset</h3>
035 * Whenever you create a new user account or reset that account's password, we must translate the end-user submitted
036 * raw/plaintext password value to a string format that is much safer to store.  You do that by calling the
037 * {@link #encryptPassword(Object)} method to create the safer value.  For
038 * example:
039 * <pre>
040 * String submittedPlaintextPassword = ...
041 * String encryptedValue = passwordService.encryptPassword(submittedPlaintextPassword);
042 * ...
043 * userAccount.setPassword(encryptedValue);
044 * userAccount.save(); //create or update to your data store
045 * </pre>
046 * Be sure to save this encrypted password in your data store and never the original/raw submitted password.
047 * <h3>Login Password Comparison</h3>
048 * Shiro performs the comparison during login automatically.  Along with your {@code PasswordService}, you just
049 * have to configure a {@link PasswordMatcher} on a realm that has password-based accounts.   During a login attempt,
050 * shiro will use the {@code PasswordMatcher} and the {@code PasswordService} to automatically compare submitted
051 * passwords.
052 * <p/>
053 * For example, if using Shiro's INI, here is how you might configure the PasswordMatcher and PasswordService:
054 * <pre>
055 * [main]
056 * ...
057 * passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
058 * # configure the passwordService to use the settings you desire
059 * ...
060 * passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
061 * passwordMatcher.passwordService = $passwordService
062 * ...
063 * # Finally, set the matcher on a realm that requires password matching for account authentication:
064 * myRealm = ...
065 * myRealm.credentialsMatcher = $passwordMatcher
066 * </pre>
067 *
068 * @see DefaultPasswordService
069 * @see PasswordMatcher
070 * @since 1.2
071 */
072public interface PasswordService {
073
074    /**
075     * Converts the specified plaintext password (usually acquired from your application's 'new user' or 'password reset'
076     * workflow) into a formatted string safe for storage.  The returned string can be safely saved with the
077     * corresponding user account record (e.g. as a 'password' attribute).
078     * <p/>
079     * It is expected that the String returned from this method will be presented to the
080     * {@link #passwordsMatch(Object, String) passwordsMatch(plaintext,encrypted)} method when performing a
081     * password comparison check.
082     * <h3>Usage</h3>
083     * The input argument type can be any 'byte backed' {@code Object} - almost always either a
084     * String or character array representing passwords (character arrays are often a safer way to represent passwords
085     * as they can be cleared/nulled-out after use.  Any argument type supported by
086     * {@link ByteSource.Util#isCompatible(Object)} is valid.
087     * <p/>
088     * For example:
089     * <pre>
090     * String rawPassword = ...
091     * String encryptedValue = passwordService.encryptPassword(rawPassword);
092     * </pre>
093     * or, identically:
094     * <pre>
095     * char[] rawPasswordChars = ...
096     * String encryptedValue = passwordService.encryptPassword(rawPasswordChars);
097     * </pre>
098     * <p/>
099     * The resulting {@code encryptedValue} should be stored with the account to be retrieved later during a
100     * login attempt.  For example:
101     * <pre>
102     * String encryptedValue = passwordService.encryptPassword(rawPassword);
103     * ...
104     * userAccount.setPassword(encryptedValue);
105     * userAccount.save(); //create or update to your data store
106     * </pre>
107     *
108     * @param plaintextPassword the raw password as 'byte-backed' object (String, character array, {@link ByteSource},
109     *                          etc) usually acquired from your application's 'new user' or 'password reset' workflow.
110     * @return the encrypted password, formatted for storage.
111     * @throws IllegalArgumentException if the argument cannot be easily converted to bytes as defined by
112     *                                  {@link ByteSource.Util#isCompatible(Object)}.
113     * @see ByteSource.Util#isCompatible(Object)
114     */
115    String encryptPassword(Object plaintextPassword) throws IllegalArgumentException;
116
117    /**
118     * Returns {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password,
119     * {@code false} otherwise.
120     * <h3>Usage</h3>
121     * The {@code submittedPlaintext} argument type can be any 'byte backed' {@code Object} - almost always either a
122     * String or character array representing passwords (character arrays are often a safer way to represent passwords
123     * as they can be cleared/nulled-out after use.  Any argument type supported by
124     * {@link ByteSource.Util#isCompatible(Object)} is valid.
125     * <p/>
126     * For example:
127     * <pre>
128     * String submittedPassword = ...
129     * passwordService.passwordsMatch(submittedPassword, encryptedPassword);
130     * </pre>
131     * or similarly:
132     * <pre>
133     * char[] submittedPasswordCharacters = ...
134     * passwordService.passwordsMatch(submittedPasswordCharacters, encryptedPassword);
135     * </pre>
136     *
137     * @param submittedPlaintext a raw/plaintext password submitted by an end user/Subject.
138     * @param encrypted          the previously encrypted password known to be associated with an account.
139     *                           This value is expected to have been previously generated from the
140     *                           {@link #encryptPassword(Object) encryptPassword} method (typically
141     *                           when the account is created or the account's password is reset).
142     * @return {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password,
143     *         {@code false} otherwise.
144     * @see ByteSource.Util#isCompatible(Object)
145     */
146    boolean passwordsMatch(Object submittedPlaintext, String encrypted);
147}