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.crypto.hash;
20  
21  import org.apache.shiro.lang.util.ByteSource;
22  import org.apache.shiro.lang.util.SimpleByteSource;
23  
24  import java.util.Map;
25  import java.util.Optional;
26  import java.util.concurrent.ConcurrentHashMap;
27  
28  import static java.util.Objects.requireNonNull;
29  
30  /**
31   * A {@code HashRequest} is composed of data that will be used by a {@link HashService} to compute a hash (aka
32   * 'digest').  While you can instantiate a concrete {@code HashRequest} class directly, most will find using the
33   * {@link HashRequest.Builder} more convenient.
34   *
35   * @see HashRequest.Builder
36   * @since 1.2
37   */
38  public interface HashRequest {
39  
40      /**
41       * Returns the source data that will be hashed by a {@link HashService}. For example, this might be a
42       * {@code ByteSource} representation of a password, or file, etc.
43       *
44       * @return the source data that will be hashed by a {@link HashService}.
45       */
46      ByteSource getSource();
47  
48      /**
49       * Returns a salt to be used by the {@link HashService} during hash computation, or {@code null} if no salt is
50       * provided as part of the request.
51       * <p/>
52       * Note that a {@code null} value does not necessarily mean a salt won't be used at all - it just
53       * means that the request didn't include one.  The servicing {@link HashService} is free to provide a salting
54       * strategy for a request, even if the request did not specify one.
55       *
56       * @return a salt to be used by the {@link HashService} during hash computation, or {@code null} if no salt is
57       * provided as part of the request.
58       */
59      Optional<ByteSource> getSalt();
60  
61      /**
62       * Returns the name of the hash algorithm the {@code HashService} should use when computing the {@link Hash}, or
63       * {@code null} if the default algorithm configuration of the {@code HashService} should be used.  A non-null value
64       * overrides the {@code HashService}'s configuration for a single request.
65       * <p/>
66       * Note that a {@code HashService} is free to ignore this value if it determines that the algorithm is not
67       * sufficient to meet a desired level of security.
68       *
69       * @return the name of the hash algorithm the {@code HashService} should use when computing the {@link Hash}, or
70       * {@code null} if the default algorithm configuration of the {@code HashService} should be used.
71       */
72      Optional<String> getAlgorithmName();
73  
74      /**
75       * Returns various parameters for the requested hash.
76       *
77       * <p>If the map is empty for a specific parameter, the implementation must select the default.</p>
78       *
79       * <p>Implementations should provide a nested {@code .Parameters} class with {@code public static final String}s
80       * for convenience.</p>
81       *
82       * <p>Example parameters the number of requested hash iterations (does not apply to bcrypt),
83       * memory and cpu constrains, etc.
84       * Please find their specific names in the implementation’s nested {@code .Parameters} class.</p>
85       *
86       * @return the parameters for the requested hash to be used when computing the final {@code Hash} result.
87       * @throws NullPointerException if any of the values is {@code null}.
88       */
89      Map<String, Object> getParameters();
90  
91      /**
92       * A Builder class representing the Builder design pattern for constructing {@link HashRequest} instances.
93       *
94       * @see SimpleHashRequest
95       * @since 1.2
96       */
97      class Builder {
98  
99          private ByteSource source;
100         private ByteSource salt = SimpleByteSource.empty();
101         private final Map<String, Object> parameters = new ConcurrentHashMap<>();
102         private String algorithmName;
103 
104         /**
105          * Default no-arg constructor.
106          */
107         public Builder() {
108         }
109 
110         /**
111          * Sets the source data that will be hashed by a {@link HashService}. For example, this might be a
112          * {@code ByteSource} representation of a password, or file, etc.
113          *
114          * @param source the source data that will be hashed by a {@link HashService}.
115          * @return this {@code Builder} instance for method chaining.
116          * @see HashRequest#getSource()
117          * @see #setSource(Object)
118          */
119         public Builder setSource(ByteSource source) {
120             this.source = source;
121             return this;
122         }
123 
124         /**
125          * Sets the source data that will be hashed by a {@link HashService}.
126          * <p/>
127          * This is a convenience alternative to {@link #setSource(ByteSource)}: it will attempt to convert the
128          * argument into a {@link ByteSource} instance using Shiro's default conversion heuristics
129          * (as defined by {@link ByteSource.Util#isCompatible(Object) ByteSource.Util.isCompatible}.  If the object
130          * cannot be heuristically converted to a {@code ByteSource}, an {@code IllegalArgumentException} will be
131          * thrown.
132          *
133          * @param source the byte-backed source data that will be hashed by a {@link HashService}.
134          * @return this {@code Builder} instance for method chaining.
135          * @throws IllegalArgumentException if the argument cannot be heuristically converted to a {@link ByteSource}
136          *                                  instance.
137          * @see HashRequest#getSource()
138          * @see #setSource(ByteSource)
139          */
140         public Builder setSource(Object source) throws IllegalArgumentException {
141             this.source = ByteSource.Util.bytes(source);
142             return this;
143         }
144 
145         /**
146          * Sets a salt to be used by the {@link HashService} during hash computation.
147          * <p/>
148          * <b>NOTE</b>: not calling this method does not necessarily mean a salt won't be used at all - it just
149          * means that the request didn't include a salt.  The servicing {@link HashService} is free to provide a salting
150          * strategy for a request, even if the request did not specify one.  You can always check the result
151          * {@code Hash} {@link Hash#getSalt() getSalt()} method to see what the actual
152          * salt was (if any), which may or may not match this request salt.
153          *
154          * @param salt a salt to be used by the {@link HashService} during hash computation
155          * @return this {@code Builder} instance for method chaining.
156          * @see HashRequest#getSalt()
157          */
158         public Builder setSalt(ByteSource salt) {
159             this.salt = salt;
160             return this;
161         }
162 
163         /**
164          * Sets a salt to be used by the {@link HashService} during hash computation.
165          * <p/>
166          * This is a convenience alternative to {@link #setSalt(ByteSource)}: it will attempt to convert the
167          * argument into a {@link ByteSource} instance using Shiro's default conversion heuristics
168          * (as defined by {@link ByteSource.Util#isCompatible(Object) ByteSource.Util.isCompatible}.  If the object
169          * cannot be heuristically converted to a {@code ByteSource}, an {@code IllegalArgumentException} will be
170          * thrown.
171          *
172          * @param salt a salt to be used by the {@link HashService} during hash computation.
173          * @return this {@code Builder} instance for method chaining.
174          * @throws IllegalArgumentException if the argument cannot be heuristically converted to a {@link ByteSource}
175          *                                  instance.
176          * @see #setSalt(ByteSource)
177          * @see HashRequest#getSalt()
178          */
179         public Builder setSalt(Object salt) throws IllegalArgumentException {
180             this.salt = ByteSource.Util.bytes(salt);
181             return this;
182         }
183 
184         public Builder addParameter(String parameterName, Object parameterValue) {
185             this.parameters.put(parameterName, requireNonNull(parameterValue));
186             return this;
187         }
188 
189         public Builder withParameters(Map<String, Object> parameters) {
190             this.parameters.clear();
191             this.parameters.putAll(requireNonNull(parameters));
192             return this;
193         }
194 
195         /**
196          * Sets the name of the hash algorithm the {@code HashService} should use when computing the {@link Hash}.
197          * Not calling this method or setting it to {@code null} indicates the the default algorithm configuration of
198          * the {@code HashService} should be used.  A non-null value
199          * overrides the {@code HashService}'s configuration for a single request.
200          * <p/>
201          * Note that a {@code HashService} is free to ignore this value if it determines that the algorithm is not
202          * sufficient to meet a desired level of security. You can always check the result
203          * {@code Hash} {@link Hash#getAlgorithmName() getAlgorithmName()} method to see what the actual
204          * algorithm was, which may or may not match this request salt.
205          *
206          * @param algorithmName the name of the hash algorithm the {@code HashService} should use when computing the
207          *                      {@link Hash}, or {@code null} if the default algorithm configuration of the
208          *                      {@code HashService} should be used.
209          * @return this {@code Builder} instance for method chaining.
210          * @see HashRequest#getAlgorithmName()
211          */
212         public Builder setAlgorithmName(String algorithmName) {
213             this.algorithmName = algorithmName;
214             return this;
215         }
216 
217         /**
218          * Builds a {@link HashRequest} instance reflecting the specified configuration.
219          *
220          * @return a {@link HashRequest} instance reflecting the specified configuration.
221          */
222         public HashRequest build() {
223             return new SimpleHashRequest(this.algorithmName, this.source, this.salt, this.parameters);
224         }
225     }
226 }