15
15
*/
16
16
package com .innoq .spring .cookie .flash ;
17
17
18
+ import com .innoq .spring .cookie .security .CookieValueSigner ;
18
19
import org .springframework .util .Assert ;
19
20
import org .springframework .web .servlet .FlashMap ;
20
21
import org .springframework .web .servlet .support .AbstractFlashMapManager ;
24
25
import javax .servlet .http .HttpServletResponse ;
25
26
import java .util .List ;
26
27
28
+ import static java .nio .charset .StandardCharsets .UTF_8 ;
29
+ import static java .security .MessageDigest .isEqual ;
27
30
import static org .springframework .web .util .WebUtils .getCookie ;
28
31
29
32
public final class CookieFlashMapManager extends AbstractFlashMapManager {
30
33
31
34
private static final String DEFAULT_COOKIE_NAME = "flash" ;
32
35
33
36
private final FlashMapListCodec codec ;
37
+ private final CookieValueSigner signer ;
34
38
private final String cookieName ;
35
39
36
- public CookieFlashMapManager (FlashMapListCodec codec ) {
37
- this (codec , DEFAULT_COOKIE_NAME );
40
+ public CookieFlashMapManager (FlashMapListCodec codec ,
41
+ CookieValueSigner signer ) {
42
+ this (codec , signer , DEFAULT_COOKIE_NAME );
38
43
}
39
44
40
- public CookieFlashMapManager (FlashMapListCodec codec , String cookieName ) {
45
+ public CookieFlashMapManager (FlashMapListCodec codec ,
46
+ CookieValueSigner signer , String cookieName ) {
41
47
Assert .notNull (codec , "FlashMapListCodec must not be null" );
48
+ Assert .notNull (signer , "CookieValueSigner must not be null" );
42
49
Assert .hasText (cookieName , "Cookie name must not be null or empty" );
43
50
this .codec = codec ;
51
+ this .signer = signer ;
44
52
this .cookieName = cookieName ;
45
53
}
46
54
@@ -52,7 +60,7 @@ protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request) {
52
60
}
53
61
54
62
final String value = cookie .getValue ();
55
- return codec . decode (value );
63
+ return decode (value );
56
64
}
57
65
58
66
@ Override
@@ -65,7 +73,7 @@ protected void updateFlashMaps(List<FlashMap> flashMaps,
65
73
if (flashMaps .isEmpty ()) {
66
74
cookie .setMaxAge (0 );
67
75
} else {
68
- final String value = codec . encode (flashMaps );
76
+ final String value = encode (flashMaps );
69
77
cookie .setValue (value );
70
78
}
71
79
response .addCookie (cookie );
@@ -75,4 +83,38 @@ protected void updateFlashMaps(List<FlashMap> flashMaps,
75
83
protected Object getFlashMapsMutex (HttpServletRequest request ) {
76
84
return null ;
77
85
}
86
+
87
+ private List <FlashMap > decode (String value ) {
88
+ final String [] signatureAndPayload = reverse (value ).split ("--" , 2 );
89
+ if (signatureAndPayload .length != 2 ) {
90
+ // TODO logging
91
+ return null ;
92
+ }
93
+
94
+ final String signature = reverse (signatureAndPayload [0 ]);
95
+ final String payload = reverse (signatureAndPayload [1 ]);
96
+
97
+ if (!isVerified (payload , signature )) {
98
+ // TODO logging
99
+ return null ;
100
+ }
101
+
102
+ return codec .decode (payload );
103
+ }
104
+
105
+
106
+ private String encode (List <FlashMap > flashMaps ) {
107
+ final String payload = codec .encode (flashMaps );
108
+ final String signature = signer .sign (payload );
109
+ return payload + "--" + signature ;
110
+ }
111
+
112
+ private boolean isVerified (String payload , String digest ) {
113
+ final String signature = signer .sign (payload );
114
+ return isEqual (digest .getBytes (UTF_8 ), signature .getBytes (UTF_8 ));
115
+ }
116
+
117
+ private static String reverse (String s ) {
118
+ return new StringBuilder (s ).reverse ().toString ();
119
+ }
78
120
}
0 commit comments