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.authc.AuthenticationInfo; 022import org.apache.shiro.authc.AuthenticationToken; 023import org.apache.shiro.authc.SaltedAuthenticationInfo; 024import org.apache.shiro.crypto.hash.Hash; 025import org.apache.shiro.crypto.hash.SimpleHash; 026import org.apache.shiro.lang.codec.Base64; 027import org.apache.shiro.lang.codec.Hex; 028import org.apache.shiro.lang.util.SimpleByteSource; 029import org.apache.shiro.lang.util.StringUtils; 030 031import static java.util.Objects.requireNonNull; 032 033/** 034 * A {@code HashedCredentialMatcher} provides support for hashing of supplied {@code AuthenticationToken} credentials 035 * before being compared to those in the {@code AuthenticationInfo} from the data store. 036 * <p/> 037 * Credential hashing is one of the most common security techniques when safeguarding a user's private credentials 038 * (passwords, keys, etc.). Most developers never want to store their users' credentials in plain form, viewable by 039 * anyone, so they often hash the users' credentials before they are saved in the data store. 040 * <p/> 041 * This class (and its subclasses) function as follows: 042 * <ol> 043 * <li>Hash the {@code AuthenticationToken} credentials supplied by the user during their login.</li> 044 * <li>Compare this hashed value directly with the {@code AuthenticationInfo} credentials stored in the system 045 * (the stored account credentials are expected to already be in hashed form).</li> 046 * <li>If these two values are {@link #equals(Object, Object) equal}, the submitted credentials match, otherwise 047 * they do not.</li> 048 * </ol> 049 * <h2>Salting and Multiple Hash Iterations</h2> 050 * Because simple hashing is usually not good enough for secure applications, this class also supports 'salting' 051 * and multiple hash iterations. Please read this excellent 052 * <a href="http://www.owasp.org/index.php/Hashing_Java" _target="blank">Hashing Java article</a> to learn about 053 * salting and multiple iterations and why you might want to use them. (Note of sections 5 054 * "Why add salt?" and 6 "Hardening against the attacker's attack").</p> 055 * <h4>Real World Case Study</h4> 056 * In April 2010, some public Atlassian Jira and Confluence 057 * installations (Apache Software Foundation, Codehaus, etc.) were the target of account attacks and user accounts 058 * were compromised. The reason? Jira and Confluence at the time did not salt user passwords and attackers were 059 * able to use dictionary attacks to compromise user accounts (Atlassian has since 060 * <a href="http://blogs.atlassian.com/news/2010/04/oh_man_what_a_day_an_update_on_our_security_breach.html"> 061 * fixed the problem</a> of course). 062 * <p/> 063 * The lesson? 064 * <p/> 065 * <b>ALWAYS, ALWAYS, ALWAYS SALT USER PASSWORDS!</b> 066 * <p/> 067 * <h3>Salting</h3> 068 * Prior to Shiro 1.1, salts could be obtained based on the end-user submitted 069 * {@link AuthenticationToken AuthenticationToken} via the now-deprecated 070 * {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) getSalt(AuthenticationToken)} method. This however 071 * could constitute a security hole since ideally salts should never be obtained based on what a user can submit. 072 * User-submitted salt mechanisms are <em>much</em> more susceptible to dictionary attacks and <b>SHOULD NOT</b> be 073 * used in secure systems. Instead, salts should ideally be a secure randomly-generated number that is generated when 074 * the user account is created. The secure number should never be disseminated to the user and always kept private 075 * by the application. 076 * <h4>Shiro 1.1</h4> 077 * As of Shiro 1.1, it is expected that any salt used to hash the submitted credentials will be obtained from the 078 * stored account information (represented as an {@link AuthenticationInfo AuthenticationInfo} instance). This is much 079 * more secure because the salt value remains private to the application (Shiro will never store this value). 080 * <p/> 081 * To enable this, {@code Realm}s should return {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances 082 * during authentication. {@code HashedCredentialsMatcher} implementations will then use the provided 083 * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt credentialsSalt} for hashing. To avoid 084 * security risks, 085 * <b>it is highly recommended that any existing {@code Realm} implementations that support hashed credentials are 086 * updated to return {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances as soon as possible</b>. 087 * <h4>Shiro 1.0 Backwards Compatibility</h4> 088 * Because of the identified security risk, {@code Realm} implementations that support credentials hashing should 089 * be updated to return {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances as 090 * soon as possible. 091 * <p/> 092 * If this is not possible for some reason, this class will retain 1.0 backwards-compatible behavior of obtaining 093 * the salt via the now-deprecated {@link #getSalt(AuthenticationToken) getSalt(AuthenticationToken)} method. This 094 * method will only be invoked if a {@code Realm} <em>does not</em> return 095 * {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances and {@link #isHashSalted() hashSalted} is 096 * {@code true}. 097 * But please note that the {@link #isHashSalted() hashSalted} property and the 098 * {@link #getSalt(AuthenticationToken) getSalt(AuthenticationToken)} methods will be removed before the Shiro 2.0 099 * release. 100 * <h3>Multiple Hash Iterations</h3> 101 * If you hash your users' credentials multiple times before persisting to the data store, you will also need to 102 * set this class's {@link #setHashIterations(int) hashIterations} property. See the 103 * <a href="http://www.owasp.org/index.php/Hashing_Java" _target="blank">Hashing Java article</a>'s 104 * <a href="http://www.owasp.org/index.php/Hashing_Java#Hardening_against_the_attacker.27s_attack"> 105 * "Hardening against the attacker's attack"</a> section to learn more about why you might want to use 106 * multiple hash iterations. 107 * <h2>MD5 & SHA-1 Notice</h2> 108 * <a href="http://en.wikipedia.org/wiki/MD5">MD5</a> and 109 * <a href="http://en.wikipedia.org/wiki/SHA_hash_functions">SHA-1</a> algorithms are now known to be vulnerable to 110 * compromise and/or collisions (read the linked pages for more). While most applications are ok with either of these 111 * two, if your application mandates high security, use the SHA-256 (or higher) hashing algorithms and their 112 * supporting {@code CredentialsMatcher} implementations. 113 * 114 * @see org.apache.shiro.crypto.hash.Sha256Hash 115 * @see org.apache.shiro.crypto.hash.Sha384Hash 116 * @see org.apache.shiro.crypto.hash.Sha256Hash 117 * @since 0.9 118 */ 119public class HashedCredentialsMatcher extends SimpleCredentialsMatcher { 120 121 /** 122 * @since 1.1 123 */ 124 private String hashAlgorithm; 125 private int hashIterations; 126 private boolean hashSalted; 127 private boolean storedCredentialsHexEncoded; 128 129 /** 130 * JavaBeans-compatible no-arg constructor intended for use in IoC/Dependency Injection environments. If you 131 * use this constructor, you <em>MUST</em> also additionally set the 132 * {@link #setHashAlgorithmName(String) hashAlgorithmName} property. 133 */ 134 public HashedCredentialsMatcher() { 135 this.hashAlgorithm = null; 136 this.hashSalted = false; 137 this.hashIterations = 1; 138 //false means Base64-encoded 139 this.storedCredentialsHexEncoded = true; 140 } 141 142 /** 143 * Creates an instance using the specified {@link #getHashAlgorithmName() hashAlgorithmName} to hash submitted 144 * credentials. 145 * 146 * @param hashAlgorithmName the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} 147 * to use when performing hashes for credentials matching. 148 * @since 1.1 149 */ 150 public HashedCredentialsMatcher(String hashAlgorithmName) { 151 this(); 152 if (!StringUtils.hasText(hashAlgorithmName)) { 153 throw new IllegalArgumentException("hashAlgorithmName cannot be null or empty."); 154 } 155 this.hashAlgorithm = hashAlgorithmName; 156 } 157 158 /** 159 * Returns the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use 160 * when performing hashes for credentials matching. 161 * 162 * @return the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use 163 * when performing hashes for credentials matching. 164 * @since 1.1 165 */ 166 public String getHashAlgorithmName() { 167 return hashAlgorithm; 168 } 169 170 /** 171 * Sets the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use 172 * when performing hashes for credentials matching. 173 * 174 * @param hashAlgorithmName the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} 175 * to use when performing hashes for credentials matching. 176 * @since 1.1 177 */ 178 public void setHashAlgorithmName(String hashAlgorithmName) { 179 this.hashAlgorithm = hashAlgorithmName; 180 } 181 182 /** 183 * Returns {@code true} if the system's stored credential hash is Hex encoded, {@code false} if it 184 * is Base64 encoded. 185 * <p/> 186 * Default value is {@code true} for convenience - all of Shiro's {@link Hash Hash#toString()} 187 * implementations return Hex encoded values by default, making this class's use with those implementations 188 * easier. 189 * 190 * @return {@code true} if the system's stored credential hash is Hex encoded, {@code false} if it 191 * is Base64 encoded. Default is {@code true} 192 */ 193 public boolean isStoredCredentialsHexEncoded() { 194 return storedCredentialsHexEncoded; 195 } 196 197 /** 198 * Sets the indicator if this system's stored credential hash is Hex encoded or not. 199 * <p/> 200 * A value of {@code true} will cause this class to decode the system credential from Hex, a 201 * value of {@code false} will cause this class to decode the system credential from Base64. 202 * <p/> 203 * Unless overridden via this method, the default value is {@code true} for convenience - all of Shiro's 204 * {@link Hash Hash#toString()} implementations return Hex encoded values by default, making this class's use with 205 * those implementations easier. 206 * 207 * @param storedCredentialsHexEncoded the indicator if this system's stored credential hash is Hex 208 * encoded or not ('not' automatically implying it is Base64 encoded). 209 */ 210 public void setStoredCredentialsHexEncoded(boolean storedCredentialsHexEncoded) { 211 this.storedCredentialsHexEncoded = storedCredentialsHexEncoded; 212 } 213 214 /** 215 * Returns {@code true} if a submitted {@code AuthenticationToken}'s credentials should be salted when hashing, 216 * {@code false} if it should not be salted. 217 * <p/> 218 * If enabled, the salt used will be obtained via the {@link #getSalt(AuthenticationToken) getSalt} method. 219 * <p/> 220 * The default value is {@code false}. 221 * 222 * @return {@code true} if a submitted {@code AuthenticationToken}'s credentials should be salted when hashing, 223 * {@code false} if it should not be salted. 224 * @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo} 225 * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its 226 * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method 227 * returns a non-null value. 228 * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return 229 * {@code SaltedAuthenticationInfo} instances, but <b>it is highly recommended that {@code Realm} implementations 230 * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} 231 * instances as soon as possible</b>. 232 * <p/> 233 * This is because salts should always be obtained from the stored account information and 234 * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for 235 * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user 236 * are almost impossible to break. This method will be removed in Shiro 2.0. 237 */ 238 @Deprecated 239 public boolean isHashSalted() { 240 return hashSalted; 241 } 242 243 /** 244 * Sets whether to salt a submitted {@code AuthenticationToken}'s credentials when hashing. 245 * <p/> 246 * If enabled, the salt used will be obtained via the 247 * {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) getCredentialsSalt} method. 248 * </p> 249 * The default value is {@code false}. 250 * 251 * @param hashSalted whether to salt a submitted {@code AuthenticationToken}'s credentials when hashing. 252 * @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo} 253 * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its 254 * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} 255 * method returns a non-null value. 256 * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return 257 * {@code SaltedAuthenticationInfo} instances, but <b>it is highly recommended that {@code Realm} implementations 258 * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} 259 * instances as soon as possible</b>. 260 * <p/> 261 * This is because salts should always be obtained from the stored account information and 262 * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for 263 * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user 264 * are almost impossible to break. This method will be removed in Shiro 2.0. 265 */ 266 @Deprecated 267 public void setHashSalted(boolean hashSalted) { 268 this.hashSalted = hashSalted; 269 } 270 271 /** 272 * Returns the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before 273 * comparing to the credentials stored in the system. 274 * <p/> 275 * Unless overridden, the default value is {@code 1}, meaning a normal hash execution will occur. 276 * 277 * @return the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before 278 * comparing to the credentials stored in the system. 279 */ 280 public int getHashIterations() { 281 return hashIterations; 282 } 283 284 /** 285 * Sets the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before comparing 286 * to the credentials stored in the system. 287 * <p/> 288 * Unless overridden, the default value is {@code 1}, meaning a normal single hash execution will occur. 289 * <p/> 290 * If this argument is less than 1 (i.e. 0 or negative), the default value of 1 is applied. There must always be 291 * at least 1 hash iteration (otherwise there would be no hash). 292 * 293 * @param hashIterations the number of times to hash a submitted {@code AuthenticationToken}'s credentials. 294 */ 295 public void setHashIterations(int hashIterations) { 296 this.hashIterations = Math.max(hashIterations, 1); 297 } 298 299 /** 300 * Returns a salt value used to hash the token's credentials. 301 * <p/> 302 * This default implementation merely returns {@code token.getPrincipal()}, effectively using the user's 303 * identity (username, user id, etc.) as the salt, a most common technique. If you wish to provide the 304 * authentication token's salt another way, you may override this method. 305 * 306 * @param token the AuthenticationToken submitted during the authentication attempt. 307 * @return a salt value to use to hash the authentication token's credentials. 308 * @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo} 309 * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its 310 * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method 311 * returns a non-null value. 312 * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return 313 * {@code SaltedAuthenticationInfo} instances, but <b>it is highly recommended that {@code Realm} implementations 314 * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} 315 * instances as soon as possible</b>.<p/> 316 * This is because salts should always be obtained from the stored account information and 317 * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for 318 * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user 319 * are almost impossible to break. This method will be removed in Shiro 2.0. 320 */ 321 @Deprecated 322 protected Object getSalt(AuthenticationToken token) { 323 return token.getPrincipal(); 324 } 325 326 /** 327 * Returns a {@link Hash Hash} instance representing the already-hashed AuthenticationInfo credentials stored in the system. 328 * <p/> 329 * This method reconstructs a {@link Hash Hash} instance based on a {@code info.getCredentials} call, 330 * but it does <em>not</em> hash that value - it is expected that method call will return an already-hashed value. 331 * <p/> 332 * This implementation's reconstruction effort functions as follows: 333 * <ol> 334 * <li>Convert {@code account.getCredentials()} to a byte array via the {@link #toBytes toBytes} method. 335 * <li>If {@code account.getCredentials()} was originally a String or char[] before {@code toBytes} was 336 * called, check for encoding: 337 * <li>If {@link #storedCredentialsHexEncoded storedCredentialsHexEncoded}, Hex decode that byte array, otherwise 338 * Base64 decode the byte array</li> 339 * <li>Set the byte[] array directly on the {@code Hash} implementation and return it.</li> 340 * </ol> 341 * 342 * @param info the AuthenticationInfo from which to retrieve the credentials which assumed to be in already-hashed form. 343 * @return a {@link Hash Hash} instance representing the given AuthenticationInfo's stored credentials. 344 */ 345 @Override 346 protected Object getCredentials(AuthenticationInfo info) { 347 Object credentials = info.getCredentials(); 348 349 byte[] storedBytes = toBytes(credentials); 350 351 if (credentials instanceof String || credentials instanceof char[]) { 352 //account.credentials were a char[] or String, so 353 //we need to do text decoding first: 354 if (isStoredCredentialsHexEncoded()) { 355 storedBytes = Hex.decode(storedBytes); 356 } else { 357 storedBytes = Base64.decode(storedBytes); 358 } 359 } 360 SimpleHash hash = newHashInstance(); 361 hash.setBytes(storedBytes); 362 return hash; 363 } 364 365 /** 366 * This implementation first hashes the {@code token}'s credentials, potentially using a 367 * {@code salt} if the {@code info} argument is a 368 * {@link org.apache.shiro.authc.SaltedAuthenticationInfo SaltedAuthenticationInfo}. It then compares the hash 369 * against the {@code AuthenticationInfo}'s 370 * {@link #getCredentials(org.apache.shiro.authc.AuthenticationInfo) already-hashed credentials}. This method 371 * returns {@code true} if those two values are {@link #equals(Object, Object) equal}, {@code false} otherwise. 372 * 373 * @param token the {@code AuthenticationToken} submitted during the authentication attempt. 374 * @param info the {@code AuthenticationInfo} stored in the system matching the token principal 375 * @return {@code true} if the provided token credentials hash match to the stored account credentials hash, 376 * {@code false} otherwise 377 * @since 1.1 378 */ 379 @Override 380 public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { 381 Object tokenHashedCredentials = hashProvidedCredentials(token, info); 382 Object accountCredentials = getCredentials(info); 383 return equals(tokenHashedCredentials, accountCredentials); 384 } 385 386 /** 387 * Hash the provided {@code token}'s credentials using the salt stored with the account if the 388 * {@code info} instance is an {@code instanceof} {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} (see 389 * the class-level JavaDoc for why this is the preferred approach). 390 * <p/> 391 * If the {@code info} instance is <em>not</em> 392 * an {@code instanceof} {@code SaltedAuthenticationInfo}, the logic will fall back to Shiro 1.0 393 * backwards-compatible logic: it will first check to see {@link #isHashSalted() isHashSalted} and if so, will try 394 * to acquire the salt from {@link #getSalt(AuthenticationToken) getSalt(AuthenticationToken)}. See the class-level 395 * JavaDoc for why this is not recommended. This 'fallback' logic exists only for backwards-compatibility. 396 * {@code Realm}s should be updated as soon as possible to return {@code SaltedAuthenticationInfo} instances 397 * if account credentials salting is enabled (highly recommended for password-based systems). 398 * 399 * @param token the submitted authentication token from which its credentials will be hashed 400 * @param info the stored account data, potentially used to acquire a salt 401 * @return the token credentials hash 402 * @since 1.1 403 */ 404 protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) { 405 final Object salt; 406 if (info instanceof SaltedAuthenticationInfo) { 407 salt = ((SaltedAuthenticationInfo) info).getCredentialsSalt(); 408 } else if (isHashSalted()) { 409 //retain 1.0 backwards compatibility: 410 salt = getSalt(token); 411 } else { 412 salt = SimpleByteSource.empty(); 413 } 414 return hashProvidedCredentials(token.getCredentials(), salt, getHashIterations()); 415 } 416 417 /** 418 * Returns the {@link #getHashAlgorithmName() hashAlgorithmName} property, but will throw an 419 * {@link IllegalStateException} if it has not been set. 420 * 421 * @return the required {@link #getHashAlgorithmName() hashAlgorithmName} property 422 * @throws IllegalStateException if the property has not been set prior to calling this method. 423 * @since 1.1 424 */ 425 private String assertHashAlgorithmName() throws IllegalStateException { 426 String hashAlgorithmName = getHashAlgorithmName(); 427 if (hashAlgorithmName == null) { 428 String msg = "Required 'hashAlgorithmName' property has not been set. This is required to execute " 429 + "the hashing algorithm."; 430 throw new IllegalStateException(msg); 431 } 432 return hashAlgorithmName; 433 } 434 435 /** 436 * Hashes the provided credentials a total of {@code hashIterations} times, using the given salt. The hash 437 * implementation/algorithm used is based on the {@link #getHashAlgorithmName() hashAlgorithmName} property. 438 * 439 * @param credentials the submitted authentication token's credentials to hash 440 * @param salt the value to salt the hash. Cannot be {@code null}, but an empty ByteSource. 441 * @param hashIterations the number of times to hash the credentials. At least one hash will always occur though, 442 * even if this argument is 0 or negative. 443 * @return the hashed value of the provided credentials, according to the specified salt and hash iterations. 444 * @throws NullPointerException if salt is {@code null}. 445 */ 446 protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) { 447 String hashAlgorithmName = assertHashAlgorithmName(); 448 return new SimpleHash(hashAlgorithmName, credentials, requireNonNull(salt, "salt cannot be null."), hashIterations); 449 } 450 451 /** 452 * Returns a new, <em>uninitialized</em> instance, without its byte array set. Used as a utility method in the 453 * {@link SimpleCredentialsMatcher#getCredentials(org.apache.shiro.authc.AuthenticationInfo) 454 * getCredentials(AuthenticationInfo)} implementation. 455 * 456 * @return a new, <em>uninitialized</em> instance, without its byte array set. 457 */ 458 protected SimpleHash newHashInstance() { 459 String hashAlgorithmName = assertHashAlgorithmName(); 460 return new SimpleHash(hashAlgorithmName); 461 } 462 463}