Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
AbstractRememberMeManager |
|
| 1.4482758620689655;1.448 |
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.mgt; | |
20 | ||
21 | import org.apache.shiro.authc.AuthenticationException; | |
22 | import org.apache.shiro.authc.AuthenticationInfo; | |
23 | import org.apache.shiro.authc.AuthenticationToken; | |
24 | import org.apache.shiro.authc.RememberMeAuthenticationToken; | |
25 | import org.apache.shiro.codec.Base64; | |
26 | import org.apache.shiro.crypto.AesCipherService; | |
27 | import org.apache.shiro.crypto.CipherService; | |
28 | import org.apache.shiro.io.DefaultSerializer; | |
29 | import org.apache.shiro.io.Serializer; | |
30 | import org.apache.shiro.subject.PrincipalCollection; | |
31 | import org.apache.shiro.subject.Subject; | |
32 | import org.apache.shiro.subject.SubjectContext; | |
33 | import org.apache.shiro.util.ByteSource; | |
34 | import org.slf4j.Logger; | |
35 | import org.slf4j.LoggerFactory; | |
36 | ||
37 | /** | |
38 | * Abstract implementation of the {@code RememberMeManager} interface that handles | |
39 | * {@link #setSerializer(org.apache.shiro.io.Serializer) serialization} and | |
40 | * {@link #setCipherService encryption} of the remembered user identity. | |
41 | * <p/> | |
42 | * The remembered identity storage location and details are left to subclasses. | |
43 | * <h2>Default encryption key</h2> | |
44 | * This implementation uses an {@link AesCipherService AesCipherService} for strong encryption by default. It also | |
45 | * uses a default generated symmetric key to both encrypt and decrypt data. As AES is a symmetric cipher, the same | |
46 | * {@code key} is used to both encrypt and decrypt data, BUT NOTE: | |
47 | * <p/> | |
48 | * Because Shiro is an open-source project, if anyone knew that you were using Shiro's default | |
49 | * {@code key}, they could download/view the source, and with enough effort, reconstruct the {@code key} | |
50 | * and decode encrypted data at will. | |
51 | * <p/> | |
52 | * Of course, this key is only really used to encrypt the remembered {@code PrincipalCollection} which is typically | |
53 | * a user id or username. So if you do not consider that sensitive information, and you think the default key still | |
54 | * makes things 'sufficiently difficult', then you can ignore this issue. | |
55 | * <p/> | |
56 | * However, if you do feel this constitutes sensitive information, it is recommended that you provide your own | |
57 | * {@code key} via the {@link #setCipherKey setCipherKey} method to a key known only to your application, | |
58 | * guaranteeing that no third party can decrypt your data. You can generate your own key by calling the | |
59 | * {@code CipherService}'s {@link org.apache.shiro.crypto.AesCipherService#generateNewKey() generateNewKey} method | |
60 | * and using that result as the {@link #setCipherKey cipherKey} configuration attribute. | |
61 | * | |
62 | * @since 0.9 | |
63 | */ | |
64 | public abstract class AbstractRememberMeManager implements RememberMeManager { | |
65 | ||
66 | /** | |
67 | * private inner log instance. | |
68 | */ | |
69 | 1 | private static final Logger log = LoggerFactory.getLogger(AbstractRememberMeManager.class); |
70 | ||
71 | /** | |
72 | * The following Base64 string was generated by auto-generating an AES Key: | |
73 | * <pre> | |
74 | * AesCipherService aes = new AesCipherService(); | |
75 | * byte[] key = aes.generateNewKey().getEncoded(); | |
76 | * String base64 = Base64.encodeToString(key); | |
77 | * </pre> | |
78 | * The value of 'base64' was copied-n-pasted here: | |
79 | */ | |
80 | 1 | private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA=="); |
81 | ||
82 | /** | |
83 | * Serializer to use for converting PrincipalCollection instances to/from byte arrays | |
84 | */ | |
85 | private Serializer<PrincipalCollection> serializer; | |
86 | ||
87 | /** | |
88 | * Cipher to use for encrypting/decrypting serialized byte arrays for added security | |
89 | */ | |
90 | private CipherService cipherService; | |
91 | ||
92 | /** | |
93 | * Cipher encryption key to use with the Cipher when encrypting data | |
94 | */ | |
95 | private byte[] encryptionCipherKey; | |
96 | ||
97 | /** | |
98 | * Cipher decryption key to use with the Cipher when decrypting data | |
99 | */ | |
100 | private byte[] decryptionCipherKey; | |
101 | ||
102 | /** | |
103 | * Default constructor that initializes a {@link DefaultSerializer} as the {@link #getSerializer() serializer} and | |
104 | * an {@link AesCipherService} as the {@link #getCipherService() cipherService}. | |
105 | */ | |
106 | 2 | public AbstractRememberMeManager() { |
107 | 2 | this.serializer = new DefaultSerializer<PrincipalCollection>(); |
108 | 2 | this.cipherService = new AesCipherService(); |
109 | 2 | setCipherKey(DEFAULT_CIPHER_KEY_BYTES); |
110 | 2 | } |
111 | ||
112 | /** | |
113 | * Returns the {@code Serializer} used to serialize and deserialize {@link PrincipalCollection} instances for | |
114 | * persistent remember me storage. | |
115 | * <p/> | |
116 | * Unless overridden by the {@link #setSerializer} method, the default instance is a | |
117 | * {@link org.apache.shiro.io.DefaultSerializer}. | |
118 | * | |
119 | * @return the {@code Serializer} used to serialize and deserialize {@link PrincipalCollection} instances for | |
120 | * persistent remember me storage. | |
121 | */ | |
122 | public Serializer<PrincipalCollection> getSerializer() { | |
123 | 0 | return serializer; |
124 | } | |
125 | ||
126 | /** | |
127 | * Sets the {@code Serializer} used to serialize and deserialize {@link PrincipalCollection} instances for | |
128 | * persistent remember me storage. | |
129 | * <p/> | |
130 | * Unless overridden by this method, the default instance is a {@link DefaultSerializer}. | |
131 | * | |
132 | * @param serializer the {@code Serializer} used to serialize and deserialize {@link PrincipalCollection} instances | |
133 | * for persistent remember me storage. | |
134 | */ | |
135 | public void setSerializer(Serializer<PrincipalCollection> serializer) { | |
136 | 0 | this.serializer = serializer; |
137 | 0 | } |
138 | ||
139 | /** | |
140 | * Returns the {@code CipherService} to use for encrypting and decrypting serialized identity data to prevent easy | |
141 | * inspection of Subject identity data. | |
142 | * <p/> | |
143 | * Unless overridden by the {@link #setCipherService} method, the default instance is an {@link AesCipherService}. | |
144 | * | |
145 | * @return the {@code Cipher} to use for encrypting and decrypting serialized identity data to prevent easy | |
146 | * inspection of Subject identity data | |
147 | */ | |
148 | public CipherService getCipherService() { | |
149 | 0 | return cipherService; |
150 | } | |
151 | ||
152 | /** | |
153 | * Sets the {@code CipherService} to use for encrypting and decrypting serialized identity data to prevent easy | |
154 | * inspection of Subject identity data. | |
155 | * <p/> | |
156 | * If the CipherService is a symmetric CipherService (using the same key for both encryption and decryption), you | |
157 | * should set your key via the {@link #setCipherKey(byte[])} method. | |
158 | * <p/> | |
159 | * If the CipherService is an asymmetric CipherService (different keys for encryption and decryption, such as | |
160 | * public/private key pairs), you should set your encryption and decryption key via the respective | |
161 | * {@link #setEncryptionCipherKey(byte[])} and {@link #setDecryptionCipherKey(byte[])} methods. | |
162 | * <p/> | |
163 | * <b>N.B.</b> Unless overridden by this method, the default CipherService instance is an | |
164 | * {@link AesCipherService}. This {@code RememberMeManager} implementation already has a configured symmetric key | |
165 | * to use for encryption and decryption, but it is recommended to provide your own for added security. See the | |
166 | * class-level JavaDoc for more information and why it might be good to provide your own. | |
167 | * | |
168 | * @param cipherService the {@code CipherService} to use for encrypting and decrypting serialized identity data to | |
169 | * prevent easy inspection of Subject identity data. | |
170 | */ | |
171 | public void setCipherService(CipherService cipherService) { | |
172 | 0 | this.cipherService = cipherService; |
173 | 0 | } |
174 | ||
175 | /** | |
176 | * Returns the cipher key to use for encryption operations. | |
177 | * | |
178 | * @return the cipher key to use for encryption operations. | |
179 | * @see #setCipherService for a description of the various {@code get/set*Key} methods. | |
180 | */ | |
181 | public byte[] getEncryptionCipherKey() { | |
182 | 0 | return encryptionCipherKey; |
183 | } | |
184 | ||
185 | /** | |
186 | * Sets the encryption key to use for encryption operations. | |
187 | * | |
188 | * @param encryptionCipherKey the encryption key to use for encryption operations. | |
189 | * @see #setCipherService for a description of the various {@code get/set*Key} methods. | |
190 | */ | |
191 | public void setEncryptionCipherKey(byte[] encryptionCipherKey) { | |
192 | 2 | this.encryptionCipherKey = encryptionCipherKey; |
193 | 2 | } |
194 | ||
195 | /** | |
196 | * Returns the decryption cipher key to use for decryption operations. | |
197 | * | |
198 | * @return the cipher key to use for decryption operations. | |
199 | * @see #setCipherService for a description of the various {@code get/set*Key} methods. | |
200 | */ | |
201 | public byte[] getDecryptionCipherKey() { | |
202 | 0 | return decryptionCipherKey; |
203 | } | |
204 | ||
205 | /** | |
206 | * Sets the decryption key to use for decryption operations. | |
207 | * | |
208 | * @param decryptionCipherKey the decryption key to use for decryption operations. | |
209 | * @see #setCipherService for a description of the various {@code get/set*Key} methods. | |
210 | */ | |
211 | public void setDecryptionCipherKey(byte[] decryptionCipherKey) { | |
212 | 2 | this.decryptionCipherKey = decryptionCipherKey; |
213 | 2 | } |
214 | ||
215 | /** | |
216 | * Convenience method that returns the cipher key to use for <em>both</em> encryption and decryption. | |
217 | * <p/> | |
218 | * <b>N.B.</b> This method can only be called if the underlying {@link #getCipherService() cipherService} is a symmetric | |
219 | * CipherService which by definition uses the same key for both encryption and decryption. If using an asymmetric | |
220 | * CipherService public/private key pair, you cannot use this method, and should instead use the | |
221 | * {@link #getEncryptionCipherKey()} and {@link #getDecryptionCipherKey()} methods individually. | |
222 | * <p/> | |
223 | * The default {@link AesCipherService} instance is a symmetric cipher service, so this method can be used if you are | |
224 | * using the default. | |
225 | * | |
226 | * @return the symmetric cipher key used for both encryption and decryption. | |
227 | */ | |
228 | public byte[] getCipherKey() { | |
229 | //Since this method should only be used with symmetric ciphers | |
230 | //(where the enc and dec keys are the same), either is fine, just return one of them: | |
231 | 0 | return getEncryptionCipherKey(); |
232 | } | |
233 | ||
234 | /** | |
235 | * Convenience method that sets the cipher key to use for <em>both</em> encryption and decryption. | |
236 | * <p/> | |
237 | * <b>N.B.</b> This method can only be called if the underlying {@link #getCipherService() cipherService} is a | |
238 | * symmetric CipherService?which by definition uses the same key for both encryption and decryption. If using an | |
239 | * asymmetric CipherService?(such as a public/private key pair), you cannot use this method, and should instead use | |
240 | * the {@link #setEncryptionCipherKey(byte[])} and {@link #setDecryptionCipherKey(byte[])} methods individually. | |
241 | * <p/> | |
242 | * The default {@link AesCipherService} instance is a symmetric CipherService, so this method can be used if you | |
243 | * are using the default. | |
244 | * | |
245 | * @param cipherKey the symmetric cipher key to use for both encryption and decryption. | |
246 | */ | |
247 | public void setCipherKey(byte[] cipherKey) { | |
248 | //Since this method should only be used in symmetric ciphers | |
249 | //(where the enc and dec keys are the same), set it on both: | |
250 | 2 | setEncryptionCipherKey(cipherKey); |
251 | 2 | setDecryptionCipherKey(cipherKey); |
252 | 2 | } |
253 | ||
254 | /** | |
255 | * Forgets (removes) any remembered identity data for the specified {@link Subject} instance. | |
256 | * | |
257 | * @param subject the subject instance for which identity data should be forgotten from the underlying persistence | |
258 | * mechanism. | |
259 | */ | |
260 | protected abstract void forgetIdentity(Subject subject); | |
261 | ||
262 | /** | |
263 | * Determines whether or not remember me services should be performed for the specified token. This method returns | |
264 | * {@code true} iff: | |
265 | * <ol> | |
266 | * <li>The token is not {@code null} and</li> | |
267 | * <li>The token is an {@code instanceof} {@link RememberMeAuthenticationToken} and</li> | |
268 | * <li>{@code token}.{@link org.apache.shiro.authc.RememberMeAuthenticationToken#isRememberMe() isRememberMe()} is | |
269 | * {@code true}</li> | |
270 | * </ol> | |
271 | * | |
272 | * @param token the authentication token submitted during the successful authentication attempt. | |
273 | * @return true if remember me services should be performed as a result of the successful authentication attempt. | |
274 | */ | |
275 | protected boolean isRememberMe(AuthenticationToken token) { | |
276 | 0 | return token != null && (token instanceof RememberMeAuthenticationToken) && |
277 | ((RememberMeAuthenticationToken) token).isRememberMe(); | |
278 | } | |
279 | ||
280 | /** | |
281 | * Reacts to the successful login attempt by first always {@link #forgetIdentity(Subject) forgetting} any previously | |
282 | * stored identity. Then if the {@code token} | |
283 | * {@link #isRememberMe(org.apache.shiro.authc.AuthenticationToken) is a RememberMe} token, the associated identity | |
284 | * will be {@link #rememberIdentity(org.apache.shiro.subject.Subject, org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) remembered} | |
285 | * for later retrieval during a new user session. | |
286 | * | |
287 | * @param subject the subject for which the principals are being remembered. | |
288 | * @param token the token that resulted in a successful authentication attempt. | |
289 | * @param info the authentication info resulting from the successful authentication attempt. | |
290 | */ | |
291 | public void onSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info) { | |
292 | //always clear any previous identity: | |
293 | 0 | forgetIdentity(subject); |
294 | ||
295 | //now save the new identity: | |
296 | 0 | if (isRememberMe(token)) { |
297 | 0 | rememberIdentity(subject, token, info); |
298 | } else { | |
299 | 0 | if (log.isDebugEnabled()) { |
300 | 0 | log.debug("AuthenticationToken did not indicate RememberMe is requested. " + |
301 | "RememberMe functionality will not be executed for corresponding account."); | |
302 | } | |
303 | } | |
304 | 0 | } |
305 | ||
306 | /** | |
307 | * Remembers a subject-unique identity for retrieval later. This implementation first | |
308 | * {@link #getIdentityToRemember resolves} the exact | |
309 | * {@link PrincipalCollection principals} to remember. It then remembers the principals by calling | |
310 | * {@link #rememberIdentity(org.apache.shiro.subject.Subject, org.apache.shiro.subject.PrincipalCollection)}. | |
311 | * <p/> | |
312 | * This implementation ignores the {@link AuthenticationToken} argument, but it is available to subclasses if | |
313 | * necessary for custom logic. | |
314 | * | |
315 | * @param subject the subject for which the principals are being remembered. | |
316 | * @param token the token that resulted in a successful authentication attempt. | |
317 | * @param authcInfo the authentication info resulting from the successful authentication attempt. | |
318 | */ | |
319 | public void rememberIdentity(Subject subject, AuthenticationToken token, AuthenticationInfo authcInfo) { | |
320 | 0 | PrincipalCollection principals = getIdentityToRemember(subject, authcInfo); |
321 | 0 | rememberIdentity(subject, principals); |
322 | 0 | } |
323 | ||
324 | /** | |
325 | * Returns {@code info}.{@link org.apache.shiro.authc.AuthenticationInfo#getPrincipals() getPrincipals()} and | |
326 | * ignores the {@link Subject} argument. | |
327 | * | |
328 | * @param subject the subject for which the principals are being remembered. | |
329 | * @param info the authentication info resulting from the successful authentication attempt. | |
330 | * @return the {@code PrincipalCollection} to remember. | |
331 | */ | |
332 | protected PrincipalCollection getIdentityToRemember(Subject subject, AuthenticationInfo info) { | |
333 | 0 | return info.getPrincipals(); |
334 | } | |
335 | ||
336 | /** | |
337 | * Remembers the specified account principals by first | |
338 | * {@link #convertPrincipalsToBytes(org.apache.shiro.subject.PrincipalCollection) converting} them to a byte | |
339 | * array and then {@link #rememberSerializedIdentity(org.apache.shiro.subject.Subject, byte[]) remembers} that | |
340 | * byte array. | |
341 | * | |
342 | * @param subject the subject for which the principals are being remembered. | |
343 | * @param accountPrincipals the principals to remember for retrieval later. | |
344 | */ | |
345 | protected void rememberIdentity(Subject subject, PrincipalCollection accountPrincipals) { | |
346 | 0 | byte[] bytes = convertPrincipalsToBytes(accountPrincipals); |
347 | 0 | rememberSerializedIdentity(subject, bytes); |
348 | 0 | } |
349 | ||
350 | /** | |
351 | * Converts the given principal collection the byte array that will be persisted to be 'remembered' later. | |
352 | * <p/> | |
353 | * This implementation first {@link #serialize(org.apache.shiro.subject.PrincipalCollection) serializes} the | |
354 | * principals to a byte array and then {@link #encrypt(byte[]) encrypts} that byte array. | |
355 | * | |
356 | * @param principals the {@code PrincipalCollection} to convert to a byte array | |
357 | * @return the representative byte array to be persisted for remember me functionality. | |
358 | */ | |
359 | protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) { | |
360 | 0 | byte[] bytes = serialize(principals); |
361 | 0 | if (getCipherService() != null) { |
362 | 0 | bytes = encrypt(bytes); |
363 | } | |
364 | 0 | return bytes; |
365 | } | |
366 | ||
367 | /** | |
368 | * Persists the identity bytes to a persistent store for retrieval later via the | |
369 | * {@link #getRememberedSerializedIdentity(SubjectContext)} method. | |
370 | * | |
371 | * @param subject the Subject for which the identity is being serialized. | |
372 | * @param serialized the serialized bytes to be persisted. | |
373 | */ | |
374 | protected abstract void rememberSerializedIdentity(Subject subject, byte[] serialized); | |
375 | ||
376 | /** | |
377 | * Implements the interface method by first {@link #getRememberedSerializedIdentity(SubjectContext) acquiring} | |
378 | * the remembered serialized byte array. Then it {@link #convertBytesToPrincipals(byte[], SubjectContext) converts} | |
379 | * them and returns the re-constituted {@link PrincipalCollection}. If no remembered principals could be | |
380 | * obtained, {@code null} is returned. | |
381 | * <p/> | |
382 | * If any exceptions are thrown, the {@link #onRememberedPrincipalFailure(RuntimeException, SubjectContext)} method | |
383 | * is called to allow any necessary post-processing (such as immediately removing any previously remembered | |
384 | * values for safety). | |
385 | * | |
386 | * @param subjectContext the contextual data, usually provided by a {@link Subject.Builder} implementation, that | |
387 | * is being used to construct a {@link Subject} instance. | |
388 | * @return the remembered principals or {@code null} if none could be acquired. | |
389 | */ | |
390 | public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) { | |
391 | 2 | PrincipalCollection principals = null; |
392 | try { | |
393 | 2 | byte[] bytes = getRememberedSerializedIdentity(subjectContext); |
394 | //SHIRO-138 - only call convertBytesToPrincipals if bytes exist: | |
395 | 2 | if (bytes != null && bytes.length > 0) { |
396 | 0 | principals = convertBytesToPrincipals(bytes, subjectContext); |
397 | } | |
398 | 0 | } catch (RuntimeException re) { |
399 | 0 | principals = onRememberedPrincipalFailure(re, subjectContext); |
400 | 2 | } |
401 | ||
402 | 2 | return principals; |
403 | } | |
404 | ||
405 | /** | |
406 | * Based on the given subject context data, retrieves the previously persisted serialized identity, or | |
407 | * {@code null} if there is no available data. The context map is usually populated by a {@link Subject.Builder} | |
408 | * implementation. See the {@link SubjectFactory} class constants for Shiro's known map keys. | |
409 | * | |
410 | * @param subjectContext the contextual data, usually provided by a {@link Subject.Builder} implementation, that | |
411 | * is being used to construct a {@link Subject} instance. To be used to assist with data | |
412 | * lookup. | |
413 | * @return the previously persisted serialized identity, or {@code null} if there is no available data for the | |
414 | * Subject. | |
415 | */ | |
416 | protected abstract byte[] getRememberedSerializedIdentity(SubjectContext subjectContext); | |
417 | ||
418 | /** | |
419 | * If a {@link #getCipherService() cipherService} is available, it will be used to first decrypt the byte array. | |
420 | * Then the bytes are then {@link #deserialize(byte[]) deserialized} and then returned. | |
421 | * | |
422 | * @param bytes the bytes to decrypt if necessary and then deserialize. | |
423 | * @param subjectContext the contextual data, usually provided by a {@link Subject.Builder} implementation, that | |
424 | * is being used to construct a {@link Subject} instance. | |
425 | * @return the de-serialized and possibly decrypted principals | |
426 | */ | |
427 | protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) { | |
428 | 0 | if (getCipherService() != null) { |
429 | 0 | bytes = decrypt(bytes); |
430 | } | |
431 | 0 | return deserialize(bytes); |
432 | } | |
433 | ||
434 | /** | |
435 | * Called when an exception is thrown while trying to retrieve principals. The default implementation logs a | |
436 | * debug message and forgets ('unremembers') the problem identity by calling | |
437 | * {@link #forgetIdentity(SubjectContext) forgetIdentity(context)} and then immediately re-throws the | |
438 | * exception to allow the calling component to react accordingly. | |
439 | * <p/> | |
440 | * This method implementation never returns an | |
441 | * object - it always rethrows, but can be overridden by subclasses for custom handling behavior. | |
442 | * <p/> | |
443 | * This most commonly would be called when an encryption key is updated and old principals are retrieved that have | |
444 | * been encrypted with the previous key. | |
445 | * | |
446 | * @param e the exception that was thrown. | |
447 | * @param context the contextual data, usually provided by a {@link Subject.Builder} implementation, that | |
448 | * is being used to construct a {@link Subject} instance. | |
449 | * @return nothing - the original {@code RuntimeException} is propagated in all cases. | |
450 | */ | |
451 | protected PrincipalCollection onRememberedPrincipalFailure(RuntimeException e, SubjectContext context) { | |
452 | 0 | if (log.isDebugEnabled()) { |
453 | 0 | log.debug("There was a failure while trying to retrieve remembered principals. This could be due to a " + |
454 | "configuration problem or corrupted principals. This could also be due to a recently " + | |
455 | "changed encryption key. The remembered identity will be forgotten and not used for this " + | |
456 | "request.", e); | |
457 | } | |
458 | 0 | forgetIdentity(context); |
459 | //propagate - security manager implementation will handle and warn appropriately | |
460 | 0 | throw e; |
461 | } | |
462 | ||
463 | /** | |
464 | * Encrypts the byte array by using the configured {@link #getCipherService() cipherService}. | |
465 | * | |
466 | * @param serialized the serialized object byte array to be encrypted | |
467 | * @return an encrypted byte array returned by the configured {@link #getCipherService () cipher}. | |
468 | */ | |
469 | protected byte[] encrypt(byte[] serialized) { | |
470 | 0 | byte[] value = serialized; |
471 | 0 | CipherService cipherService = getCipherService(); |
472 | 0 | if (cipherService != null) { |
473 | 0 | ByteSource byteSource = cipherService.encrypt(serialized, getEncryptionCipherKey()); |
474 | 0 | value = byteSource.getBytes(); |
475 | } | |
476 | 0 | return value; |
477 | } | |
478 | ||
479 | /** | |
480 | * Decrypts the byte array using the configured {@link #getCipherService() cipherService}. | |
481 | * | |
482 | * @param encrypted the encrypted byte array to decrypt | |
483 | * @return the decrypted byte array returned by the configured {@link #getCipherService () cipher}. | |
484 | */ | |
485 | protected byte[] decrypt(byte[] encrypted) { | |
486 | 0 | byte[] serialized = encrypted; |
487 | 0 | CipherService cipherService = getCipherService(); |
488 | 0 | if (cipherService != null) { |
489 | 0 | ByteSource byteSource = cipherService.decrypt(encrypted, getDecryptionCipherKey()); |
490 | 0 | serialized = byteSource.getBytes(); |
491 | } | |
492 | 0 | return serialized; |
493 | } | |
494 | ||
495 | /** | |
496 | * Serializes the given {@code principals} by serializing them to a byte array by using the | |
497 | * {@link #getSerializer() serializer}'s {@link Serializer#serialize(Object) serialize} method. | |
498 | * | |
499 | * @param principals the principal collection to serialize to a byte array | |
500 | * @return the serialized principal collection in the form of a byte array | |
501 | */ | |
502 | protected byte[] serialize(PrincipalCollection principals) { | |
503 | 0 | return getSerializer().serialize(principals); |
504 | } | |
505 | ||
506 | /** | |
507 | * De-serializes the given byte array by using the {@link #getSerializer() serializer}'s | |
508 | * {@link Serializer#deserialize deserialize} method. | |
509 | * | |
510 | * @param serializedIdentity the previously serialized {@code PrincipalCollection} as a byte array | |
511 | * @return the de-serialized (reconstituted) {@code PrincipalCollection} | |
512 | */ | |
513 | protected PrincipalCollection deserialize(byte[] serializedIdentity) { | |
514 | 0 | return getSerializer().deserialize(serializedIdentity); |
515 | } | |
516 | ||
517 | /** | |
518 | * Reacts to a failed login by immediately {@link #forgetIdentity(org.apache.shiro.subject.Subject) forgetting} any | |
519 | * previously remembered identity. This is an additional security feature to prevent any remenant identity data | |
520 | * from being retained in case the authentication attempt is not being executed by the expected user. | |
521 | * | |
522 | * @param subject the subject which executed the failed login attempt | |
523 | * @param token the authentication token resulting in a failed login attempt - ignored by this implementation | |
524 | * @param ae the exception thrown as a result of the failed login attempt - ignored by this implementation | |
525 | */ | |
526 | public void onFailedLogin(Subject subject, AuthenticationToken token, AuthenticationException ae) { | |
527 | 0 | forgetIdentity(subject); |
528 | 0 | } |
529 | ||
530 | /** | |
531 | * Reacts to a subject logging out of the application and immediately | |
532 | * {@link #forgetIdentity(org.apache.shiro.subject.Subject) forgets} any previously stored identity and returns. | |
533 | * | |
534 | * @param subject the subject logging out. | |
535 | */ | |
536 | public void onLogout(Subject subject) { | |
537 | 0 | forgetIdentity(subject); |
538 | 0 | } |
539 | } |