1
1
/*
2
- * Copyright 2002-2022 the original author or authors.
2
+ * Copyright 2002-2025 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
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 ;
32
33
import org .springframework .security .authorization .AuthorizationDecision ;
33
34
import org .springframework .security .authorization .AuthorizationManager ;
34
35
import org .springframework .security .core .Authentication ;
36
+ import org .springframework .security .messaging .util .matcher .DestinationPathPatternMessageMatcher ;
35
37
import org .springframework .security .messaging .util .matcher .MessageMatcher ;
36
38
import org .springframework .security .messaging .util .matcher .SimpDestinationMessageMatcher ;
37
39
import org .springframework .security .messaging .util .matcher .SimpMessageTypeMatcher ;
@@ -87,12 +89,11 @@ private MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> ma
87
89
if (!matcher .matches ((Message ) message )) {
88
90
return null ;
89
91
}
90
- if (matcher instanceof SimpDestinationMessageMatcher simp ) {
91
- return new MessageAuthorizationContext <>(message , simp .extractPathVariables (message ));
92
+ if (matcher instanceof Builder . LazySimpDestinationMessageMatcher pathMatcher ) {
93
+ return new MessageAuthorizationContext <>(message , pathMatcher .extractPathVariables (message ));
92
94
}
93
- if (matcher instanceof Builder .LazySimpDestinationMessageMatcher ) {
94
- Builder .LazySimpDestinationMessageMatcher path = (Builder .LazySimpDestinationMessageMatcher ) matcher ;
95
- return new MessageAuthorizationContext <>(message , path .extractPathVariables (message ));
95
+ if (matcher instanceof Builder .LazySimpDestinationPatternMessageMatcher pathMatcher ) {
96
+ return new MessageAuthorizationContext <>(message , pathMatcher .extractPathVariables (message ));
96
97
}
97
98
return new MessageAuthorizationContext <>(message );
98
99
}
@@ -112,8 +113,11 @@ public static final class Builder {
112
113
113
114
private final List <Entry <AuthorizationManager <MessageAuthorizationContext <?>>>> mappings = new ArrayList <>();
114
115
116
+ @ Deprecated
115
117
private Supplier <PathMatcher > pathMatcher = AntPathMatcher ::new ;
116
118
119
+ private boolean useHttpPathSeparator = true ;
120
+
117
121
public Builder () {
118
122
}
119
123
@@ -132,11 +136,11 @@ public Builder.Constraint anyMessage() {
132
136
* @return the Expression to associate
133
137
*/
134
138
public Builder .Constraint nullDestMatcher () {
135
- return matchers (SimpDestinationMessageMatcher .NULL_DESTINATION_MATCHER );
139
+ return matchers (DestinationPathPatternMessageMatcher .NULL_DESTINATION_MATCHER );
136
140
}
137
141
138
142
/**
139
- * Maps a {@link List} of {@link SimpDestinationMessageMatcher } instances.
143
+ * Maps a {@link List} of {@link SimpMessageTypeMatcher } instances.
140
144
* @param typesToMatch the {@link SimpMessageType} instance to match on
141
145
* @return the {@link Builder.Constraint} associated to the matchers.
142
146
*/
@@ -156,35 +160,90 @@ public Builder.Constraint simpTypeMatchers(SimpMessageType... typesToMatch) {
156
160
* @param patterns the patterns to create
157
161
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
158
162
* from.
163
+ * @deprecated use {@link #destinationPathPatterns(String...)}
159
164
*/
165
+ @ Deprecated
160
166
public Builder .Constraint simpDestMatchers (String ... patterns ) {
161
167
return simpDestMatchers (null , patterns );
162
168
}
163
169
170
+ /**
171
+ * Allows the creation of a security {@link Constraint} applying to messages whose
172
+ * destinations match the provided {@code patterns}.
173
+ * <p>
174
+ * The matching of each pattern is performed by a
175
+ * {@link DestinationPathPatternMessageMatcher} instance that matches
176
+ * irrespectively of {@link SimpMessageType}. If no destination is found on the
177
+ * {@code Message}, then each {@code Matcher} returns false.
178
+ * </p>
179
+ * @param patterns the destination path patterns to which the security
180
+ * {@code Constraint} will be applicable
181
+ * @since 6.5
182
+ */
183
+ public Builder .Constraint destinationPathPatterns (String ... patterns ) {
184
+ return destinationPathPatterns (null , patterns );
185
+ }
186
+
164
187
/**
165
188
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that
166
189
* match on {@code SimpMessageType.MESSAGE}. If no destination is found on the
167
190
* Message, then the Matcher returns false.
168
191
* @param patterns the patterns to create
169
192
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
170
193
* from.
194
+ * @deprecated use {@link #destinationPathPatterns(String...)}
171
195
*/
196
+ @ Deprecated
172
197
public Builder .Constraint simpMessageDestMatchers (String ... patterns ) {
173
198
return simpDestMatchers (SimpMessageType .MESSAGE , patterns );
174
199
}
175
200
201
+ /**
202
+ * Allows the creation of a security {@link Constraint} applying to messages of
203
+ * the type {@code SimpMessageType.MESSAGE} whose destinations match the provided
204
+ * {@code patterns}.
205
+ * <p>
206
+ * The matching of each pattern is performed by a
207
+ * {@link DestinationPathPatternMessageMatcher}. If no destination is found on the
208
+ * {@code Message}, then each {@code Matcher} returns false.
209
+ * @param patterns the patterns to create
210
+ * {@link DestinationPathPatternMessageMatcher} from.
211
+ * @since 6.5
212
+ */
213
+ public Builder .Constraint simpTypeMessageDestinationPatterns (String ... patterns ) {
214
+ return destinationPathPatterns (SimpMessageType .MESSAGE , patterns );
215
+ }
216
+
176
217
/**
177
218
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that
178
219
* match on {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the
179
220
* Message, then the Matcher returns false.
180
221
* @param patterns the patterns to create
181
222
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
182
223
* from.
224
+ * @deprecated use {@link #simpTypeSubscribeDestinationPatterns(String...)}
183
225
*/
226
+ @ Deprecated
184
227
public Builder .Constraint simpSubscribeDestMatchers (String ... patterns ) {
185
228
return simpDestMatchers (SimpMessageType .SUBSCRIBE , patterns );
186
229
}
187
230
231
+ /**
232
+ * Allows the creation of a security {@link Constraint} applying to messages of
233
+ * the type {@code SimpMessageType.SUBSCRIBE} whose destinations match the
234
+ * provided {@code patterns}.
235
+ * <p>
236
+ * The matching of each pattern is performed by a
237
+ * {@link DestinationPathPatternMessageMatcher}. If no destination is found on the
238
+ * {@code Message}, then each {@code Matcher} returns false.
239
+ * @param patterns the patterns to create
240
+ * {@link DestinationPathPatternMessageMatcher} from.
241
+ * @since 6.5
242
+ */
243
+ public Builder .Constraint simpTypeSubscribeDestinationPatterns (String ... patterns ) {
244
+ return destinationPathPatterns (SimpMessageType .SUBSCRIBE , patterns );
245
+ }
246
+
188
247
/**
189
248
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances. If no
190
249
* destination is found on the Message, then the Matcher returns false.
@@ -195,7 +254,9 @@ public Builder.Constraint simpSubscribeDestMatchers(String... patterns) {
195
254
* from.
196
255
* @return the {@link Builder.Constraint} that is associated to the
197
256
* {@link MessageMatcher}
257
+ * @deprecated use {@link #destinationPathPatterns(String...)}
198
258
*/
259
+ @ Deprecated
199
260
private Builder .Constraint simpDestMatchers (SimpMessageType type , String ... patterns ) {
200
261
List <MessageMatcher <?>> matchers = new ArrayList <>(patterns .length );
201
262
for (String pattern : patterns ) {
@@ -205,13 +266,52 @@ private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patt
205
266
return new Builder .Constraint (matchers );
206
267
}
207
268
269
+ /**
270
+ * Allows the creation of a security {@link Constraint} applying to messages of
271
+ * the provided {@code type} whose destinations match the provided
272
+ * {@code patterns}.
273
+ * <p>
274
+ * The matching of each pattern is performed by a
275
+ * {@link DestinationPathPatternMessageMatcher}. If no destination is found on the
276
+ * {@code Message}, then each {@code Matcher} returns false.
277
+ * </p>
278
+ * @param type the {@link SimpMessageType} to match on. If null, the
279
+ * {@link SimpMessageType} is not considered for matching.
280
+ * @param patterns the patterns to create
281
+ * {@link DestinationPathPatternMessageMatcher} 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
+
208
306
/**
209
307
* The {@link PathMatcher} to be used with the
210
308
* {@link Builder#simpDestMatchers(String...)}. The default is to use the default
211
309
* constructor of {@link AntPathMatcher}.
212
310
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
213
311
* @return the {@link Builder} for further customization.
312
+ * @deprecated use {@link #messageRouteSeparator()} to alter the path separator
214
313
*/
314
+ @ Deprecated
215
315
public Builder simpDestPathMatcher (PathMatcher pathMatcher ) {
216
316
Assert .notNull (pathMatcher , "pathMatcher cannot be null" );
217
317
this .pathMatcher = () -> pathMatcher ;
@@ -224,7 +324,9 @@ public Builder simpDestPathMatcher(PathMatcher pathMatcher) {
224
324
* computation or lookup of the {@link PathMatcher}.
225
325
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
226
326
* @return the {@link Builder} for further customization.
327
+ * @deprecated use {@link #messageRouteSeparator()} to alter the path separator
227
328
*/
329
+ @ Deprecated
228
330
public Builder simpDestPathMatcher (Supplier <PathMatcher > pathMatcher ) {
229
331
Assert .notNull (pathMatcher , "pathMatcher cannot be null" );
230
332
this .pathMatcher = pathMatcher ;
@@ -240,9 +342,7 @@ public Builder simpDestPathMatcher(Supplier<PathMatcher> pathMatcher) {
240
342
*/
241
343
public Builder .Constraint matchers (MessageMatcher <?>... matchers ) {
242
344
List <MessageMatcher <?>> builders = new ArrayList <>(matchers .length );
243
- for (MessageMatcher <?> matcher : matchers ) {
244
- builders .add (matcher );
245
- }
345
+ builders .addAll (Arrays .asList (matchers ));
246
346
return new Builder .Constraint (builders );
247
347
}
248
348
@@ -381,6 +481,7 @@ public Builder access(AuthorizationManager<MessageAuthorizationContext<?>> autho
381
481
382
482
}
383
483
484
+ @ Deprecated
384
485
private final class LazySimpDestinationMessageMatcher implements MessageMatcher <Object > {
385
486
386
487
private final Supplier <SimpDestinationMessageMatcher > delegate ;
@@ -412,6 +513,37 @@ Map<String, String> extractPathVariables(Message<?> message) {
412
513
413
514
}
414
515
516
+ private static final class LazySimpDestinationPatternMessageMatcher implements MessageMatcher <Object > {
517
+
518
+ private final Supplier <DestinationPathPatternMessageMatcher > delegate ;
519
+
520
+ private LazySimpDestinationPatternMessageMatcher (String pattern , SimpMessageType type ,
521
+ boolean useHttpPathSeparator ) {
522
+ this .delegate = SingletonSupplier .of (() -> {
523
+ DestinationPathPatternMessageMatcher .Builder builder = (useHttpPathSeparator )
524
+ ? DestinationPathPatternMessageMatcher .withDefaults ()
525
+ : DestinationPathPatternMessageMatcher .messageRoute ();
526
+ if (type == null ) {
527
+ return builder .matcher (pattern );
528
+ }
529
+ if (SimpMessageType .MESSAGE == type || SimpMessageType .SUBSCRIBE == type ) {
530
+ return builder .messageType (type ).matcher (pattern );
531
+ }
532
+ throw new IllegalStateException (type + " is not supported since it does not have a destination" );
533
+ });
534
+ }
535
+
536
+ @ Override
537
+ public boolean matches (Message <?> message ) {
538
+ return this .delegate .get ().matches (message );
539
+ }
540
+
541
+ Map <String , String > extractPathVariables (Message <?> message ) {
542
+ return this .delegate .get ().extractPathVariables (message );
543
+ }
544
+
545
+ }
546
+
415
547
}
416
548
417
549
private static final class Entry <T > {
@@ -420,7 +552,7 @@ private static final class Entry<T> {
420
552
421
553
private final T entry ;
422
554
423
- Entry (MessageMatcher requestMatcher , T entry ) {
555
+ Entry (MessageMatcher <?> requestMatcher , T entry ) {
424
556
this .messageMatcher = requestMatcher ;
425
557
this .entry = entry ;
426
558
}
0 commit comments