17
17
package org .springframework .security .messaging .access .intercept ;
18
18
19
19
import java .util .ArrayList ;
20
+ import java .util .Arrays ;
20
21
import java .util .List ;
21
22
import java .util .Map ;
22
23
import java .util .function .Supplier ;
25
26
import org .apache .commons .logging .LogFactory ;
26
27
27
28
import org .springframework .core .log .LogMessage ;
29
+ import org .springframework .http .server .PathContainer ;
28
30
import org .springframework .messaging .Message ;
29
31
import org .springframework .messaging .simp .SimpMessageType ;
30
32
import org .springframework .security .authorization .AuthenticatedAuthorizationManager ;
34
36
import org .springframework .security .authorization .SingleResultAuthorizationManager ;
35
37
import org .springframework .security .core .Authentication ;
36
38
import org .springframework .security .messaging .util .matcher .MessageMatcher ;
39
+ import org .springframework .security .messaging .util .matcher .PathPatternMessageMatcher ;
37
40
import org .springframework .security .messaging .util .matcher .SimpDestinationMessageMatcher ;
38
41
import org .springframework .security .messaging .util .matcher .SimpMessageTypeMatcher ;
39
42
import org .springframework .util .AntPathMatcher ;
40
43
import org .springframework .util .Assert ;
41
44
import org .springframework .util .PathMatcher ;
42
45
import org .springframework .util .function .SingletonSupplier ;
46
+ import org .springframework .web .util .pattern .PathPatternParser ;
43
47
44
48
public final class MessageMatcherDelegatingAuthorizationManager implements AuthorizationManager <Message <?>> {
45
49
@@ -88,12 +92,11 @@ private MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> ma
88
92
if (!matcher .matches ((Message ) message )) {
89
93
return null ;
90
94
}
91
- if (matcher instanceof SimpDestinationMessageMatcher simp ) {
92
- return new MessageAuthorizationContext <>(message , simp .extractPathVariables (message ));
95
+ if (matcher instanceof Builder . LazySimpDestinationMessageMatcher pathMatcher ) {
96
+ return new MessageAuthorizationContext <>(message , pathMatcher .extractPathVariables (message ));
93
97
}
94
- if (matcher instanceof Builder .LazySimpDestinationMessageMatcher ) {
95
- Builder .LazySimpDestinationMessageMatcher path = (Builder .LazySimpDestinationMessageMatcher ) matcher ;
96
- return new MessageAuthorizationContext <>(message , path .extractPathVariables (message ));
98
+ if (matcher instanceof Builder .LazySimpDestinationPatternMessageMatcher pathMatcher ) {
99
+ return new MessageAuthorizationContext <>(message , pathMatcher .extractPathVariables (message ));
97
100
}
98
101
return new MessageAuthorizationContext <>(message );
99
102
}
@@ -113,8 +116,11 @@ public static final class Builder {
113
116
114
117
private final List <Entry <AuthorizationManager <MessageAuthorizationContext <?>>>> mappings = new ArrayList <>();
115
118
119
+ @ Deprecated
116
120
private Supplier <PathMatcher > pathMatcher = AntPathMatcher ::new ;
117
121
122
+ private boolean useHttpPathSeparator = true ;
123
+
118
124
public Builder () {
119
125
}
120
126
@@ -133,11 +139,11 @@ public Builder.Constraint anyMessage() {
133
139
* @return the Expression to associate
134
140
*/
135
141
public Builder .Constraint nullDestMatcher () {
136
- return matchers (SimpDestinationMessageMatcher .NULL_DESTINATION_MATCHER );
142
+ return matchers (PathPatternMessageMatcher .NULL_DESTINATION_MATCHER );
137
143
}
138
144
139
145
/**
140
- * Maps a {@link List} of {@link SimpDestinationMessageMatcher } instances.
146
+ * Maps a {@link List} of {@link SimpMessageTypeMatcher } instances.
141
147
* @param typesToMatch the {@link SimpMessageType} instance to match on
142
148
* @return the {@link Builder.Constraint} associated to the matchers.
143
149
*/
@@ -157,35 +163,88 @@ public Builder.Constraint simpTypeMatchers(SimpMessageType... typesToMatch) {
157
163
* @param patterns the patterns to create
158
164
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
159
165
* from.
166
+ * @deprecated use {@link #destinationPathPatterns(String...)}
160
167
*/
168
+ @ Deprecated
161
169
public Builder .Constraint simpDestMatchers (String ... patterns ) {
162
170
return simpDestMatchers (null , patterns );
163
171
}
164
172
173
+ /**
174
+ * Allows the creation of a security {@link Constraint} applying to messages whose
175
+ * destinations match the provided {@code patterns}.
176
+ * <p>
177
+ * The matching of each pattern is performed by a
178
+ * {@link PathPatternMessageMatcher} instance that matches irrespectively of
179
+ * {@link SimpMessageType}. If no destination is found on the {@code Message},
180
+ * then each {@code Matcher} returns false.
181
+ * </p>
182
+ * @param patterns the destination path patterns to which the security
183
+ * {@code Constraint} will be applicable
184
+ * @since 6.5
185
+ */
186
+ public Builder .Constraint destinationPathPatterns (String ... patterns ) {
187
+ return destinationPathPatterns (null , patterns );
188
+ }
189
+
165
190
/**
166
191
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that
167
192
* match on {@code SimpMessageType.MESSAGE}. If no destination is found on the
168
193
* Message, then the Matcher returns false.
169
194
* @param patterns the patterns to create
170
195
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
171
196
* from.
197
+ * @deprecated use {@link #destinationPathPatterns(String...)}
172
198
*/
199
+ @ Deprecated
173
200
public Builder .Constraint simpMessageDestMatchers (String ... patterns ) {
174
201
return simpDestMatchers (SimpMessageType .MESSAGE , patterns );
175
202
}
176
203
204
+ /**
205
+ * Allows the creation of a security {@link Constraint} applying to messages of
206
+ * the type {@code SimpMessageType.MESSAGE} whose destinations match the provided
207
+ * {@code patterns}.
208
+ * <p>
209
+ * The matching of each pattern is performed by a
210
+ * {@link PathPatternMessageMatcher}. If no destination is found on the
211
+ * {@code Message}, then each {@code Matcher} returns false.
212
+ * @param patterns the patterns to create {@link PathPatternMessageMatcher} from.
213
+ * @since 6.5
214
+ */
215
+ public Builder .Constraint simpTypeMessageDestinationPatterns (String ... patterns ) {
216
+ return destinationPathPatterns (SimpMessageType .MESSAGE , patterns );
217
+ }
218
+
177
219
/**
178
220
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that
179
221
* match on {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the
180
222
* Message, then the Matcher returns false.
181
223
* @param patterns the patterns to create
182
224
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
183
225
* from.
226
+ * @deprecated use {@link #simpTypeSubscribeDestinationPatterns(String...)}
184
227
*/
228
+ @ Deprecated
185
229
public Builder .Constraint simpSubscribeDestMatchers (String ... patterns ) {
186
230
return simpDestMatchers (SimpMessageType .SUBSCRIBE , patterns );
187
231
}
188
232
233
+ /**
234
+ * Allows the creation of a security {@link Constraint} applying to messages of
235
+ * the type {@code SimpMessageType.SUBSCRIBE} whose destinations match the
236
+ * provided {@code patterns}.
237
+ * <p>
238
+ * The matching of each pattern is performed by a
239
+ * {@link PathPatternMessageMatcher}. If no destination is found on the
240
+ * {@code Message}, then each {@code Matcher} returns false.
241
+ * @param patterns the patterns to create {@link PathPatternMessageMatcher} from.
242
+ * @since 6.5
243
+ */
244
+ public Builder .Constraint simpTypeSubscribeDestinationPatterns (String ... patterns ) {
245
+ return destinationPathPatterns (SimpMessageType .SUBSCRIBE , patterns );
246
+ }
247
+
189
248
/**
190
249
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances. If no
191
250
* destination is found on the Message, then the Matcher returns false.
@@ -196,7 +255,9 @@ public Builder.Constraint simpSubscribeDestMatchers(String... patterns) {
196
255
* from.
197
256
* @return the {@link Builder.Constraint} that is associated to the
198
257
* {@link MessageMatcher}
258
+ * @deprecated use {@link #destinationPathPatterns(String...)}
199
259
*/
260
+ @ Deprecated
200
261
private Builder .Constraint simpDestMatchers (SimpMessageType type , String ... patterns ) {
201
262
List <MessageMatcher <?>> matchers = new ArrayList <>(patterns .length );
202
263
for (String pattern : patterns ) {
@@ -206,13 +267,51 @@ private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patt
206
267
return new Builder .Constraint (matchers );
207
268
}
208
269
270
+ /**
271
+ * Allows the creation of a security {@link Constraint} applying to messages of
272
+ * the provided {@code type} whose destinations match the provided
273
+ * {@code patterns}.
274
+ * <p>
275
+ * The matching of each pattern is performed by a
276
+ * {@link PathPatternMessageMatcher}. If no destination is found on the
277
+ * {@code Message}, then each {@code Matcher} returns false.
278
+ * </p>
279
+ * @param type the {@link SimpMessageType} to match on. If null, the
280
+ * {@link SimpMessageType} is not considered for matching.
281
+ * @param patterns the patterns to create {@link PathPatternMessageMatcher} from.
282
+ * @return the {@link Builder.Constraint} that is associated to the
283
+ * {@link MessageMatcher}s
284
+ * @since 6.5
285
+ */
286
+ private Builder .Constraint destinationPathPatterns (SimpMessageType type , String ... patterns ) {
287
+ List <MessageMatcher <?>> matchers = new ArrayList <>(patterns .length );
288
+ for (String pattern : patterns ) {
289
+ MessageMatcher <Object > matcher = new LazySimpDestinationPatternMessageMatcher (pattern , type ,
290
+ this .useHttpPathSeparator );
291
+ matchers .add (matcher );
292
+ }
293
+ return new Builder .Constraint (matchers );
294
+ }
295
+
296
+ /**
297
+ * Instruct this builder to match message destinations using the separator
298
+ * configured in
299
+ * {@link org.springframework.http.server.PathContainer.Options#MESSAGE_ROUTE}
300
+ */
301
+ public Builder messageRouteSeparator () {
302
+ this .useHttpPathSeparator = false ;
303
+ return this ;
304
+ }
305
+
209
306
/**
210
307
* The {@link PathMatcher} to be used with the
211
308
* {@link Builder#simpDestMatchers(String...)}. The default is to use the default
212
309
* constructor of {@link AntPathMatcher}.
213
310
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
214
311
* @return the {@link Builder} for further customization.
312
+ * @deprecated use {@link #messageRouteSeparator()} to alter the path separator
215
313
*/
314
+ @ Deprecated
216
315
public Builder simpDestPathMatcher (PathMatcher pathMatcher ) {
217
316
Assert .notNull (pathMatcher , "pathMatcher cannot be null" );
218
317
this .pathMatcher = () -> pathMatcher ;
@@ -225,7 +324,9 @@ public Builder simpDestPathMatcher(PathMatcher pathMatcher) {
225
324
* computation or lookup of the {@link PathMatcher}.
226
325
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
227
326
* @return the {@link Builder} for further customization.
327
+ * @deprecated use {@link #messageRouteSeparator()} to alter the path separator
228
328
*/
329
+ @ Deprecated
229
330
public Builder simpDestPathMatcher (Supplier <PathMatcher > pathMatcher ) {
230
331
Assert .notNull (pathMatcher , "pathMatcher cannot be null" );
231
332
this .pathMatcher = pathMatcher ;
@@ -241,9 +342,7 @@ public Builder simpDestPathMatcher(Supplier<PathMatcher> pathMatcher) {
241
342
*/
242
343
public Builder .Constraint matchers (MessageMatcher <?>... matchers ) {
243
344
List <MessageMatcher <?>> builders = new ArrayList <>(matchers .length );
244
- for (MessageMatcher <?> matcher : matchers ) {
245
- builders .add (matcher );
246
- }
345
+ builders .addAll (Arrays .asList (matchers ));
247
346
return new Builder .Constraint (builders );
248
347
}
249
348
@@ -382,6 +481,7 @@ public Builder access(AuthorizationManager<MessageAuthorizationContext<?>> autho
382
481
383
482
}
384
483
484
+ @ Deprecated
385
485
private final class LazySimpDestinationMessageMatcher implements MessageMatcher <Object > {
386
486
387
487
private final Supplier <SimpDestinationMessageMatcher > delegate ;
@@ -413,6 +513,40 @@ Map<String, String> extractPathVariables(Message<?> message) {
413
513
414
514
}
415
515
516
+ private static final class LazySimpDestinationPatternMessageMatcher implements MessageMatcher <Object > {
517
+
518
+ private final Supplier <PathPatternMessageMatcher > delegate ;
519
+
520
+ private LazySimpDestinationPatternMessageMatcher (String pattern , SimpMessageType type ,
521
+ boolean useHttpPathSeparator ) {
522
+ this .delegate = SingletonSupplier .of (() -> {
523
+ PathPatternParser dotSeparatedPathParser = new PathPatternParser ();
524
+ dotSeparatedPathParser .setPathOptions (PathContainer .Options .MESSAGE_ROUTE );
525
+ PathPatternMessageMatcher .Builder builder = (useHttpPathSeparator )
526
+ ? PathPatternMessageMatcher .withDefaults ()
527
+ : PathPatternMessageMatcher .withPathPatternParser (dotSeparatedPathParser );
528
+ if (type == null ) {
529
+ return builder .matcher (pattern );
530
+ }
531
+ if (SimpMessageType .MESSAGE == type || SimpMessageType .SUBSCRIBE == type ) {
532
+ return builder .matcher (pattern , type );
533
+ }
534
+ throw new IllegalStateException (type + " is not supported since it does not have a destination" );
535
+ });
536
+ }
537
+
538
+ @ Override
539
+ public boolean matches (Message <?> message ) {
540
+ return this .delegate .get ().matches (message );
541
+ }
542
+
543
+ Map <String , String > extractPathVariables (Message <?> message ) {
544
+ MatchResult matchResult = this .delegate .get ().matcher (message );
545
+ return matchResult .getVariables ();
546
+ }
547
+
548
+ }
549
+
416
550
}
417
551
418
552
private static final class Entry <T > {
@@ -421,7 +555,7 @@ private static final class Entry<T> {
421
555
422
556
private final T entry ;
423
557
424
- Entry (MessageMatcher requestMatcher , T entry ) {
558
+ Entry (MessageMatcher <?> requestMatcher , T entry ) {
425
559
this .messageMatcher = requestMatcher ;
426
560
this .entry = entry ;
427
561
}
0 commit comments