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 }