From f7c028c8221ac06c0da167f666fffdf5e9e2f3a9 Mon Sep 17 00:00:00 2001 From: Nathanael Law Date: Fri, 18 Oct 2019 16:52:05 -0600 Subject: [PATCH] Handle %2F in usernames Replaces the simple string replacement scheme of "/" -> "%2F" which breaks when "%2F" is in the original username with a conditional URL-safe Base64 scheme. --- .../messaging/simp/SimpMessagingTemplate.java | 5 +++-- .../user/DefaultUserDestinationResolver.java | 5 +++-- .../simp/SimpMessagingTemplateTests.java | 16 ++++++++++++++- .../DefaultUserDestinationResolverTests.java | 20 ++++++++++++++++++- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpMessagingTemplate.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpMessagingTemplate.java index c3ddf8a894a1..628380a54dfa 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpMessagingTemplate.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpMessagingTemplate.java @@ -31,7 +31,7 @@ import org.springframework.messaging.support.MessageHeaderInitializer; import org.springframework.messaging.support.NativeMessageHeaderAccessor; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; +import org.springframework.util.Base64Utils; /** * An implementation of @@ -224,7 +224,8 @@ public void convertAndSendToUser(String user, String destination, Object payload throws MessagingException { Assert.notNull(user, "User must not be null"); - user = StringUtils.replace(user, "/", "%2F"); + if (user.startsWith("B64:") || user.contains("/")) + user = "B64:" + Base64Utils.encodeToUrlSafeString(user.getBytes()); destination = destination.startsWith("/") ? destination : "/" + destination; super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java index 5f71ec962ba0..8f6a3a066402 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java @@ -31,7 +31,7 @@ import org.springframework.messaging.simp.SimpMessageType; import org.springframework.util.Assert; import org.springframework.util.PathMatcher; -import org.springframework.util.StringUtils; +import org.springframework.util.Base64Utils; /** * A default implementation of {@code UserDestinationResolver} that relies @@ -214,7 +214,8 @@ private ParseResult parseMessage(MessageHeaders headers, String sourceDest) { String actualDest = sourceDest.substring(userEnd); String subscribeDest = this.prefix.substring(0, prefixEnd - 1) + actualDest; String userName = sourceDest.substring(prefixEnd, userEnd); - userName = StringUtils.replace(userName, "%2F", "/"); + if (userName.startsWith("B64:")) + userName = new String(Base64Utils.decodeFromUrlSafeString(userName.split("B64:")[1])); String sessionId = SimpMessageHeaderAccessor.getSessionId(headers); Set sessionIds; diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/SimpMessagingTemplateTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/SimpMessagingTemplateTests.java index 7b4343aac88c..265367e07eb3 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/SimpMessagingTemplateTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/SimpMessagingTemplateTests.java @@ -83,7 +83,21 @@ public void convertAndSendToUserWithEncoding() { MessageHeaderAccessor.getAccessor(messages.get(0), SimpMessageHeaderAccessor.class); assertThat(headerAccessor).isNotNull(); - assertThat(headerAccessor.getDestination()).isEqualTo("/user/https:%2F%2Fjoe.openid.example.org%2F/queue/foo"); + assertThat(headerAccessor.getDestination()).isEqualTo("/user/B64:aHR0cHM6Ly9qb2Uub3BlbmlkLmV4YW1wbGUub3JnLw==/queue/foo"); + } + + @Test + public void convertAndSendToUserWithEncodingOfPercentTwoEff() { + this.messagingTemplate.convertAndSendToUser("https%3A%2F%2Fjoe.openid.example.org%2F|911276df-8a4f-4fda-986a-0713aba85b5e", "/queue/foo", "data"); + List> messages = this.messageChannel.getMessages(); + + assertThat(messages.size()).isEqualTo(1); + + SimpMessageHeaderAccessor headerAccessor = + MessageHeaderAccessor.getAccessor(messages.get(0), SimpMessageHeaderAccessor.class); + + assertThat(headerAccessor).isNotNull(); + assertThat(headerAccessor.getDestination()).isEqualTo("/user/https%3A%2F%2Fjoe.openid.example.org%2F|911276df-8a4f-4fda-986a-0713aba85b5e/queue/foo"); } @Test diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolverTests.java index c2887f5d1b25..e0d3a99f87b4 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolverTests.java @@ -27,6 +27,7 @@ import org.springframework.messaging.simp.TestPrincipal; import org.springframework.messaging.support.MessageBuilder; import org.springframework.util.StringUtils; +import org.springframework.util.Base64Utils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -180,7 +181,24 @@ public void handleMessageEncodedUserName() { simpUser.addSessions(new TestSimpSession("openid123")); given(this.registry.getUser(userName)).willReturn(simpUser); - String destination = "/user/" + StringUtils.replace(userName, "/", "%2F") + "/queue/foo"; + String destination = "/user/B64:" + Base64Utils.encodeToUrlSafeString(userName.getBytes()) + "/queue/foo"; + + Message message = createMessage(SimpMessageType.MESSAGE, new TestPrincipal("joe"), null, destination); + UserDestinationResult actual = this.resolver.resolveDestination(message); + + assertThat(actual.getTargetDestinations().size()).isEqualTo(1); + assertThat(actual.getTargetDestinations().iterator().next()).isEqualTo("/queue/foo-useropenid123"); + } + + @Test + public void handleMessageEncodedUserNameWithPercentTwoEff() { + String userName = "https%3A%2F%2Fjoe.openid.example.org%2F|911276df-8a4f-4fda-986a-0713aba85b5e"; + + TestSimpUser simpUser = new TestSimpUser(userName); + simpUser.addSessions(new TestSimpSession("openid123")); + given(this.registry.getUser(userName)).willReturn(simpUser); + + String destination = "/user/" + userName + "/queue/foo"; Message message = createMessage(SimpMessageType.MESSAGE, new TestPrincipal("joe"), null, destination); UserDestinationResult actual = this.resolver.resolveDestination(message);