From 3a79a62cfbb2a4c4fde4f50fb81c54584c26ffc0 Mon Sep 17 00:00:00 2001 From: "Lam, Doris T (319E)" Date: Mon, 2 Aug 2021 14:10:42 -0700 Subject: [PATCH 01/18] try generating token with permissions info included --- example/example.gradle | 4 +- .../example/config/ExampleSecurityConfig.java | 2 + .../mms/example/config/LoggingFilter.java | 46 +++++ .../mms/example/controllers/MMS5Auth.java | 180 ++++++++++++++++++ .../BranchGroupPermRepository.java | 2 + .../rdb/repositories/BranchRepository.java | 3 + .../BranchUserPermRepository.java | 3 + .../ProjectGroupPermRepository.java | 2 + .../rdb/repositories/ProjectRepository.java | 1 + .../ProjectUserPermRepository.java | 2 + 10 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java create mode 100644 example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java diff --git a/example/example.gradle b/example/example.gradle index 87b646db8..e85b25479 100644 --- a/example/example.gradle +++ b/example/example.gradle @@ -26,11 +26,13 @@ dependencies { project(':search'), project(':storage'), project(':groups'), + project(':rdb'), 'org.springframework.boot:spring-boot-starter-web', 'org.postgresql:postgresql:42.2.5', //'mysql:mysql-connector-java:8.0.17', 'org.springdoc:springdoc-openapi-ui:1.3.1', - 'org.springdoc:springdoc-openapi-security:1.3.1' + 'org.springdoc:springdoc-openapi-security:1.3.1', + 'io.jsonwebtoken:jjwt-api:0.10.5' ) testImplementation( diff --git a/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java b/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java index c0cd41795..08b7989c9 100644 --- a/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java +++ b/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java @@ -12,6 +12,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -40,6 +41,7 @@ public void configure(HttpSecurity http) throws Exception { http.csrf().disable().authorizeRequests().anyRequest().permitAll().and().httpBasic(); http.headers().cacheControl(); http.addFilterAfter(corsFilter(), ExceptionTranslationFilter.class); + http.addFilterAfter(new LoggingFilter(), AnonymousAuthenticationFilter.class); authSecurityConfig.setAuthConfig(http); } diff --git a/example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java b/example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java new file mode 100644 index 000000000..c7b3c6103 --- /dev/null +++ b/example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java @@ -0,0 +1,46 @@ +package org.openmbee.mms.example.config; + +import java.io.IOException; +import java.util.UUID; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +public class LoggingFilter implements Filter { + private final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class); + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) + throws IOException, ServletException { + String corr = UUID.randomUUID().toString(); + long time = System.currentTimeMillis(); + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + String user = "anonymousUser"; + if (auth != null) { + user = auth.getName(); + } + HttpServletRequest r = (HttpServletRequest) req; + String query = r.getQueryString(); + query = query == null ? "" : ("?" + query); + LOGGER.info("req - {} - {} - {} - {}", user, r.getMethod(), r.getRequestURI() + query, corr); + + chain.doFilter(req, resp); + + time = System.currentTimeMillis() - time; + HttpServletResponse res = (HttpServletResponse)resp; + auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null) { + user = auth.getName(); + } + LOGGER.info("res - {} - {} - {} - {} - {} - {}ms ", user, r.getMethod(), r.getRequestURI() + query, corr, res.getStatus(), time); + } +} + diff --git a/example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java b/example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java new file mode 100644 index 000000000..66f4e09fb --- /dev/null +++ b/example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java @@ -0,0 +1,180 @@ +package org.openmbee.mms.example.controllers; + +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.crypto.SecretKey; +import org.openmbee.mms.authenticator.security.JwtAuthenticationRequest; +import org.openmbee.mms.authenticator.security.JwtAuthenticationResponse; +import org.openmbee.mms.data.domains.global.Branch; +import org.openmbee.mms.data.domains.global.BranchGroupPerm; +import org.openmbee.mms.data.domains.global.BranchUserPerm; +import org.openmbee.mms.data.domains.global.Project; +import org.openmbee.mms.data.domains.global.ProjectGroupPerm; +import org.openmbee.mms.data.domains.global.ProjectUserPerm; +import org.openmbee.mms.rdb.repositories.BranchGroupPermRepository; +import org.openmbee.mms.rdb.repositories.BranchRepository; +import org.openmbee.mms.rdb.repositories.BranchUserPermRepository; +import org.openmbee.mms.rdb.repositories.ProjectGroupPermRepository; +import org.openmbee.mms.rdb.repositories.ProjectRepository; +import org.openmbee.mms.rdb.repositories.ProjectUserPermRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.Jwts; + +@RestController +@RequestMapping("/mms5auth") +public class MMS5Auth { + private AuthenticationManager authenticationManager; + private ProjectUserPermRepository projectUserPerms; + private ProjectGroupPermRepository projectGroupPerms; + private BranchUserPermRepository branchUserPerms; + private BranchGroupPermRepository branchGroupPerms; + private ProjectRepository projectRepo; + private BranchRepository branchRepo; + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + private Long expiration; + + @Autowired + public MMS5Auth(AuthenticationManager authenticationManager, + ProjectGroupPermRepository projectGroupPerms, + ProjectUserPermRepository projectUserPerms, + BranchUserPermRepository branchUserPerms, + BranchGroupPermRepository branchGroupPerms, + ProjectRepository projectRepo, + BranchRepository branchRepo) { + this.authenticationManager = authenticationManager; + this.projectUserPerms = projectUserPerms; + this.projectGroupPerms = projectGroupPerms; + this.branchUserPerms = branchUserPerms; + this.branchGroupPerms = branchGroupPerms; + this.projectRepo = projectRepo; + this.branchRepo = branchRepo; + + } + + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) + @SecurityRequirements(value = {}) + @Transactional(readOnly = true) + public JwtAuthenticationResponse createAuthenticationToken( + @RequestBody JwtAuthenticationRequest authenticationRequest) { + final Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), + authenticationRequest.getPassword())); + + SecurityContextHolder.getContext().setAuthentication(authentication); + + final UserDetails userDetails = (UserDetails) authentication.getPrincipal(); + Collection groups = authentication.getAuthorities(); + + Map o = new HashMap<>(); + Map perms = new HashMap<>(); + o.put("permissions", perms); + o.put("sub", userDetails.getUsername()); + + Map> projectPerms = new HashMap<>(); + for (ProjectUserPerm perm: projectUserPerms.findAllByUser_Username(userDetails.getUsername())) { + String projectId = perm.getProject().getProjectId(); + String role = perm.getRole().getName(); + updateProjectPerm(projectPerms, projectId, role); + Map> branchPerms = new HashMap<>(); + for (BranchUserPerm perm2: branchUserPerms.findAllByUser_UsernameAndBranch_Project_ProjectId(userDetails.getUsername(), projectId)) { + updateProjectPerm(branchPerms, perm2.getBranch().getBranchId(), perm2.getRole().getName()); + } + projectPerms.get(projectId).put("branches", branchPerms); + } + for (GrantedAuthority group: groups) { + for (ProjectGroupPerm perm: projectGroupPerms.findAllByGroup_Name(group.getAuthority())) { + String projectId = perm.getProject().getProjectId(); + String role = perm.getRole().getName(); + updateProjectPerm(projectPerms, projectId, role); + if (!(projectPerms.get(projectId)).containsKey("branches")){ + (projectPerms.get(projectId)).put("branches", new HashMap>()); + } + Map> branchPerms = (Map>) (projectPerms.get(projectId)).get("branches"); + for (BranchGroupPerm perm2: branchGroupPerms.findAllByGroup_NameAndBranch_Project_ProjectId(group.getAuthority(), projectId)) { + updateProjectPerm(branchPerms, perm2.getBranch().getBranchId(), perm2.getRole().getName()); + } + } + } + for (Map projectPerm: projectPerms.values()) { + projectPerm.put("branches", ((Map)projectPerm.get("branches")).values()); + } + perms.put("projects", projectPerms.values()); + final String token = generateToken(o); + return new JwtAuthenticationResponse(token); + } + + @GetMapping + @SecurityRequirements(value = {}) + @Transactional(readOnly = true) + public JwtAuthenticationResponse createAnonAuthenticationToken() { + String username = "anonymous"; + Map o = new HashMap<>(); + Map perms = new HashMap<>(); + o.put("permissions", perms); + o.put("sub", username); + List publicProjects = projectRepo.findAllByIsPublicTrue(); + Map> projectPerms = new HashMap<>(); + for (Project project: publicProjects) { + updateProjectPerm(projectPerms, project.getProjectId(), "READER"); + Map> branchPerms = new HashMap<>(); + for (Branch branch: branchRepo.findAllByProject_ProjectId(project.getProjectId())) { + updateProjectPerm(branchPerms, branch.getBranchId(), "READER"); + } + projectPerms.get(project.getProjectId()).put("branches", branchPerms); + } + for (Map projectPerm: projectPerms.values()) { + projectPerm.put("branches", ((Map)projectPerm.get("branches")).values()); + } + perms.put("projects", projectPerms.values()); + final String token = generateToken(o); + return new JwtAuthenticationResponse(token); + } + + private void updateProjectPerm(Map> projectPerms, String projectId, String role) { + if (!projectPerms.containsKey(projectId)) { + projectPerms.put(projectId, new HashMap<>()); + } + Map projectPerm = projectPerms.get(projectId); + projectPerm.put("id", projectId); + String existingRole = (String) projectPerm.get("role"); + role = existingRole == null || existingRole.equals("READER") || role.equals("ADMIN") ? role : existingRole; + projectPerm.put("role", role); + } + + private String generateToken(Map claims) { + return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()) + .signWith(getSecretKey()) + .compact(); + } + + private SecretKey getSecretKey() { + return Keys.hmacShaKeyFor(secret.getBytes()); + } + private Date generateExpirationDate() { + return new Date(System.currentTimeMillis() + expiration * 1000); + } +} diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchGroupPermRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchGroupPermRepository.java index b0129ab81..0b09a0227 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchGroupPermRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchGroupPermRepository.java @@ -20,6 +20,8 @@ public interface BranchGroupPermRepository extends JpaRepository findByBranchAndGroupAndInheritedIsFalse(Branch b, Group g); + List findAllByGroup_NameAndBranch_Project_ProjectId(String group, String projectId); + boolean existsByBranchAndGroup_NameInAndRoleIn(Branch b, Set groups, Set roles); void deleteByBranchAndGroup_NameInAndInheritedIsFalse(Branch b, Set groups); diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchRepository.java index 44bb6e9a8..65345c1a7 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchRepository.java @@ -1,5 +1,6 @@ package org.openmbee.mms.rdb.repositories; +import java.util.List; import java.util.Optional; import org.openmbee.mms.data.domains.global.Branch; import org.springframework.data.jpa.repository.JpaRepository; @@ -10,4 +11,6 @@ public interface BranchRepository extends JpaRepository { Optional findByProject_ProjectIdAndBranchId(String projectId, String branchId); + List findAllByProject_ProjectId(String projectId); + } diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchUserPermRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchUserPermRepository.java index 76a8b33d0..df101debb 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchUserPermRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/BranchUserPermRepository.java @@ -1,5 +1,6 @@ package org.openmbee.mms.rdb.repositories; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -19,6 +20,8 @@ public interface BranchUserPermRepository extends JpaRepository findByBranchAndUserAndInheritedIsFalse(Branch b, User u); + List findAllByUser_UsernameAndBranch_Project_ProjectId(String user, String projectId); + boolean existsByBranchAndUser_UsernameAndRoleIn(Branch b, String user, Set roles); void deleteByBranchAndUser_UsernameInAndInheritedIsFalse(Branch b, Set users); diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectGroupPermRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectGroupPermRepository.java index d8f9f8b97..36c971989 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectGroupPermRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectGroupPermRepository.java @@ -24,6 +24,8 @@ public interface ProjectGroupPermRepository extends JpaRepository findAllByProjectAndRole_Name(Project proj, String r); + List findAllByGroup_Name(String group); + boolean existsByProjectAndGroup_NameInAndRoleIn(Project proj, Set groups, Set roles); void deleteByProjectAndGroup_NameInAndInheritedIsFalse(Project proj, Set groups); diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectRepository.java index be7b12cfc..c5bf01dd2 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectRepository.java @@ -17,4 +17,5 @@ public interface ProjectRepository extends JpaRepository { List findAllByOrganizationOrganizationId(String id); + List findAllByIsPublicTrue(); } diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectUserPermRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectUserPermRepository.java index 216395e7e..da6976213 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectUserPermRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectUserPermRepository.java @@ -24,6 +24,8 @@ public interface ProjectUserPermRepository extends JpaRepository findAllByProjectAndRole_Name(Project proj, String r); + List findAllByUser_Username(String user); + boolean existsByProjectAndUser_UsernameAndRoleIn(Project proj, String user, Set roles); void deleteByProjectAndUser_UsernameInAndInheritedIsFalse(Project proj, Set users); From 8e429fe4954b06fd2dcb24435a89d0dbecec1051 Mon Sep 17 00:00:00 2001 From: "Lam, Doris T (319E)" Date: Mon, 2 Aug 2021 17:52:13 -0700 Subject: [PATCH 02/18] allow default credential chain for s3 --- storage/README.rst | 2 ++ .../org/openmbee/mms/storage/S3Storage.java | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/storage/README.rst b/storage/README.rst index a26396672..d668760da 100644 --- a/storage/README.rst +++ b/storage/README.rst @@ -7,6 +7,8 @@ This is an implementation of the ``artifacts`` interface using s3 and should wor `MinIO `_ is an open source s3 compatible object storage, it can be used standalone or can add a s3 api layer on top of existing providers using MinIO Gateway, for example, `NAS `_ +If s3.access_key or s3.secret_key are omitted, will follow the `default credentials chain `_ + Configuration ^^^^^^^^^^^^^ diff --git a/storage/src/main/java/org/openmbee/mms/storage/S3Storage.java b/storage/src/main/java/org/openmbee/mms/storage/S3Storage.java index fb722ea38..176afd758 100644 --- a/storage/src/main/java/org/openmbee/mms/storage/S3Storage.java +++ b/storage/src/main/java/org/openmbee/mms/storage/S3Storage.java @@ -4,6 +4,7 @@ import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; @@ -36,11 +37,11 @@ public class S3Storage implements ArtifactStorage { @Value("${s3.endpoint}") private String ENDPOINT; - @Value("${s3.access_key}") - private String ACCESS_KEY; + @Value("${s3.access_key:#{null}}") + private Optional ACCESS_KEY; - @Value("${s3.secret_key}") - private String SECRET_KEY; + @Value("${s3.secret_key:#{null}}") + private Optional SECRET_KEY; @Value("${s3.region}") private String REGION; @@ -53,18 +54,21 @@ public class S3Storage implements ArtifactStorage { private AmazonS3 getClient() { if (s3Client == null) { - AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY); ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setSignerOverride("AWSS3V4SignerType"); - s3Client = AmazonS3ClientBuilder + AmazonS3ClientBuilder builder = AmazonS3ClientBuilder .standard() .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(ENDPOINT, REGION)) .withPathStyleAccessEnabled(true) - .withClientConfiguration(clientConfiguration) - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .build(); + .withClientConfiguration(clientConfiguration); + if (ACCESS_KEY.isPresent() && SECRET_KEY.isPresent()) { + AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY.get(), SECRET_KEY.get()); + s3Client = builder.withCredentials(new AWSStaticCredentialsProvider(credentials)).build(); + } else { + s3Client = builder.withCredentials(DefaultAWSCredentialsProviderChain.getInstance()).build(); + } if (!s3Client.doesBucketExistV2(getBucket())) { try { s3Client.createBucket(getBucket()); @@ -99,6 +103,7 @@ public String store(byte[] data, ElementJson element, String mimetype) { try { getClient().putObject(por); } catch (RuntimeException e) { + logger.error("Error storing artifact: ", e); throw new InternalErrorException(e); } return location; From 3084e3dd7924ba11cb5c94bdfddba72aeb227bd1 Mon Sep 17 00:00:00 2001 From: "Lam, Doris T (319E)" Date: Tue, 3 Aug 2021 10:42:54 -0700 Subject: [PATCH 03/18] added more queries for org perms --- .../openmbee/mms/rdb/repositories/OrgGroupPermRepository.java | 2 ++ .../openmbee/mms/rdb/repositories/OrgUserPermRepository.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgGroupPermRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgGroupPermRepository.java index e5975a67d..c352b00f6 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgGroupPermRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgGroupPermRepository.java @@ -22,6 +22,8 @@ public interface OrgGroupPermRepository extends JpaRepository findAllByOrganizationAndRole_Name(Organization org, String r); + List findAllByGroup_Name(String group); + boolean existsByOrganizationAndGroup_NameInAndRoleIn(Organization org, Set user, Set roles); void deleteByOrganizationAndGroup_NameIn(Organization org, Set groups); diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgUserPermRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgUserPermRepository.java index ee2690ad3..ee1af231e 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgUserPermRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrgUserPermRepository.java @@ -22,6 +22,8 @@ public interface OrgUserPermRepository extends JpaRepository List findAllByOrganizationAndRole_Name(Organization org, String r); + List findAllByUser_Username(String username); + boolean existsByOrganizationAndUser_UsernameAndRoleIn(Organization org, String user, Set roles); void deleteByOrganizationAndUser_UsernameIn(Organization org, Set users); From 30db2375af0a97892ccf29442bca7ae25262ed55 Mon Sep 17 00:00:00 2001 From: "Lam, Doris T (319E)" Date: Tue, 3 Aug 2021 10:48:24 -0700 Subject: [PATCH 04/18] find public orgs --- .../openmbee/mms/rdb/repositories/OrganizationRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrganizationRepository.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrganizationRepository.java index c5d2d716d..60f491ad1 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrganizationRepository.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/OrganizationRepository.java @@ -1,5 +1,6 @@ package org.openmbee.mms.rdb.repositories; +import java.util.List; import java.util.Optional; import org.openmbee.mms.data.domains.global.Organization; import org.springframework.data.jpa.repository.JpaRepository; @@ -12,4 +13,6 @@ public interface OrganizationRepository extends JpaRepository findByOrganizationName(String name); + List findAllByIsPublicTrue(); + } From ab9d8f78477187c5c6ab26765b0ae7b14261889c Mon Sep 17 00:00:00 2001 From: "Lam, Doris T (319E)" Date: Tue, 3 Aug 2021 10:52:41 -0700 Subject: [PATCH 05/18] remove example tests --- .../example/config/ExampleSecurityConfig.java | 2 - .../mms/example/config/LoggingFilter.java | 46 ----- .../mms/example/controllers/MMS5Auth.java | 180 ------------------ 3 files changed, 228 deletions(-) delete mode 100644 example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java delete mode 100644 example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java diff --git a/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java b/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java index 08b7989c9..c0cd41795 100644 --- a/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java +++ b/example/src/main/java/org/openmbee/mms/example/config/ExampleSecurityConfig.java @@ -12,7 +12,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.access.ExceptionTranslationFilter; -import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -41,7 +40,6 @@ public void configure(HttpSecurity http) throws Exception { http.csrf().disable().authorizeRequests().anyRequest().permitAll().and().httpBasic(); http.headers().cacheControl(); http.addFilterAfter(corsFilter(), ExceptionTranslationFilter.class); - http.addFilterAfter(new LoggingFilter(), AnonymousAuthenticationFilter.class); authSecurityConfig.setAuthConfig(http); } diff --git a/example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java b/example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java deleted file mode 100644 index c7b3c6103..000000000 --- a/example/src/main/java/org/openmbee/mms/example/config/LoggingFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.openmbee.mms.example.config; - -import java.io.IOException; -import java.util.UUID; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; - -public class LoggingFilter implements Filter { - private final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class); - - @Override - public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) - throws IOException, ServletException { - String corr = UUID.randomUUID().toString(); - long time = System.currentTimeMillis(); - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - String user = "anonymousUser"; - if (auth != null) { - user = auth.getName(); - } - HttpServletRequest r = (HttpServletRequest) req; - String query = r.getQueryString(); - query = query == null ? "" : ("?" + query); - LOGGER.info("req - {} - {} - {} - {}", user, r.getMethod(), r.getRequestURI() + query, corr); - - chain.doFilter(req, resp); - - time = System.currentTimeMillis() - time; - HttpServletResponse res = (HttpServletResponse)resp; - auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth != null) { - user = auth.getName(); - } - LOGGER.info("res - {} - {} - {} - {} - {} - {}ms ", user, r.getMethod(), r.getRequestURI() + query, corr, res.getStatus(), time); - } -} - diff --git a/example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java b/example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java deleted file mode 100644 index 66f4e09fb..000000000 --- a/example/src/main/java/org/openmbee/mms/example/controllers/MMS5Auth.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.openmbee.mms.example.controllers; - -import io.swagger.v3.oas.annotations.security.SecurityRequirements; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.crypto.SecretKey; -import org.openmbee.mms.authenticator.security.JwtAuthenticationRequest; -import org.openmbee.mms.authenticator.security.JwtAuthenticationResponse; -import org.openmbee.mms.data.domains.global.Branch; -import org.openmbee.mms.data.domains.global.BranchGroupPerm; -import org.openmbee.mms.data.domains.global.BranchUserPerm; -import org.openmbee.mms.data.domains.global.Project; -import org.openmbee.mms.data.domains.global.ProjectGroupPerm; -import org.openmbee.mms.data.domains.global.ProjectUserPerm; -import org.openmbee.mms.rdb.repositories.BranchGroupPermRepository; -import org.openmbee.mms.rdb.repositories.BranchRepository; -import org.openmbee.mms.rdb.repositories.BranchUserPermRepository; -import org.openmbee.mms.rdb.repositories.ProjectGroupPermRepository; -import org.openmbee.mms.rdb.repositories.ProjectRepository; -import org.openmbee.mms.rdb.repositories.ProjectUserPermRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import io.jsonwebtoken.security.Keys; -import io.jsonwebtoken.Jwts; - -@RestController -@RequestMapping("/mms5auth") -public class MMS5Auth { - private AuthenticationManager authenticationManager; - private ProjectUserPermRepository projectUserPerms; - private ProjectGroupPermRepository projectGroupPerms; - private BranchUserPermRepository branchUserPerms; - private BranchGroupPermRepository branchGroupPerms; - private ProjectRepository projectRepo; - private BranchRepository branchRepo; - - @Value("${jwt.secret}") - private String secret; - - @Value("${jwt.expiration}") - private Long expiration; - - @Autowired - public MMS5Auth(AuthenticationManager authenticationManager, - ProjectGroupPermRepository projectGroupPerms, - ProjectUserPermRepository projectUserPerms, - BranchUserPermRepository branchUserPerms, - BranchGroupPermRepository branchGroupPerms, - ProjectRepository projectRepo, - BranchRepository branchRepo) { - this.authenticationManager = authenticationManager; - this.projectUserPerms = projectUserPerms; - this.projectGroupPerms = projectGroupPerms; - this.branchUserPerms = branchUserPerms; - this.branchGroupPerms = branchGroupPerms; - this.projectRepo = projectRepo; - this.branchRepo = branchRepo; - - } - - @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) - @SecurityRequirements(value = {}) - @Transactional(readOnly = true) - public JwtAuthenticationResponse createAuthenticationToken( - @RequestBody JwtAuthenticationRequest authenticationRequest) { - final Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), - authenticationRequest.getPassword())); - - SecurityContextHolder.getContext().setAuthentication(authentication); - - final UserDetails userDetails = (UserDetails) authentication.getPrincipal(); - Collection groups = authentication.getAuthorities(); - - Map o = new HashMap<>(); - Map perms = new HashMap<>(); - o.put("permissions", perms); - o.put("sub", userDetails.getUsername()); - - Map> projectPerms = new HashMap<>(); - for (ProjectUserPerm perm: projectUserPerms.findAllByUser_Username(userDetails.getUsername())) { - String projectId = perm.getProject().getProjectId(); - String role = perm.getRole().getName(); - updateProjectPerm(projectPerms, projectId, role); - Map> branchPerms = new HashMap<>(); - for (BranchUserPerm perm2: branchUserPerms.findAllByUser_UsernameAndBranch_Project_ProjectId(userDetails.getUsername(), projectId)) { - updateProjectPerm(branchPerms, perm2.getBranch().getBranchId(), perm2.getRole().getName()); - } - projectPerms.get(projectId).put("branches", branchPerms); - } - for (GrantedAuthority group: groups) { - for (ProjectGroupPerm perm: projectGroupPerms.findAllByGroup_Name(group.getAuthority())) { - String projectId = perm.getProject().getProjectId(); - String role = perm.getRole().getName(); - updateProjectPerm(projectPerms, projectId, role); - if (!(projectPerms.get(projectId)).containsKey("branches")){ - (projectPerms.get(projectId)).put("branches", new HashMap>()); - } - Map> branchPerms = (Map>) (projectPerms.get(projectId)).get("branches"); - for (BranchGroupPerm perm2: branchGroupPerms.findAllByGroup_NameAndBranch_Project_ProjectId(group.getAuthority(), projectId)) { - updateProjectPerm(branchPerms, perm2.getBranch().getBranchId(), perm2.getRole().getName()); - } - } - } - for (Map projectPerm: projectPerms.values()) { - projectPerm.put("branches", ((Map)projectPerm.get("branches")).values()); - } - perms.put("projects", projectPerms.values()); - final String token = generateToken(o); - return new JwtAuthenticationResponse(token); - } - - @GetMapping - @SecurityRequirements(value = {}) - @Transactional(readOnly = true) - public JwtAuthenticationResponse createAnonAuthenticationToken() { - String username = "anonymous"; - Map o = new HashMap<>(); - Map perms = new HashMap<>(); - o.put("permissions", perms); - o.put("sub", username); - List publicProjects = projectRepo.findAllByIsPublicTrue(); - Map> projectPerms = new HashMap<>(); - for (Project project: publicProjects) { - updateProjectPerm(projectPerms, project.getProjectId(), "READER"); - Map> branchPerms = new HashMap<>(); - for (Branch branch: branchRepo.findAllByProject_ProjectId(project.getProjectId())) { - updateProjectPerm(branchPerms, branch.getBranchId(), "READER"); - } - projectPerms.get(project.getProjectId()).put("branches", branchPerms); - } - for (Map projectPerm: projectPerms.values()) { - projectPerm.put("branches", ((Map)projectPerm.get("branches")).values()); - } - perms.put("projects", projectPerms.values()); - final String token = generateToken(o); - return new JwtAuthenticationResponse(token); - } - - private void updateProjectPerm(Map> projectPerms, String projectId, String role) { - if (!projectPerms.containsKey(projectId)) { - projectPerms.put(projectId, new HashMap<>()); - } - Map projectPerm = projectPerms.get(projectId); - projectPerm.put("id", projectId); - String existingRole = (String) projectPerm.get("role"); - role = existingRole == null || existingRole.equals("READER") || role.equals("ADMIN") ? role : existingRole; - projectPerm.put("role", role); - } - - private String generateToken(Map claims) { - return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()) - .signWith(getSecretKey()) - .compact(); - } - - private SecretKey getSecretKey() { - return Keys.hmacShaKeyFor(secret.getBytes()); - } - private Date generateExpirationDate() { - return new Date(System.currentTimeMillis() + expiration * 1000); - } -} From 1cb0a5ccb8ae4fb655baabe64c5d285dfdb01ba4 Mon Sep 17 00:00:00 2001 From: "Lam, Doris T (319E)" Date: Tue, 3 Aug 2021 10:53:57 -0700 Subject: [PATCH 06/18] revert --- example/example.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/example/example.gradle b/example/example.gradle index e85b25479..87b646db8 100644 --- a/example/example.gradle +++ b/example/example.gradle @@ -26,13 +26,11 @@ dependencies { project(':search'), project(':storage'), project(':groups'), - project(':rdb'), 'org.springframework.boot:spring-boot-starter-web', 'org.postgresql:postgresql:42.2.5', //'mysql:mysql-connector-java:8.0.17', 'org.springdoc:springdoc-openapi-ui:1.3.1', - 'org.springdoc:springdoc-openapi-security:1.3.1', - 'io.jsonwebtoken:jjwt-api:0.10.5' + 'org.springdoc:springdoc-openapi-security:1.3.1' ) testImplementation( From 890037e49790a6270a99e5a54580c2d7bad0da6a Mon Sep 17 00:00:00 2001 From: Enquier Date: Wed, 15 Sep 2021 08:59:09 -0600 Subject: [PATCH 07/18] Add fix to allow authenticated users to "Get" user data --- .../openmbee/mms/localuser/controllers/LocalUserController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java b/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java index 4d908cccc..615616170 100644 --- a/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java +++ b/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java @@ -43,7 +43,7 @@ public UserCreateRequest createUser(@RequestBody UserCreateRequest req) { } @GetMapping(value = "/users") - @PreAuthorize(AuthorizationConstants.IS_MMSADMIN) + @PreAuthorize("isAuthenticated()") public UsersResponse getUsers() { UsersResponse res = new UsersResponse(); res.setUsers(userDetailsService.getUsers()); From be16390a9383b28801278dc7abea8a8bb797483f Mon Sep 17 00:00:00 2001 From: Enquier Date: Mon, 20 Sep 2021 16:28:34 -0600 Subject: [PATCH 08/18] Add proposal for users controller and runJava --- build.gradle | 35 ++++++++++++++++++- .../controllers/LocalUserController.java | 19 ++++++---- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 8e2930869..1c1ff72b5 100644 --- a/build.gradle +++ b/build.gradle @@ -157,4 +157,37 @@ subprojects { sign publishing.publications.mavenJava } } -} \ No newline at end of file + +} + +task copyJar { + copy { + from layout.projectDirectory.dir("example/build/libs") + into layout.buildDirectory.dir("libs") + include "*.jar" + rename '(.*)', 'app.jar' + } + copy { + from layout.projectDirectory.dir("example/src/main/resources") + into layout.buildDirectory.dir("config") + include "*.properties" + } +} + +copyJar.dependsOn(':example:bootJar') + + + +task runJava(type: JavaExec, dependsOn: copyJar) { + workingDir layout.buildDirectory + + environment "SPRING_PROFILES_ACTIVE", "local" + + ignoreExitValue true + classpath = files(project.buildDir.toPath().toString() + "/libs/app.jar") + standardOutput = System.out + errorOutput = System.err + jvmArgs '--add-opens', 'java.base/java.lang=ALL-UNNAMED', '-Djdk.tls.client.protocols="TLSv1.1"' + +} + diff --git a/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java b/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java index 615616170..4b67a4fc1 100644 --- a/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java +++ b/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java @@ -6,6 +6,7 @@ import org.openmbee.mms.core.exceptions.NotFoundException; import org.openmbee.mms.core.exceptions.UnauthorizedException; import org.openmbee.mms.core.utils.AuthenticationUtils; +import org.openmbee.mms.data.domains.global.User; import org.openmbee.mms.localuser.security.UserCreateRequest; import org.openmbee.mms.localuser.security.UserDetailsServiceImpl; import org.openmbee.mms.localuser.security.UsersResponse; @@ -14,10 +15,10 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; @RestController @Tag(name = "Auth") @@ -44,9 +45,15 @@ public UserCreateRequest createUser(@RequestBody UserCreateRequest req) { @GetMapping(value = "/users") @PreAuthorize("isAuthenticated()") - public UsersResponse getUsers() { + public UsersResponse getUsers(@RequestParam(required = false) String user) { UsersResponse res = new UsersResponse(); - res.setUsers(userDetailsService.getUsers()); + List users = new ArrayList<>(); + if (user != null) { + users.add(userDetailsService.loadUserByUsername(user).getUser()); + } else { + users = userDetailsService.getUsers(); + } + res.setUsers(users); return res; } From d186c2e1c9c380b599878c95a35958941885a206 Mon Sep 17 00:00:00 2001 From: Enquier Date: Mon, 20 Sep 2021 18:33:15 -0600 Subject: [PATCH 09/18] Adding ability to update LDAP user on fixed interval;Adding First/Last name --- .../resources/application.properties.example | 3 ++ .../openmbee/mms/ldap/LdapSecurityConfig.java | 47 ++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/example/src/main/resources/application.properties.example b/example/src/main/resources/application.properties.example index 367f032d3..234fcd9ce 100644 --- a/example/src/main/resources/application.properties.example +++ b/example/src/main/resources/application.properties.example @@ -16,6 +16,9 @@ ldap.provider.password= ldap.user.dn.pattern=uid={0} ldap.user.attributes.username= ldap.user.attributes.email= +ldap.user.attributes.firstname= +ldap.user.attributes.lastname= +ldap.user.attributes.update=24 ldap.group.role.attribute=cn ldap.group.search.base= ldap.group.search.filter=uniqueMember={0} diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index 6ce9185d0..ede76fb50 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -1,8 +1,11 @@ package org.openmbee.mms.ldap; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import org.openmbee.mms.core.config.AuthorizationConstants; +import org.openmbee.mms.data.domains.global.Base; import org.openmbee.mms.data.domains.global.Group; import org.openmbee.mms.rdb.repositories.GroupRepository; import org.openmbee.mms.rdb.repositories.UserRepository; @@ -52,9 +55,18 @@ public class LdapSecurityConfig { @Value("${ldap.user.attributes.username:uid}") private String userAttributesUsername; + @Value("${ldap.user.attributes.firstname:givenname}") + private String userAttributesFirstName; + + @Value("${ldap.user.attributes.lastname:sn}") + private String userAttributesLastName; + @Value("${ldap.user.attributes.email:mail}") private String userAttributesEmail; + @Value("${ldap.user.attributes.update:24}") + private int userAttributesUpdate; + @Value("${ldap.group.search.base:#{''}}") private String groupSearchBase; @@ -115,18 +127,17 @@ private CustomLdapAuthoritiesPopulator(BaseLdapPathContextSource ldapContextSour public Collection getGrantedAuthorities( DirContextOperations userData, String username) { Optional userOptional = userRepository.findByUsername(username); + if (!userOptional.isPresent()) { - User newUser = new User(); - newUser.setEmail(userData.getStringAttribute(userAttributesEmail)); - newUser.setUsername(userData.getStringAttribute(userAttributesUsername)); - newUser.setEnabled(true); - newUser.setAdmin(false); - userRepository.save(newUser); + User newUser = saveLdapUser(userData); userOptional = Optional.of(newUser); } User user = userOptional.get(); + if (user.getModified().isBefore(Instant.now().minus(userAttributesUpdate, ChronoUnit.HOURS))) { + saveLdapUser(userData, user); + } user.setPassword(null); String userDn = userAttributesUsername + "=" + user.getUsername() + "," + providerBase; @@ -178,4 +189,28 @@ public BaseLdapPathContextSource contextSource() { return contextSource; } + private User saveLdapUser(DirContextOperations userData, User saveUser) { + if (!saveUser.getEmail().equals(userData.getStringAttribute(userAttributesEmail))) { + saveUser.setEmail(userData.getStringAttribute(userAttributesEmail)); + } + if (!saveUser.getFirstName().equals(userData.getStringAttribute(userAttributesFirstName))) { + saveUser.setFirstName(userData.getStringAttribute(userAttributesFirstName)); + } + if (!saveUser.getLastName().equals(userData.getStringAttribute(userAttributesLastName))) { + saveUser.setLastName(userData.getStringAttribute(userAttributesLastName)); + } + + saveUser.setEnabled(true); + saveUser.setAdmin(false); + + return saveUser; + } + + private User saveLdapUser(DirContextOperations userData) { + User user = saveLdapUser(userData, new User()); + user.setUsername(userData.getStringAttribute(userAttributesUsername)); + userRepository.save(user); + + return user; + } } \ No newline at end of file From 576a08c3a79f988ae688cc85ba85e5f02f07975b Mon Sep 17 00:00:00 2001 From: Enquier Date: Tue, 21 Sep 2021 15:03:29 -0600 Subject: [PATCH 10/18] move admin and enable logic to create only side --- .../main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index ede76fb50..deaf0b87d 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -200,17 +200,17 @@ private User saveLdapUser(DirContextOperations userData, User saveUser) { saveUser.setLastName(userData.getStringAttribute(userAttributesLastName)); } - saveUser.setEnabled(true); - saveUser.setAdmin(false); - return saveUser; } private User saveLdapUser(DirContextOperations userData) { User user = saveLdapUser(userData, new User()); user.setUsername(userData.getStringAttribute(userAttributesUsername)); + user.setEnabled(true); + user.setAdmin(false); userRepository.save(user); + return user; } } \ No newline at end of file From 1006d1731e45e630d13528da7365628e0b48c86b Mon Sep 17 00:00:00 2001 From: Enquier Date: Tue, 21 Sep 2021 15:10:16 -0600 Subject: [PATCH 11/18] Rename ldap methods for clairity --- .../main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index deaf0b87d..cdc21e6b4 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -129,7 +129,7 @@ public Collection getGrantedAuthorities( Optional userOptional = userRepository.findByUsername(username); if (!userOptional.isPresent()) { - User newUser = saveLdapUser(userData); + User newUser = createLdapUser(userData); userOptional = Optional.of(newUser); } @@ -203,7 +203,7 @@ private User saveLdapUser(DirContextOperations userData, User saveUser) { return saveUser; } - private User saveLdapUser(DirContextOperations userData) { + private User createLdapUser(DirContextOperations userData) { User user = saveLdapUser(userData, new User()); user.setUsername(userData.getStringAttribute(userAttributesUsername)); user.setEnabled(true); From bdece2d333dde31117f01f5c7d05c4cac18a1a33 Mon Sep 17 00:00:00 2001 From: Jason Han Date: Wed, 22 Sep 2021 11:25:44 -0700 Subject: [PATCH 12/18] Implementing checksums in artifacts --- .../mms/artifacts/json/ArtifactJson.java | 13 +++++++++++ .../artifacts/objects/ArtifactResponse.java | 9 ++++++++ .../service/DefaultArtifactService.java | 23 ++++++++++++++++--- example/artifacts.postman_collection.json | 4 +++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/artifacts/src/main/java/org/openmbee/mms/artifacts/json/ArtifactJson.java b/artifacts/src/main/java/org/openmbee/mms/artifacts/json/ArtifactJson.java index 1d7b6d97a..e350e4bd3 100644 --- a/artifacts/src/main/java/org/openmbee/mms/artifacts/json/ArtifactJson.java +++ b/artifacts/src/main/java/org/openmbee/mms/artifacts/json/ArtifactJson.java @@ -20,6 +20,7 @@ public class ArtifactJson extends HashMap { public static final String EXTENSION = "extension"; public static final String LOCATION = "location"; public static final String LOCATIONTYPE = "locationType"; + public static final String CHECKSUM = "checksum"; public ArtifactJson() { super(); @@ -77,6 +78,18 @@ public ArtifactJson setLocationType(String locationType) { return this; } + @JsonProperty(CHECKSUM) + @Schema(accessMode = Schema.AccessMode.READ_ONLY) + public String getChecksum() { + return (String) this.get(CHECKSUM); + } + + @JsonProperty(CHECKSUM) + public ArtifactJson setChecksum(String checksum) { + this.put(CHECKSUM, checksum); + return this; + } + public static List getArtifacts(ElementJson elementJson){ List rawArtifacts = (List)elementJson.get(ARTIFACTS); diff --git a/artifacts/src/main/java/org/openmbee/mms/artifacts/objects/ArtifactResponse.java b/artifacts/src/main/java/org/openmbee/mms/artifacts/objects/ArtifactResponse.java index aef92ba60..269d1b632 100644 --- a/artifacts/src/main/java/org/openmbee/mms/artifacts/objects/ArtifactResponse.java +++ b/artifacts/src/main/java/org/openmbee/mms/artifacts/objects/ArtifactResponse.java @@ -3,6 +3,7 @@ public class ArtifactResponse { private String mimeType; private String extension; + private String checksum; private byte[] data; public String getMimeType() { @@ -21,6 +22,14 @@ public void setExtension(String extension) { this.extension = extension; } + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + public byte[] getData() { return data; } diff --git a/artifacts/src/main/java/org/openmbee/mms/artifacts/service/DefaultArtifactService.java b/artifacts/src/main/java/org/openmbee/mms/artifacts/service/DefaultArtifactService.java index 3d665e3e2..3a1c0f094 100644 --- a/artifacts/src/main/java/org/openmbee/mms/artifacts/service/DefaultArtifactService.java +++ b/artifacts/src/main/java/org/openmbee/mms/artifacts/service/DefaultArtifactService.java @@ -16,10 +16,14 @@ import org.openmbee.mms.json.ElementJson; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.DigestUtils; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; @Service public class DefaultArtifactService implements ArtifactService { @@ -54,6 +58,7 @@ public ArtifactResponse get(String projectId, String refId, String id, Map artifacts = ArtifactJson.getArtifacts(elementJson); ArtifactJson artifact; @@ -128,6 +134,7 @@ private ElementJson attachOrUpdateArtifact(ElementJson elementJson, String artif artifact.setExtension(fileExtension); artifact.setMimeType(mimeType); artifact.setLocationType(type); + artifact.setChecksum(checksum); ArtifactJson.setArtifacts(elementJson, artifacts); return elementJson; @@ -166,6 +173,16 @@ private String getMimeTypeOfFile(MultipartFile file) { return file.getContentType(); } + public static String getChecksumOfFile(MultipartFile file) { + String checksum = ""; + try { + checksum = DigestUtils.md5DigestAsHex(file.getBytes()); + } catch (IOException ioe) { + throw new BadRequestException(ioe); + } + return checksum; + } + private NodeService getNodeService(String projectId) { return serviceFactory.getNodeService(getProjectType(projectId)); } diff --git a/example/artifacts.postman_collection.json b/example/artifacts.postman_collection.json index c96bbe376..f6300eb4d 100644 --- a/example/artifacts.postman_collection.json +++ b/example/artifacts.postman_collection.json @@ -206,6 +206,7 @@ " pm.expect(jsonData.elements.length).to.eql(1);", " pm.expect(jsonData.elements[0]['_artifacts'].length).to.eq(1);", " pm.expect(jsonData.elements[0]['_artifacts'][0].location).to.include('arta/x/jpg/')", + " pm.expect(jsonData.elements[0]['_artifacts'][0].checksum).to.include('c946d2fc350ad561fdb3c23c86a81343')", " pm.environment.set(\"commit-1-loc\", pm.response.json().elements[0]['_artifacts'][0].location);", " pm.environment.set(\"x-commit-1\", jsonData.elements[0][\"_commitId\"]);", "});", @@ -310,7 +311,8 @@ "pm.test(\"response element has 1 artifact\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData.elements[0]['_artifacts'].length).to.eq(1);", - "});" + " pm.expect(jsonData.elements[0]['_artifacts'][0].checksum).to.include('5407655262fcca873c2f407f2dead2cf')", + "});" ], "type": "text/javascript" } From 299b9b367e1ed46a823948b7d398b4d3200c814a Mon Sep 17 00:00:00 2001 From: Enquier Date: Wed, 22 Sep 2021 14:09:19 -0600 Subject: [PATCH 13/18] Remove extra tasks from gradle --- build.gradle | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index 1c1ff72b5..e76bd4e9d 100644 --- a/build.gradle +++ b/build.gradle @@ -158,36 +158,4 @@ subprojects { } } -} - -task copyJar { - copy { - from layout.projectDirectory.dir("example/build/libs") - into layout.buildDirectory.dir("libs") - include "*.jar" - rename '(.*)', 'app.jar' - } - copy { - from layout.projectDirectory.dir("example/src/main/resources") - into layout.buildDirectory.dir("config") - include "*.properties" - } -} - -copyJar.dependsOn(':example:bootJar') - - - -task runJava(type: JavaExec, dependsOn: copyJar) { - workingDir layout.buildDirectory - - environment "SPRING_PROFILES_ACTIVE", "local" - - ignoreExitValue true - classpath = files(project.buildDir.toPath().toString() + "/libs/app.jar") - standardOutput = System.out - errorOutput = System.err - jvmArgs '--add-opens', 'java.base/java.lang=ALL-UNNAMED', '-Djdk.tls.client.protocols="TLSv1.1"' - -} - +} \ No newline at end of file From 485ee2e7b4208138de460b70e91e9f7d9bc5a8f3 Mon Sep 17 00:00:00 2001 From: Enquier Date: Wed, 22 Sep 2021 14:23:51 -0600 Subject: [PATCH 14/18] .... --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e76bd4e9d..6f274e1d9 100644 --- a/build.gradle +++ b/build.gradle @@ -158,4 +158,4 @@ subprojects { } } -} \ No newline at end of file +} From 0b54b755b3a384c8338b67abeda4cd16d9a513c0 Mon Sep 17 00:00:00 2001 From: Jason Han Date: Wed, 6 Oct 2021 12:58:45 -0700 Subject: [PATCH 15/18] Bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4224876f0..21320ea0e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=4.0.4 +version=4.0.5 group=org.openmbee.mms springBootVersion=2.2.6.RELEASE From 46ff2df93924343d983a66882c12a4401331be0c Mon Sep 17 00:00:00 2001 From: Jason Han Date: Tue, 12 Oct 2021 16:08:55 -0700 Subject: [PATCH 16/18] Mitigate possible NPE --- .../org/openmbee/mms/ldap/LdapSecurityConfig.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index cdc21e6b4..980c2e2c3 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -190,13 +190,22 @@ public BaseLdapPathContextSource contextSource() { } private User saveLdapUser(DirContextOperations userData, User saveUser) { - if (!saveUser.getEmail().equals(userData.getStringAttribute(userAttributesEmail))) { + if (userData.attributeExists(userAttributesEmail) && + userData.getStringAttribute(userAttributesEmail) != null && + !saveUser.getEmail().equals(userData.getStringAttribute(userAttributesEmail)) + ) { saveUser.setEmail(userData.getStringAttribute(userAttributesEmail)); } - if (!saveUser.getFirstName().equals(userData.getStringAttribute(userAttributesFirstName))) { + if (userData.attributeExists(userAttributesFirstName) && + userData.getStringAttribute(userAttributesFirstName) != null && + !saveUser.getFirstName().equals(userData.getStringAttribute(userAttributesFirstName)) + ) { saveUser.setFirstName(userData.getStringAttribute(userAttributesFirstName)); } - if (!saveUser.getLastName().equals(userData.getStringAttribute(userAttributesLastName))) { + if (userData.attributeExists(userAttributesLastName) && + userData.getStringAttribute(userAttributesLastName) != null && + !saveUser.getLastName().equals(userData.getStringAttribute(userAttributesLastName)) + ) { saveUser.setLastName(userData.getStringAttribute(userAttributesLastName)); } From 118e051aa2db79871937e5a9fab0640575df2304 Mon Sep 17 00:00:00 2001 From: Jason Han Date: Tue, 12 Oct 2021 17:54:42 -0700 Subject: [PATCH 17/18] Fix the right npe --- .../java/org/openmbee/mms/ldap/LdapSecurityConfig.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index 980c2e2c3..840d27491 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -190,20 +190,17 @@ public BaseLdapPathContextSource contextSource() { } private User saveLdapUser(DirContextOperations userData, User saveUser) { - if (userData.attributeExists(userAttributesEmail) && - userData.getStringAttribute(userAttributesEmail) != null && + if (saveUser.getEmail() != null && !saveUser.getEmail().equals(userData.getStringAttribute(userAttributesEmail)) ) { saveUser.setEmail(userData.getStringAttribute(userAttributesEmail)); } - if (userData.attributeExists(userAttributesFirstName) && - userData.getStringAttribute(userAttributesFirstName) != null && + if (saveUser.getFirstName()!= null && !saveUser.getFirstName().equals(userData.getStringAttribute(userAttributesFirstName)) ) { saveUser.setFirstName(userData.getStringAttribute(userAttributesFirstName)); } - if (userData.attributeExists(userAttributesLastName) && - userData.getStringAttribute(userAttributesLastName) != null && + if (saveUser.getLastName() != null && !saveUser.getLastName().equals(userData.getStringAttribute(userAttributesLastName)) ) { saveUser.setLastName(userData.getStringAttribute(userAttributesLastName)); From d2f6b36b3258e91345cbf6971e317d3351e3e8cb Mon Sep 17 00:00:00 2001 From: Jason Han Date: Tue, 12 Oct 2021 17:55:54 -0700 Subject: [PATCH 18/18] Always try to save attribute if null --- .../main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java index 840d27491..01bde33e6 100644 --- a/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java +++ b/ldap/src/main/java/org/openmbee/mms/ldap/LdapSecurityConfig.java @@ -190,17 +190,17 @@ public BaseLdapPathContextSource contextSource() { } private User saveLdapUser(DirContextOperations userData, User saveUser) { - if (saveUser.getEmail() != null && + if (saveUser.getEmail() == null || !saveUser.getEmail().equals(userData.getStringAttribute(userAttributesEmail)) ) { saveUser.setEmail(userData.getStringAttribute(userAttributesEmail)); } - if (saveUser.getFirstName()!= null && + if (saveUser.getFirstName() == null || !saveUser.getFirstName().equals(userData.getStringAttribute(userAttributesFirstName)) ) { saveUser.setFirstName(userData.getStringAttribute(userAttributesFirstName)); } - if (saveUser.getLastName() != null && + if (saveUser.getLastName() == null || !saveUser.getLastName().equals(userData.getStringAttribute(userAttributesLastName)) ) { saveUser.setLastName(userData.getStringAttribute(userAttributesLastName));