From e8411cb52291cd785677b87366cedc562bea63c8 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Thu, 15 Feb 2024 14:20:56 -0800 Subject: [PATCH 01/10] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3774f57..8a2eda8 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ java -jar wildfirestorage-cli/target/wildfirestorage-cli-1.0-SNAPSHOT.jar search ### Example 7 Regex based matching with LIKE ``` -search "filePath LIKE ''" --offset=0 --limit=100 --token="" +search " LIKE ''" --offset=0 --limit=100 --token="" ``` ### Supported Query Operators From c75d35220d38a8d49837770389c87b3af36c8018 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Thu, 15 Feb 2024 23:39:02 -0800 Subject: [PATCH 02/10] Change fileName with absolute file name --- .../main/java/com/sjsu/wildfirestorage/NetcdfFileReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wildfirestorage-core/src/main/java/com/sjsu/wildfirestorage/NetcdfFileReader.java b/wildfirestorage-core/src/main/java/com/sjsu/wildfirestorage/NetcdfFileReader.java index 156c6f7..02a35d6 100644 --- a/wildfirestorage-core/src/main/java/com/sjsu/wildfirestorage/NetcdfFileReader.java +++ b/wildfirestorage-core/src/main/java/com/sjsu/wildfirestorage/NetcdfFileReader.java @@ -51,7 +51,7 @@ public Metadata processFile(int maxReadSize) { this.maxReadSize = maxReadSize; Metadata metadata = new Metadata(); String fileNameStr = netcdfFilepath.substring(netcdfFilepath.lastIndexOf('/') + 1); - metadata.fileName = Set.of(fileNameStr); + metadata.fileName = Set.of(netcdfFilepath); metadata.filePath = Set.of(netcdfFilepath.substring(0, netcdfFilepath.lastIndexOf('/') + 1)); //File Size From e3d9cb51407fa4fe63951b1c6eb92d4d6f2cfce7 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Fri, 16 Feb 2024 21:24:45 -0800 Subject: [PATCH 03/10] Use existing share links, fixed fileName usage --- wildfirestorage-cli/pom.xml | 2 +- .../controller/FilesController.java | 31 +++++++++-------- .../controller/ShareLinkController.java | 34 +++++++++++++------ 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/wildfirestorage-cli/pom.xml b/wildfirestorage-cli/pom.xml index 2d9630a..b4b04bc 100644 --- a/wildfirestorage-cli/pom.xml +++ b/wildfirestorage-cli/pom.xml @@ -34,7 +34,7 @@ - wildfirestorage-spring + wildfirestorage-cli org.springframework.boot diff --git a/wildfirestorage-fileserver/src/main/java/com/sjsu/wildfirestorage/controller/FilesController.java b/wildfirestorage-fileserver/src/main/java/com/sjsu/wildfirestorage/controller/FilesController.java index 763b017..3744072 100644 --- a/wildfirestorage-fileserver/src/main/java/com/sjsu/wildfirestorage/controller/FilesController.java +++ b/wildfirestorage-fileserver/src/main/java/com/sjsu/wildfirestorage/controller/FilesController.java @@ -1,14 +1,13 @@ package com.sjsu.wildfirestorage.controller; import com.sjsu.wildfirestorage.Metadata; -import com.sjsu.wildfirestorage.MetadataRequest; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; -import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import java.io.*; import java.util.Map; @@ -38,7 +37,7 @@ public void downloadFile(@PathVariable String digestString, HttpServletRequest r private void downloadHelper(Metadata result, HttpServletRequest request, HttpServletResponse response) { try { - RandomAccessFile file = new RandomAccessFile((String)result.filePath.toArray()[0], "r"); + RandomAccessFile file = new RandomAccessFile((String)result.fileName.toArray()[0], "r"); long fileLength = file.length(); String rangeHeader = request.getHeader("Range"); @@ -97,18 +96,22 @@ private void downloadHelper(Metadata result, HttpServletRequest request, HttpSer @GetMapping("/share/{shareId}") public void downloadSharedFile(@PathVariable String shareId, HttpServletRequest request, HttpServletResponse response) { - final String verifyUri = metadataServerUrl + "/api/share-link/verify"; + try { + final String verifyUri = metadataServerUrl + "/api/share-link/verify"; + + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", request.getHeader("Authorization")); + HttpEntity entity = new HttpEntity<>(shareId, headers); + Metadata result = restTemplate.postForObject(verifyUri, entity, Metadata.class); + if (result == null) { + return; + } + downloadHelper(result, request, response); - RestTemplate restTemplate = new RestTemplate(); - HttpHeaders headers = new HttpHeaders(); - headers.add("Authorization", request.getHeader("Authorization")); - HttpEntity entity = new HttpEntity<>(shareId, headers); - Metadata result = restTemplate.postForObject(verifyUri, entity, Metadata.class); - if(result == null) { - return; + restTemplate.postForObject(metadataServerUrl + "/api/share-link/downloadhistory", entity, Integer.class); + } catch (HttpStatusCodeException ex) { + response.setStatus(ex.getStatusCode().value()); } - downloadHelper(result, request, response); - - restTemplate.postForObject(metadataServerUrl + "/api/share-link/downloadhistory", entity, Integer.class); } } \ No newline at end of file diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java index b17df01..59dd242 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java @@ -49,26 +49,28 @@ public class ShareLinkController { public String create(@RequestBody String filePathOrDigest) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); Query query = new Query(); - Criteria fp = Criteria.where("filePath").is(filePathOrDigest); + Criteria fp = Criteria.where("fileName").is(filePathOrDigest); Criteria ds = Criteria.where("digestString").is(filePathOrDigest); query.addCriteria(new Criteria().orOperator(fp, ds)); query.fields().exclude("variables", "globalAttributes"); List res = mongoTemplate.find(query, Metadata.class, METADATA_COLLECTION); - ShareLink shareLink = new ShareLink(); if(!res.isEmpty()) { + Query linkQuery = new Query(Criteria.where("fileDigest").is(res.get(0).digestString)); + linkQuery.addCriteria(Criteria.where("createdBy").is(getCurrentUserName())); + List existing = mongoTemplate.find(linkQuery, ShareLink.class, SHARE_LINKS_COLLECTION); + if(!existing.isEmpty()) { + return fileServerUrl + "/api/share/" + existing.get(0).shareId; + } + ShareLink shareLink = new ShareLink(); shareLink.fileDigest = res.get(0).digestString; + shareLink.createdBy = getCurrentUserName(); + shareLink.shareId = UUID.randomUUID().toString().replace("-", ""); + shareLink.createdAt = LocalDateTime.now(); + mongoTemplate.insert(shareLink, "share-links"); + return fileServerUrl + "/api/share/" + shareLink.shareId; } else { return "FILE_NOT_FOUND"; } - if(auth.getPrincipal() instanceof DefaultOAuth2AuthenticatedPrincipal) { - shareLink.createdBy = (String) ((DefaultOAuth2AuthenticatedPrincipal) (auth.getPrincipal())).getAttribute("name"); - } else { - shareLink.createdBy = (String) ((DefaultOidcUser) (auth.getPrincipal())).getAttribute("name"); - } - shareLink.shareId = UUID.randomUUID().toString().replace("-", ""); - shareLink.createdAt = LocalDateTime.now(); - mongoTemplate.insert(shareLink, "share-links"); - return fileServerUrl + "/api/share/" + shareLink.shareId; } @PostMapping("/verify") @@ -81,6 +83,7 @@ public DBObject verify(@RequestBody String shareId) { } logger.info("Verification success"); Query query2 = new Query(Criteria.where("digestString").is(res.get(0).fileDigest)); + query2.fields().exclude("variables", "globalAttributes"); List res2 = mongoTemplate.find(query2, DBObject.class, METADATA_COLLECTION); logger.info((res.isEmpty() || res2 == null)? "Digest string not found":"Success, returning metadata"); return (res.isEmpty() || res2 == null)? null : res2.get(0); @@ -103,4 +106,13 @@ public Integer addDownloadHistory(@RequestBody String shareId, HttpServletReques logger.info("Add download history successful"); return 0; } + + private String getCurrentUserName() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if(auth.getPrincipal() instanceof DefaultOAuth2AuthenticatedPrincipal) { + return (String) ((DefaultOAuth2AuthenticatedPrincipal) (auth.getPrincipal())).getAttribute("name"); + } else { + return (String) ((DefaultOidcUser) (auth.getPrincipal())).getAttribute("name"); + } + } } From 15e380132e43898dbb4fa06756a88edd72015ccc Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Thu, 22 Feb 2024 20:08:31 -0800 Subject: [PATCH 04/10] Fixed 500 -> 401 error --- .../spring/controller/SecurityConfiguration.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java index 2826610..7c13111 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java @@ -15,6 +15,7 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; +import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -84,7 +85,7 @@ public AuthenticationManager opaque() { return new DefaultOAuth2AuthenticatedPrincipal("user", Map.of("name", userInfo.get("name")), null); } else { - return null; + throw new BadOpaqueTokenException("Invalid token " + token); } }; return new OpaqueTokenAuthenticationProvider(introspectionClient)::authenticate; From 423d21bafd913cb0f57245736f4bdb798f99d015 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Mon, 26 Feb 2024 23:40:50 -0800 Subject: [PATCH 05/10] Added Authorization Roles --- .../spring/controller/DatasetController.java | 3 + .../spring/controller/MetadataController.java | 11 +++ .../controller/OAuth2LoginSuccessHandler.java | 2 +- .../spring/controller/OauthController.java | 24 ++++-- .../controller/SecurityConfiguration.java | 86 ++++++++++++++++--- .../controller/ShareLinkController.java | 7 +- .../controller/StatisticsController.java | 3 + .../CustomOAuth2User.java | 0 .../CustomOAuth2UserService.java | 9 +- .../wildfirestorage/spring/util/UserInfo.java | 9 ++ 10 files changed, 126 insertions(+), 28 deletions(-) rename wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/{controller => services}/CustomOAuth2User.java (100%) rename wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/{controller => services}/CustomOAuth2UserService.java (68%) diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/DatasetController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/DatasetController.java index ede6a67..b16b10e 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/DatasetController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/DatasetController.java @@ -14,6 +14,8 @@ import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.io.IOException; @@ -33,6 +35,7 @@ public class DatasetController { private final Path datasetCreationLog = Paths.get("DatasetCreation.log"); + @PreAuthorize("hasRole('USER')") @PostMapping("/dataset") public int upsertDataset() throws MongoWriteException { AggregationOptions options = AggregationOptions.builder().allowDiskUse(true).build(); diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/MetadataController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/MetadataController.java index e9b0345..1d49707 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/MetadataController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/MetadataController.java @@ -12,6 +12,8 @@ import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import java.util.Date; @@ -33,6 +35,7 @@ public class MetadataController { * @return a list of matching Metadata documents * @throws JSQLParserException */ + @PreAuthorize("hasRole('USER')") @PostMapping("/metadata/search") public List search(@RequestBody MetadataRequest request) throws JSQLParserException { Query query = new Query(); @@ -52,8 +55,11 @@ public List search(@RequestBody MetadataRequest request) throws JSQLPa return res; } + @PreAuthorize("hasRole('USER')") @PostMapping("/metadata/search/count") public long searchCount(@RequestBody MetadataRequest request) throws JSQLParserException { + SecurityContextHolder.getContext().getAuthentication().getAuthorities().forEach(ga -> System.out.println("^^^^^^^^^^^"+ga)); + System.out.println(); Query query = new Query(); Criteria criteria = CriteriaBuilder.buildFromSQL(request.searchQuery); if(criteria != null) { @@ -65,6 +71,7 @@ public long searchCount(@RequestBody MetadataRequest request) throws JSQLParserE return mongoTemplate.count(query, Metadata.class); } + @PreAuthorize("hasRole('GUEST')") @GetMapping("/metadata/{digestString}") public DBObject getMetadataByDigest(@PathVariable String digestString) { Query query = new Query(Criteria.where("digestString").is(digestString)); @@ -77,6 +84,7 @@ public DBObject getMetadataByDigest(@PathVariable String digestString) { * @param fileName the file whose metadata is to be retrieved * @return Metadata related to the filename */ + @PreAuthorize("hasRole('USER')") @GetMapping("/metadata") public List getFileMetadata(@RequestParam("filename") String fileName) { Query query = new Query(Criteria.where("fileName").regex(".*"+fileName+".*")); @@ -90,6 +98,7 @@ public List getFileMetadata(@RequestParam("filename") String fileName) * @return 0 on success * @throws MongoWriteException */ + @PreAuthorize("hasRole('USER')") @PostMapping("/metadata") public int upsertMetadata(@RequestBody Metadata metadata) throws MongoWriteException { // Convert string date to date type to allow querying on dates @@ -123,6 +132,7 @@ public int upsertMetadata(@RequestBody Metadata metadata) throws MongoWriteExcep return 0; } + @PreAuthorize("hasRole('ADMIN')") @GetMapping("/metadata/filepath") public List getFilePaths(@RequestParam("limit") int limit, @RequestParam("offset") int offset) { Aggregation aggregation = Aggregation.newAggregation( @@ -140,6 +150,7 @@ public List getFilePaths(@RequestParam("limit") int limit, @RequestParam return files; } + @PreAuthorize("hasRole('ADMIN')") @PostMapping("/metadata/filepath") public int deleteMetadata(@RequestBody List filePaths) { Query query = new Query(Criteria.where("filePath").in(filePaths)); diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java index 72dc081..ac7be9c 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java @@ -19,7 +19,7 @@ public class OAuth2LoginSuccessHandler extends SavedRequestAwareAuthenticationSu @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { this.setAlwaysUseDefaultTargetUrl(true); - this.setDefaultTargetUrl(frontendUrl); + this.setDefaultTargetUrl("/"); super.onAuthenticationSuccess(request, response, authentication); } } diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java index 5416d45..ed18c8c 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java @@ -7,12 +7,9 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; -import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -33,10 +30,12 @@ public class OauthController { @Value("${custom.expireAfterSeconds:2592000/}") private long expireAfterSeconds; - + + @PreAuthorize("hasRole('GUEST')") @GetMapping("/") - public String index () { return "index.html"; } + public String index () { return "home.html"; } + @PreAuthorize("hasRole('GUEST')") @GetMapping("/user") public ResponseEntity user(OAuth2User user) { Map details = user.getAttributes(); @@ -49,15 +48,20 @@ public ResponseEntity info(Principal user) { return new ResponseEntity<>(user.toString(), HttpStatus.OK); } + @PreAuthorize("hasRole('GUEST')") @GetMapping("/token") public ResponseEntity token(OAuth2AuthenticationToken user) { String opaqueToken = getOpaqueToken(user); - return new ResponseEntity<>("token=" + opaqueToken, HttpStatus.OK); + return new ResponseEntity<>("Your token is: " + opaqueToken, HttpStatus.OK); } public String getOpaqueToken(OAuth2AuthenticationToken user) { String name = user.getPrincipal().getAttribute("name"); - Query query = new Query(Criteria.where("name").is(name)); + String email = user.getPrincipal().getAttribute("email"); + if(email == null) { + email = user.getPrincipal().getAttribute("login") + "@github"; + } + Query query = new Query(Criteria.where("email").is(email)); var opaqueTokenMap = mongoTemplate.find(query, Map.class, USER_COLLECTION); String opaqueToken = null; if(!opaqueTokenMap.isEmpty()) { @@ -70,8 +74,10 @@ public String getOpaqueToken(OAuth2AuthenticationToken user) { opaqueToken = Base64.getUrlEncoder().encodeToString(randomBytes); Map map = new HashMap<>(); map.put("name", name); + map.put("email", email); map.put("token", opaqueToken); map.put("expiry", Instant.now().plusSeconds(expireAfterSeconds)); + map.put("role", "ROLE_GUEST"); mongoTemplate.insert(map, USER_COLLECTION); } return opaqueToken; diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java index 7c13111..9e0d347 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/SecurityConfiguration.java @@ -7,13 +7,23 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManagerResolver; import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; +import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority; +import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; @@ -23,31 +33,35 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @Configuration @EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration { - private String user; @Autowired private OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler; @Value("${custom.allowedCorsOrigins:}") private List corsOrigins; + @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(CsrfConfigurer::disable) .cors(cors -> cors.configurationSource(corsConfigurationSource())) - .authorizeHttpRequests(ac -> ac.requestMatchers("/error") - .permitAll().anyRequest().authenticated()) + .authorizeHttpRequests(ac -> + ac.requestMatchers("/error") + .permitAll() +// .requestMatchers("/api").hasRole("ADMIN") + .anyRequest().authenticated()) .oauth2Login(oauth2 -> { - oauth2.successHandler(oAuth2LoginSuccessHandler); - }).logout(Customizer.withDefaults()); + oauth2.userInfoEndpoint().userAuthoritiesMapper(userAuthoritiesMapper()) + .and() + .successHandler(oAuth2LoginSuccessHandler); + }) + .logout(Customizer.withDefaults()); http.oauth2ResourceServer().authenticationManagerResolver(customAuthenticationManager()); return http.build(); } @@ -82,12 +96,60 @@ public AuthenticationManager opaque() { OpaqueTokenIntrospector introspectionClient = token -> { Map userInfo = UserInfo.getUser(token); if (userInfo != null) { - return new DefaultOAuth2AuthenticatedPrincipal("user", Map.of("name", userInfo.get("name")), null); - } - else { + return new DefaultOAuth2AuthenticatedPrincipal("user", Map.of("name", userInfo.get("name")), + List.of(new SimpleGrantedAuthority((String) userInfo.get("role")))); + } else { throw new BadOpaqueTokenException("Invalid token " + token); } }; return new OpaqueTokenAuthenticationProvider(introspectionClient)::authenticate; } + + private GrantedAuthoritiesMapper userAuthoritiesMapper() { + return (authorities) -> { + Set mappedAuthorities = new HashSet<>(); + authorities.forEach(authority -> { + Map userInfo = null; + if (authority.getAuthority().equals("OAUTH2_USER")) { + userInfo = UserInfo.getUserBy("email", (String) ((OAuth2UserAuthority) authority).getAttributes().get("login") + "@github"); + + if (userInfo != null && userInfo.get("role") != null) { + GrantedAuthority ga = new SimpleGrantedAuthority((String) userInfo.get("role")); + mappedAuthorities.add(ga); + } else { + GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_GUEST"); + mappedAuthorities.add(ga); + } + } else if (authority.getAuthority().equals("OIDC_USER")) { + userInfo = UserInfo.getUserBy("email", (String) ((OidcUserAuthority) authority).getAttributes().get("email")); + + if (userInfo != null && userInfo.get("role") != null) { + GrantedAuthority ga = new SimpleGrantedAuthority((String) userInfo.get("role")); + mappedAuthorities.add(ga); + } else { + GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_GUEST"); + mappedAuthorities.add(ga); + } + } else { + mappedAuthorities.add(authority); + } + }); + return mappedAuthorities; + }; + } + + @Bean + static RoleHierarchy roleHierarchy() { + RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); + hierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER\n" + + "ROLE_USER > ROLE_GUEST"); + return hierarchy; + } + + @Bean + static MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) { + DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + expressionHandler.setRoleHierarchy(roleHierarchy); + return expressionHandler; + } } diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java index 59dd242..f2651a7 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/ShareLinkController.java @@ -15,6 +15,7 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.http.HttpHeaders; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; @@ -25,9 +26,7 @@ import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.UUID; @RestController @@ -45,6 +44,8 @@ public class ShareLinkController { @Autowired private MongoTemplate mongoTemplate; + + @PreAuthorize("hasRole('USER')") @PostMapping("/create") public String create(@RequestBody String filePathOrDigest) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -73,6 +74,7 @@ public String create(@RequestBody String filePathOrDigest) { } } + @PreAuthorize("hasRole('GUEST')") @PostMapping("/verify") public DBObject verify(@RequestBody String shareId) { Query query = new Query(Criteria.where("shareId").is(shareId)); @@ -89,6 +91,7 @@ public DBObject verify(@RequestBody String shareId) { return (res.isEmpty() || res2 == null)? null : res2.get(0); } + @PreAuthorize("hasRole('GUEST')") @PostMapping("/downloadhistory") public Integer addDownloadHistory(@RequestBody String shareId, HttpServletRequest request, HttpServletResponse response) { Query query = new Query(Criteria.where("shareId").is(shareId)); diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/StatisticsController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/StatisticsController.java index 42bb5d4..cae3083 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/StatisticsController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/StatisticsController.java @@ -8,6 +8,8 @@ import org.springframework.data.mongodb.core.aggregation.AggregationResults; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -27,6 +29,7 @@ public class StatisticsController { public final String METADATA_COLLECTION = "metadata"; public final String DATASET_COLLECTION = "dataset"; + @PreAuthorize("hasRole('USER')") @GetMapping("/stats/metadataBasic") public HashMap metadataBasic (@RequestParam("collectionName") String collectionName) { HashMap res = new HashMap<>(); diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/CustomOAuth2User.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2User.java similarity index 100% rename from wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/CustomOAuth2User.java rename to wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2User.java diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/CustomOAuth2UserService.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java similarity index 68% rename from wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/CustomOAuth2UserService.java rename to wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java index 9dec594..2a51d80 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/CustomOAuth2UserService.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java @@ -1,4 +1,4 @@ -package com.sjsu.wildfirestorage.spring.controller; +package com.sjsu.wildfirestorage.spring.services; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; @@ -7,10 +7,11 @@ import org.springframework.stereotype.Service; @Service -public class CustomOAuth2UserService extends DefaultOAuth2UserService { +public class CustomOAuth2UserService extends DefaultOAuth2UserService { @Override - public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { - OAuth2User user = super.loadUser(userRequest); + public OAuth2User loadUser(OAuth2UserRequest userRequest) + throws OAuth2AuthenticationException { + OAuth2User user = super.loadUser(userRequest); return new CustomOAuth2User(user); } } \ No newline at end of file diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/util/UserInfo.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/util/UserInfo.java index afa38a9..054932d 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/util/UserInfo.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/util/UserInfo.java @@ -36,4 +36,13 @@ public static Map getUser (String token) { } return null; } + + public static Map getUserBy (String key, String value) { + Query query = new Query(Criteria.where(key).is(value)); + var opaqueTokenMap = mongoTemplate.find(query, Map.class, USER_COLLECTION); + if (!opaqueTokenMap.isEmpty()) { + return opaqueTokenMap.get(0); + } + return null; + } } From c75b0218bf8f64906b11ed5a471789b320cc371e Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Mon, 26 Feb 2024 23:43:46 -0800 Subject: [PATCH 06/10] Added home page --- .../src/main/resources/static/home.html | 22 +++++++++++++++++++ .../src/main/resources/static/token.html | 13 +++++++++++ 2 files changed, 35 insertions(+) create mode 100644 wildfirestorage-spring/src/main/resources/static/home.html create mode 100644 wildfirestorage-spring/src/main/resources/static/token.html diff --git a/wildfirestorage-spring/src/main/resources/static/home.html b/wildfirestorage-spring/src/main/resources/static/home.html new file mode 100644 index 0000000..b5a1e30 --- /dev/null +++ b/wildfirestorage-spring/src/main/resources/static/home.html @@ -0,0 +1,22 @@ + + + + + +
+
+

