-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add DestinationPathPatternMessageMatcher #16635
base: main
Are you sure you want to change the base?
Add DestinationPathPatternMessageMatcher #16635
Conversation
Closes spring-projectsgh-16500 Signed-off-by: Pat McCusker <[email protected]>
de8c0ce
to
31b962b
Compare
Hi @jzheaux, not sure if there are notifications on Draft PRs but I wanted to get your thoughts on how things looked in here so far. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the draft, @pat-mccusker, this is a great start.
As far as your question about the prototype bean method, we should have an opt-in strategy that says that an application wants to start using DestinationPathPatternMessageMatcher
instead of PathMatcher
.
I think you can follow the pattern in PathPatternRequestMatcherBuilderFactoryBean
. This is a factory bean that publishes a PathPatternRequestMatcher.Builder
instances that applications and the DSL can use to build request matchers.
If you introduced DestinationPathPatternMessageMatcherBuilderFactoryBean
, then you could do the same here, e.g. "if DestinationPathPatternMessageMatcher.Builder bean exists, then I use that to construct request matchers instead of working with path matcher"
* {@link org.springframework.http.server.PathContainer.Options#MESSAGE_ROUTE} | ||
* separator | ||
*/ | ||
public static Builder messageRoute() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of messageRoute()
, let's expose the PathPatternParser
that will be used. This will allow the application to configure PathOptions
as well as anything else needed.
* {@code Constraint} will be applicable | ||
* @since 6.5 | ||
*/ | ||
public Builder.Constraint destinationPathPatterns(String... patterns) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is another way to opt-in, I'd prefer to leave the methods that take a String
the same. The reason is that it still describes what the application is doing: matching a simp destination.
* configured in | ||
* {@link org.springframework.http.server.PathContainer.Options#MESSAGE_ROUTE} | ||
*/ | ||
public Builder messageRouteSeparator() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably too specific for the DSL. The application in this case should constructor their own message matcher instance.
@@ -224,7 +324,9 @@ public Builder simpDestPathMatcher(PathMatcher pathMatcher) { | |||
* computation or lookup of the {@link PathMatcher}. | |||
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null. | |||
* @return the {@link Builder} for further customization. | |||
* @deprecated use {@link #messageRouteSeparator()} to alter the path separator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead, let's begin with directing them to use #matchers
to construct their own matcher.
@@ -412,6 +513,37 @@ Map<String, String> extractPathVariables(Message<?> message) { | |||
|
|||
} | |||
|
|||
private static final class LazySimpDestinationPatternMessageMatcher implements MessageMatcher<Object> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing deferral work is there to address an eager instantiation issue caused by trying to resolve the Spring Websocket PathMatcher
instance too early. When we aren't using PathMatcher
, then this lazy-loading is likely unnecessary.
@@ -43,30 +43,30 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests { | |||
void checkWhenPermitAllThenPermits() { | |||
AuthorizationManager<Message<?>> authorizationManager = builder().anyMessage().permitAll().build(); | |||
Message<?> message = new GenericMessage<>(new Object()); | |||
assertThat(authorizationManager.check(mock(Supplier.class), message).isGranted()).isTrue(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please leave these as-is. Even though check
is deprecated, we want to make sure it keeps working until we are ready to remove it.
@Test | ||
void checkWhenMessageTypeAndPathPatternMatches() { | ||
AuthorizationManager<Message<?>> authorizationManager = builder() | ||
.simpTypeMessageDestinationPatterns("/destination") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the following convention:
.matcher(pathOne).rule()
.matcher(pathTwo).rule()
// ...
So, in this case, it would look something like:
.simpTypeMessageDestinationPatterns("/destination").permitAll()
.simpTypeSubscribeDestinationPatterns("/destination").denyAll()
// ...
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright 2002-2024 the original author or authors. | |||
* Copyright 2002-2025 the original author or authors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there are no other changes here, please go ahead and revert the copyright year so that this file is left out of the PR. Please do this for any other files like this one.
@@ -87,12 +89,11 @@ private MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> ma | |||
if (!matcher.matches((Message) message)) { | |||
return null; | |||
} | |||
if (matcher instanceof SimpDestinationMessageMatcher simp) { | |||
return new MessageAuthorizationContext<>(message, simp.extractPathVariables(message)); | |||
if (matcher instanceof Builder.LazySimpDestinationMessageMatcher pathMatcher) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we make the change to MessageMatcher
suggested in this PR, then this casting can all be removed.
* @author Pat McCusker | ||
* @since 6.5 | ||
*/ | ||
public final class DestinationPathPatternMessageMatcher implements MessageMatcher<Object> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be called PathPatternMessageMatcher
.
The reason is that it already contains more aspects of the message than the destination and may contain more in the future. So far, it doesn't seem materially different from PathPatternRequestMatcher
and so we don't want to give the impression that it is by using a more specific name.
Note that otherwise, we'd want to call PathPatternRequestMatcher
something more like UriPathPatternRequestMatcher
. Which, at least for our purposes, doesn't add much information about what it is for.
Closes gh-16500
I wasn't sure that this configuration was safe to remove so I wanted to point it out. In WebSocketMessageBrokerSecurityConfigurationTests an
AntPathMatcher
is configured with a '.' path separator, and this test will fail if the mentioned config is simply removed. If consumers of spring-security are configuring aPathMatcher
in aSimpAnnotationMethodMessageHandler
instance, then this matching would cease to function correctly as far as I can tell.This led me to delegating the destination pattern matching to one or another
PathPatternRouteMatcher
s depending on which path separator is configured by theMessageMatcherDelegatingAuthorizationManager.Builder
, but I've left the original builder configuration in place for the moment.