/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.shiro.authc.credential; import org.apache.shiro.util.ByteSource; /** * A {@code PasswordService} supports common use cases when using passwords as a credentials mechanism. * <p/> * Most importantly, implementations of this interface are expected to employ best-practices to ensure that * passwords remain as safe as possible in application environments. * <h2>Usage</h2> * A {@code PasswordService} is used at two different times during an application's lifecycle: * <ul> * <li>When creating a user account or resetting their password</li> * <li>When a user logs in, when passwords must be compared</li> * </ul> * <h3>Account Creation or Password Reset</h3> * Whenever you create a new user account or reset that account's password, we must translate the end-user submitted * raw/plaintext password value to a string format that is much safer to store. You do that by calling the * {@link #encryptPassword(Object)} method to create the safer value. For * example: * <pre> * String submittedPlaintextPassword = ... * String encryptedValue = passwordService.encryptPassword(submittedPlaintextPassword); * ... * userAccount.setPassword(encryptedValue); * userAccount.save(); //create or update to your data store * </pre> * Be sure to save this encrypted password in your data store and never the original/raw submitted password. * <h3>Login Password Comparison</h3> * Shiro performs the comparison during login automatically. Along with your {@code PasswordService}, you just * have to configure a {@link PasswordMatcher} on a realm that has password-based accounts. During a login attempt, * shiro will use the {@code PasswordMatcher} and the {@code PasswordService} to automatically compare submitted * passwords. * <p/> * For example, if using Shiro's INI, here is how you might configure the PasswordMatcher and PasswordService: * <pre> * [main] * ... * passwordService = org.apache.shiro.authc.credential.DefaultPasswordService * # configure the passwordService to use the settings you desire * ... * passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher * passwordMatcher.passwordService = $passwordService * ... * # Finally, set the matcher on a realm that requires password matching for account authentication: * myRealm = ... * myRealm.credentialsMatcher = $passwordMatcher * </pre> * * @see DefaultPasswordService * @see PasswordMatcher * @since 1.2 */ public interface PasswordService { /** * Converts the specified plaintext password (usually acquired from your application's 'new user' or 'password reset' * workflow) into a formatted string safe for storage. The returned string can be safely saved with the * corresponding user account record (e.g. as a 'password' attribute). * <p/> * It is expected that the String returned from this method will be presented to the * {@link #passwordsMatch(Object, String) passwordsMatch(plaintext,encrypted)} method when performing a * password comparison check. * <h3>Usage</h3> * The input argument type can be any 'byte backed' {@code Object} - almost always either a * String or character array representing passwords (character arrays are often a safer way to represent passwords * as they can be cleared/nulled-out after use. Any argument type supported by * {@link ByteSource.Util#isCompatible(Object)} is valid. * <p/> * For example: * <pre> * String rawPassword = ... * String encryptedValue = passwordService.encryptPassword(rawPassword); * </pre> * or, identically: * <pre> * char[] rawPasswordChars = ... * String encryptedValue = passwordService.encryptPassword(rawPasswordChars); * </pre> * <p/> * The resulting {@code encryptedValue} should be stored with the account to be retrieved later during a * login attempt. For example: * <pre> * String encryptedValue = passwordService.encryptPassword(rawPassword); * ... * userAccount.setPassword(encryptedValue); * userAccount.save(); //create or update to your data store * </pre> * * @param plaintextPassword the raw password as 'byte-backed' object (String, character array, {@link ByteSource}, * etc) usually acquired from your application's 'new user' or 'password reset' workflow. * @return the encrypted password, formatted for storage. * @throws IllegalArgumentException if the argument cannot be easily converted to bytes as defined by * {@link ByteSource.Util#isCompatible(Object)}. * @see ByteSource.Util#isCompatible(Object) */ String encryptPassword(Object plaintextPassword) throws IllegalArgumentException; /** * Returns {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password, * {@code false} otherwise. * <h3>Usage</h3> * The {@code submittedPlaintext} argument type can be any 'byte backed' {@code Object} - almost always either a * String or character array representing passwords (character arrays are often a safer way to represent passwords * as they can be cleared/nulled-out after use. Any argument type supported by * {@link ByteSource.Util#isCompatible(Object)} is valid. * <p/> * For example: * <pre> * String submittedPassword = ... * passwordService.passwordsMatch(submittedPassword, encryptedPassword); * </pre> * or similarly: * <pre> * char[] submittedPasswordCharacters = ... * passwordService.passwordsMatch(submittedPasswordCharacters, encryptedPassword); * </pre> * * @param submittedPlaintext a raw/plaintext password submitted by an end user/Subject. * @param encrypted the previously encrypted password known to be associated with an account. * This value is expected to have been previously generated from the * {@link #encryptPassword(Object) encryptPassword} method (typically * when the account is created or the account's password is reset). * @return {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password, * {@code false} otherwise. * @see ByteSource.Util#isCompatible(Object) */ boolean passwordsMatch(Object submittedPlaintext, String encrypted); }