From 5a8ed6cd3d66f4e79f5407605bc8a56552491f66 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Mon, 22 Mar 2021 17:51:33 +0100
Subject: [PATCH] Added URL encoding of group names and configuration for
 allowing encoded backslash character

---
 .../java/it/inaf/ia2/gms/GmsApplication.java  |  3 +++
 .../controller/JWTWebServiceController.java   | 24 +++++++++++++++----
 .../ia2/gms/service/GroupNameService.java     |  4 ++++
 .../ia2/gms/service/GroupNameServiceTest.java | 14 +++++------
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/gms/src/main/java/it/inaf/ia2/gms/GmsApplication.java b/gms/src/main/java/it/inaf/ia2/gms/GmsApplication.java
index be65afa..77a4f80 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/GmsApplication.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/GmsApplication.java
@@ -16,6 +16,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 public class GmsApplication {
 
     public static void main(String[] args) {
+        // Needed to use %5C (backslash URL encoded) in path variables (otherwise BadRequest error is sent)
+        System.setProperty("org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH", "true");
+
         SpringApplication.run(GmsApplication.class, args);
     }
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
index da64a1a..a3d57a0 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
@@ -21,6 +21,8 @@ import it.inaf.ia2.gms.service.SearchService;
 import it.inaf.ia2.rap.data.RapUser;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -105,8 +107,10 @@ public class JWTWebServiceController {
      * be defined adding ".+", otherwise Spring will think it is a file
      * extension (thanks https://stackoverflow.com/a/16333149/771431)
      */
-    @GetMapping(value = {"/ws/jwt/search/{group:.+}", "/vo/search/{group:.+}"}, produces = MediaType.TEXT_PLAIN_VALUE)
-    public void isMemberOf(@PathVariable("group") String group, HttpServletResponse response) throws IOException {
+    @GetMapping(value = {"/ws/jwt/search/**", "/vo/search/**"}, produces = MediaType.TEXT_PLAIN_VALUE)
+    public void isMemberOf(HttpServletRequest request, HttpServletResponse response) throws IOException {
+
+        String group = getGroupFromRequest(request, "/ws/jwt/search/", "/vo/search/");
 
         List<String> groupNames = groupNameService.extractGroupNames(group);
 
@@ -338,8 +342,10 @@ public class JWTWebServiceController {
         response.setStatus(HttpServletResponse.SC_CREATED);
     }
 
-    @GetMapping(value = {"/ws/jwt/email/{group:.+}", "/email/{group:.+}"}, produces = MediaType.TEXT_PLAIN_VALUE)
-    public void getEmailOfMembers(@PathVariable("group") String groupNames, @RequestParam("permission") Optional<Permission> permission, HttpServletResponse response) throws IOException {
+    @GetMapping(value = {"/ws/jwt/email/**", "/email/**"}, produces = MediaType.TEXT_PLAIN_VALUE)
+    public void getEmailOfMembers(HttpServletRequest request, @RequestParam("permission") Optional<Permission> permission, HttpServletResponse response) throws IOException {
+
+        String groupNames = getGroupFromRequest(request, "/ws/jwt/email/", "/email/");
 
         GroupEntity groupEntity = groupNameService.getGroupFromNames(Optional.of(groupNames));
 
@@ -379,4 +385,14 @@ public class JWTWebServiceController {
         responseBody.put("mergedId", mergedId);
         return ResponseEntity.ok(responseBody);
     }
+
+    private String getGroupFromRequest(HttpServletRequest request, String... basePaths) {
+        for (String basePath : basePaths) {
+            String completeBasePath = request.getContextPath() + basePath;
+            if (request.getRequestURI().startsWith(completeBasePath)) {
+                return URLDecoder.decode(request.getRequestURI().substring(completeBasePath.length()), StandardCharsets.UTF_8);
+            }
+        }
+        return "";
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupNameService.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupNameService.java
index ffb5d2b..f6651e0 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupNameService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupNameService.java
@@ -3,6 +3,8 @@ package it.inaf.ia2.gms.service;
 import it.inaf.ia2.gms.exception.BadRequestException;
 import it.inaf.ia2.gms.persistence.GroupsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -136,6 +138,8 @@ public class GroupNameService {
             return new ArrayList<>();
         }
 
+        groupStr = URLDecoder.decode(groupStr, StandardCharsets.UTF_8);
+
         List<String> names = new ArrayList<>();
         String currentName = "";
         for (int i = 0; i < groupStr.length(); i++) {
diff --git a/gms/src/test/java/it/inaf/ia2/gms/service/GroupNameServiceTest.java b/gms/src/test/java/it/inaf/ia2/gms/service/GroupNameServiceTest.java
index 6cec8b7..826e91e 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/service/GroupNameServiceTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/service/GroupNameServiceTest.java
@@ -31,7 +31,7 @@ public class GroupNameServiceTest {
     private GroupNameService groupNameService;
 
     @Test
-    public void getNamesTest() {
+    public void testGetNames() {
 
         GroupEntity group = new GroupEntity();
         group.setName("Child\\.withDot");
@@ -54,7 +54,7 @@ public class GroupNameServiceTest {
     }
 
     @Test
-    public void getRootTest() {
+    public void testGetRoot() {
 
         Set<String> groupIds = new HashSet<>();
         groupIds.add("ROOT");
@@ -79,9 +79,9 @@ public class GroupNameServiceTest {
     }
 
     @Test
-    public void extractGroupNamesTest() {
+    public void testExtractGroupNames() {
 
-        List<String> names = groupNameService.extractGroupNames("group1.people.name\\.surname.another\\.composite");
+        List<String> names = groupNameService.extractGroupNames("group1.people.name\\.surname.another%5C.composite");
 
         assertEquals(4, names.size());
         assertEquals("group1", names.get(0));
@@ -89,14 +89,14 @@ public class GroupNameServiceTest {
         assertEquals("name.surname", names.get(2));
         assertEquals("another.composite", names.get(3));
     }
-
+    
     @Test
-    public void extractGroupNamesTestEmpty() {
+    public void testExtractGroupNamesEmpty() {
         assertTrue(groupNameService.extractGroupNames("").isEmpty());
     }
 
     @Test
-    public void extractGroupNamesTestNull() {
+    public void testExtractGroupNamesNull() {
         assertTrue(groupNameService.extractGroupNames(null).isEmpty());
     }
 
-- 
GitLab