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/build.gradle b/build.gradle index 8e2930869..6f274e1d9 100644 --- a/build.gradle +++ b/build.gradle @@ -157,4 +157,5 @@ subprojects { sign publishing.publications.mavenJava } } -} \ No newline at end of file + +} 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" } 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/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 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..01bde33e6 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 = createLdapUser(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,34 @@ public BaseLdapPathContextSource contextSource() { return contextSource; } + private User saveLdapUser(DirContextOperations userData, User saveUser) { + if (saveUser.getEmail() == null || + !saveUser.getEmail().equals(userData.getStringAttribute(userAttributesEmail)) + ) { + saveUser.setEmail(userData.getStringAttribute(userAttributesEmail)); + } + if (saveUser.getFirstName() == null || + !saveUser.getFirstName().equals(userData.getStringAttribute(userAttributesFirstName)) + ) { + saveUser.setFirstName(userData.getStringAttribute(userAttributesFirstName)); + } + if (saveUser.getLastName() == null || + !saveUser.getLastName().equals(userData.getStringAttribute(userAttributesLastName)) + ) { + saveUser.setLastName(userData.getStringAttribute(userAttributesLastName)); + } + + return saveUser; + } + + private User createLdapUser(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 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..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") @@ -43,10 +44,16 @@ public UserCreateRequest createUser(@RequestBody UserCreateRequest req) { } @GetMapping(value = "/users") - @PreAuthorize(AuthorizationConstants.IS_MMSADMIN) - public UsersResponse getUsers() { + @PreAuthorize("isAuthenticated()") + 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; } 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/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); 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(); + } 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); 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;