This is an automated email from the ASF dual-hosted git repository.

lahirujayathilake pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata.git


The following commit(s) were added to refs/heads/master by this push:
     new e76920dc24 Public private resources (#535)
e76920dc24 is described below

commit e76920dc246003ec0efe0e6cba87b43f0f75e487
Author: Ganning Xu <[email protected]>
AuthorDate: Sat Jul 19 21:08:05 2025 -0700

    Public private resources (#535)
    
    * backend support for public/private resources
    
    * spotless
    
    * fix bug with local threads maintaining state across requests
---
 .../research/service/config/AuthzTokenFilter.java  | 65 +++++++++++-----------
 .../service/controller/ResourceController.java     |  3 +-
 .../research/service/handlers/ResourceHandler.java | 53 +++++++++++++++---
 .../research/service/model/UserContext.java        |  9 +++
 .../service/model/repo/ResourceRepository.java     | 52 ++++++++++++++++-
 5 files changed, 136 insertions(+), 46 deletions(-)

diff --git 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/AuthzTokenFilter.java
 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/AuthzTokenFilter.java
index 5b459f8405..fa55625547 100644
--- 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/AuthzTokenFilter.java
+++ 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/AuthzTokenFilter.java
@@ -69,47 +69,46 @@ public class AuthzTokenFilter extends OncePerRequestFilter {
                 || path.startsWith("/v3/api-docs")
                 || path.startsWith("/swagger-ui")
                 || path.startsWith("/swagger-resources")
-                || path.startsWith("/webjars/")
-                || path.startsWith("/api/v1/rf/resources/public");
+                || path.startsWith("/webjars/");
     }
 
     @Override
     protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse response, FilterChain filterChain)
             throws ServletException, IOException {
+        try {
+            String authorizationHeader = request.getHeader("Authorization");
+            String xClaimsHeader = request.getHeader("X-Claims");
+
+            if (request.getMethod().equals("OPTIONS")) {
+                filterChain.doFilter(request, response);
+                return;
+            }
+
+            if (authorizationHeader != null && 
authorizationHeader.startsWith("Bearer ") && xClaimsHeader != null) {
+                try {
+                    String accessToken = authorizationHeader.substring(7); // 
Remove "Bearer " prefix
+                    ObjectMapper objectMapper = new ObjectMapper();
+                    Map<String, String> claimsMap = 
objectMapper.readValue(xClaimsHeader, new TypeReference<>() {});
+
+                    AuthzToken authzToken = new AuthzToken();
+                    authzToken.setAccessToken(accessToken);
+                    authzToken.setClaimsMap(claimsMap);
+                    UserContext.setAuthzToken(authzToken);
+
+                    UserProfile userProfile = airavataService.getUserProfile(
+                            authzToken, getClaim(authzToken, USERNAME_CLAIM), 
getClaim(authzToken, GATEWAY_CLAIM));
+                    UserContext.setUser(userProfile);
+                } catch (Exception e) {
+                    LOGGER.error("Invalid authorization data", e);
+                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, 
"Invalid authorization data");
+                    return;
+                }
+            }
 
-        String authorizationHeader = request.getHeader("Authorization");
-        String xClaimsHeader = request.getHeader("X-Claims");
-
-        if (request.getMethod().equals("OPTIONS")) {
             filterChain.doFilter(request, response);
-            return;
-        }
-
-        if (authorizationHeader == null || 
!authorizationHeader.startsWith("Bearer ") || xClaimsHeader == null) {
-            LOGGER.error("Missing or invalid Authorization header");
-            return;
+        } finally {
+            UserContext.clear();
         }
-
-        try {
-            String accessToken = authorizationHeader.substring(7); // Remove 
"Bearer " prefix
-            ObjectMapper objectMapper = new ObjectMapper();
-            Map<String, String> claimsMap = 
objectMapper.readValue(xClaimsHeader, new TypeReference<>() {});
-
-            AuthzToken authzToken = new AuthzToken();
-            authzToken.setAccessToken(accessToken);
-            authzToken.setClaimsMap(claimsMap);
-            UserContext.setAuthzToken(authzToken);
-
-            UserProfile userProfile = airavataService.getUserProfile(
-                    authzToken, getClaim(authzToken, USERNAME_CLAIM), 
getClaim(authzToken, GATEWAY_CLAIM));
-            UserContext.setUser(userProfile);
-        } catch (Exception e) {
-            LOGGER.error("Invalid authorization data", e);
-            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid 
authorization data");
-            return;
-        }
-
-        filterChain.doFilter(request, response);
     }
 
     private static String getClaim(AuthzToken authzToken, String claimId) {
diff --git 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java
 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java
index d20de6bb65..af849205fd 100644
--- 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java
+++ 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java
@@ -134,13 +134,14 @@ public class ResourceController {
                 typeList.add(DatasetResource.class);
             }
         }
+
         Page<Resource> response = resourceHandler.getAllResources(pageNumber, 
pageSize, typeList, tags, nameSearch);
 
         return ResponseEntity.ok(response);
     }
 
     @Operation(summary = "Get resource by name")
