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.codec.CodecSupport;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import java.security.MessageDigest;
28  import java.util.Arrays;
29  
30  
31  /**
32   * Simple CredentialsMatcher implementation.  Supports direct (plain) comparison for credentials of type
33   * byte[], char[], and Strings, and if the arguments do not match these types, then reverts back to simple
34   * <code>Object.equals</code> comparison.
35   * <p/>
36   * <p>Hashing comparisons (the most common technique used in secure applications) are not supported by this class, but
37   * instead by the {@link org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher}.
38   *
39   * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher
40   * @since 0.9
41   */
42  public class SimpleCredentialsMatcher extends CodecSupport implements CredentialsMatcher {
43  
44      private static final Logger log = LoggerFactory.getLogger(SimpleCredentialsMatcher.class);
45  
46      /**
47       * Returns the {@code token}'s credentials.
48       * <p/>
49       * <p>This default implementation merely returns
50       * {@link AuthenticationToken#getCredentials() authenticationToken.getCredentials()} and exists as a template hook
51       * if subclasses wish to obtain the credentials in a different way or convert them to a different format before
52       * returning.
53       *
54       * @param token the {@code AuthenticationToken} submitted during the authentication attempt.
55       * @return the {@code token}'s associated credentials.
56       */
57      protected Object getCredentials(AuthenticationToken token) {
58          return token.getCredentials();
59      }
60  
61      /**
62       * Returns the {@code account}'s credentials.
63       * <p/>
64       * <p>This default implementation merely returns
65       * {@link AuthenticationInfo#getCredentials() account.getCredentials()} and exists as a template hook if subclasses
66       * wish to obtain the credentials in a different way or convert them to a different format before
67       * returning.
68       *
69       * @param info the {@code AuthenticationInfo} stored in the data store to be compared against the submitted authentication
70       *             token's credentials.
71       * @return the {@code account}'s associated credentials.
72       */
73      protected Object getCredentials(AuthenticationInfo info) {
74          return info.getCredentials();
75      }
76  
77      /**
78       * Returns {@code true} if the {@code tokenCredentials} argument is logically equal to the
79       * {@code accountCredentials} argument.
80       * <p/>
81       * <p>If both arguments are either a byte array (byte[]), char array (char[]) or String, they will be both be
82       * converted to raw byte arrays via the {@link #toBytes toBytes} method first, and then resulting byte arrays
83       * are compared via {@link Arrays#equals(byte[], byte[]) Arrays.equals(byte[],byte[])}.</p>
84       * <p/>
85       * <p>If either argument cannot be converted to a byte array as described, a simple Object <code>equals</code>
86       * comparison is made.</p>
87       * <p/>
88       * <p>Subclasses should override this method for more explicit equality checks.
89       *
90       * @param tokenCredentials   the {@code AuthenticationToken}'s associated credentials.
91       * @param accountCredentials the {@code AuthenticationInfo}'s stored credentials.
92       * @return {@code true} if the {@code tokenCredentials} are equal to the {@code accountCredentials}.
93       */
94      protected boolean equals(Object tokenCredentials, Object accountCredentials) {
95          if (log.isDebugEnabled()) {
96              log.debug("Performing credentials equality check for tokenCredentials of type [" +
97                      tokenCredentials.getClass().getName() + " and accountCredentials of type [" +
98                      accountCredentials.getClass().getName() + "]");
99          }
100         if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) {
101             if (log.isDebugEnabled()) {
102                 log.debug("Both credentials arguments can be easily converted to byte arrays.  Performing " +
103                         "array equals comparison");
104             }
105             byte[] tokenBytes = toBytes(tokenCredentials);
106             byte[] accountBytes = toBytes(accountCredentials);
107             return MessageDigest.isEqual(tokenBytes, accountBytes);
108         } else {
109             return accountCredentials.equals(tokenCredentials);
110         }
111     }
112 
113     /**
114      * This implementation acquires the {@code token}'s credentials
115      * (via {@link #getCredentials(AuthenticationToken) getCredentials(token)})
116      * and then the {@code account}'s credentials
117      * (via {@link #getCredentials(org.apache.shiro.authc.AuthenticationInfo) getCredentials(account)}) and then passes both of
118      * them to the {@link #equals(Object,Object) equals(tokenCredentials, accountCredentials)} method for equality
119      * comparison.
120      *
121      * @param token the {@code AuthenticationToken} submitted during the authentication attempt.
122      * @param info  the {@code AuthenticationInfo} stored in the system matching the token principal.
123      * @return {@code true} if the provided token credentials are equal to the stored account credentials,
124      *         {@code false} otherwise
125      */
126     public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
127         Object tokenCredentials = getCredentials(token);
128         Object accountCredentials = getCredentials(info);
129         return equals(tokenCredentials, accountCredentials);
130     }
131 
132 }