1717package  org .springframework .security .messaging .access .intercept ;
1818
1919import  java .util .ArrayList ;
20+ import  java .util .Arrays ;
2021import  java .util .List ;
2122import  java .util .Map ;
2223import  java .util .function .Supplier ;
2526import  org .apache .commons .logging .LogFactory ;
2627
2728import  org .springframework .core .log .LogMessage ;
29+ import  org .springframework .http .server .PathContainer ;
2830import  org .springframework .messaging .Message ;
2931import  org .springframework .messaging .simp .SimpMessageType ;
3032import  org .springframework .security .authorization .AuthenticatedAuthorizationManager ;
3436import  org .springframework .security .authorization .SingleResultAuthorizationManager ;
3537import  org .springframework .security .core .Authentication ;
3638import  org .springframework .security .messaging .util .matcher .MessageMatcher ;
39+ import  org .springframework .security .messaging .util .matcher .PathPatternMessageMatcher ;
3740import  org .springframework .security .messaging .util .matcher .SimpDestinationMessageMatcher ;
3841import  org .springframework .security .messaging .util .matcher .SimpMessageTypeMatcher ;
3942import  org .springframework .util .AntPathMatcher ;
4043import  org .springframework .util .Assert ;
4144import  org .springframework .util .PathMatcher ;
4245import  org .springframework .util .function .SingletonSupplier ;
46+ import  org .springframework .web .util .pattern .PathPatternParser ;
4347
4448public  final  class  MessageMatcherDelegatingAuthorizationManager  implements  AuthorizationManager <Message <?>> {
4549
@@ -88,12 +92,11 @@ private MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> ma
8892		if  (!matcher .matches ((Message ) message )) {
8993			return  null ;
9094		}
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 ));
9397		}
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 ));
97100		}
98101		return  new  MessageAuthorizationContext <>(message );
99102	}
@@ -113,8 +116,11 @@ public static final class Builder {
113116
114117		private  final  List <Entry <AuthorizationManager <MessageAuthorizationContext <?>>>> mappings  = new  ArrayList <>();
115118
119+ 		@ Deprecated 
116120		private  Supplier <PathMatcher > pathMatcher  = AntPathMatcher ::new ;
117121
122+ 		private  boolean  useHttpPathSeparator  = true ;
123+ 
118124		public  Builder () {
119125		}
120126
@@ -133,11 +139,11 @@ public Builder.Constraint anyMessage() {
133139		 * @return the Expression to associate 
134140		 */ 
135141		public  Builder .Constraint  nullDestMatcher () {
136- 			return  matchers (SimpDestinationMessageMatcher .NULL_DESTINATION_MATCHER );
142+ 			return  matchers (PathPatternMessageMatcher .NULL_DESTINATION_MATCHER );
137143		}
138144
139145		/** 
140- 		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher } instances. 
146+ 		 * Maps a {@link List} of {@link SimpMessageTypeMatcher } instances. 
141147		 * @param typesToMatch the {@link SimpMessageType} instance to match on 
142148		 * @return the {@link Builder.Constraint} associated to the matchers. 
143149		 */ 
@@ -157,35 +163,88 @@ public Builder.Constraint simpTypeMatchers(SimpMessageType... typesToMatch) {
157163		 * @param patterns the patterns to create 
158164		 * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} 
159165		 * from. 
166+ 		 * @deprecated use {@link #destinationPathPatterns(String...)} 
160167		 */ 
168+ 		@ Deprecated 
161169		public  Builder .Constraint  simpDestMatchers (String ... patterns ) {
162170			return  simpDestMatchers (null , patterns );
163171		}
164172
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+ 
165190		/** 
166191		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that 
167192		 * match on {@code SimpMessageType.MESSAGE}. If no destination is found on the 
168193		 * Message, then the Matcher returns false. 
169194		 * @param patterns the patterns to create 
170195		 * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} 
171196		 * from. 
197+ 		 * @deprecated use {@link #destinationPathPatterns(String...)} 
172198		 */ 
199+ 		@ Deprecated 
173200		public  Builder .Constraint  simpMessageDestMatchers (String ... patterns ) {
174201			return  simpDestMatchers (SimpMessageType .MESSAGE , patterns );
175202		}
176203
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+ 
177219		/** 
178220		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that 
179221		 * match on {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the 
180222		 * Message, then the Matcher returns false. 
181223		 * @param patterns the patterns to create 
182224		 * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} 
183225		 * from. 
226+ 		 * @deprecated use {@link #simpTypeSubscribeDestinationPatterns(String...)} 
184227		 */ 
228+ 		@ Deprecated 
185229		public  Builder .Constraint  simpSubscribeDestMatchers (String ... patterns ) {
186230			return  simpDestMatchers (SimpMessageType .SUBSCRIBE , patterns );
187231		}
188232
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+ 
189248		/** 
190249		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances. If no 
191250		 * destination is found on the Message, then the Matcher returns false. 
@@ -196,7 +255,9 @@ public Builder.Constraint simpSubscribeDestMatchers(String... patterns) {
196255		 * from. 
197256		 * @return the {@link Builder.Constraint} that is associated to the 
198257		 * {@link MessageMatcher} 
258+ 		 * @deprecated use {@link #destinationPathPatterns(String...)} 
199259		 */ 
260+ 		@ Deprecated 
200261		private  Builder .Constraint  simpDestMatchers (SimpMessageType  type , String ... patterns ) {
201262			List <MessageMatcher <?>> matchers  = new  ArrayList <>(patterns .length );
202263			for  (String  pattern  : patterns ) {
@@ -206,13 +267,51 @@ private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patt
206267			return  new  Builder .Constraint (matchers );
207268		}
208269
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+ 
209306		/** 
210307		 * The {@link PathMatcher} to be used with the 
211308		 * {@link Builder#simpDestMatchers(String...)}. The default is to use the default 
212309		 * constructor of {@link AntPathMatcher}. 
213310		 * @param pathMatcher the {@link PathMatcher} to use. Cannot be null. 
214311		 * @return the {@link Builder} for further customization. 
312+ 		 * @deprecated use {@link #messageRouteSeparator()} to alter the path separator 
215313		 */ 
314+ 		@ Deprecated 
216315		public  Builder  simpDestPathMatcher (PathMatcher  pathMatcher ) {
217316			Assert .notNull (pathMatcher , "pathMatcher cannot be null" );
218317			this .pathMatcher  = () -> pathMatcher ;
@@ -225,7 +324,9 @@ public Builder simpDestPathMatcher(PathMatcher pathMatcher) {
225324		 * computation or lookup of the {@link PathMatcher}. 
226325		 * @param pathMatcher the {@link PathMatcher} to use. Cannot be null. 
227326		 * @return the {@link Builder} for further customization. 
327+ 		 * @deprecated use {@link #messageRouteSeparator()} to alter the path separator 
228328		 */ 
329+ 		@ Deprecated 
229330		public  Builder  simpDestPathMatcher (Supplier <PathMatcher > pathMatcher ) {
230331			Assert .notNull (pathMatcher , "pathMatcher cannot be null" );
231332			this .pathMatcher  = pathMatcher ;
@@ -241,9 +342,7 @@ public Builder simpDestPathMatcher(Supplier<PathMatcher> pathMatcher) {
241342		 */ 
242343		public  Builder .Constraint  matchers (MessageMatcher <?>... matchers ) {
243344			List <MessageMatcher <?>> builders  = new  ArrayList <>(matchers .length );
244- 			for  (MessageMatcher <?> matcher  : matchers ) {
245- 				builders .add (matcher );
246- 			}
345+ 			builders .addAll (Arrays .asList (matchers ));
247346			return  new  Builder .Constraint (builders );
248347		}
249348
@@ -382,6 +481,7 @@ public Builder access(AuthorizationManager<MessageAuthorizationContext<?>> autho
382481
383482		}
384483
484+ 		@ Deprecated 
385485		private  final  class  LazySimpDestinationMessageMatcher  implements  MessageMatcher <Object > {
386486
387487			private  final  Supplier <SimpDestinationMessageMatcher > delegate ;
@@ -413,6 +513,40 @@ Map<String, String> extractPathVariables(Message<?> message) {
413513
414514		}
415515
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+ 
416550	}
417551
418552	private  static  final  class  Entry <T > {
@@ -421,7 +555,7 @@ private static final class Entry<T> {
421555
422556		private  final  T  entry ;
423557
424- 		Entry (MessageMatcher  requestMatcher , T  entry ) {
558+ 		Entry (MessageMatcher <?>  requestMatcher , T  entry ) {
425559			this .messageMatcher  = requestMatcher ;
426560			this .entry  = entry ;
427561		}
0 commit comments