-    @GetMapping("/public/search")
+    @GetMapping("/search")
     public ResponseEntity<List<Resource>> searchResource(
             @RequestParam(value = "type") ResourceTypeEnum type,
             @RequestParam(value = "name", required = false) String name) {
diff --git 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java
 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java
index 0e84a2b36f..d4bff347f4 100644
--- 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java
+++ 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java
@@ -30,6 +30,7 @@ import org.apache.airavata.research.service.AiravataService;
 import org.apache.airavata.research.service.dto.CreateResourceRequest;
 import org.apache.airavata.research.service.dto.ModifyResourceRequest;
 import org.apache.airavata.research.service.dto.ResourceResponse;
+import org.apache.airavata.research.service.enums.PrivacyEnum;
 import org.apache.airavata.research.service.enums.ResourceTypeEnum;
 import org.apache.airavata.research.service.enums.StateEnum;
 import org.apache.airavata.research.service.enums.StatusEnum;
@@ -224,14 +225,23 @@ public class ResourceHandler {
     }
 
     public Resource getResourceById(String id) {
-        // Your logic to fetch the resource by ID
         Optional<Resource> opResource = 
resourceRepository.findByIdAndState(id, StateEnum.ACTIVE);
 
         if (opResource.isEmpty()) {
             throw new EntityNotFoundException("Resource not found: " + id);
         }
 
-        return opResource.get();
+        Resource resource = opResource.get();
+        boolean isAuthenticated = UserContext.isAuthenticated();
+
+        if (resource.getPrivacy().equals(PrivacyEnum.PUBLIC)) {
+            return resource;
+        } else if (isAuthenticated
+                && 
resource.getAuthors().contains(UserContext.userId().toLowerCase())) {
+            return resource;
+        } else {
+            throw new EntityNotFoundException("Resource not found: " + id);
+        }
     }
 
     public boolean deleteResourceById(String id) {
@@ -259,13 +269,11 @@ public class ResourceHandler {
 
     public Page<Resource> getAllResources(
             int pageNumber, int pageSize, List<Class<? extends Resource>> 
typeList, String[] tag, String nameSearch) {
-        Pageable pageable = PageRequest.of(pageNumber, pageSize);
-        if (tag == null || tag.length == 0) {
-            return resourceRepository.findAllByTypes(typeList, nameSearch, 
pageable);
+        boolean isAuthenticated = UserContext.isAuthenticated();
+        if (isAuthenticated) {
+            return getAllResourcesUserSignedIn(pageNumber, pageSize, typeList, 
tag, nameSearch, UserContext.userId());
         }
-
-        return resourceRepository.findAllByTypesAndAllTags(
-                typeList, tag, tag.length, nameSearch.toLowerCase(), pageable);
+        return getAllPublicResources(pageNumber, pageSize, typeList, tag, 
nameSearch);
     }
 
     public List<Tag> getAllTags() {
@@ -277,7 +285,34 @@ public class ResourceHandler {
     }
 
     public List<Resource> getAllResourcesByTypeAndName(Class<? extends 
Resource> type, String name) {
+        return resourceRepository.findByTypeAndNameContainingIgnoreCase(type, 
name.toLowerCase(), UserContext.userId());
+    }
+
+    private Page<Resource> getAllPublicResources(
+            int pageNumber, int pageSize, List<Class<? extends Resource>> 
typeList, String[] tag, String nameSearch) {
+        Pageable pageable = PageRequest.of(pageNumber, pageSize);
+        if (tag == null || tag.length == 0) {
+            return resourceRepository.findAllByTypes(typeList, nameSearch, 
pageable);
+        }
+
+        return resourceRepository.findAllByTypesAndAllTags(
+                typeList, tag, tag.length, nameSearch.toLowerCase(), pageable);
+    }
+
+    private Page<Resource> getAllResourcesUserSignedIn(
+            int pageNumber,
+            int pageSize,
+            List<Class<? extends Resource>> typeList,
+            String[] tag,
+            String nameSearch,
+            String userId) {
+        Pageable pageable = PageRequest.of(pageNumber, pageSize);
+
+        if (tag == null || tag.length == 0) {
+            return resourceRepository.findAllByTypesForUser(typeList, 
nameSearch.toLowerCase(), userId, pageable);
+        }
 
-        return resourceRepository.findByTypeAndNameContainingIgnoreCase(type, 
name.toLowerCase());
+        return resourceRepository.findAllByTypesAndAllTagsForUser(
+                typeList, tag, (long) tag.length, nameSearch.toLowerCase(), 
userId, pageable);
     }
 }
diff --git 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/UserContext.java
 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/UserContext.java
index abb71aa862..b6c1b52887 100644
--- 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/UserContext.java
+++ 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/UserContext.java
@@ -50,4 +50,13 @@ public class UserContext {
     public static String gatewayId() {
         return CURRENT_USER.get().getGatewayId();
     }
+
+    public static boolean isAuthenticated() {
+        return AUTHZ_TOKEN.get() != null;
+    }
+
+    public static void clear() {
+        AUTHZ_TOKEN.remove();
+        CURRENT_USER.remove();
+    }
 }
diff --git 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java
 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java
index e53058ab10..98e7b27a2f 100644
--- 
a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java
+++ 
b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java
@@ -36,8 +36,11 @@ public interface ResourceRepository extends 
JpaRepository<Resource, String> {
     @Query(
             """
                     SELECT r
-                    FROM #{#entityName} r
-                    WHERE TYPE(r) IN :types AND r.name LIKE CONCAT('%', 
:nameSearch, '%') AND r.state = 'ACTIVE'
+                    FROM Resource r
+                    WHERE TYPE(r) IN :types
+                      AND r.name LIKE CONCAT('%', :nameSearch, '%')
+                      AND r.state = 'ACTIVE'
+                      AND r.privacy = 'PUBLIC'
                     ORDER BY r.name
                     """)
     Page<Resource> findAllByTypes(
@@ -45,6 +48,23 @@ public interface ResourceRepository extends 
JpaRepository<Resource, String> {
             @Param("nameSearch") String nameSearch,
             Pageable pageable);
 
+    @Query(
+            """
+            SELECT DISTINCT r
+            FROM Resource r
+            JOIN r.authors a
+            WHERE r.class IN :typeList
+              AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, '%'))
+              AND r.state = 'ACTIVE'
+              AND (r.privacy = 'PUBLIC' or a = :userId)
+            ORDER BY r.name
+            """)
+    Page<Resource> findAllByTypesForUser(
+            @Param("typeList") List<Class<? extends Resource>> typeList,
+            @Param("nameSearch") String nameSearch,
+            @Param("userId") String userId,
+            Pageable pageable);
+
     @Query(
             """
                     SELECT r
@@ -54,6 +74,7 @@ public interface ResourceRepository extends 
JpaRepository<Resource, String> {
                       AND t.value IN :tags
                       AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, 
'%'))
                       AND r.state = 'ACTIVE'
+                      AND r.privacy = 'PUBLIC'
                     GROUP BY r
                     HAVING COUNT(DISTINCT t.value) = :tagCount
                     ORDER BY r.name
@@ -65,15 +86,40 @@ public interface ResourceRepository extends 
JpaRepository<Resource, String> {
             @Param("nameSearch") String nameSearch,
             Pageable pageable);
 
+    @Query(
+            """
+            SELECT r
+            FROM Resource r
+            JOIN r.tags t
+            JOIN r.authors a
+            WHERE r.class IN :typeList
+              AND t.value IN :tags
+              AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, '%'))
+              AND r.state = 'ACTIVE'
+              AND (r.privacy = 'PUBLIC' OR a = :userId)
+            GROUP BY r
+            HAVING COUNT(DISTINCT t.value) = :tagCount
+            ORDER BY r.name
+            """)
+    Page<Resource> findAllByTypesAndAllTagsForUser(
+            @Param("typeList") List<Class<? extends Resource>> typeList,
+            @Param("tags") String[] tags,
+            @Param("tagCount") Long tagCount,
+            @Param("nameSearch") String nameSearch,
+            @Param("userId") String userId,
+            Pageable pageable);
+
     @Query(
             """
                     SELECT r
                     FROM Resource r
+                    JOIN r.authors a
                     WHERE TYPE(r) = :type AND r.state = 'ACTIVE'
                     AND LOWER(r.name) LIKE LOWER(CONCAT('%', :name, '%'))
+                    AND (r.privacy = "PUBLIC" OR a = :userId)
                     """)
     List<Resource> findByTypeAndNameContainingIgnoreCase(
-            @Param("type") Class<? extends Resource> type, @Param("name") 
String name);
+            @Param("type") Class<? extends Resource> type, @Param("name") 
String name, @Param("userId") String userId);
 
     Optional<Resource> findByIdAndState(String id, StateEnum state);
 }

Reply via email to