Hello! What would you like to do?

+
+ +
+
+ +
+
+
+ + \ No newline at end of file diff --git a/wildfirestorage-spring/src/main/resources/static/token.html b/wildfirestorage-spring/src/main/resources/static/token.html new file mode 100644 index 0000000..d2f6c62 --- /dev/null +++ b/wildfirestorage-spring/src/main/resources/static/token.html @@ -0,0 +1,13 @@ + + + + + +
+
+

Your token is

+
content
+
+
+ + \ No newline at end of file From e8da16d3ed4a74eefdd728d6a2f456a429fbfea9 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Tue, 27 Feb 2024 21:22:43 -0800 Subject: [PATCH 07/10] Moved pages to react --- wildfirestorage-spring/app/package-lock.json | 42 ++++++++++++++ wildfirestorage-spring/app/package.json | 1 + wildfirestorage-spring/app/src/App.js | 31 +++++----- .../src/components/forbidden/forbidden.jsx | 12 ++++ .../app/src/components/home/home.jsx | 25 ++++++++ .../app/src/components/landing/landing.jsx | 44 ++++++++++++++ .../app/src/components/token/token.jsx | 57 +++++++++++++++++++ .../src/components/workspace/workspace.jsx | 20 +------ .../controller/OAuth2LoginSuccessHandler.java | 2 +- .../spring/controller/OauthController.java | 8 ++- .../src/main/resources/static/home.html | 22 ------- .../src/main/resources/static/token.html | 13 ----- 12 files changed, 203 insertions(+), 74 deletions(-) create mode 100644 wildfirestorage-spring/app/src/components/forbidden/forbidden.jsx create mode 100644 wildfirestorage-spring/app/src/components/home/home.jsx create mode 100644 wildfirestorage-spring/app/src/components/landing/landing.jsx create mode 100644 wildfirestorage-spring/app/src/components/token/token.jsx delete mode 100644 wildfirestorage-spring/src/main/resources/static/home.html delete mode 100644 wildfirestorage-spring/src/main/resources/static/token.html diff --git a/wildfirestorage-spring/app/package-lock.json b/wildfirestorage-spring/app/package-lock.json index 4954075..c2fde13 100644 --- a/wildfirestorage-spring/app/package-lock.json +++ b/wildfirestorage-spring/app/package-lock.json @@ -26,6 +26,7 @@ }, "devDependencies": { "daisyui": "^3.9.3", + "react-router-dom": "^6.22.1", "tailwindcss": "^3.3.3" } }, @@ -3474,6 +3475,15 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.1.tgz", + "integrity": "sha512-zcU0gM3z+3iqj8UX45AmWY810l3oUmXM7uH4dt5xtzvMhRtYVhKGOmgOd1877dOPPepfCjUv57w+syamWIYe7w==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -16796,6 +16806,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", + "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", + "dev": true, + "dependencies": { + "@remix-run/router": "1.15.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.1.tgz", + "integrity": "sha512-iwMyyyrbL7zkKY7MRjOVRy+TMnS/OPusaFVxM2P11x9dzSzGmLsebkCvYirGq0DWB9K9hOspHYYtDz33gE5Duw==", + "dev": true, + "dependencies": { + "@remix-run/router": "1.15.1", + "react-router": "6.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/wildfirestorage-spring/app/package.json b/wildfirestorage-spring/app/package.json index 089bd73..2f3fe38 100644 --- a/wildfirestorage-spring/app/package.json +++ b/wildfirestorage-spring/app/package.json @@ -46,6 +46,7 @@ }, "devDependencies": { "daisyui": "^3.9.3", + "react-router-dom": "^6.22.1", "tailwindcss": "^3.3.3" } } diff --git a/wildfirestorage-spring/app/src/App.js b/wildfirestorage-spring/app/src/App.js index 1264fca..8f5c289 100644 --- a/wildfirestorage-spring/app/src/App.js +++ b/wildfirestorage-spring/app/src/App.js @@ -1,26 +1,21 @@ import './App.css'; -import SideBar from './components/sidebar/sidebar'; -import MapContainer from './components/map-container/mapContainer'; -import Navbar from './components/navbar/navbar'; -import Workspace from './components/workspace/workspace'; +import Home from './components/home/home'; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import Landing from './components/landing/landing'; +import Token from './components/token/token'; +import Forbidden from './components/forbidden/forbidden'; function App() { return ( -
- -
- -
- -
-
- -
-
-
+ + + } /> + } /> + } /> + } /> + + ) } diff --git a/wildfirestorage-spring/app/src/components/forbidden/forbidden.jsx b/wildfirestorage-spring/app/src/components/forbidden/forbidden.jsx new file mode 100644 index 0000000..de8a7f8 --- /dev/null +++ b/wildfirestorage-spring/app/src/components/forbidden/forbidden.jsx @@ -0,0 +1,12 @@ +const Forbidden = () => { + return ( +
+
+

Uh oh! Looks like you do not have access to use this feature :(

+

Please contact the admin if you think this is incorrect!

+
+
+ ); +} + +export default Forbidden; \ No newline at end of file diff --git a/wildfirestorage-spring/app/src/components/home/home.jsx b/wildfirestorage-spring/app/src/components/home/home.jsx new file mode 100644 index 0000000..ee2863f --- /dev/null +++ b/wildfirestorage-spring/app/src/components/home/home.jsx @@ -0,0 +1,25 @@ +import SideBar from '../sidebar/sidebar'; +import MapContainer from '../map-container/mapContainer'; +import Workspace from '../workspace/workspace'; +import Navbar from '../navbar/navbar'; + +const Home = () => { + return ( +
+ +
+ +
+ +
+
+ +
+
+
+ ); +} + +export default Home; \ No newline at end of file diff --git a/wildfirestorage-spring/app/src/components/landing/landing.jsx b/wildfirestorage-spring/app/src/components/landing/landing.jsx new file mode 100644 index 0000000..52bca47 --- /dev/null +++ b/wildfirestorage-spring/app/src/components/landing/landing.jsx @@ -0,0 +1,44 @@ +import { useNavigate } from "react-router-dom"; + +const Landing = () => { + const navigate = useNavigate(); + + const goToSearch = async () => { + const response = await fetch("/checkAccess", { + method: "GET", + headers: { + "Content-Type": "application/json", + "Accept": "text/plain, application/json", + }, + credentials: "include", + redirect: "follow", + }); + if (response.redirected) { + document.location = response.url; + } else if (response.status === 403) { + navigate("/forbidden"); + } else { + navigate("/home"); + } + } + + return ( +
+
+

Hello! What would you like to do?

+
+ +
+
+ +
+
+
+ ); +} + +export default Landing; \ No newline at end of file diff --git a/wildfirestorage-spring/app/src/components/token/token.jsx b/wildfirestorage-spring/app/src/components/token/token.jsx new file mode 100644 index 0000000..0b17fac --- /dev/null +++ b/wildfirestorage-spring/app/src/components/token/token.jsx @@ -0,0 +1,57 @@ +import { useDispatch, useSelector } from 'react-redux'; +import { setOpaqueToken } from '../../redux/userSlice'; +import { useEffect, useState } from 'react'; +import { GoCopy } from 'react-icons/go'; + +const Token = () => { + + const dispatch = useDispatch(); + const [token, setToken] = useState(); + + const getToken = async () => { + const response = await fetch("/token", { + method: "GET", + headers: { + "Content-Type": "application/json", + "Accept": "text/plain, application/json", + }, + credentials: "include", + redirect: "follow", + }); + if (response.redirected) { + document.location = response.url; + } + let d = await response.text(); + dispatch(setOpaqueToken(d)); + setToken(d); + console.log("tokennnn", d) + } + + useEffect(() => { + getToken(); + }, []) + + const copyToClipboard = (event) => { + navigator.clipboard.writeText(token); + } + + return ( +
+
+

Your token is

+
+
{token}
+
+
+ +
+
+
+
+
+ ) +} + +export default Token; \ No newline at end of file diff --git a/wildfirestorage-spring/app/src/components/workspace/workspace.jsx b/wildfirestorage-spring/app/src/components/workspace/workspace.jsx index 01b4c6b..e94b2fa 100644 --- a/wildfirestorage-spring/app/src/components/workspace/workspace.jsx +++ b/wildfirestorage-spring/app/src/components/workspace/workspace.jsx @@ -4,7 +4,6 @@ import SearchResultContainer from '../searchResultContainer/searchResultContaine import { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { setMetadata } from '../../redux/metadataSlice'; -import { setOpaqueToken } from '../../redux/userSlice'; import {addQuery, deleteQuery, setQueryCount} from '../../redux/filterSlice'; import Modal from '../modal/modal'; import {setSearchTerm} from "../../redux/searchTermSlice"; @@ -63,7 +62,6 @@ const Workspace = () => { useEffect(() => { getData(); - getToken(); getQueryCount(); }, []) @@ -76,23 +74,7 @@ const Workspace = () => { getData(); }, [limit, offset]) - const getToken = async () => { - const response = await fetch("/token", { - method: "GET", - headers: { - "Content-Type": "application/json", - "Accept": "text/html, application/json", - }, - credentials: "include", - redirect: "follow", - }); - if (response.redirected) { - document.location = response.url; - } - let d = await response.text(); - dispatch(setOpaqueToken(d.substring(6))); - console.log("tokennnn", d) - } + const handleDeleteFilter = (event) => { const deleteID = event.target.parentNode.id diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java index ac7be9c..72dc081 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OAuth2LoginSuccessHandler.java @@ -19,7 +19,7 @@ public class OAuth2LoginSuccessHandler extends SavedRequestAwareAuthenticationSu @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { this.setAlwaysUseDefaultTargetUrl(true); - this.setDefaultTargetUrl("/"); + this.setDefaultTargetUrl(frontendUrl); super.onAuthenticationSuccess(request, response, authentication); } } diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java index ed18c8c..20cddd0 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java @@ -52,7 +52,13 @@ public ResponseEntity info(Principal user) { @GetMapping("/token") public ResponseEntity token(OAuth2AuthenticationToken user) { String opaqueToken = getOpaqueToken(user); - return new ResponseEntity<>("Your token is: " + opaqueToken, HttpStatus.OK); + return new ResponseEntity<>(opaqueToken, HttpStatus.OK); + } + + @PreAuthorize("hasRole('USER')") + @GetMapping("/checkAccess") + public ResponseEntity checkAccess() { + return new ResponseEntity<>(true, HttpStatus.OK); } public String getOpaqueToken(OAuth2AuthenticationToken user) { diff --git a/wildfirestorage-spring/src/main/resources/static/home.html b/wildfirestorage-spring/src/main/resources/static/home.html deleted file mode 100644 index b5a1e30..0000000 --- a/wildfirestorage-spring/src/main/resources/static/home.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - -
-
-

Hello! What would you like to do?

-
- -
-
- -
-
-
- - \ No newline at end of file diff --git a/wildfirestorage-spring/src/main/resources/static/token.html b/wildfirestorage-spring/src/main/resources/static/token.html deleted file mode 100644 index d2f6c62..0000000 --- a/wildfirestorage-spring/src/main/resources/static/token.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -
-
-

Your token is

-
content
-
-
- - \ No newline at end of file From cac344e1794e0fe542b9824ece78f71bb851c3e5 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Tue, 27 Feb 2024 21:27:26 -0800 Subject: [PATCH 08/10] Removed unnecessary files --- .../spring/services/CustomOAuth2User.java | 26 ------------------- .../services/CustomOAuth2UserService.java | 17 ------------ 2 files changed, 43 deletions(-) delete mode 100644 wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2User.java delete mode 100644 wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2User.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2User.java deleted file mode 100644 index 2cda56e..0000000 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2User.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.sjsu.wildfirestorage.spring.controller; - -import java.util.Collection; -import java.util.Map; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.core.user.OAuth2User; - -public class CustomOAuth2User implements OAuth2User { - private OAuth2User oauth2User; - public CustomOAuth2User(OAuth2User oauth2User) { - this.oauth2User = oauth2User; - } - @Override - public Map getAttributes() { - return oauth2User.getAttributes(); - } - @Override - public Collection getAuthorities() { - return oauth2User.getAuthorities(); - } - @Override - public String getName() { - return oauth2User.getAttribute("name"); - } -} diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java deleted file mode 100644 index 2a51d80..0000000 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/services/CustomOAuth2UserService.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.sjsu.wildfirestorage.spring.services; - -import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Service; - -@Service -public class CustomOAuth2UserService extends DefaultOAuth2UserService { - @Override - public OAuth2User loadUser(OAuth2UserRequest userRequest) - throws OAuth2AuthenticationException { - OAuth2User user = super.loadUser(userRequest); - return new CustomOAuth2User(user); - } -} \ No newline at end of file From b31c96aa0c343bc63cbb1af74a304f54ee99022a Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Tue, 27 Feb 2024 22:58:38 -0800 Subject: [PATCH 09/10] Fixed links --- .../app/src/components/landing/landing.jsx | 32 +++++++++++++++++-- .../components/map-container/mapContainer.jsx | 10 +++--- .../app/src/components/token/token.jsx | 29 ++--------------- .../spring/controller/OauthController.java | 10 +++--- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/wildfirestorage-spring/app/src/components/landing/landing.jsx b/wildfirestorage-spring/app/src/components/landing/landing.jsx index 52bca47..a4236eb 100644 --- a/wildfirestorage-spring/app/src/components/landing/landing.jsx +++ b/wildfirestorage-spring/app/src/components/landing/landing.jsx @@ -1,10 +1,14 @@ -import { useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; +import { useDispatch } from 'react-redux'; +import { setOpaqueToken } from '../../redux/userSlice'; +import { useEffect } from 'react'; const Landing = () => { const navigate = useNavigate(); + const dispatch = useDispatch(); const goToSearch = async () => { - const response = await fetch("/checkAccess", { + const response = await fetch("/api/oauth/checkAccess", { method: "GET", headers: { "Content-Type": "application/json", @@ -22,13 +26,35 @@ const Landing = () => { } } + const getToken = async () => { + const response = await fetch("/api/oauth/token", { + method: "GET", + headers: { + "Content-Type": "application/json", + "Accept": "text/plain, application/json", + }, + credentials: "include", + redirect: "follow", + }); + if (response.redirected) { + document.location = response.url; + } + let d = await response.text(); + dispatch(setOpaqueToken(d)); + console.log("tokennnn", d) + } + + useEffect(() => { + getToken(); + }, []) + return (

Hello! What would you like to do?

- +
Generate Token
diff --git a/wildfirestorage-spring/app/src/components/map-container/mapContainer.jsx b/wildfirestorage-spring/app/src/components/map-container/mapContainer.jsx index 3f1d0f4..237d025 100644 --- a/wildfirestorage-spring/app/src/components/map-container/mapContainer.jsx +++ b/wildfirestorage-spring/app/src/components/map-container/mapContainer.jsx @@ -77,10 +77,12 @@ const MapContainer = () => { map.data.remove(feature); }) for (let record of metadataRecords) { - let geoJsonFeature = feature(record.location); - geoJsonFeature.properties = { "id": record.digestString } - map.data.addGeoJson(geoJsonFeature); - map.data.addGeoJson(centroid(record.location)); + if(record.location) { + let geoJsonFeature = feature(record.location); + geoJsonFeature.properties = { "id": record.digestString } + map.data.addGeoJson(geoJsonFeature); + map.data.addGeoJson(centroid(record.location)); + } } } diff --git a/wildfirestorage-spring/app/src/components/token/token.jsx b/wildfirestorage-spring/app/src/components/token/token.jsx index 0b17fac..a71b8e2 100644 --- a/wildfirestorage-spring/app/src/components/token/token.jsx +++ b/wildfirestorage-spring/app/src/components/token/token.jsx @@ -1,35 +1,10 @@ -import { useDispatch, useSelector } from 'react-redux'; -import { setOpaqueToken } from '../../redux/userSlice'; -import { useEffect, useState } from 'react'; import { GoCopy } from 'react-icons/go'; +import { useSelector } from 'react-redux'; const Token = () => { - const dispatch = useDispatch(); - const [token, setToken] = useState(); + const token = useSelector(state => state.userReducer.opaqueToken) - const getToken = async () => { - const response = await fetch("/token", { - method: "GET", - headers: { - "Content-Type": "application/json", - "Accept": "text/plain, application/json", - }, - credentials: "include", - redirect: "follow", - }); - if (response.redirected) { - document.location = response.url; - } - let d = await response.text(); - dispatch(setOpaqueToken(d)); - setToken(d); - console.log("tokennnn", d) - } - - useEffect(() => { - getToken(); - }, []) const copyToClipboard = (event) => { navigator.clipboard.writeText(token); diff --git a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java index 20cddd0..3f77f54 100644 --- a/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java +++ b/wildfirestorage-spring/src/main/java/com/sjsu/wildfirestorage/spring/controller/OauthController.java @@ -33,30 +33,30 @@ public class OauthController { @PreAuthorize("hasRole('GUEST')") @GetMapping("/") - public String index () { return "home.html"; } + public String index () { return "index.html"; } @PreAuthorize("hasRole('GUEST')") - @GetMapping("/user") + @GetMapping("/api/oauth/user") public ResponseEntity user(OAuth2User user) { Map details = user.getAttributes(); var name = details.get("login"); return new ResponseEntity<>(name.toString(), HttpStatus.OK); } - @GetMapping("/userInfo") + @GetMapping("/api/oauth/userInfo") public ResponseEntity info(Principal user) { return new ResponseEntity<>(user.toString(), HttpStatus.OK); } @PreAuthorize("hasRole('GUEST')") - @GetMapping("/token") + @GetMapping("/api/oauth/token") public ResponseEntity token(OAuth2AuthenticationToken user) { String opaqueToken = getOpaqueToken(user); return new ResponseEntity<>(opaqueToken, HttpStatus.OK); } @PreAuthorize("hasRole('USER')") - @GetMapping("/checkAccess") + @GetMapping("/api/oauth/checkAccess") public ResponseEntity checkAccess() { return new ResponseEntity<>(true, HttpStatus.OK); } From 9eebcab5e9a075166ac284b24c7e736ffd304b56 Mon Sep 17 00:00:00 2001 From: Apoorva Mohite Date: Tue, 27 Feb 2024 23:16:48 -0800 Subject: [PATCH 10/10] Moved getToken to App.js --- wildfirestorage-spring/app/src/App.js | 25 ++++++++++++++++++ .../app/src/components/landing/landing.jsx | 26 ------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/wildfirestorage-spring/app/src/App.js b/wildfirestorage-spring/app/src/App.js index 8f5c289..59d7c57 100644 --- a/wildfirestorage-spring/app/src/App.js +++ b/wildfirestorage-spring/app/src/App.js @@ -4,8 +4,33 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import Landing from './components/landing/landing'; import Token from './components/token/token'; import Forbidden from './components/forbidden/forbidden'; +import { useDispatch } from 'react-redux'; +import { setOpaqueToken } from './redux/userSlice'; +import { useEffect } from 'react'; function App() { + const dispatch = useDispatch(); + + const getToken = async () => { + const response = await fetch("/api/oauth/token", { + method: "GET", + headers: { + "Content-Type": "application/json", + "Accept": "text/plain, application/json", + }, + credentials: "include", + redirect: "follow", + }); + if (response.redirected) { + document.location = response.url; + } + let d = await response.text(); + dispatch(setOpaqueToken(d)); + console.log("tokennnn", d) + } + useEffect(() => { + getToken(); + }, []) return ( diff --git a/wildfirestorage-spring/app/src/components/landing/landing.jsx b/wildfirestorage-spring/app/src/components/landing/landing.jsx index a4236eb..be63977 100644 --- a/wildfirestorage-spring/app/src/components/landing/landing.jsx +++ b/wildfirestorage-spring/app/src/components/landing/landing.jsx @@ -1,11 +1,7 @@ import { Link, useNavigate } from "react-router-dom"; -import { useDispatch } from 'react-redux'; -import { setOpaqueToken } from '../../redux/userSlice'; -import { useEffect } from 'react'; const Landing = () => { const navigate = useNavigate(); - const dispatch = useDispatch(); const goToSearch = async () => { const response = await fetch("/api/oauth/checkAccess", { @@ -26,28 +22,6 @@ const Landing = () => { } } - const getToken = async () => { - const response = await fetch("/api/oauth/token", { - method: "GET", - headers: { - "Content-Type": "application/json", - "Accept": "text/plain, application/json", - }, - credentials: "include", - redirect: "follow", - }); - if (response.redirected) { - document.location = response.url; - } - let d = await response.text(); - dispatch(setOpaqueToken(d)); - console.log("tokennnn", d) - } - - useEffect(() => { - getToken(); - }, []) - return (