View Javadoc
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  package org.apache.shiro.authc.credential;
20  
21  import org.apache.shiro.authc.AuthenticationInfo;
22  import org.apache.shiro.authc.AuthenticationToken;
23  import org.apache.shiro.authc.SimpleAuthenticationInfo;
24  import org.apache.shiro.authc.UsernamePasswordToken;
25  import org.apache.shiro.crypto.SecureRandomNumberGenerator;
26  import org.apache.shiro.crypto.hash.Sha1Hash;
27  import org.apache.shiro.subject.PrincipalCollection;
28  import org.apache.shiro.subject.SimplePrincipalCollection;
29  import org.apache.shiro.util.ByteSource;
30  import org.junit.Test;
31  
32  import static org.junit.Assert.assertTrue;
33  
34  /**
35   * Tests for the {@link org.apache.shiro.authc.credential.HashedCredentialsMatcher} class.
36   */
37  public class HashedCredentialsMatcherTest {
38  
39      /**
40       * Test new Shiro 1.1 functionality, where the salt is obtained from the stored account information, as it
41       * should be.  See <a href="https://issues.apache.org/jira/browse/SHIRO-186">SHIRO-186</a>
42       */
43      @Test
44      public void testSaltedAuthenticationInfo() {
45          //use SHA-1 hashing in this test:
46          HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Sha1Hash.ALGORITHM_NAME);
47  
48          //simulate a user account with a SHA-1 hashed and salted password:
49          ByteSource salt = new SecureRandomNumberGenerator().nextBytes();
50          Object hashedPassword = new Sha1Hash("password", salt);
51          SimpleAuthenticationInfo account = new SimpleAuthenticationInfo("username", hashedPassword, salt, "realmName");
52  
53          //simulate a username/password (plaintext) token created in response to a login attempt:
54          AuthenticationToken token = new UsernamePasswordToken("username", "password");
55  
56          //verify the hashed token matches what is in the account:
57          assertTrue(matcher.doCredentialsMatch(token, account));
58      }
59  
60      /**
61       * Test backwards compatibility of unsalted credentials before
62       * <a href="https://issues.apache.org/jira/browse/SHIRO-186">SHIRO-186</a> edits.
63       */
64      @Test
65      public void testBackwardsCompatibleUnsaltedAuthenticationInfo() {
66          HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Sha1Hash.ALGORITHM_NAME);
67  
68          //simulate an account with SHA-1 hashed password (no salt)
69          final String username = "username";
70          final String password = "password";
71          final Object hashedPassword = new Sha1Hash(password).getBytes();
72          AuthenticationInfo account = new AuthenticationInfo() {
73              public PrincipalCollection getPrincipals() {
74                  return new SimplePrincipalCollection(username, "realmName");
75              }
76  
77              public Object getCredentials() {
78                  return hashedPassword;
79              }
80          };
81  
82          //simulate a username/password (plaintext) token created in response to a login attempt:
83          AuthenticationToken token = new UsernamePasswordToken("username", "password");
84  
85          //verify the hashed token matches what is in the account:
86          assertTrue(matcher.doCredentialsMatch(token, account));
87      }
88  
89      /**
90       * Test backwards compatibility of salted credentials before
91       * <a href="https://issues.apache.org/jira/browse/SHIRO-186">SHIRO-186</a> edits.
92       */
93      @Test
94      public void testBackwardsCompatibleSaltedAuthenticationInfo() {
95          HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Sha1Hash.ALGORITHM_NAME);
96          //enable this for Shiro 1.0 backwards compatibility:
97          matcher.setHashSalted(true);
98  
99          //simulate an account with SHA-1 hashed password, using the username as the salt
100         //(BAD IDEA, but backwards-compatible):
101         final String username = "username";
102         final String password = "password";
103         final Object hashedPassword = new Sha1Hash(password, username).getBytes();
104         AuthenticationInfo account = new AuthenticationInfo() {
105             public PrincipalCollection getPrincipals() {
106                 return new SimplePrincipalCollection(username, "realmName");
107             }
108 
109             public Object getCredentials() {
110                 return hashedPassword;
111             }
112         };
113 
114         //simulate a username/password (plaintext) token created in response to a login attempt:
115         AuthenticationToken token = new UsernamePasswordToken("username", "password");
116 
117         //verify the hashed token matches what is in the account:
118         assertTrue(matcher.doCredentialsMatch(token, account));
119     }
120 }