From bdbc364ac2a58d14601a4863efac491b49a1cfdf Mon Sep 17 00:00:00 2001 From: pfurio Date: Thu, 18 Jul 2024 15:30:45 +0200 Subject: [PATCH 01/10] catalog: ensure password change and reset use same policy, #TASK-6494 --- .../CatalogAuthenticationManager.java | 4 ++-- .../opencga/catalog/managers/UserManager.java | 5 ++++- .../opencga/core/common/PasswordUtils.java | 16 +++++++++------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/CatalogAuthenticationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/CatalogAuthenticationManager.java index 65280a1be61..61f9fef8079 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/CatalogAuthenticationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/CatalogAuthenticationManager.java @@ -17,7 +17,6 @@ package org.opencb.opencga.catalog.auth.authentication; import io.jsonwebtoken.SignatureAlgorithm; -import org.apache.commons.lang3.RandomStringUtils; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.opencga.catalog.db.DBAdaptorFactory; import org.opencb.opencga.catalog.db.api.UserDBAdaptor; @@ -26,6 +25,7 @@ import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.core.common.MailUtils; +import org.opencb.opencga.core.common.PasswordUtils; import org.opencb.opencga.core.config.AuthenticationOrigin; import org.opencb.opencga.core.config.Email; import org.opencb.opencga.core.models.user.AuthenticationResponse; @@ -125,7 +125,7 @@ public String createNonExpiringToken(String organizationId, String userId, Map user = dbAdaptorFactory.getCatalogUserDBAdaptor(organizationId) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java index 4c9f03d12e1..35c8bd46b64 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java @@ -84,6 +84,9 @@ public void changePassword(String organizationId, String userId, String oldPassw if (oldPassword.equals(newPassword)) { throw new CatalogException("New password is the same as the old password."); } + if (!PasswordUtils.isStrongPassword(newPassword)) { + throw new CatalogException("Invalid password. " + PasswordUtils.PASSWORD_REQUIREMENT); + } getUserDBAdaptor(organizationId).checkId(userId); String authOrigin = getAuthenticationOriginId(organizationId, userId); @@ -174,7 +177,7 @@ public OpenCGAResult create(User user, String password, String token) thro try { if (StringUtils.isNotEmpty(password) && !PasswordUtils.isStrongPassword(password)) { - throw new CatalogException("Invalid password. Check password strength for user " + user.getId()); + throw new CatalogException("Invalid password. " + PasswordUtils.PASSWORD_REQUIREMENT); } if (user.getProjects() != null && !user.getProjects().isEmpty()) { throw new CatalogException("Creating user and projects in a single transaction is forbidden"); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java b/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java index 17255ae3255..d0e102cebed 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java @@ -1,5 +1,6 @@ package org.opencb.opencga.core.common; +import org.passay.CharacterData; import org.passay.*; import java.util.ArrayList; @@ -7,6 +8,11 @@ public class PasswordUtils { + public static final int MIN_STRONG_PASSWORD_LENGTH = 8; + public static final int DEFAULT_PASSWORD_LENGTH = 10; + public static final String PASSWORD_REQUIREMENT = "Password must contain at least " + MIN_STRONG_PASSWORD_LENGTH + + " characters, including at least one uppercase letter, one lowercase letter, one digit and one special character."; + private final static CharacterRule SPECIAL_CHARACTER_RULE = new CharacterRule(new CharacterData() { @Override public String getErrorCode() { @@ -20,7 +26,7 @@ public String getCharacters() { }); public static String getStrongRandomPassword() { - return getStrongRandomPassword(10); + return getStrongRandomPassword(DEFAULT_PASSWORD_LENGTH); } public static String getStrongRandomPassword(int length) { @@ -33,14 +39,10 @@ public static String getStrongRandomPassword(int length) { } public static boolean isStrongPassword(String password) { - return isStrongPassword(password, 8); - } - - public static boolean isStrongPassword(String password, int minLength) { List rules = new ArrayList<>(); //Rule 1: Password length should be in between - //minLength and 100 characters - rules.add(new LengthRule(minLength, 100)); + //MIN_STRONG_PASSWORD_LENGTH and 100 characters + rules.add(new LengthRule(MIN_STRONG_PASSWORD_LENGTH, 100)); //Rule 2: No whitespace allowed rules.add(new WhitespaceRule()); //Rule 3.a: At least one Upper-case character From b006b5514dc8e7a6800339a77fae9082cb82c635 Mon Sep 17 00:00:00 2001 From: pfurio Date: Tue, 23 Jul 2024 11:49:10 +0200 Subject: [PATCH 02/10] catalog: archive old password, #TASK-6494 --- .../catalog/FixStatusIndexesMigration.java | 2 +- .../storage/AddAllelesColumnToPhoenix.java | 2 +- ...llegalConcurrentFileLoadingsMigration.java | 2 +- .../v3/v3_2_1/AddPasswordHistory.java | 42 ++ .../MoveUserAccountToInternalMigration.java | 47 ++ opencga-catalog/pom.xml | 5 + .../AzureADAuthenticationManager.java | 6 +- .../LDAPAuthenticationManager.java | 8 +- .../opencga/catalog/db/api/UserDBAdaptor.java | 14 +- .../OrganizationMongoDBAdaptorFactory.java | 2 +- .../db/mongodb/UserMongoDBAdaptor.java | 77 +- .../db/mongodb/converters/UserConverter.java | 15 +- .../CatalogAuthenticationException.java | 5 + .../catalog/managers/AbstractManager.java | 36 +- .../catalog/managers/AdminManager.java | 4 +- .../catalog/managers/CatalogManager.java | 3 +- .../opencga/catalog/managers/JobManager.java | 4 +- .../opencga/catalog/managers/NoteManager.java | 16 +- .../catalog/managers/OrganizationManager.java | 6 +- .../catalog/managers/ProjectManager.java | 2 +- .../opencga/catalog/managers/UserManager.java | 140 ++-- .../catalog/managers/AbstractManagerTest.java | 23 + .../catalog/managers/CatalogManagerTest.java | 558 +-------------- .../managers/ClinicalAnalysisManagerTest.java | 10 +- .../managers/OrganizationManagerTest.java | 2 +- .../catalog/managers/ProjectManagerTest.java | 3 +- .../catalog/managers/UserManagerTest.java | 664 ++++++++++++++++++ .../templates/TemplateManagerTest.java | 20 +- .../opencga/core/api/FieldConstants.java | 13 +- .../opencb/opencga/core/common/TimeUtils.java | 7 + .../core/config/AccountConfiguration.java | 42 ++ .../opencga/core/config/Configuration.java | 46 +- .../opencga/core/models/user/Account.java | 46 +- .../opencga/core/models/user/Password.java | 48 ++ .../opencb/opencga/core/models/user/User.java | 68 +- .../core/models/user/UserInternal.java | 30 +- pom.xml | 2 +- 37 files changed, 1270 insertions(+), 750 deletions(-) rename opencga-app/src/main/java/org/opencb/opencga/app/migrations/{ => v2}/v2_12_4/catalog/FixStatusIndexesMigration.java (97%) rename opencga-app/src/main/java/org/opencb/opencga/app/migrations/{ => v2}/v2_12_5/storage/AddAllelesColumnToPhoenix.java (95%) rename opencga-app/src/main/java/org/opencb/opencga/app/migrations/{ => v2}/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java (99%) create mode 100644 opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java create mode 100644 opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java create mode 100644 opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java create mode 100644 opencga-core/src/main/java/org/opencb/opencga/core/config/AccountConfiguration.java create mode 100644 opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_4/catalog/FixStatusIndexesMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_4/catalog/FixStatusIndexesMigration.java similarity index 97% rename from opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_4/catalog/FixStatusIndexesMigration.java rename to opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_4/catalog/FixStatusIndexesMigration.java index ae73bcdc578..e1953673252 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_4/catalog/FixStatusIndexesMigration.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_4/catalog/FixStatusIndexesMigration.java @@ -1,4 +1,4 @@ -package org.opencb.opencga.app.migrations.v2_12_4.catalog; +package org.opencb.opencga.app.migrations.v2.v2_12_4.catalog; import org.bson.Document; import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_5/storage/AddAllelesColumnToPhoenix.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_5/storage/AddAllelesColumnToPhoenix.java similarity index 95% rename from opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_5/storage/AddAllelesColumnToPhoenix.java rename to opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_5/storage/AddAllelesColumnToPhoenix.java index 4efa260d965..93104000f20 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_5/storage/AddAllelesColumnToPhoenix.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_5/storage/AddAllelesColumnToPhoenix.java @@ -1,4 +1,4 @@ -package org.opencb.opencga.app.migrations.v2_12_5.storage; +package org.opencb.opencga.app.migrations.v2.v2_12_5.storage; import org.opencb.opencga.app.migrations.StorageMigrationTool; import org.opencb.opencga.catalog.migration.Migration; diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java similarity index 99% rename from opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java rename to opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java index 132e1357f1b..6d30f1a4de7 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2/v2_12_5/storage/DetectIllegalConcurrentFileLoadingsMigration.java @@ -1,4 +1,4 @@ -package org.opencb.opencga.app.migrations.v2_12_5.storage; +package org.opencb.opencga.app.migrations.v2.v2_12_5.storage; import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java new file mode 100644 index 00000000000..d0fb6af2d12 --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java @@ -0,0 +1,42 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_1; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.apache.commons.lang3.StringUtils; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Migration(id = "add_archivePasswords_array", + description = "Add password history #6494", version = "3.2.1", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240723) +public class AddPasswordHistory extends MigrationTool { + + @Override + protected void run() throws Exception { + Bson query = Filters.exists("_archivePasswords", false); + Bson projection = Projections.include("_password"); + migrateCollection(Arrays.asList(OrganizationMongoDBAdaptorFactory.USER_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_USER_COLLECTION), + query, projection, (document, bulk) -> { + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + + // Add _archivePasswords + String currentPassword = document.getString("_password"); + List archivePasswords = new ArrayList<>(); + if (StringUtils.isNotEmpty(currentPassword)) { + archivePasswords.add(currentPassword); + } + updateDocument.getSet().put("_archivePasswords", archivePasswords); + + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), updateDocument.toFinalUpdateDocument())); + }); + } + +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java new file mode 100644 index 00000000000..64a824ec8ed --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java @@ -0,0 +1,47 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_1; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Arrays; + +@Migration(id = "move_user_account_to_internal", + description = "Move account to internal.account #6494", version = "3.2.1", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240723) +public class MoveUserAccountToInternalMigration extends MigrationTool { + + @Override + protected void run() throws Exception { + Bson query = Filters.exists("account", true); + Bson projection = Projections.include("internal", "account"); + migrateCollection(Arrays.asList(OrganizationMongoDBAdaptorFactory.USER_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_USER_COLLECTION), + query, projection, (document, bulk) -> { + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + + Document account = document.get("account", Document.class); + Document internal = document.get("internal", Document.class); + internal.put("account", account); + + updateDocument.getSet().put("expirationDate", internal.get("lastModified")); + updateDocument.getSet().put("creationDate", account.get("creationDate")); + account.remove("creationDate"); + + Document password = new Document() + .append("expirationDate", null) + .append("lastChangedDate", internal.get("lastModified")); + account.put("password", password); + account.put("failedAttempts", internal.get("failedAttempts")); + internal.remove("failedAttempts"); + + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), updateDocument.toFinalUpdateDocument())); + }); + } +} diff --git a/opencga-catalog/pom.xml b/opencga-catalog/pom.xml index 7457317446b..c55f55fadd5 100644 --- a/opencga-catalog/pom.xml +++ b/opencga-catalog/pom.xml @@ -61,6 +61,11 @@ + + org.mockito + mockito-core + test + org.apache.commons commons-collections4 diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AzureADAuthenticationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AzureADAuthenticationManager.java index f104f8fdf93..6a3a0480c28 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AzureADAuthenticationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AzureADAuthenticationManager.java @@ -39,6 +39,7 @@ import org.opencb.opencga.catalog.auth.authentication.azure.AuthenticationProvider; import org.opencb.opencga.catalog.exceptions.CatalogAuthenticationException; import org.opencb.opencga.catalog.exceptions.CatalogException; +import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.AuthenticationOrigin; import org.opencb.opencga.core.models.JwtPayload; import org.opencb.opencga.core.models.user.*; @@ -382,8 +383,9 @@ private List extractUserInformation(List(), attributes); userList.add(user); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/LDAPAuthenticationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/LDAPAuthenticationManager.java index 35fe615d161..f79eb85b19d 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/LDAPAuthenticationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/LDAPAuthenticationManager.java @@ -198,9 +198,11 @@ public List getRemoteUserInformation(List userStringList) throws C Map attributes = new HashMap<>(); attributes.put("LDAP_RDN", rdn); - User user = new User(uid, displayName, mail, usersSearch, new Account() - .setAuthentication(new Account.AuthenticationOrigin(originId, false)), new UserInternal(new UserStatus()), - new UserQuota(-1, -1, -1, -1), new ArrayList<>(), new HashMap<>(), new LinkedList<>(), attributes); + Account account = new Account() + .setAuthentication(new Account.AuthenticationOrigin(originId, false)); + User user = new User(uid, displayName, mail, usersSearch, TimeUtils.getTime(), TimeUtils.getTime(), + new UserInternal(new UserStatus(), account), + new UserQuota(-1, -1, -1, -1), new HashMap<>(), new LinkedList<>(), attributes); userList.add(user); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java index 3099262e917..bc25060061e 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java @@ -118,14 +118,18 @@ enum QueryParams implements QueryParam { NAME("name", TEXT_ARRAY, ""), EMAIL("email", TEXT_ARRAY, ""), ORGANIZATION("organization", TEXT_ARRAY, ""), + CREATION_DATE("creationDate", TEXT_ARRAY, ""), + MODIFICATION_DATE("modificationDate", TEXT_ARRAY, ""), INTERNAL("internal", OBJECT, ""), - INTERNAL_FAILED_ATTEMPTS("internal.failedAttempts", INTEGER, ""), INTERNAL_STATUS_ID("internal.status.id", TEXT, ""), INTERNAL_STATUS_DATE("internal.status.date", TEXT, ""), - ACCOUNT("account", TEXT_ARRAY, ""), - ACCOUNT_AUTHENTICATION_ID("account.authentication.id", TEXT, ""), - ACCOUNT_CREATION_DATE("account.creationDate", TEXT, ""), - ACCOUNT_EXPIRATION_DATE("account.expirationDate", TEXT, ""), + INTERNAL_ACCOUNT("internal.account", TEXT_ARRAY, ""), + INTERNAL_ACCOUNT_AUTHENTICATION_ID("internal.account.authentication.id", TEXT, ""), + INTERNAL_ACCOUNT_FAILED_ATTEMPTS("internal.account.failedAttempts", INTEGER, ""), + INTERNAL_ACCOUNT_CREATION_DATE("internal.account.creationDate", TEXT, ""), + INTERNAL_ACCOUNT_EXPIRATION_DATE("internal.account.expirationDate", TEXT, ""), + INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE("internal.account.password.expirationDate", TEXT, ""), + INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE("internal.account.password.lastChangeDate", TEXT, ""), QUOTA("quota", OBJECT, ""), ATTRIBUTES("attributes", TEXT, ""), // "Format: where is [<|<=|>|>=|==|!=|~|!~]" diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java index b1c1c6704ec..fbc54430a22 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java @@ -119,7 +119,7 @@ public class OrganizationMongoDBAdaptorFactory { private final NoteMongoDBAdaptor notesDBAdaptor; private final OrganizationMongoDBAdaptor organizationDBAdaptor; - private final UserMongoDBAdaptor userDBAdaptor; + private UserMongoDBAdaptor userDBAdaptor; private final ProjectMongoDBAdaptor projectDBAdaptor; private final StudyMongoDBAdaptor studyDBAdaptor; private final IndividualMongoDBAdaptor individualDBAdaptor; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 19a9a6cd1f3..581ed6f1620 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -19,6 +19,7 @@ import com.mongodb.client.ClientSession; import com.mongodb.client.model.Filters; import com.mongodb.client.model.Updates; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.StringUtils; import org.bson.Document; @@ -54,6 +55,7 @@ import org.opencb.opencga.core.response.OpenCGAResult; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.function.Consumer; @@ -72,6 +74,7 @@ public class UserMongoDBAdaptor extends CatalogMongoDBAdaptor implements UserDBA private UserConverter userConverter; private static final String PRIVATE_PASSWORD = "_password"; + private static final String ARCHIVE_PASSWORD = "_archivePasswords"; public UserMongoDBAdaptor(MongoDBCollection userCollection, MongoDBCollection deletedUserCollection, Configuration configuration, OrganizationMongoDBAdaptorFactory dbAdaptorFactory) { @@ -118,6 +121,7 @@ private void insert(ClientSession clientSession, User user, String password) thr Document userDocument = userConverter.convertToStorageType(user); userDocument.append(ID, user.getId()); userDocument.append(PRIVATE_PASSWORD, encryptPassword(password)); + userDocument.append(ARCHIVE_PASSWORD, Collections.singletonList(encryptPassword(password))); userCollection.insert(clientSession, userDocument, null); } @@ -132,15 +136,7 @@ public OpenCGAResult get(String userId, QueryOptions options) @Override public OpenCGAResult changePassword(String userId, String oldPassword, String newPassword) throws CatalogDBException, CatalogAuthenticationException { - Document bson = new Document(ID, userId) - .append(PRIVATE_PASSWORD, encryptPassword(oldPassword)); - Bson set = Updates.set(PRIVATE_PASSWORD, encryptPassword(newPassword)); - - DataResult result = userCollection.update(bson, set, null); - if (result.getNumUpdated() == 0) { //0 query matches. - throw CatalogAuthenticationException.incorrectUserOrPassword("Internal"); - } - return new OpenCGAResult(result); + return setPassword(userId, oldPassword, newPassword); } @Override @@ -160,15 +156,54 @@ public void authenticate(String userId, String password) throws CatalogAuthentic @Override public OpenCGAResult resetPassword(String userId, String email, String newPassword) throws CatalogDBException { - Query query = new Query(QueryParams.ID.key(), userId); - query.append(QueryParams.EMAIL.key(), email); - Bson bson = parseQuery(query); + return setPassword(userId, null, newPassword); + } + + public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, String newPassword) throws CatalogDBException { + List queryFilter = new ArrayList<>(); + queryFilter.add(Filters.eq(QueryParams.ID.key(), userId)); + queryFilter.add(Filters.ne(ARCHIVE_PASSWORD, encryptPassword(newPassword))); + if (StringUtils.isNotEmpty(oldPassword)) { + queryFilter.add(Filters.eq(PRIVATE_PASSWORD, encryptPassword(oldPassword))); + } + Bson query = Filters.and(queryFilter); - Bson set = Updates.set(PRIVATE_PASSWORD, encryptPassword(newPassword)); + UpdateDocument updateDocument = new UpdateDocument(); + String encryptedPassword = encryptPassword(newPassword); + updateDocument.getSet().put(PRIVATE_PASSWORD, encryptedPassword); + updateDocument.getPush().put(ARCHIVE_PASSWORD, encryptedPassword); + updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE.key(), TimeUtils.getTime()); + if (configuration.getAccount().getPasswordExpirationDays() > 0) { + Date date = TimeUtils.addDaysToCurrentDate(configuration.getAccount().getPasswordExpirationDays()); + String stringDate = TimeUtils.getTime(date); + updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE.key(), stringDate); + } + Document update = updateDocument.toFinalUpdateDocument(); - DataResult result = userCollection.update(bson, set, null); - if (result.getNumUpdated() == 0) { //0 query matches. - throw new CatalogDBException("Bad user or email"); + logger.debug("Change password: query '{}'; update: '{}'", query.toBsonDocument(), update); + DataResult result = userCollection.update(query, update, null); + if (result.getNumUpdated() == 0) { + if (result.getNumMatches() == 0) { + Query userQuery = new Query(QueryParams.ID.key(), userId); + OpenCGAResult queryResult = nativeGet(userQuery, + new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(PRIVATE_PASSWORD, ARCHIVE_PASSWORD))); + if (queryResult.getNumResults() == 0) { + throw new CatalogDBException("Could not update the password. User not found."); + } + Document userDocument = queryResult.first(); + if (StringUtils.isNotEmpty(oldPassword)) { + String dbPassword = userDocument.getString(PRIVATE_PASSWORD); + if (!encryptPassword(oldPassword).equals(dbPassword)) { + throw new CatalogDBException("Could not update the password. Please, verify that the current password is correct."); + } + } + List archivePassword = userDocument.getList(ARCHIVE_PASSWORD, String.class); + if (archivePassword.contains(encryptedPassword)) { + throw new CatalogDBException("Could not update the password. The new password has already been used. Please, use" + + " a different one."); + } + } + throw new CatalogDBException("Could not update the password. Please, verify that the current password is correct."); } return new OpenCGAResult(result); } @@ -409,7 +444,7 @@ public OpenCGAResult nativeGet(Query query, QueryOptions options) throws Catalog for (Document user : queryResult.getResults()) { ArrayList projects = (ArrayList) user.get("projects"); - if (projects.size() > 0) { + if (CollectionUtils.isNotEmpty(projects)) { List projectsTmp = new ArrayList<>(projects.size()); for (Document project : projects) { Query query1 = new Query(ProjectDBAdaptor.QueryParams.UID.key(), project.get(ProjectDBAdaptor @@ -429,7 +464,7 @@ public OpenCGAResult nativeGet(Query query, QueryOptions options) throws Catalog public OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions queryOptions) throws CatalogDBException { UpdateDocument document = new UpdateDocument(); - final String[] acceptedParams = {QueryParams.NAME.key(), QueryParams.EMAIL.key(), ACCOUNT_EXPIRATION_DATE.key()}; + final String[] acceptedParams = {QueryParams.NAME.key(), QueryParams.EMAIL.key(), INTERNAL_ACCOUNT_EXPIRATION_DATE.key()}; filterStringParams(parameters, document.getSet(), acceptedParams); if (parameters.containsKey(QueryParams.INTERNAL_STATUS_ID.key())) { @@ -437,7 +472,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions quer document.getSet().put(QueryParams.INTERNAL_STATUS_DATE.key(), TimeUtils.getTime()); } - final String[] acceptedIntParams = {INTERNAL_FAILED_ATTEMPTS.key()}; + final String[] acceptedIntParams = {INTERNAL_ACCOUNT_FAILED_ATTEMPTS.key()}; filterIntParams(parameters, document.getSet(), acceptedIntParams); final String[] acceptedObjectParams = {QueryParams.QUOTA.key()}; @@ -670,8 +705,8 @@ private Bson parseQuery(Query query) throws CatalogDBException { case EMAIL: case ORGANIZATION: case INTERNAL_STATUS_DATE: - case ACCOUNT_AUTHENTICATION_ID: - case ACCOUNT_CREATION_DATE: + case INTERNAL_ACCOUNT_AUTHENTICATION_ID: + case INTERNAL_ACCOUNT_CREATION_DATE: case TOOL_ID: case TOOL_NAME: case TOOL_ALIAS: diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java index 604a6073d0f..32420556a73 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java @@ -33,17 +33,12 @@ public UserConverter() { @Override public User convertToDataModelType(Document document) { - // TODO: Remove this piece of code once we are sure User contains the migrated new account type from 1.4.2 - Document account = (Document) document.get("account"); - if (account != null && account.get("authentication") == null) { - String authOrigin = account.getString("authOrigin"); - Document authentication = new Document() - .append("id", authOrigin) - .append("application", false); - account.put("authentication", authentication); + User user = super.convertToDataModelType(document); + // Add account to deprecated place + if (user.getInternal() != null && user.getInternal().getAccount() != null) { + user.setAccount(user.getInternal().getAccount()); } - - return super.convertToDataModelType(document); + return user; } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/exceptions/CatalogAuthenticationException.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/exceptions/CatalogAuthenticationException.java index 3853e91607f..8ac1b5c385f 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/exceptions/CatalogAuthenticationException.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/exceptions/CatalogAuthenticationException.java @@ -76,6 +76,11 @@ public static CatalogAuthenticationException accountIsExpired(String userId, Str + " talk to your organization owner/administrator."); } + public static CatalogAuthenticationException passwordExpired(String userId, String expirationDate) { + return new CatalogAuthenticationException("The password for the user account '" + userId + "' expired on " + expirationDate + + ". Please, reset your password or talk to your organization owner/administrator."); + } + public static CatalogAuthenticationException userNotAllowed(String domain) { return new CatalogAuthenticationException(domain + ": User not allowed to access the system."); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AbstractManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AbstractManager.java index 3d3611c5414..da7566340ac 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AbstractManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AbstractManager.java @@ -73,68 +73,72 @@ public abstract class AbstractManager { logger = LoggerFactory.getLogger(this.getClass()); } + protected DBAdaptorFactory getCatalogDBAdaptorFactory() { + return catalogDBAdaptorFactory; + } + protected MigrationDBAdaptor getMigrationDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getMigrationDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getMigrationDBAdaptor(organization); } protected MetaDBAdaptor getCatalogMetaDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogMetaDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogMetaDBAdaptor(organization); } protected OrganizationDBAdaptor getOrganizationDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogOrganizationDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogOrganizationDBAdaptor(organization); } protected UserDBAdaptor getUserDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogUserDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogUserDBAdaptor(organization); } protected ProjectDBAdaptor getProjectDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogProjectDbAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogProjectDbAdaptor(organization); } protected StudyDBAdaptor getStudyDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogStudyDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogStudyDBAdaptor(organization); } protected FileDBAdaptor getFileDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogFileDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogFileDBAdaptor(organization); } protected SampleDBAdaptor getSampleDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogSampleDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogSampleDBAdaptor(organization); } protected IndividualDBAdaptor getIndividualDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogIndividualDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogIndividualDBAdaptor(organization); } protected JobDBAdaptor getJobDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogJobDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogJobDBAdaptor(organization); } protected AuditDBAdaptor getAuditDbAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogAuditDbAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogAuditDbAdaptor(organization); } protected CohortDBAdaptor getCohortDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogCohortDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogCohortDBAdaptor(organization); } protected PanelDBAdaptor getPanelDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogPanelDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogPanelDBAdaptor(organization); } protected FamilyDBAdaptor getFamilyDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getCatalogFamilyDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getCatalogFamilyDBAdaptor(organization); } protected ClinicalAnalysisDBAdaptor getClinicalAnalysisDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getClinicalAnalysisDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getClinicalAnalysisDBAdaptor(organization); } protected InterpretationDBAdaptor getInterpretationDBAdaptor(String organization) throws CatalogDBException { - return catalogDBAdaptorFactory.getInterpretationDBAdaptor(organization); + return getCatalogDBAdaptorFactory().getInterpretationDBAdaptor(organization); } protected void fixQueryObject(Query query) { diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AdminManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AdminManager.java index 09bc57aabf1..7edf1030496 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AdminManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/AdminManager.java @@ -67,7 +67,7 @@ public OpenCGAResult userSearch(String organizationId, Query query, QueryO query.remove(ParamConstants.USER); } if (query.containsKey(ParamConstants.USER_CREATION_DATE)) { - query.put(UserDBAdaptor.QueryParams.ACCOUNT_CREATION_DATE.key(), query.get(ParamConstants.USER_CREATION_DATE)); + query.put(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_CREATION_DATE.key(), query.get(ParamConstants.USER_CREATION_DATE)); query.remove(ParamConstants.USER_CREATION_DATE); } @@ -134,7 +134,7 @@ public List getOrganizationIds(String token) throws CatalogException { JwtPayload payload = catalogManager.getUserManager().validateToken(token); try { authorizationManager.checkIsOpencgaAdministrator(payload); - List organizationIds = catalogDBAdaptorFactory.getOrganizationIds(); + List organizationIds = getCatalogDBAdaptorFactory().getOrganizationIds(); auditManager.audit(ParamConstants.ADMIN_ORGANIZATION, payload.getUserId(), Enums.Action.FETCH_ORGANIZATION_IDS, Enums.Resource.STUDY, "", "", "", "", new ObjectMap(), new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/CatalogManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/CatalogManager.java index 1409b1e9d4c..030505395d0 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/CatalogManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/CatalogManager.java @@ -48,7 +48,6 @@ import org.opencb.opencga.core.models.project.ProjectCreateParams; import org.opencb.opencga.core.models.project.ProjectOrganism; import org.opencb.opencga.core.models.study.Study; -import org.opencb.opencga.core.models.user.Account; import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.response.OpenCGAResult; import org.slf4j.Logger; @@ -278,7 +277,7 @@ private void privateInstall(String algorithm, String secretKey, String password, organizationConfiguration, null), QueryOptions.empty(), null); - User user = new User(OPENCGA, new Account().setExpirationDate("")) + User user = new User(OPENCGA) .setEmail(StringUtils.isEmpty(email) ? "opencga@admin.com" : email) .setOrganization(ADMIN_ORGANIZATION); userManager.create(user, password, null); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/JobManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/JobManager.java index b8b9ba55bae..fe7ffc18e44 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/JobManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/JobManager.java @@ -421,7 +421,7 @@ public OpenCGAResult kill(String studyStr, String jobId, String token) thro } ObjectMap params = new ObjectMap(JobDBAdaptor.QueryParams.INTERNAL_KILL_JOB_REQUESTED.key(), true); - OpenCGAResult update = catalogDBAdaptorFactory.getCatalogJobDBAdaptor(organizationId).update(job.getUid(), params, + OpenCGAResult update = getCatalogDBAdaptorFactory().getCatalogJobDBAdaptor(organizationId).update(job.getUid(), params, QueryOptions.empty()); auditManager.audit(organizationId, userId, Enums.Action.KILL_JOB, Enums.Resource.JOB, jobId, jobUuid, study.getId(), @@ -816,7 +816,7 @@ public DBIterator iterator(String studyId, Query query, QueryOptions option public OpenCGAResult countInOrganization(String organizationId, Query query, String token) throws CatalogException { JwtPayload jwtPayload = userManager.validateToken(token); authorizationManager.checkIsOpencgaAdministrator(jwtPayload); - return catalogDBAdaptorFactory.getCatalogJobDBAdaptor(organizationId).count(query); + return getCatalogDBAdaptorFactory().getCatalogJobDBAdaptor(organizationId).count(query); } @Override diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java index b3c7139bd30..4628126dc51 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java @@ -54,7 +54,7 @@ private OpenCGAResult internalGet(String organizationId, long studyUid, St } else { query.put(NoteDBAdaptor.QueryParams.ID.key(), noteId); } - OpenCGAResult result = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).get(query, QueryOptions.empty()); + OpenCGAResult result = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).get(query, QueryOptions.empty()); if (result.getNumResults() == 0) { throw CatalogException.notFound("note", Collections.singletonList(noteId)); } @@ -88,7 +88,7 @@ public OpenCGAResult searchOrganizationNote(Query query, QueryOptions opti queryCopy.put(NoteDBAdaptor.QueryParams.VISIBILITY.key(), Note.Visibility.PUBLIC); } - OpenCGAResult result = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).get(queryCopy, optionsCopy); + OpenCGAResult result = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).get(queryCopy, optionsCopy); auditManager.auditSearch(organizationId, tokenPayload.getUserId(), Enums.Resource.NOTE, "", "", auditParams, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); return result; @@ -131,7 +131,7 @@ public OpenCGAResult searchStudyNote(String studyStr, Query query, QueryOp queryCopy.put(NoteDBAdaptor.QueryParams.VISIBILITY.key(), Note.Visibility.PUBLIC); } - OpenCGAResult result = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).get(queryCopy, optionsCopy); + OpenCGAResult result = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).get(queryCopy, optionsCopy); auditManager.auditSearch(organizationId, tokenPayload.getUserId(), Enums.Resource.NOTE, studyId, studyUuid, auditParams, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); return result; @@ -209,11 +209,11 @@ public OpenCGAResult createStudyNote(String studyStr, NoteCreateParams not private OpenCGAResult create(Note note, QueryOptions options, JwtPayload tokenPayload) throws CatalogException { String organizationId = tokenPayload.getOrganization(); validateNewNote(note, tokenPayload.getUserId()); - OpenCGAResult insert = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).insert(note); + OpenCGAResult insert = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).insert(note); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { // Fetch created note Query query = new Query(NoteDBAdaptor.QueryParams.UID.key(), note.getUid()); - OpenCGAResult result = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).get(query, options); + OpenCGAResult result = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).get(query, options); insert.setResults(result.getResults()); } return insert; @@ -302,11 +302,11 @@ private OpenCGAResult update(long noteUid, NoteUpdateParams noteUpdatePara // Write who's performing the update updateMap.put(NoteDBAdaptor.QueryParams.USER_ID.key(), tokenPayload.getUserId()); - OpenCGAResult update = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).update(noteUid, updateMap, + OpenCGAResult update = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).update(noteUid, updateMap, QueryOptions.empty()); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { // Fetch updated note - OpenCGAResult result = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(organizationId).get(noteUid, options); + OpenCGAResult result = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).get(noteUid, options); update.setResults(result.getResults()); } return update; @@ -379,7 +379,7 @@ public OpenCGAResult deleteStudyNote(String studyStr, String noteId, Query } private OpenCGAResult delete(Note note, QueryOptions options, JwtPayload jwtPayload) throws CatalogException { - OpenCGAResult delete = catalogDBAdaptorFactory.getCatalogNoteDBAdaptor(jwtPayload.getOrganization()).delete(note); + OpenCGAResult delete = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(jwtPayload.getOrganization()).delete(note); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { delete.setResults(Collections.singletonList(note)); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java index 90b83a92728..2612ea7f633 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java @@ -185,7 +185,7 @@ public OpenCGAResult create(OrganizationCreateParams organizationC organization = organizationCreateParams.toOrganization(); validateOrganizationForCreation(organization, userId); - queryResult = catalogDBAdaptorFactory.createOrganization(organization, options, userId); + queryResult = getCatalogDBAdaptorFactory().createOrganization(organization, options, userId); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { OpenCGAResult result = getOrganizationDBAdaptor(organization.getId()).get(options); organization = result.first(); @@ -211,7 +211,7 @@ public OpenCGAResult create(OrganizationCreateParams organizationC auditManager.auditCreate(ParamConstants.ADMIN_ORGANIZATION, userId, Enums.Resource.ORGANIZATION, organization.getId(), "", "", "", auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); try { - catalogDBAdaptorFactory.deleteOrganization(organization); + getCatalogDBAdaptorFactory().deleteOrganization(organization); } catch (Exception e1) { logger.error("Error deleting organization from catalog after failing creating the folder in the filesystem", e1); throw e; @@ -592,7 +592,7 @@ Set getOrganizationOwnerAndAdmins(String organizationId) throws CatalogE public List getOrganizationIds(String token) throws CatalogException { JwtPayload tokenPayload = catalogManager.getUserManager().validateToken(token); authorizationManager.checkIsOpencgaAdministrator(tokenPayload, "get all organization ids"); - return catalogDBAdaptorFactory.getOrganizationIds(); + return getCatalogDBAdaptorFactory().getOrganizationIds(); } private void privatizeResults(OpenCGAResult result) { diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ProjectManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ProjectManager.java index beda16bfa2e..dcfecf341f6 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ProjectManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ProjectManager.java @@ -562,7 +562,7 @@ public void importReleases(String organizationId, String owner, String inputDirS } OpenCGAResult userDataResult = getUserDBAdaptor(organizationId).get(owner, new QueryOptions(QueryOptions.INCLUDE, - Collections.singletonList(UserDBAdaptor.QueryParams.ACCOUNT.key()))); + Collections.singletonList(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT.key()))); if (userDataResult.getNumResults() == 0) { throw new CatalogException("User " + owner + " not found"); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java index 35c8bd46b64..9fa16ae9d64 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java @@ -36,10 +36,12 @@ import org.opencb.opencga.core.api.ParamConstants; import org.opencb.opencga.core.common.PasswordUtils; import org.opencb.opencga.core.common.TimeUtils; +import org.opencb.opencga.core.config.AuthenticationOrigin; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.models.JwtPayload; import org.opencb.opencga.core.models.audit.AuditRecord; import org.opencb.opencga.core.models.common.Enums; +import org.opencb.opencga.core.models.common.InternalStatus; import org.opencb.opencga.core.models.organizations.Organization; import org.opencb.opencga.core.models.study.Group; import org.opencb.opencga.core.models.study.GroupUpdateParams; @@ -60,8 +62,8 @@ */ public class UserManager extends AbstractManager { - static final QueryOptions INCLUDE_ACCOUNT_AND_INTERNAL = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( - UserDBAdaptor.QueryParams.ID.key(), UserDBAdaptor.QueryParams.ACCOUNT.key(), UserDBAdaptor.QueryParams.INTERNAL.key())); + static final QueryOptions INCLUDE_INTERNAL = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( + UserDBAdaptor.QueryParams.ID.key(), UserDBAdaptor.QueryParams.INTERNAL.key())); protected static Logger logger = LoggerFactory.getLogger(UserManager.class); private final CatalogIOManager catalogIOManager; private final AuthenticationFactory authenticationFactory; @@ -130,36 +132,54 @@ public OpenCGAResult create(User user, String password, String token) thro // Initialise fields ParamUtils.checkObj(user, "User"); ParamUtils.checkValidUserId(user.getId()); - ParamUtils.checkParameter(user.getName(), "name"); + user.setName(ParamUtils.defaultString(user.getName(), user.getId())); user.setEmail(ParamUtils.defaultString(user.getEmail(), "")); if (StringUtils.isNotEmpty(user.getEmail())) { checkEmail(user.getEmail()); } - user.setAccount(ParamUtils.defaultObject(user.getAccount(), Account::new)); - user.getAccount().setCreationDate(TimeUtils.getTime()); - if (StringUtils.isEmpty(user.getAccount().getExpirationDate())) { - // By default, user accounts will be valid for 1 year when they are created. - user.getAccount().setExpirationDate(organization.getConfiguration().getDefaultUserExpirationDate()); - Date date = TimeUtils.add1YeartoDate(new Date()); - user.getAccount().setExpirationDate(TimeUtils.getTime(date)); - } else { - // Validate expiration date is not over - ParamUtils.checkDateIsNotExpired(user.getAccount().getExpirationDate(), "account.expirationDate"); - } - user.setInternal(new UserInternal(new UserStatus(UserStatus.READY))); + user.setCreationDate(ParamUtils.checkDateOrGetCurrentDate(user.getCreationDate(), + UserDBAdaptor.QueryParams.CREATION_DATE.key())); + user.setModificationDate(ParamUtils.checkDateOrGetCurrentDate(user.getModificationDate(), + UserDBAdaptor.QueryParams.MODIFICATION_DATE.key())); + + user.setInternal(ParamUtils.defaultObject(user.getInternal(), UserInternal::new)); + user.getInternal().setStatus(new UserStatus(InternalStatus.READY)); user.setQuota(ParamUtils.defaultObject(user.getQuota(), UserQuota::new)); user.setProjects(ParamUtils.defaultObject(user.getProjects(), Collections::emptyList)); user.setConfigs(ParamUtils.defaultObject(user.getConfigs(), HashMap::new)); user.setFilters(ParamUtils.defaultObject(user.getFilters(), LinkedList::new)); user.setAttributes(ParamUtils.defaultObject(user.getAttributes(), Collections::emptyMap)); + // Init account + user.getInternal().setAccount(ParamUtils.defaultObject(user.getInternal().getAccount(), Account::new)); + Account account = user.getInternal().getAccount(); + account.setPassword(ParamUtils.defaultObject(account.getPassword(), Password::new)); + if (StringUtils.isEmpty(account.getExpirationDate())) { + account.setExpirationDate(organization.getConfiguration().getDefaultUserExpirationDate()); + } else { + // Validate expiration date is not over + ParamUtils.checkDateIsNotExpired(account.getExpirationDate(), UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_EXPIRATION_DATE.key()); + } if (StringUtils.isEmpty(password)) { Map authOriginMap = authenticationFactory.getOrganizationAuthenticationManagers(organizationId); - if (!authOriginMap.containsKey(user.getAccount().getAuthentication().getId())) { - throw new CatalogException("Unknown authentication origin id '" + user.getAccount().getAuthentication() + "'"); + if (!authOriginMap.containsKey(account.getAuthentication().getId())) { + throw new CatalogException("Unknown authentication origin id '" + account.getAuthentication() + "'"); } } else { - user.getAccount().setAuthentication(new Account.AuthenticationOrigin(CatalogAuthenticationManager.OPENCGA, false)); + account.setAuthentication(new Account.AuthenticationOrigin(CatalogAuthenticationManager.OPENCGA, false)); + } + + // Set password expiration + if (AuthenticationOrigin.AuthenticationType.OPENCGA.name().equals(account.getAuthentication().getId())) { + account.getPassword().setLastChangeDate(TimeUtils.getTime()); + } + if (!AuthenticationOrigin.AuthenticationType.OPENCGA.name().equals(account.getAuthentication().getId()) + || configuration.getAccount().getPasswordExpirationDays() <= 0) { + // User password doesn't expire or it's not managed by OpenCGA + account.getPassword().setExpirationDate(null); + } else { + Date date = TimeUtils.addDaysToCurrentDate(configuration.getAccount().getPasswordExpirationDays()); + account.getPassword().setExpirationDate(TimeUtils.getTime(date)); } if (!ParamConstants.ADMIN_ORGANIZATION.equals(organizationId) || !OPENCGA.equals(user.getId())) { @@ -213,7 +233,6 @@ public OpenCGAResult create(User user, String password, String token) thro public OpenCGAResult create(String id, String name, String email, String password, String organization, Long quota, String token) throws CatalogException { User user = new User(id, name, email, organization, new UserInternal(new UserStatus())) - .setAccount(new Account("", "", null)) .setQuota(new UserQuota().setMaxDisk(quota != null ? quota : -1)); return create(user, password, token); } @@ -244,7 +263,8 @@ public OpenCGAResult search(@Nullable String organizationId, Query query, // Fix query params if (query.containsKey(ParamConstants.USER_AUTHENTICATION_ORIGIN)) { - query.put(UserDBAdaptor.QueryParams.ACCOUNT_AUTHENTICATION_ID.key(), query.get(ParamConstants.USER_AUTHENTICATION_ORIGIN)); + query.put(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_AUTHENTICATION_ID.key(), + query.get(ParamConstants.USER_AUTHENTICATION_ORIGIN)); query.remove(ParamConstants.USER_AUTHENTICATION_ORIGIN); } @@ -269,11 +289,12 @@ public JwtPayload validateToken(String token) throws CatalogException { authOrigin = CatalogAuthenticationManager.OPENCGA; } else { OpenCGAResult userResult = getUserDBAdaptor(jwtPayload.getOrganization()).get(jwtPayload.getUserId(), - INCLUDE_ACCOUNT_AND_INTERNAL); + INCLUDE_INTERNAL); if (userResult.getNumResults() == 0) { throw new CatalogException("User '" + jwtPayload.getUserId() + "' could not be found."); } - authOrigin = userResult.first().getAccount().getAuthentication().getId(); + User user = userResult.first(); + authOrigin = user.getInternal().getAccount().getAuthentication().getId(); } authenticationFactory.validateToken(jwtPayload.getOrganization(), authOrigin, token); @@ -478,8 +499,10 @@ public void importRemoteEntities(String organizationId, String authOrigin, List< } } else { for (String applicationId : idList) { - User application = new User(applicationId, new Account() - .setAuthentication(new Account.AuthenticationOrigin(authOrigin, true))) + Account account = new Account() + .setAuthentication(new Account.AuthenticationOrigin(authOrigin, true)); + User application = new User(applicationId) + .setInternal(new UserInternal(new UserStatus(UserStatus.READY), account)) .setEmail("mail@mail.co.uk"); application.setOrganization(organizationId); create(application, null, token); @@ -785,7 +808,7 @@ public AuthenticationResponse login(String organizationId, String username, Stri if (OPENCGA.equals(username)) { organizationId = ParamConstants.ADMIN_ORGANIZATION; } else { - List organizationIds = catalogDBAdaptorFactory.getOrganizationIds(); + List organizationIds = getCatalogDBAdaptorFactory().getOrganizationIds(); if (organizationIds.size() == 2) { organizationId = organizationIds.stream().filter(s -> !ParamConstants.ADMIN_ORGANIZATION.equals(s)).findFirst().get(); } else { @@ -794,38 +817,56 @@ public AuthenticationResponse login(String organizationId, String username, Stri } } - OpenCGAResult userOpenCGAResult = getUserDBAdaptor(organizationId).get(username, INCLUDE_ACCOUNT_AND_INTERNAL); + OpenCGAResult userOpenCGAResult = getUserDBAdaptor(organizationId).get(username, INCLUDE_INTERNAL); if (userOpenCGAResult.getNumResults() == 1) { User user = userOpenCGAResult.first(); // Only local OPENCGA users that are not superadmins can be automatically banned or their accounts be expired boolean userCanBeBanned = !ParamConstants.ADMIN_ORGANIZATION.equals(organizationId) - && CatalogAuthenticationManager.OPENCGA.equals(user.getAccount().getAuthentication().getId()); + && CatalogAuthenticationManager.OPENCGA.equals(user.getInternal().getAccount().getAuthentication().getId()); // We check if (userCanBeBanned) { // Check user is not banned, suspended or has an expired account if (UserStatus.BANNED.equals(user.getInternal().getStatus().getId())) { throw CatalogAuthenticationException.userIsBanned(username); } - Date date = TimeUtils.toDate(user.getAccount().getExpirationDate()); - if (date == null) { - throw new CatalogException("Unexpected null expiration date for user '" + username + "'."); + if (UserStatus.SUSPENDED.equals(user.getInternal().getStatus().getId())) { + throw CatalogAuthenticationException.userIsSuspended(username); } - if (date.before(new Date())) { - throw CatalogAuthenticationException.accountIsExpired(username, user.getAccount().getExpirationDate()); + Account account2 = user.getInternal().getAccount(); + if (account2.getPassword().getExpirationDate() != null) { + Account account1 = user.getInternal().getAccount(); + Date passwordExpirationDate = TimeUtils.toDate(account1.getPassword().getExpirationDate()); + if (passwordExpirationDate == null) { + throw new CatalogException("Unexpected null 'passwordExpirationDate' for user '" + username + "'."); + } + if (passwordExpirationDate.before(new Date())) { + Account account = user.getInternal().getAccount(); + throw CatalogAuthenticationException.passwordExpired(username, account.getPassword().getExpirationDate()); + } + } + if (user.getInternal().getAccount().getExpirationDate() != null) { + Date date = TimeUtils.toDate(user.getInternal().getAccount().getExpirationDate()); + if (date == null) { + throw new CatalogException("Unexpected null 'expirationDate' for user '" + username + "'."); + } + if (date.before(new Date())) { + throw CatalogAuthenticationException.accountIsExpired(username, + user.getInternal().getAccount().getExpirationDate()); + } } } - if (UserStatus.SUSPENDED.equals(user.getInternal().getStatus().getId())) { - throw CatalogAuthenticationException.userIsSuspended(username); - } - authId = userOpenCGAResult.first().getAccount().getAuthentication().getId(); + User user1 = userOpenCGAResult.first(); + authId = user1.getInternal().getAccount().getAuthentication().getId(); try { response = authenticationFactory.authenticate(organizationId, authId, username, password); } catch (CatalogAuthenticationException e) { if (userCanBeBanned) { // We can only lock the account if it is not the root user - int failedAttempts = userOpenCGAResult.first().getInternal().getFailedAttempts(); - ObjectMap updateParams = new ObjectMap(UserDBAdaptor.QueryParams.INTERNAL_FAILED_ATTEMPTS.key(), failedAttempts + 1); - if (failedAttempts >= (configuration.getMaxLoginAttempts() - 1)) { + UserInternal userInternal = userOpenCGAResult.first().getInternal(); + int failedAttempts = userInternal.getAccount().getFailedAttempts(); + ObjectMap updateParams = new ObjectMap(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_FAILED_ATTEMPTS.key(), + failedAttempts + 1); + if (failedAttempts >= (configuration.getAccount().getMaxLoginAttempts() - 1)) { // Ban the account updateParams.append(UserDBAdaptor.QueryParams.INTERNAL_STATUS_ID.key(), UserStatus.BANNED); } @@ -838,10 +879,13 @@ public AuthenticationResponse login(String organizationId, String username, Stri } // If it was a local user and the counter of failed attempts was greater than 0, we reset it - if (userCanBeBanned && userOpenCGAResult.first().getInternal().getFailedAttempts() > 0) { - // Reset login failed attempts counter - ObjectMap updateParams = new ObjectMap(UserDBAdaptor.QueryParams.INTERNAL_FAILED_ATTEMPTS.key(), 0); - getUserDBAdaptor(organizationId).update(username, updateParams); + if (userCanBeBanned) { + UserInternal userInternal = userOpenCGAResult.first().getInternal(); + if (userInternal.getAccount().getFailedAttempts() > 0) { + // Reset login failed attempts counter + ObjectMap updateParams = new ObjectMap(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_FAILED_ATTEMPTS.key(), 0); + getUserDBAdaptor(organizationId).update(username, updateParams); + } } } else { // We attempt to login the user with the different authentication managers @@ -992,7 +1036,7 @@ public OpenCGAResult changeStatus(String organizationId, String userId, St // Update user status and reset failed attempts to 0 ObjectMap updateParams = new ObjectMap(UserDBAdaptor.QueryParams.INTERNAL_STATUS_ID.key(), status); if (UserStatus.READY.equals(status)) { - updateParams.put(UserDBAdaptor.QueryParams.INTERNAL_FAILED_ATTEMPTS.key(), 0); + updateParams.put(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_FAILED_ATTEMPTS.key(), 0); } OpenCGAResult result = getUserDBAdaptor(userIdOrganization).update(userId, updateParams); @@ -1059,9 +1103,10 @@ public String getNonExpiringToken(String organizationId, String userId, Map userOpenCGAResult = getUserDBAdaptor(organizationId).get(user, INCLUDE_ACCOUNT_AND_INTERNAL); + OpenCGAResult userOpenCGAResult = getUserDBAdaptor(organizationId).get(user, INCLUDE_INTERNAL); if (userOpenCGAResult.getNumResults() == 1) { - String authId = userOpenCGAResult.first().getAccount().getAuthentication().getId(); + User user1 = userOpenCGAResult.first(); + String authId = user1.getInternal().getAccount().getAuthentication().getId(); return authenticationFactory.getOrganizationAuthenticationManager(organizationId, authId); } else { throw new CatalogException("User '" + user + "' not found."); @@ -1492,7 +1537,8 @@ private String getAuthenticationOriginId(String organizationId, String userId) t if (user == null || user.getNumResults() == 0) { throw new CatalogException(userId + " user not found"); } - return user.first().getAccount().getAuthentication().getId(); + User user1 = user.first(); + return user1.getInternal().getAccount().getAuthentication().getId(); } /** diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java index 9044dd2f7c0..4bafb0cc4e0 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java @@ -23,13 +23,17 @@ import org.junit.experimental.categories.Category; import org.junit.rules.ExpectedException; import org.junit.rules.TestName; +import org.mockito.Mockito; import org.opencb.commons.datastore.core.DataResult; import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.commons.test.GenericTest; import org.opencb.opencga.TestParamConstants; import org.opencb.opencga.catalog.auth.authorization.AuthorizationManager; +import org.opencb.opencga.catalog.db.api.UserDBAdaptor; import org.opencb.opencga.catalog.db.mongodb.MongoBackupUtils; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptorFactory; +import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.utils.FqnUtils; import org.opencb.opencga.catalog.utils.ParamUtils; @@ -474,4 +478,23 @@ private void createDummyData(CatalogManager catalogManager) throws CatalogExcept } + protected CatalogManager mockCatalogManager() throws CatalogDBException { + CatalogManager spy = Mockito.spy(catalogManager); + UserManager userManager = spy.getUserManager(); + UserManager userManagerSpy = Mockito.spy(userManager); + Mockito.doReturn(userManagerSpy).when(spy).getUserManager(); + MongoDBAdaptorFactory mongoDBAdaptorFactory = mockMongoDBAdaptorFactory(); + Mockito.doReturn(mongoDBAdaptorFactory).when(userManagerSpy).getCatalogDBAdaptorFactory(); + return spy; + } + + protected MongoDBAdaptorFactory mockMongoDBAdaptorFactory() throws CatalogDBException { + MongoDBAdaptorFactory catalogDBAdaptorFactory = (MongoDBAdaptorFactory) catalogManager.getUserManager().getCatalogDBAdaptorFactory(); + MongoDBAdaptorFactory dbAdaptorFactorySpy = Mockito.spy(catalogDBAdaptorFactory); + UserDBAdaptor userDBAdaptor = dbAdaptorFactorySpy.getCatalogUserDBAdaptor(organizationId); + UserDBAdaptor userDBAdaptorSpy = Mockito.spy(userDBAdaptor); + Mockito.doReturn(userDBAdaptorSpy).when(dbAdaptorFactorySpy).getCatalogUserDBAdaptor(organizationId); + return dbAdaptorFactorySpy; + } + } diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerTest.java index 73cab79045b..8f0bce1401e 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerTest.java @@ -16,13 +16,10 @@ package org.opencb.opencga.catalog.managers; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; -import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.opencb.biodata.models.common.Status; @@ -34,7 +31,10 @@ import org.opencb.opencga.TestParamConstants; import org.opencb.opencga.catalog.auth.authorization.AuthorizationManager; import org.opencb.opencga.catalog.db.api.*; -import org.opencb.opencga.catalog.exceptions.*; +import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; +import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; +import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.Constants; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.core.api.ParamConstants; @@ -43,7 +43,6 @@ import org.opencb.opencga.core.models.Acl; import org.opencb.opencga.core.models.AclEntry; import org.opencb.opencga.core.models.AclEntryList; -import org.opencb.opencga.core.models.JwtPayload; import org.opencb.opencga.core.models.cohort.Cohort; import org.opencb.opencga.core.models.cohort.CohortUpdateParams; import org.opencb.opencga.core.models.common.AnnotationSet; @@ -61,11 +60,10 @@ import org.opencb.opencga.core.models.project.ProjectOrganism; import org.opencb.opencga.core.models.sample.*; import org.opencb.opencga.core.models.study.*; -import org.opencb.opencga.core.models.user.*; +import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.response.OpenCGAResult; import org.opencb.opencga.core.testclassification.duration.MediumTests; -import javax.naming.NamingException; import java.io.IOException; import java.util.*; import java.util.concurrent.ExecutorService; @@ -73,22 +71,12 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.*; -import static org.opencb.opencga.core.common.JacksonUtils.getUpdateObjectMapper; @Category(MediumTests.class) public class CatalogManagerTest extends AbstractManagerTest { - @Test - public void createOpencgaUserTest() throws CatalogException { - thrown.expect(CatalogException.class); - thrown.expectMessage("forbidden"); - catalogManager.getUserManager().create(new User().setId(ParamConstants.OPENCGA_USER_ID).setName(orgOwnerUserId) - .setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); - } - @Test public void createStudyFailMoreThanOneProject() throws CatalogException { catalogManager.getProjectManager().incrementRelease(project1, ownerToken); @@ -102,443 +90,6 @@ public void createStudyFailMoreThanOneProject() throws CatalogException { null, null, null, null, ownerToken); } - @Test - public void testAdminUserExists() throws Exception { - String token = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); - JwtPayload payload = catalogManager.getUserManager().validateToken(token); - assertEquals(ParamConstants.OPENCGA_USER_ID, payload.getUserId()); - assertEquals(ParamConstants.ADMIN_ORGANIZATION, payload.getOrganization()); - } - - @Test - public void searchUsersTest() throws CatalogException { - OpenCGAResult search = catalogManager.getUserManager().search(organizationId, new Query(), QueryOptions.empty(), opencgaToken); - assertEquals(8, search.getNumResults()); - for (User user : search.getResults()) { - if (noAccessUserId1.equals(user.getId())) { - assertEquals(0, user.getProjects().size()); - } else if (user.getId().startsWith("normalUser")) { - assertEquals(1, user.getProjects().size()); - } else { - assertEquals(2, user.getProjects().size()); - } - } - - search = catalogManager.getUserManager().search(null, new Query(), QueryOptions.empty(), ownerToken); - assertEquals(8, search.getNumResults()); - - search = catalogManager.getUserManager().search(null, new Query(), QueryOptions.empty(), orgAdminToken2); - assertEquals(8, search.getNumResults()); - - search = catalogManager.getUserManager().search(null, new Query(), QueryOptions.empty(), orgAdminToken1); - assertEquals(8, search.getNumResults()); - - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().search(null, new Query(), - QueryOptions.empty(), studyAdminToken1)); - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().search(null, new Query(), - QueryOptions.empty(), normalToken1)); - } - - @Test - public void testGetToken() throws Exception { - String token = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); - Map claims = new HashMap<>(); - claims.put("a", "hola"); - claims.put("ab", "byw"); - // Create a token valid for 1 second - String expiringToken = catalogManager.getUserManager().getToken(ParamConstants.ADMIN_ORGANIZATION, "opencga", claims, 1L, token); - assertEquals("opencga", catalogManager.getUserManager().validateToken(expiringToken).getUserId()); - - String nonExpiringToken = catalogManager.getUserManager().getNonExpiringToken(ParamConstants.ADMIN_ORGANIZATION, "opencga", claims, token); - assertEquals("opencga", catalogManager.getUserManager().validateToken(nonExpiringToken).getUserId()); - - Thread.sleep(1000); - thrown.expect(CatalogAuthenticationException.class); - thrown.expectMessage("expired"); - assertEquals("opencga", catalogManager.getUserManager().validateToken(expiringToken).getUserId()); - } - - @Test - public void loginWithoutOrganizationId() throws CatalogException { - String token = catalogManager.getUserManager().login(null, ParamConstants.OPENCGA_USER_ID, TestParamConstants.ADMIN_PASSWORD).getToken(); - assertTrue(StringUtils.isNotEmpty(token)); - JwtPayload jwtPayload = new JwtPayload(token); - assertEquals(ParamConstants.ADMIN_ORGANIZATION, jwtPayload.getOrganization()); - - token = catalogManager.getUserManager().login(null, orgOwnerUserId, TestParamConstants.PASSWORD).getToken(); - assertTrue(StringUtils.isNotEmpty(token)); - jwtPayload = new JwtPayload(token); - assertEquals(organizationId, jwtPayload.getOrganization()); - - // Create a third organization - catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId("other").setName("Test"), QueryOptions.empty(), opencgaToken); - token = catalogManager.getUserManager().login(null, ParamConstants.OPENCGA_USER_ID, TestParamConstants.ADMIN_PASSWORD).getToken(); - assertTrue(StringUtils.isNotEmpty(token)); - jwtPayload = new JwtPayload(token); - assertEquals(ParamConstants.ADMIN_ORGANIZATION, jwtPayload.getOrganization()); - - thrown.expect(CatalogParameterException.class); - thrown.expectMessage("organization"); - catalogManager.getUserManager().login(null, orgOwnerUserId, TestParamConstants.PASSWORD); - } - - @Test - public void testCreateExistingUser() throws Exception { - thrown.expect(CatalogException.class); - thrown.expectMessage(containsString("already exists")); - catalogManager.getUserManager().create(orgOwnerUserId, "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, organizationId, - null, opencgaToken); - } - - @Test - public void testCreateAnonymousUser() throws Exception { - thrown.expect(CatalogParameterException.class); - thrown.expectMessage(containsString("reserved")); - catalogManager.getUserManager().create(ParamConstants.ANONYMOUS_USER_ID, "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, - organizationId, null, opencgaToken); - } - - @Test - public void testCreateRegisteredUser() throws Exception { - thrown.expect(CatalogParameterException.class); - thrown.expectMessage(containsString("reserved")); - catalogManager.getUserManager().create(ParamConstants.REGISTERED_USERS, "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, organizationId, null, - opencgaToken); - } - - @Test - public void testLogin() throws Exception { - catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD); - - thrown.expect(CatalogAuthenticationException.class); - thrown.expectMessage(allOf(containsString("Incorrect"), containsString("password"))); - catalogManager.getUserManager().login(organizationId, normalUserId1, "fakePassword"); - } - - @Test - public void refreshTokenTest() throws Exception { - String refreshToken = catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD).getRefreshToken(); - AuthenticationResponse authenticationResponse = catalogManager.getUserManager().refreshToken(refreshToken); - assertNotNull(authenticationResponse); - assertNotNull(authenticationResponse.getToken()); - } - - @Test - public void anonymousUserLoginTest() throws CatalogException { - AuthenticationResponse authResponse = catalogManager.getUserManager().loginAnonymous(organizationId); - assertNotNull(authResponse.getToken()); - - String org2 = "otherOrg"; - catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId(org2), QueryOptions.empty(), opencgaToken); - catalogManager.getUserManager().create(new User().setId("userFromOrg2").setName("name").setOrganization(org2).setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getOrganizationManager().update(org2, new OrganizationUpdateParams().setOwner("userFromOrg2"), null, opencgaToken); - String owner2Token = catalogManager.getUserManager().login(org2, "userFromOrg2", TestParamConstants.PASSWORD).getToken(); - Project p = catalogManager.getProjectManager().create(new ProjectCreateParams() - .setId("project") - .setOrganism(new ProjectOrganism("Homo sapiens", "GRCh38")), - INCLUDE_RESULT, owner2Token).first(); - Study study = catalogManager.getStudyManager().create(p.getFqn(), new Study().setId("study"), INCLUDE_RESULT, owner2Token).first(); - - try { - catalogManager.getUserManager().loginAnonymous(org2); - fail("Anonymous user should not get a token for that organization as it has not been granted any kind of access"); - } catch (Exception e) { - assertEquals(CatalogAuthenticationException.class, e.getClass()); - assertTrue(e.getMessage().contains("not found")); - } - - catalogManager.getStudyManager().updateGroup(study.getFqn(), ParamConstants.MEMBERS_GROUP, ParamUtils.BasicUpdateAction.ADD, - new GroupUpdateParams(Collections.singletonList("*")), owner2Token); - authResponse = catalogManager.getUserManager().loginAnonymous(org2); - assertNotNull(authResponse.getToken()); - - - catalogManager.getStudyManager().updateGroup(study.getFqn(), ParamConstants.MEMBERS_GROUP, ParamUtils.BasicUpdateAction.REMOVE, - new GroupUpdateParams(Collections.singletonList("*")), owner2Token); - thrown.expect(CatalogAuthenticationException.class); - thrown.expectMessage("not found"); - catalogManager.getUserManager().loginAnonymous(org2); - } - - @Test - public void incrementLoginAttemptsTest() throws CatalogException { - assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); - User user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); - assertEquals(1, user.getInternal().getFailedAttempts()); - assertEquals(UserStatus.READY, user.getInternal().getStatus().getId()); - - for (int i = 2; i < 5; i++) { - assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); - user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); - assertEquals(i, user.getInternal().getFailedAttempts()); - assertEquals(UserStatus.READY, user.getInternal().getStatus().getId()); - } - - assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); - user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); - assertEquals(5, user.getInternal().getFailedAttempts()); - assertEquals(UserStatus.BANNED, user.getInternal().getStatus().getId()); - - CatalogAuthenticationException incorrect = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); - assertTrue(incorrect.getMessage().contains("banned")); - user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); - assertEquals(5, user.getInternal().getFailedAttempts()); - assertEquals(UserStatus.BANNED, user.getInternal().getStatus().getId()); - - CatalogAuthenticationException authException = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD)); - assertTrue(authException.getMessage().contains("banned")); - - // Remove ban from user - catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.READY, QueryOptions.empty(), ownerToken); - user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); - assertEquals(0, user.getInternal().getFailedAttempts()); - assertEquals(UserStatus.READY, user.getInternal().getStatus().getId()); - - String token = catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD).getToken(); - assertNotNull(token); - } - - @Test - public void changeUserStatusTest() throws CatalogException { - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.BANNED, QueryOptions.empty(), normalToken1)); - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.BANNED, QueryOptions.empty(), studyAdminToken1)); - assertThrows(CatalogParameterException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.BANNED, QueryOptions.empty(), ownerToken)); - catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), ownerToken); - catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), orgAdminToken1); - catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), opencgaToken); - - catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), ownerToken); - CatalogAuthorizationException authException = assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, orgOwnerUserId, UserStatus.SUSPENDED, QueryOptions.empty(), ownerToken)); - assertTrue(authException.getMessage().contains("own account")); - - authException = assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), orgAdminToken2)); - assertTrue(authException.getMessage().contains("suspend administrators")); - - CatalogAuthenticationException incorrect = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, orgAdminUserId1, TestParamConstants.PASSWORD)); - assertTrue(incorrect.getMessage().contains("suspended")); - - catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, UserStatus.READY, QueryOptions.empty(), orgAdminToken2); - String token = catalogManager.getUserManager().login(organizationId, orgAdminUserId1, TestParamConstants.PASSWORD).getToken(); - assertNotNull(token); - - CatalogParameterException paramException = assertThrows(CatalogParameterException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, "NOT_A_STATUS", QueryOptions.empty(), orgAdminToken2)); - assertTrue(paramException.getMessage().contains("Invalid status")); - - CatalogDBException dbException = assertThrows(CatalogDBException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, "notAUser", UserStatus.SUSPENDED, QueryOptions.empty(), orgAdminToken2)); - assertTrue(dbException.getMessage().contains("not exist")); - } - - @Test - public void loginExpiredAccountTest() throws CatalogException { - // Expire account of normalUserId1 - ObjectMap params = new ObjectMap(UserDBAdaptor.QueryParams.ACCOUNT_EXPIRATION_DATE.key(), TimeUtils.getTime()); - catalogManager.getUserManager().getUserDBAdaptor(organizationId).update(normalUserId1, params); - - CatalogAuthenticationException authException = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD)); - assertTrue(authException.getMessage().contains("expired")); - - // Ensure it doesn't matter whether opencga account is expired or not - catalogManager.getUserManager().getUserDBAdaptor(ParamConstants.ADMIN_ORGANIZATION).update(ParamConstants.OPENCGA_USER_ID, params); - String token = catalogManager.getUserManager().login(ParamConstants.ADMIN_ORGANIZATION, ParamConstants.OPENCGA_USER_ID, TestParamConstants.ADMIN_PASSWORD).getToken(); - assertNotNull(token); - } - - @Test - public void updateUserTest() throws JsonProcessingException, CatalogException { - UserUpdateParams userUpdateParams = new UserUpdateParams() - .setName("newName") - .setEmail("mail@mail.com"); - ObjectMap updateParams = new ObjectMap(getUpdateObjectMapper().writeValueAsString(userUpdateParams)); - User user = catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, normalToken1).first(); - assertEquals(userUpdateParams.getName(), user.getName()); - assertEquals(userUpdateParams.getEmail(), user.getEmail()); - - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, normalToken2)); - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, opencgaToken)); - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, ownerToken)); - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, orgAdminToken1)); - assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, studyAdminToken1)); - - userUpdateParams = new UserUpdateParams() - .setEmail("notAnEmail"); - ObjectMap updateParams2 = new ObjectMap(getUpdateObjectMapper().writeValueAsString(userUpdateParams)); - assertThrows(CatalogParameterException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams2, INCLUDE_RESULT, normalToken1)); - } - - @Test - public void testGetUserInfo() throws CatalogException { - // OpenCGA administrator - DataResult user = catalogManager.getUserManager().get(organizationId, - Arrays.asList(normalUserId1, normalUserId2, normalUserId3), new QueryOptions(), opencgaToken); - assertEquals(3, user.getNumResults()); - assertEquals(normalUserId1, user.getResults().get(0).getId()); - assertEquals(normalUserId2, user.getResults().get(1).getId()); - assertEquals(normalUserId3, user.getResults().get(2).getId()); - - // Organization owner - user = catalogManager.getUserManager().get(organizationId, Arrays.asList(normalUserId1, normalUserId2, normalUserId3), - new QueryOptions(), ownerToken); - assertEquals(3, user.getNumResults()); - assertEquals(normalUserId1, user.getResults().get(0).getId()); - assertEquals(normalUserId2, user.getResults().get(1).getId()); - assertEquals(normalUserId3, user.getResults().get(2).getId()); - - // Organization administrator - user = catalogManager.getUserManager().get(organizationId, Arrays.asList(normalUserId1, normalUserId2, normalUserId3), - new QueryOptions(), orgAdminToken1); - assertEquals(3, user.getNumResults()); - assertEquals(normalUserId1, user.getResults().get(0).getId()); - assertEquals(normalUserId2, user.getResults().get(1).getId()); - assertEquals(normalUserId3, user.getResults().get(2).getId()); - - thrown.expect(CatalogAuthorizationException.class); - thrown.expectMessage("organization"); - catalogManager.getUserManager().get(organizationId, Arrays.asList(normalUserId1, normalUserId2, normalUserId3), new QueryOptions(), - studyAdminToken1); - } - - @Test - public void testGetProjectsFromUserInfo() throws CatalogException { - String userId = organizationId; - catalogManager.getUserManager().create(userId, "test", "mail@mail.com", TestParamConstants.PASSWORD, organizationId, null, - opencgaToken); - catalogManager.getStudyManager().updateGroup(studyFqn, ParamConstants.MEMBERS_GROUP, ParamUtils.BasicUpdateAction.ADD, - new GroupUpdateParams(Collections.singletonList("test")), ownerToken); - String token = catalogManager.getUserManager().login(organizationId, userId, TestParamConstants.PASSWORD).getToken(); - - DataResult user = catalogManager.getUserManager().get(organizationId, userId, new QueryOptions(), token); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(organizationId, normalUserId3, new QueryOptions(), normalToken3); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(organizationId, orgOwnerUserId, new QueryOptions(), ownerToken); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(organizationId, orgAdminUserId1, new QueryOptions(), orgAdminToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(organizationId, studyAdminUserId1, new QueryOptions(), studyAdminToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(organizationId, normalUserId1, new QueryOptions(), orgAdminToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - - user = catalogManager.getUserManager().get(null, normalUserId1, new QueryOptions(), normalToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(null, normalUserId3, new QueryOptions(), normalToken3); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(null, orgOwnerUserId, new QueryOptions(), ownerToken); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(null, orgAdminUserId1, new QueryOptions(), orgAdminToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(null, studyAdminUserId1, new QueryOptions(), studyAdminToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - - user = catalogManager.getUserManager().get(null, normalUserId1, new QueryOptions(), orgAdminToken1); - assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); - System.out.println(user.first().getProjects().size()); - } - - @Test - public void testModifyUser() throws CatalogException, InterruptedException, IOException { - ObjectMap params = new ObjectMap(); - String newName = "Changed Name " + RandomStringUtils.randomAlphanumeric(10); - String newPassword = RandomStringUtils.randomAlphanumeric(10); - String newEmail = "new@email.ac.uk"; - - params.put("name", newName); - - Thread.sleep(10); - - catalogManager.getUserManager().update(orgOwnerUserId, params, null, ownerToken); - catalogManager.getUserManager().update(orgOwnerUserId, new ObjectMap("email", newEmail), null, ownerToken); - catalogManager.getUserManager().changePassword(organizationId, orgOwnerUserId, TestParamConstants.PASSWORD, newPassword); - - List userList = catalogManager.getUserManager().get(organizationId, orgOwnerUserId, new QueryOptions(QueryOptions - .INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key(), - UserDBAdaptor.QueryParams.ATTRIBUTES.key())), ownerToken).getResults(); - User userPost = userList.get(0); - System.out.println("userPost = " + userPost); - assertEquals(userPost.getName(), newName); - assertEquals(userPost.getEmail(), newEmail); - - catalogManager.getUserManager().login(organizationId, orgOwnerUserId, newPassword); - catalogManager.getUserManager().changePassword(organizationId, orgOwnerUserId, newPassword, TestParamConstants.PASSWORD); - catalogManager.getUserManager().login(organizationId, orgOwnerUserId, TestParamConstants.PASSWORD); - - try { - params = new ObjectMap(); - params.put("password", "1234321"); - catalogManager.getUserManager().update(orgOwnerUserId, params, null, ownerToken); - fail("Expected exception"); - } catch (CatalogDBException e) { - System.out.println(e); - } - - try { - catalogManager.getUserManager().update(orgOwnerUserId, params, null, orgAdminToken1); - fail("Expected exception"); - } catch (CatalogException e) { - System.out.println(e); - } - } - - @Test - public void testUpdateUserConfig() throws CatalogException { - Map map = new HashMap<>(); - map.put("key1", "value1"); - map.put("key2", "value2"); - catalogManager.getUserManager().setConfig(normalUserId1, "a", map, normalToken1); - - Map config = (Map) catalogManager.getUserManager().getConfig(normalUserId1, "a", normalToken1).first(); - assertEquals(2, config.size()); - assertEquals("value1", config.get("key1")); - assertEquals("value2", config.get("key2")); - - map = new HashMap<>(); - map.put("key2", "value3"); - catalogManager.getUserManager().setConfig(normalUserId1, "a", map, normalToken1); - config = (Map) catalogManager.getUserManager().getConfig(normalUserId1, "a", normalToken1).first(); - assertEquals(1, config.size()); - assertEquals("value3", config.get("key2")); - - catalogManager.getUserManager().deleteConfig(normalUserId1, "a", normalToken1); - - thrown.expect(CatalogException.class); - thrown.expectMessage("not found"); - catalogManager.getUserManager().getConfig(normalUserId1, "a", normalToken1); - } - - private String getAdminToken() throws CatalogException, IOException { - return catalogManager.getUserManager().loginAsAdmin("admin").getToken(); - } - - @Test - public void createUserUsingMailAsId() throws CatalogException { - catalogManager.getUserManager().create(new User().setId("hello.mail@mymail.org").setName("Hello"), TestParamConstants.PASSWORD, ownerToken); - AuthenticationResponse login = catalogManager.getUserManager().login(organizationId, "hello.mail@mymail.org", TestParamConstants.PASSWORD); - assertNotNull(login); - User user = catalogManager.getUserManager().get(organizationId, "hello.mail@mymail.org", new QueryOptions(), login.getToken()).first(); - assertEquals("hello.mail@mymail.org", user.getId()); - } - @Test public void getGroupsTest() throws CatalogException { Group group = new Group("groupId", Arrays.asList(normalUserId2, normalUserId3)).setSyncedFrom(new Group.Sync("ldap", "bio")); @@ -564,82 +115,6 @@ public void getGroupsTest() throws CatalogException { catalogManager.getStudyManager().getCustomGroups(studyFqn, group.getId(), normalToken2); } - @Ignore - @Test - public void importLdapUsers() throws CatalogException, NamingException, IOException { - // Action only for admins - catalogManager.getUserManager().importRemoteEntities(organizationId, "ldap", Arrays.asList("pfurio", "imedina"), false, null, null, - getAdminToken()); - // TODO: Validate the users have been imported - } - - // To make this test work we will need to add a correct user and password to be able to login - @Ignore - @Test - public void loginNotRegisteredUsers() throws CatalogException { - // Action only for admins - Group group = new Group("ldap", Collections.emptyList()).setSyncedFrom(new Group.Sync("ldap", "bio")); - catalogManager.getStudyManager().createGroup(studyFqn, group, ownerToken); - catalogManager.getStudyManager().updateAcl(studyFqn, "@ldap", new StudyAclParams("", "view_only"), - ParamUtils.AclAction.SET, ownerToken); - String token = catalogManager.getUserManager().login(organizationId, orgOwnerUserId, "password").getToken(); - - assertEquals(9, catalogManager.getSampleManager().count(studyFqn, new Query(), token).getNumTotalResults()); - - // We remove the permissions for group ldap - catalogManager.getStudyManager().updateAcl(studyFqn, "@ldap", new StudyAclParams("", ""), - ParamUtils.AclAction.RESET, this.ownerToken); - - assertEquals(0, catalogManager.getSampleManager().count(studyFqn, new Query(), token).getNumTotalResults()); - } - - @Ignore - @Test - public void syncUsers() throws CatalogException { - // Action only for admins - String token = catalogManager.getUserManager().loginAsAdmin("admin").getToken(); - - catalogManager.getUserManager().importRemoteGroupOfUsers(organizationId, "ldap", "bio", "bio", studyFqn, true, token); - DataResult bio = catalogManager.getStudyManager().getGroup(studyFqn, "bio", this.ownerToken); - - assertEquals(1, bio.getNumResults()); - assertEquals(0, bio.first().getUserIds().size()); - - catalogManager.getUserManager().syncAllUsersOfExternalGroup(organizationId, studyFqn, "ldap", token); - bio = catalogManager.getStudyManager().getGroup(studyFqn, "bio", this.ownerToken); - - assertEquals(1, bio.getNumResults()); - assertTrue(!bio.first().getUserIds().isEmpty()); - } - - @Ignore - @Test - public void importLdapGroups() throws CatalogException, IOException { - // Action only for admins - String remoteGroup = "bio"; - String internalGroup = "test"; - catalogManager.getUserManager().importRemoteGroupOfUsers(organizationId, "ldap", remoteGroup, internalGroup, studyFqn, true, getAdminToken()); - - DataResult test = catalogManager.getStudyManager().getGroup(studyFqn, "test", ownerToken); - assertEquals(1, test.getNumResults()); - assertEquals("@test", test.first().getId()); - assertTrue(test.first().getUserIds().size() > 0); - -// internalGroup = "test1"; -// try { -// catalogManager.getUserManager().importRemoteGroupOfUsers("ldap", remoteGroup, internalGroup, study, getAdminToken()); -// fail("Should not be possible creating another group containing the same users that belong to a different group"); -// } catch (CatalogException e) { -// System.out.println(e.getMessage()); -// } - - remoteGroup = "bioo"; - internalGroup = "test2"; - thrown.expect(CatalogException.class); - thrown.expectMessage("not found"); - catalogManager.getUserManager().importRemoteGroupOfUsers(organizationId, "ldap", remoteGroup, internalGroup, studyFqn, true, getAdminToken()); - } - @Test public void createEmptyGroup() throws CatalogException { catalogManager.getUserManager().create("test", "test", "test@mail.com", TestParamConstants.PASSWORD, organizationId, 100L, opencgaToken); @@ -681,29 +156,6 @@ public void testAssignPermissions() throws CatalogException { assertTrue(acls.stream().map(x -> String.valueOf(x.get("member"))).collect(Collectors.toSet()).contains("@group_cancer_some_thing_else")); } - @Test - public void getUserInfoTest() throws CatalogException { - OpenCGAResult result = catalogManager.getUserManager().get(organizationId, orgOwnerUserId, QueryOptions.empty(), ownerToken); - assertEquals(1, result.getNumResults()); - assertNotNull(result.first().getProjects()); - assertEquals(2, result.first().getProjects().size()); - - result = catalogManager.getUserManager().get(organizationId, orgAdminUserId1, QueryOptions.empty(), orgAdminToken1); - assertEquals(1, result.getNumResults()); - assertNotNull(result.first().getProjects()); - assertEquals(2, result.first().getProjects().size()); - - result = catalogManager.getUserManager().get(organizationId, studyAdminUserId1, QueryOptions.empty(), studyAdminToken1); - assertEquals(1, result.getNumResults()); - assertNotNull(result.first().getProjects()); - assertEquals(2, result.first().getProjects().size()); - - result = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), normalToken1); - assertEquals(1, result.getNumResults()); - assertNotNull(result.first().getProjects()); - assertEquals(1, result.first().getProjects().size()); - } - /** * Project methods *************************** */ diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java index cf267f04b71..18a20c3667b 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java @@ -259,8 +259,8 @@ public void createMultipleCasesSameFamily() throws CatalogException { public void updateClinicalAnalystsTest() throws CatalogException { ClinicalAnalysis case1 = createDummyEnvironment(true, true).first(); - catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setOrganization(organizationId).setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("u2").setName("u2").setOrganization(organizationId).setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getUserManager().create(new User().setId("u2").setName("u2").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); // Add analysts OpenCGAResult result = catalogManager.getClinicalAnalysisManager().update(studyFqn, case1.getId(), @@ -312,7 +312,7 @@ public void updateClinicalAnalysisRequest() throws CatalogException { ClinicalAnalysis case1 = createDummyEnvironment(true, true).first(); assertTrue(StringUtils.isEmpty(case1.getRequest().getId())); - catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setOrganization(organizationId).setEmail("mail@mail.com").setAccount(new Account()), + catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setOrganization(organizationId).setEmail("mail@mail.com"), TestParamConstants.PASSWORD, opencgaToken); ClinicalRequest request = new ClinicalRequest("requestId", "bla", null, new ClinicalResponsible().setId("u1"), new HashMap<>()); @@ -350,8 +350,8 @@ public void updateClinicalAnalysisResponsible() throws CatalogException { assertEquals(orgOwnerUserId, case1.getResponsible().getId()); catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setEmail("mail@mail.com") - .setOrganization(organizationId) - .setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); + .setOrganization(organizationId), + TestParamConstants.PASSWORD, opencgaToken); ClinicalResponsible responsible = new ClinicalResponsible().setId("u1"); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/OrganizationManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/OrganizationManagerTest.java index ca9323b422d..a72d52eace3 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/OrganizationManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/OrganizationManagerTest.java @@ -287,7 +287,7 @@ private void updateAndAssertChanges(String orgId, OrganizationUserUpdateParams u User user = catalogManager.getOrganizationManager().updateUser(orgId, normalUserId1, userUpdateParams, INCLUDE_RESULT, token).first(); assertEquals(userUpdateParams.getName(), user.getName()); assertEquals(userUpdateParams.getEmail(), user.getEmail()); - assertEquals(userUpdateParams.getAccount().getExpirationDate(), user.getAccount().getExpirationDate()); + assertEquals(userUpdateParams.getAccount().getExpirationDate(), user.getInternal().getAccount().getExpirationDate()); assertEquals(userUpdateParams.getQuota().getCpuUsage(), user.getQuota().getCpuUsage()); assertEquals(userUpdateParams.getQuota().getDiskUsage(), user.getQuota().getDiskUsage()); assertEquals(userUpdateParams.getQuota().getMaxCpu(), user.getQuota().getMaxCpu()); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ProjectManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ProjectManagerTest.java index 3a0a4e4a808..85e13914da5 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ProjectManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ProjectManagerTest.java @@ -38,7 +38,6 @@ import org.opencb.opencga.core.models.project.ProjectOrganism; import org.opencb.opencga.core.models.study.GroupUpdateParams; import org.opencb.opencga.core.models.study.Study; -import org.opencb.opencga.core.models.user.Account; import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.response.OpenCGAResult; import org.opencb.opencga.core.testclassification.duration.MediumTests; @@ -89,7 +88,7 @@ public void searchSampleNoPermissions() throws CatalogException { public void searchProjects() throws CatalogException { String org2 = "otherOrg"; catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId(org2), QueryOptions.empty(), opencgaToken); - catalogManager.getUserManager().create(new User().setId("userFromOrg2").setName("name").setAccount(new Account()).setOrganization(org2), + catalogManager.getUserManager().create(new User().setId("userFromOrg2").setName("name").setOrganization(org2), TestParamConstants.PASSWORD, opencgaToken); catalogManager.getOrganizationManager().update(org2, new OrganizationUpdateParams().setOwner("userFromOrg2"), null, opencgaToken); String owner2Token = catalogManager.getUserManager().login(org2, "userFromOrg2", TestParamConstants.PASSWORD).getToken(); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java new file mode 100644 index 00000000000..7bfda8c5261 --- /dev/null +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java @@ -0,0 +1,664 @@ +package org.opencb.opencga.catalog.managers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.Mockito; +import org.opencb.commons.datastore.core.DataResult; +import org.opencb.commons.datastore.core.ObjectMap; +import org.opencb.commons.datastore.core.Query; +import org.opencb.commons.datastore.core.QueryOptions; +import org.opencb.opencga.TestParamConstants; +import org.opencb.opencga.catalog.db.api.UserDBAdaptor; +import org.opencb.opencga.catalog.exceptions.*; +import org.opencb.opencga.catalog.utils.ParamUtils; +import org.opencb.opencga.core.api.ParamConstants; +import org.opencb.opencga.core.common.PasswordUtils; +import org.opencb.opencga.core.common.TimeUtils; +import org.opencb.opencga.core.models.JwtPayload; +import org.opencb.opencga.core.models.organizations.OrganizationCreateParams; +import org.opencb.opencga.core.models.organizations.OrganizationUpdateParams; +import org.opencb.opencga.core.models.project.Project; +import org.opencb.opencga.core.models.project.ProjectCreateParams; +import org.opencb.opencga.core.models.project.ProjectOrganism; +import org.opencb.opencga.core.models.study.Group; +import org.opencb.opencga.core.models.study.GroupUpdateParams; +import org.opencb.opencga.core.models.study.Study; +import org.opencb.opencga.core.models.study.StudyAclParams; +import org.opencb.opencga.core.models.user.*; +import org.opencb.opencga.core.response.OpenCGAResult; +import org.opencb.opencga.core.testclassification.duration.MediumTests; + +import javax.naming.NamingException; +import java.io.IOException; +import java.util.*; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.opencb.opencga.core.common.JacksonUtils.getUpdateObjectMapper; + +@Category(MediumTests.class) +public class UserManagerTest extends AbstractManagerTest { + + @Test + public void createOpencgaUserTest() throws CatalogException { + thrown.expect(CatalogException.class); + thrown.expectMessage("forbidden"); + catalogManager.getUserManager().create(new User().setId(ParamConstants.OPENCGA_USER_ID).setName(orgOwnerUserId) + .setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); + } + + + @Test + public void testAdminUserExists() throws Exception { + String token = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); + JwtPayload payload = catalogManager.getUserManager().validateToken(token); + assertEquals(ParamConstants.OPENCGA_USER_ID, payload.getUserId()); + assertEquals(ParamConstants.ADMIN_ORGANIZATION, payload.getOrganization()); + } + + @Test + public void searchUsersTest() throws CatalogException { + OpenCGAResult search = catalogManager.getUserManager().search(organizationId, new Query(), QueryOptions.empty(), opencgaToken); + assertEquals(8, search.getNumResults()); + for (User user : search.getResults()) { + if (noAccessUserId1.equals(user.getId())) { + assertEquals(0, user.getProjects().size()); + } else if (user.getId().startsWith("normalUser")) { + assertEquals(1, user.getProjects().size()); + } else { + assertEquals(2, user.getProjects().size()); + } + } + + search = catalogManager.getUserManager().search(null, new Query(), QueryOptions.empty(), ownerToken); + assertEquals(8, search.getNumResults()); + + search = catalogManager.getUserManager().search(null, new Query(), QueryOptions.empty(), orgAdminToken2); + assertEquals(8, search.getNumResults()); + + search = catalogManager.getUserManager().search(null, new Query(), QueryOptions.empty(), orgAdminToken1); + assertEquals(8, search.getNumResults()); + + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().search(null, new Query(), + QueryOptions.empty(), studyAdminToken1)); + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().search(null, new Query(), + QueryOptions.empty(), normalToken1)); + } + + @Test + public void testGetToken() throws Exception { + String token = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); + Map claims = new HashMap<>(); + claims.put("a", "hola"); + claims.put("ab", "byw"); + // Create a token valid for 1 second + String expiringToken = catalogManager.getUserManager().getToken(ParamConstants.ADMIN_ORGANIZATION, "opencga", claims, 1L, token); + assertEquals("opencga", catalogManager.getUserManager().validateToken(expiringToken).getUserId()); + + String nonExpiringToken = catalogManager.getUserManager().getNonExpiringToken(ParamConstants.ADMIN_ORGANIZATION, "opencga", claims, token); + assertEquals("opencga", catalogManager.getUserManager().validateToken(nonExpiringToken).getUserId()); + + Thread.sleep(1000); + thrown.expect(CatalogAuthenticationException.class); + thrown.expectMessage("expired"); + assertEquals("opencga", catalogManager.getUserManager().validateToken(expiringToken).getUserId()); + } + + @Test + public void loginWithoutOrganizationId() throws CatalogException { + String token = catalogManager.getUserManager().login(null, ParamConstants.OPENCGA_USER_ID, TestParamConstants.ADMIN_PASSWORD).getToken(); + assertTrue(StringUtils.isNotEmpty(token)); + JwtPayload jwtPayload = new JwtPayload(token); + assertEquals(ParamConstants.ADMIN_ORGANIZATION, jwtPayload.getOrganization()); + + token = catalogManager.getUserManager().login(null, orgOwnerUserId, TestParamConstants.PASSWORD).getToken(); + assertTrue(StringUtils.isNotEmpty(token)); + jwtPayload = new JwtPayload(token); + assertEquals(organizationId, jwtPayload.getOrganization()); + + // Create a third organization + catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId("other").setName("Test"), QueryOptions.empty(), opencgaToken); + token = catalogManager.getUserManager().login(null, ParamConstants.OPENCGA_USER_ID, TestParamConstants.ADMIN_PASSWORD).getToken(); + assertTrue(StringUtils.isNotEmpty(token)); + jwtPayload = new JwtPayload(token); + assertEquals(ParamConstants.ADMIN_ORGANIZATION, jwtPayload.getOrganization()); + + thrown.expect(CatalogParameterException.class); + thrown.expectMessage("organization"); + catalogManager.getUserManager().login(null, orgOwnerUserId, TestParamConstants.PASSWORD); + } + + @Test + public void testCreateExistingUser() throws Exception { + thrown.expect(CatalogException.class); + thrown.expectMessage(containsString("already exists")); + catalogManager.getUserManager().create(orgOwnerUserId, "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, organizationId, + null, opencgaToken); + } + + @Test + public void testCreateAnonymousUser() throws Exception { + thrown.expect(CatalogParameterException.class); + thrown.expectMessage(containsString("reserved")); + catalogManager.getUserManager().create(ParamConstants.ANONYMOUS_USER_ID, "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, + organizationId, null, opencgaToken); + } + + @Test + public void testCreateRegisteredUser() throws Exception { + thrown.expect(CatalogParameterException.class); + thrown.expectMessage(containsString("reserved")); + catalogManager.getUserManager().create(ParamConstants.REGISTERED_USERS, "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, organizationId, null, + opencgaToken); + } + + @Test + public void testLogin() throws Exception { + catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD); + + thrown.expect(CatalogAuthenticationException.class); + thrown.expectMessage(allOf(containsString("Incorrect"), containsString("password"))); + catalogManager.getUserManager().login(organizationId, normalUserId1, "fakePassword"); + } + + @Test + public void refreshTokenTest() throws Exception { + String refreshToken = catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD).getRefreshToken(); + AuthenticationResponse authenticationResponse = catalogManager.getUserManager().refreshToken(refreshToken); + assertNotNull(authenticationResponse); + assertNotNull(authenticationResponse.getToken()); + } + + @Test + public void anonymousUserLoginTest() throws CatalogException { + AuthenticationResponse authResponse = catalogManager.getUserManager().loginAnonymous(organizationId); + assertNotNull(authResponse.getToken()); + + String org2 = "otherOrg"; + catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId(org2), QueryOptions.empty(), opencgaToken); + catalogManager.getUserManager().create(new User().setId("userFromOrg2").setName("name").setOrganization(org2), TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getOrganizationManager().update(org2, new OrganizationUpdateParams().setOwner("userFromOrg2"), null, opencgaToken); + String owner2Token = catalogManager.getUserManager().login(org2, "userFromOrg2", TestParamConstants.PASSWORD).getToken(); + Project p = catalogManager.getProjectManager().create(new ProjectCreateParams() + .setId("project") + .setOrganism(new ProjectOrganism("Homo sapiens", "GRCh38")), + INCLUDE_RESULT, owner2Token).first(); + Study study = catalogManager.getStudyManager().create(p.getFqn(), new Study().setId("study"), INCLUDE_RESULT, owner2Token).first(); + + try { + catalogManager.getUserManager().loginAnonymous(org2); + fail("Anonymous user should not get a token for that organization as it has not been granted any kind of access"); + } catch (Exception e) { + assertEquals(CatalogAuthenticationException.class, e.getClass()); + assertTrue(e.getMessage().contains("not found")); + } + + catalogManager.getStudyManager().updateGroup(study.getFqn(), ParamConstants.MEMBERS_GROUP, ParamUtils.BasicUpdateAction.ADD, + new GroupUpdateParams(Collections.singletonList("*")), owner2Token); + authResponse = catalogManager.getUserManager().loginAnonymous(org2); + assertNotNull(authResponse.getToken()); + + + catalogManager.getStudyManager().updateGroup(study.getFqn(), ParamConstants.MEMBERS_GROUP, ParamUtils.BasicUpdateAction.REMOVE, + new GroupUpdateParams(Collections.singletonList("*")), owner2Token); + thrown.expect(CatalogAuthenticationException.class); + thrown.expectMessage("not found"); + catalogManager.getUserManager().loginAnonymous(org2); + } + + @Test + public void incrementLoginAttemptsTest() throws CatalogException { + assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); + User user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); + UserInternal userInternal3 = user.getInternal(); + assertEquals(1, userInternal3.getAccount().getFailedAttempts()); + assertEquals(UserStatus.READY, user.getInternal().getStatus().getId()); + + for (int i = 2; i < 5; i++) { + assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); + user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); + UserInternal userInternal = user.getInternal(); + assertEquals(i, userInternal.getAccount().getFailedAttempts()); + assertEquals(UserStatus.READY, user.getInternal().getStatus().getId()); + } + + assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); + user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); + UserInternal userInternal2 = user.getInternal(); + assertEquals(5, userInternal2.getAccount().getFailedAttempts()); + assertEquals(UserStatus.BANNED, user.getInternal().getStatus().getId()); + + CatalogAuthenticationException incorrect = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, "incorrect")); + assertTrue(incorrect.getMessage().contains("banned")); + user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); + UserInternal userInternal1 = user.getInternal(); + assertEquals(5, userInternal1.getAccount().getFailedAttempts()); + assertEquals(UserStatus.BANNED, user.getInternal().getStatus().getId()); + + CatalogAuthenticationException authException = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD)); + assertTrue(authException.getMessage().contains("banned")); + + // Remove ban from user + catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.READY, QueryOptions.empty(), ownerToken); + user = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), ownerToken).first(); + UserInternal userInternal = user.getInternal(); + assertEquals(0, userInternal.getAccount().getFailedAttempts()); + assertEquals(UserStatus.READY, user.getInternal().getStatus().getId()); + + String token = catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD).getToken(); + assertNotNull(token); + } + + @Test + public void changeUserStatusTest() throws CatalogException { + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.BANNED, QueryOptions.empty(), normalToken1)); + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.BANNED, QueryOptions.empty(), studyAdminToken1)); + assertThrows(CatalogParameterException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.BANNED, QueryOptions.empty(), ownerToken)); + catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), ownerToken); + catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), orgAdminToken1); + catalogManager.getUserManager().changeStatus(organizationId, normalUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), opencgaToken); + + catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), ownerToken); + CatalogAuthorizationException authException = assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, orgOwnerUserId, UserStatus.SUSPENDED, QueryOptions.empty(), ownerToken)); + assertTrue(authException.getMessage().contains("own account")); + + authException = assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, UserStatus.SUSPENDED, QueryOptions.empty(), orgAdminToken2)); + assertTrue(authException.getMessage().contains("suspend administrators")); + + CatalogAuthenticationException incorrect = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, orgAdminUserId1, TestParamConstants.PASSWORD)); + assertTrue(incorrect.getMessage().contains("suspended")); + + catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, UserStatus.READY, QueryOptions.empty(), orgAdminToken2); + String token = catalogManager.getUserManager().login(organizationId, orgAdminUserId1, TestParamConstants.PASSWORD).getToken(); + assertNotNull(token); + + CatalogParameterException paramException = assertThrows(CatalogParameterException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, orgAdminUserId1, "NOT_A_STATUS", QueryOptions.empty(), orgAdminToken2)); + assertTrue(paramException.getMessage().contains("Invalid status")); + + CatalogDBException dbException = assertThrows(CatalogDBException.class, () -> catalogManager.getUserManager().changeStatus(organizationId, "notAUser", UserStatus.SUSPENDED, QueryOptions.empty(), orgAdminToken2)); + assertTrue(dbException.getMessage().contains("not exist")); + } + + @Test + public void loginExpiredAccountTest() throws CatalogException { + // Expire account of normalUserId1 + ObjectMap params = new ObjectMap(UserDBAdaptor.QueryParams.INTERNAL_ACCOUNT_EXPIRATION_DATE.key(), TimeUtils.getTime()); + catalogManager.getUserManager().getUserDBAdaptor(organizationId).update(normalUserId1, params); + + CatalogAuthenticationException authException = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD)); + assertTrue(authException.getMessage().contains("expired")); + + // Ensure it doesn't matter whether opencga account is expired or not + catalogManager.getUserManager().getUserDBAdaptor(ParamConstants.ADMIN_ORGANIZATION).update(ParamConstants.OPENCGA_USER_ID, params); + String token = catalogManager.getUserManager().login(ParamConstants.ADMIN_ORGANIZATION, ParamConstants.OPENCGA_USER_ID, TestParamConstants.ADMIN_PASSWORD).getToken(); + assertNotNull(token); + } + + @Test + public void updateUserTest() throws JsonProcessingException, CatalogException { + UserUpdateParams userUpdateParams = new UserUpdateParams() + .setName("newName") + .setEmail("mail@mail.com"); + ObjectMap updateParams = new ObjectMap(getUpdateObjectMapper().writeValueAsString(userUpdateParams)); + User user = catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, normalToken1).first(); + assertEquals(userUpdateParams.getName(), user.getName()); + assertEquals(userUpdateParams.getEmail(), user.getEmail()); + + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, normalToken2)); + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, opencgaToken)); + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, ownerToken)); + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, orgAdminToken1)); + assertThrows(CatalogAuthorizationException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams, INCLUDE_RESULT, studyAdminToken1)); + + userUpdateParams = new UserUpdateParams() + .setEmail("notAnEmail"); + ObjectMap updateParams2 = new ObjectMap(getUpdateObjectMapper().writeValueAsString(userUpdateParams)); + assertThrows(CatalogParameterException.class, () -> catalogManager.getUserManager().update(normalUserId1, updateParams2, INCLUDE_RESULT, normalToken1)); + } + + @Test + public void testGetUserInfo() throws CatalogException { + // OpenCGA administrator + DataResult user = catalogManager.getUserManager().get(organizationId, + Arrays.asList(normalUserId1, normalUserId2, normalUserId3), new QueryOptions(), opencgaToken); + assertEquals(3, user.getNumResults()); + assertEquals(normalUserId1, user.getResults().get(0).getId()); + assertEquals(normalUserId2, user.getResults().get(1).getId()); + assertEquals(normalUserId3, user.getResults().get(2).getId()); + + // Organization owner + user = catalogManager.getUserManager().get(organizationId, Arrays.asList(normalUserId1, normalUserId2, normalUserId3), + new QueryOptions(), ownerToken); + assertEquals(3, user.getNumResults()); + assertEquals(normalUserId1, user.getResults().get(0).getId()); + assertEquals(normalUserId2, user.getResults().get(1).getId()); + assertEquals(normalUserId3, user.getResults().get(2).getId()); + + // Organization administrator + user = catalogManager.getUserManager().get(organizationId, Arrays.asList(normalUserId1, normalUserId2, normalUserId3), + new QueryOptions(), orgAdminToken1); + assertEquals(3, user.getNumResults()); + assertEquals(normalUserId1, user.getResults().get(0).getId()); + assertEquals(normalUserId2, user.getResults().get(1).getId()); + assertEquals(normalUserId3, user.getResults().get(2).getId()); + + thrown.expect(CatalogAuthorizationException.class); + thrown.expectMessage("organization"); + catalogManager.getUserManager().get(organizationId, Arrays.asList(normalUserId1, normalUserId2, normalUserId3), new QueryOptions(), + studyAdminToken1); + } + + @Test + public void testGetProjectsFromUserInfo() throws CatalogException { + String userId = organizationId; + catalogManager.getUserManager().create(userId, "test", "mail@mail.com", TestParamConstants.PASSWORD, organizationId, null, + opencgaToken); + catalogManager.getStudyManager().updateGroup(studyFqn, ParamConstants.MEMBERS_GROUP, ParamUtils.BasicUpdateAction.ADD, + new GroupUpdateParams(Collections.singletonList("test")), ownerToken); + String token = catalogManager.getUserManager().login(organizationId, userId, TestParamConstants.PASSWORD).getToken(); + + DataResult user = catalogManager.getUserManager().get(organizationId, userId, new QueryOptions(), token); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(organizationId, normalUserId3, new QueryOptions(), normalToken3); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(organizationId, orgOwnerUserId, new QueryOptions(), ownerToken); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(organizationId, orgAdminUserId1, new QueryOptions(), orgAdminToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(organizationId, studyAdminUserId1, new QueryOptions(), studyAdminToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(organizationId, normalUserId1, new QueryOptions(), orgAdminToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + + user = catalogManager.getUserManager().get(null, normalUserId1, new QueryOptions(), normalToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(null, normalUserId3, new QueryOptions(), normalToken3); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(null, orgOwnerUserId, new QueryOptions(), ownerToken); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(null, orgAdminUserId1, new QueryOptions(), orgAdminToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(null, studyAdminUserId1, new QueryOptions(), studyAdminToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + + user = catalogManager.getUserManager().get(null, normalUserId1, new QueryOptions(), orgAdminToken1); + assertTrue(CollectionUtils.isNotEmpty(user.first().getProjects())); + System.out.println(user.first().getProjects().size()); + } + + @Test + public void testModifyUser() throws CatalogException, InterruptedException, IOException { + ObjectMap params = new ObjectMap(); + String newName = "Changed Name " + RandomStringUtils.randomAlphanumeric(10); + String newPassword = PasswordUtils.getStrongRandomPassword(); + String newEmail = "new@email.ac.uk"; + + params.put("name", newName); + + Thread.sleep(10); + + catalogManager.getUserManager().update(orgOwnerUserId, params, null, ownerToken); + catalogManager.getUserManager().update(orgOwnerUserId, new ObjectMap("email", newEmail), null, ownerToken); + catalogManager.getUserManager().changePassword(organizationId, orgOwnerUserId, TestParamConstants.PASSWORD, newPassword); + + List userList = catalogManager.getUserManager().get(organizationId, orgOwnerUserId, new QueryOptions(QueryOptions + .INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key(), + UserDBAdaptor.QueryParams.ATTRIBUTES.key())), ownerToken).getResults(); + User userPost = userList.get(0); + System.out.println("userPost = " + userPost); + assertEquals(userPost.getName(), newName); + assertEquals(userPost.getEmail(), newEmail); + + catalogManager.getUserManager().login(organizationId, orgOwnerUserId, newPassword); + CatalogDBException exception = assertThrows(CatalogDBException.class, + () -> catalogManager.getUserManager().changePassword(organizationId, orgOwnerUserId, newPassword, TestParamConstants.PASSWORD)); + assertTrue(exception.getMessage().contains("The new password has already been used")); + + String anotherPassword = PasswordUtils.getStrongRandomPassword(); + catalogManager.getUserManager().changePassword(organizationId, orgOwnerUserId, newPassword, anotherPassword); + catalogManager.getUserManager().login(organizationId, orgOwnerUserId, anotherPassword); + + try { + params = new ObjectMap(); + params.put("password", "1234321"); + catalogManager.getUserManager().update(orgOwnerUserId, params, null, ownerToken); + fail("Expected exception"); + } catch (CatalogDBException e) { + System.out.println(e); + } + + try { + catalogManager.getUserManager().update(orgOwnerUserId, params, null, orgAdminToken1); + fail("Expected exception"); + } catch (CatalogException e) { + System.out.println(e); + } + } + + @Test + public void automaticPasswordExpirationTest() throws CatalogException { + // Set 1 day of password expiration + catalogManager.getConfiguration().getAccount().setPasswordExpirationDays(1); + + String oneDay = TimeUtils.getTime(TimeUtils.addDaysToCurrentDate(1)); + String twoDays = TimeUtils.getTime(TimeUtils.addDaysToCurrentDate(2)); + + User user = new User().setId("tempUser"); + String password = PasswordUtils.getStrongRandomPassword(); + User storedUser = catalogManager.getUserManager().create(user, password, ownerToken).first(); + Account account2 = storedUser.getInternal().getAccount(); + assertTrue(Long.parseLong(oneDay) <= Long.parseLong(account2.getPassword().getExpirationDate())); + Account account1 = storedUser.getInternal().getAccount(); + assertTrue(Long.parseLong(twoDays) > Long.parseLong(account1.getPassword().getExpirationDate())); + + // Set 1 day of password expiration + catalogManager.getConfiguration().getAccount().setPasswordExpirationDays(-5); + user = new User().setId("tempUser2"); + storedUser = catalogManager.getUserManager().create(user, password, ownerToken).first(); + Account account = storedUser.getInternal().getAccount(); + assertNull(account.getPassword().getExpirationDate()); + } + + @Test + public void loginUserPasswordExpiredTest() throws CatalogException { + try (CatalogManager mockCatalogManager = mockCatalogManager()) { + UserDBAdaptor userDBAdaptor = mockCatalogManager.getUserManager().getUserDBAdaptor(organizationId); + + OpenCGAResult result = mockCatalogManager.getUserManager().get(organizationId, normalUserId1, new QueryOptions(), normalToken1); + + // Set password expired 2 days ago + Date date = TimeUtils.addDaysToCurrentDate(-2); + String beforeYesterday = TimeUtils.getTime(date); + User user = result.first(); + user.getInternal().getAccount().getPassword().setExpirationDate(beforeYesterday); + + Mockito.doReturn(result).when(userDBAdaptor).get(normalUserId1, UserManager.INCLUDE_INTERNAL); + CatalogAuthenticationException exception = assertThrows(CatalogAuthenticationException.class, + () -> mockCatalogManager.getUserManager().login(organizationId, normalUserId1, TestParamConstants.PASSWORD)); + assertTrue(exception.getMessage().contains("expired on " + beforeYesterday)); + } + } + + @Test + public void changePasswordTest() throws CatalogException { + String newPassword = PasswordUtils.getStrongRandomPassword(); + catalogManager.getUserManager().changePassword(organizationId, normalUserId1, TestParamConstants.PASSWORD, newPassword); + catalogManager.getUserManager().login(organizationId, normalUserId1, newPassword); + + CatalogDBException exception = assertThrows(CatalogDBException.class, + () -> catalogManager.getUserManager().changePassword(organizationId, normalUserId1, TestParamConstants.PASSWORD, newPassword)); + assertTrue(exception.getMessage().contains("verify that the current password is correct")); + + String anotherPassword = PasswordUtils.getStrongRandomPassword(); + catalogManager.getUserManager().changePassword(organizationId, normalUserId1, newPassword, anotherPassword); + catalogManager.getUserManager().login(organizationId, normalUserId1, anotherPassword); + } + + @Test + public void testUpdateUserConfig() throws CatalogException { + Map map = new HashMap<>(); + map.put("key1", "value1"); + map.put("key2", "value2"); + catalogManager.getUserManager().setConfig(normalUserId1, "a", map, normalToken1); + + Map config = (Map) catalogManager.getUserManager().getConfig(normalUserId1, "a", normalToken1).first(); + assertEquals(2, config.size()); + assertEquals("value1", config.get("key1")); + assertEquals("value2", config.get("key2")); + + map = new HashMap<>(); + map.put("key2", "value3"); + catalogManager.getUserManager().setConfig(normalUserId1, "a", map, normalToken1); + config = (Map) catalogManager.getUserManager().getConfig(normalUserId1, "a", normalToken1).first(); + assertEquals(1, config.size()); + assertEquals("value3", config.get("key2")); + + catalogManager.getUserManager().deleteConfig(normalUserId1, "a", normalToken1); + + thrown.expect(CatalogException.class); + thrown.expectMessage("not found"); + catalogManager.getUserManager().getConfig(normalUserId1, "a", normalToken1); + } + + private String getAdminToken() throws CatalogException, IOException { + return catalogManager.getUserManager().loginAsAdmin("admin").getToken(); + } + + @Test + public void createUserUsingMailAsId() throws CatalogException { + catalogManager.getUserManager().create(new User().setId("hello.mail@mymail.org").setName("Hello"), TestParamConstants.PASSWORD, ownerToken); + AuthenticationResponse login = catalogManager.getUserManager().login(organizationId, "hello.mail@mymail.org", TestParamConstants.PASSWORD); + assertNotNull(login); + User user = catalogManager.getUserManager().get(organizationId, "hello.mail@mymail.org", new QueryOptions(), login.getToken()).first(); + assertEquals("hello.mail@mymail.org", user.getId()); + } + + @Test + public void getUserInfoTest() throws CatalogException { + OpenCGAResult result = catalogManager.getUserManager().get(organizationId, orgOwnerUserId, QueryOptions.empty(), ownerToken); + assertEquals(1, result.getNumResults()); + assertNotNull(result.first().getProjects()); + assertEquals(2, result.first().getProjects().size()); + + result = catalogManager.getUserManager().get(organizationId, orgAdminUserId1, QueryOptions.empty(), orgAdminToken1); + assertEquals(1, result.getNumResults()); + assertNotNull(result.first().getProjects()); + assertEquals(2, result.first().getProjects().size()); + + result = catalogManager.getUserManager().get(organizationId, studyAdminUserId1, QueryOptions.empty(), studyAdminToken1); + assertEquals(1, result.getNumResults()); + assertNotNull(result.first().getProjects()); + assertEquals(2, result.first().getProjects().size()); + + result = catalogManager.getUserManager().get(organizationId, normalUserId1, QueryOptions.empty(), normalToken1); + assertEquals(1, result.getNumResults()); + assertNotNull(result.first().getProjects()); + assertEquals(1, result.first().getProjects().size()); + } + + @Ignore + @Test + public void importLdapUsers() throws CatalogException, NamingException, IOException { + // Action only for admins + catalogManager.getUserManager().importRemoteEntities(organizationId, "ldap", Arrays.asList("pfurio", "imedina"), false, null, null, + getAdminToken()); + // TODO: Validate the users have been imported + } + + // To make this test work we will need to add a correct user and password to be able to login + @Ignore + @Test + public void loginNotRegisteredUsers() throws CatalogException { + // Action only for admins + Group group = new Group("ldap", Collections.emptyList()).setSyncedFrom(new Group.Sync("ldap", "bio")); + catalogManager.getStudyManager().createGroup(studyFqn, group, ownerToken); + catalogManager.getStudyManager().updateAcl(studyFqn, "@ldap", new StudyAclParams("", "view_only"), + ParamUtils.AclAction.SET, ownerToken); + String token = catalogManager.getUserManager().login(organizationId, orgOwnerUserId, "password").getToken(); + + assertEquals(9, catalogManager.getSampleManager().count(studyFqn, new Query(), token).getNumTotalResults()); + + // We remove the permissions for group ldap + catalogManager.getStudyManager().updateAcl(studyFqn, "@ldap", new StudyAclParams("", ""), + ParamUtils.AclAction.RESET, this.ownerToken); + + assertEquals(0, catalogManager.getSampleManager().count(studyFqn, new Query(), token).getNumTotalResults()); + } + + @Ignore + @Test + public void syncUsers() throws CatalogException { + // Action only for admins + String token = catalogManager.getUserManager().loginAsAdmin("admin").getToken(); + + catalogManager.getUserManager().importRemoteGroupOfUsers(organizationId, "ldap", "bio", "bio", studyFqn, true, token); + DataResult bio = catalogManager.getStudyManager().getGroup(studyFqn, "bio", this.ownerToken); + + assertEquals(1, bio.getNumResults()); + assertEquals(0, bio.first().getUserIds().size()); + + catalogManager.getUserManager().syncAllUsersOfExternalGroup(organizationId, studyFqn, "ldap", token); + bio = catalogManager.getStudyManager().getGroup(studyFqn, "bio", this.ownerToken); + + assertEquals(1, bio.getNumResults()); + assertTrue(!bio.first().getUserIds().isEmpty()); + } + + @Ignore + @Test + public void importLdapGroups() throws CatalogException, IOException { + // Action only for admins + String remoteGroup = "bio"; + String internalGroup = "test"; + catalogManager.getUserManager().importRemoteGroupOfUsers(organizationId, "ldap", remoteGroup, internalGroup, studyFqn, true, getAdminToken()); + + DataResult test = catalogManager.getStudyManager().getGroup(studyFqn, "test", ownerToken); + assertEquals(1, test.getNumResults()); + assertEquals("@test", test.first().getId()); + assertTrue(test.first().getUserIds().size() > 0); + +// internalGroup = "test1"; +// try { +// catalogManager.getUserManager().importRemoteGroupOfUsers("ldap", remoteGroup, internalGroup, study, getAdminToken()); +// fail("Should not be possible creating another group containing the same users that belong to a different group"); +// } catch (CatalogException e) { +// System.out.println(e.getMessage()); +// } + + remoteGroup = "bioo"; + internalGroup = "test2"; + thrown.expect(CatalogException.class); + thrown.expectMessage("not found"); + catalogManager.getUserManager().importRemoteGroupOfUsers(organizationId, "ldap", remoteGroup, internalGroup, studyFqn, true, getAdminToken()); + } + + +} diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/templates/TemplateManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/templates/TemplateManagerTest.java index f7b28721987..ca96f875326 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/templates/TemplateManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/templates/TemplateManagerTest.java @@ -11,7 +11,6 @@ import org.opencb.opencga.catalog.templates.TemplateManager; import org.opencb.opencga.catalog.templates.config.TemplateManifest; import org.opencb.opencga.core.models.study.Study; -import org.opencb.opencga.core.models.user.Account; import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.testclassification.duration.MediumTests; @@ -25,11 +24,14 @@ public class TemplateManagerTest extends AbstractManagerTest { public void test() throws Exception { CatalogManager catalogManager = catalogManagerResource.getCatalogManager(); - catalogManager.getUserManager().create(new User().setId("user1").setName("User 1").setOrganization(organizationId).setAccount(new Account()), + catalogManager.getUserManager().create(new User().setId("user1").setName("User 1").setOrganization(organizationId), + TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getUserManager().create(new User().setId("user2").setName("User 2").setOrganization(organizationId), + TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getUserManager().create(new User().setId("user3").setName("User 3").setOrganization(organizationId), + TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getUserManager().create(new User().setId("user4").setName("User 4").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("user2").setName("User 2").setOrganization(organizationId).setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("user3").setName("User 3").setOrganization(organizationId).setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("user4").setName("User 4").setOrganization(organizationId).setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); catalogManager.getProjectManager().create("project", "Project", "", "hsapiens", "common", "GRCh38", QueryOptions.empty(), ownerToken); catalogManager.getStudyManager().create("project", new Study().setId("study"), QueryOptions.empty(), ownerToken); @@ -54,13 +56,13 @@ public void test() throws Exception { public void test_yaml() throws Exception { CatalogManager catalogManager = catalogManagerResource.getCatalogManager(); - catalogManager.getUserManager().create(new User().setId("user1").setName("User 1").setOrganization(organizationId).setAccount(new Account()), + catalogManager.getUserManager().create(new User().setId("user1").setName("User 1").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("user2").setName("User 2").setOrganization(organizationId).setAccount(new Account()), + catalogManager.getUserManager().create(new User().setId("user2").setName("User 2").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("user3").setName("User 3").setOrganization(organizationId).setAccount(new Account()), + catalogManager.getUserManager().create(new User().setId("user3").setName("User 3").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); - catalogManager.getUserManager().create(new User().setId("user4").setName("User 4").setOrganization(organizationId).setAccount(new Account()), + catalogManager.getUserManager().create(new User().setId("user4").setName("User 4").setOrganization(organizationId), TestParamConstants.PASSWORD, opencgaToken); catalogManager.getProjectManager().create("project", "Project", "", "hsapiens", "common", "GRCh38", QueryOptions.empty(), ownerToken); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java b/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java index 835f89a61a6..d4f3142bc1d 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java @@ -441,9 +441,16 @@ public class FieldConstants { public static final String USER_ACCOUNT = "User account."; //Account - public static final String ACCOUNT_TYPE = "User account type can have the values GUEST, FULL and ADMINISTRATOR."; - public static final String ACCOUNT_EXPIRATION_DATE_DESCRIPTION = "Date the account expires."; - public static final String ACCOUNT_AUTHENTICATION = "How the account is authenticated"; + public static final String INTERNAL_ACCOUNT_EXPIRATION_DATE_DESCRIPTION = "Date the account expires."; + public static final String INTERNAL_ACCOUNT_FAILED_ATTEMPTS_DESCRIPTION = "Number of consecutive failed attempts. When the user logs" + + " in successfully, this field is automatically reset to 0."; + public static final String INTERNAL_ACCOUNT_PASSWORD_DESCRIPTION = "Object containing the last time the password was changed and the" + + " expiration date."; + public static final String INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE_DESCRIPTION = "Date the user's password was last changed. This " + + "field will be null if the user account origin is different from OpenCGA."; + public static final String INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE_DESCRIPTION = "Date the user's password expires. This field will" + + " be null if the user account origin is different from OpenCGA and the passwordExpiration feature is disabled."; + public static final String INTERNAL_ACCOUNT_AUTHENTICATION = "How the account is authenticated"; public static final String USER_QUOTA = "User quota"; public static final String USER_PROJECTS = "A List with related projects."; public static final String USER_SHARED_PROJECTS = "A List with shared projects."; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/common/TimeUtils.java b/opencga-core/src/main/java/org/opencb/opencga/core/common/TimeUtils.java index da6aa39f1f6..c0574f0afdf 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/common/TimeUtils.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/common/TimeUtils.java @@ -135,6 +135,13 @@ public static Date add1YeartoDate(Date date) { return new Date(cal.getTimeInMillis()); } + public static Date addDaysToCurrentDate(int days) { + Calendar cal = new GregorianCalendar(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_YEAR, days); + return new Date(cal.getTimeInMillis()); + } + public static Date toDate(String dateStr) { Date date = null; try { diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/config/AccountConfiguration.java b/opencga-core/src/main/java/org/opencb/opencga/core/config/AccountConfiguration.java new file mode 100644 index 00000000000..f467a93d37d --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/config/AccountConfiguration.java @@ -0,0 +1,42 @@ +package org.opencb.opencga.core.config; + +public class AccountConfiguration { + + private int maxLoginAttempts; + private int passwordExpirationDays; + + public AccountConfiguration() { + } + + public AccountConfiguration(int maxLoginAttempts, int passwordExpirationDays) { + this.maxLoginAttempts = maxLoginAttempts; + this.passwordExpirationDays = passwordExpirationDays; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("AccountConfiguration{"); + sb.append("maxLoginAttempts=").append(maxLoginAttempts); + sb.append(", passwordExpirationDays=").append(passwordExpirationDays); + sb.append('}'); + return sb.toString(); + } + + public int getMaxLoginAttempts() { + return maxLoginAttempts; + } + + public AccountConfiguration setMaxLoginAttempts(int maxLoginAttempts) { + this.maxLoginAttempts = maxLoginAttempts; + return this; + } + + public int getPasswordExpirationDays() { + return passwordExpirationDays; + } + + public AccountConfiguration setPasswordExpirationDays(int passwordExpirationDays) { + this.passwordExpirationDays = passwordExpirationDays; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/config/Configuration.java b/opencga-core/src/main/java/org/opencb/opencga/core/config/Configuration.java index 600def109ff..b7b869c728c 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/config/Configuration.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/config/Configuration.java @@ -44,7 +44,7 @@ public class Configuration { private String workspace; private String jobDir; - private int maxLoginAttempts; + private AccountConfiguration account; private Monitor monitor; private HealthCheck healthCheck; @@ -79,6 +79,7 @@ public Configuration() { analysis = new Analysis(); panel = new Panel(); server = new ServerConfiguration(); + account = new AccountConfiguration(); } public void serialize(OutputStream configurationOututStream) throws IOException { @@ -113,7 +114,6 @@ public static Configuration load(InputStream configurationInputStream, String fo } catch (IOException e) { throw new IOException("Configuration file could not be parsed: " + e.getMessage(), e); } - addDefaultValueIfMissing(configuration); // We must always overwrite configuration with environment parameters @@ -122,8 +122,15 @@ public static Configuration load(InputStream configurationInputStream, String fo } private static void addDefaultValueIfMissing(Configuration configuration) { - if (configuration.getMaxLoginAttempts() <= 0) { - configuration.setMaxLoginAttempts(5); + if (configuration.getAccount() == null) { + configuration.setAccount(new AccountConfiguration()); + } + if (configuration.getAccount().getMaxLoginAttempts() <= 0) { + configuration.getAccount().setMaxLoginAttempts(5); + } + if (configuration.getAccount().getPasswordExpirationDays() < 0) { + // Disable password expiration by default + configuration.getAccount().setPasswordExpirationDays(0); } } @@ -147,7 +154,8 @@ private static void overwriteWithEnvironmentVariables(Configuration configuratio configuration.getMonitor().setPort(Integer.parseInt(value)); break; case "OPENCGA.MAX_LOGIN_ATTEMPTS": - configuration.setMaxLoginAttempts(Integer.parseInt(value)); + case "OPENCGA.ACCOUNT.MAX_LOGIN_ATTEMPTS": + configuration.getAccount().setMaxLoginAttempts(Integer.parseInt(value)); break; case "OPENCGA_EXECUTION_MODE": case "OPENCGA_EXECUTION_ID": @@ -203,6 +211,16 @@ public static void reportUnusedField(String field, Object value) { } } + public static void reportMovedField(String previousField, String newField, Object value) { + // Report only if the value is not null and not an empty string + if (value != null && !(value instanceof String && ((String) value).isEmpty())) { + if (reportedFields.add(previousField)) { + // Only log the first time a field is found + logger.warn("Option '{}' with value '{}' was moved to '{}'.", previousField, value, newField); + } + } + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("Configuration{"); @@ -211,7 +229,7 @@ public String toString() { sb.append(", databasePrefix='").append(databasePrefix).append('\''); sb.append(", workspace='").append(workspace).append('\''); sb.append(", jobDir='").append(jobDir).append('\''); - sb.append(", maxLoginAttempts=").append(maxLoginAttempts); + sb.append(", account=").append(account); sb.append(", monitor=").append(monitor); sb.append(", healthCheck=").append(healthCheck); sb.append(", audit=").append(audit); @@ -292,12 +310,24 @@ public Configuration setJobDir(String jobDir) { return this; } + public AccountConfiguration getAccount() { + return account; + } + + public Configuration setAccount(AccountConfiguration account) { + this.account = account; + return this; + } + + @Deprecated public int getMaxLoginAttempts() { - return maxLoginAttempts; + return account.getMaxLoginAttempts(); } + @Deprecated public Configuration setMaxLoginAttempts(int maxLoginAttempts) { - this.maxLoginAttempts = maxLoginAttempts; + reportMovedField("configuration.yml#maxLoginAttempts", "configuration.yml#account.maxLoginAttempts", maxLoginAttempts); + account.setMaxLoginAttempts(maxLoginAttempts); return this; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Account.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Account.java index f31d4d477b4..293ade331be 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Account.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Account.java @@ -27,44 +27,49 @@ */ public class Account { - @DataField(id = "creationDate", indexed = true, - description = FieldConstants.GENERIC_CREATION_DATE_DESCRIPTION) - private String creationDate; - @DataField(id = "expirationDate", indexed = true, - description = FieldConstants.ACCOUNT_EXPIRATION_DATE_DESCRIPTION) + description = FieldConstants.INTERNAL_ACCOUNT_EXPIRATION_DATE_DESCRIPTION) private String expirationDate; + @DataField(id = "password", since = "3.2.1", description = FieldConstants.INTERNAL_ACCOUNT_PASSWORD_DESCRIPTION) + private Password password; + + @DataField(id = "failedAttempts", description = FieldConstants.INTERNAL_ACCOUNT_FAILED_ATTEMPTS_DESCRIPTION) + private int failedAttempts; @DataField(id = "authentication", indexed = true, uncommentedClasses = {"AccountType"}, - description = FieldConstants.ACCOUNT_AUTHENTICATION) + description = FieldConstants.INTERNAL_ACCOUNT_AUTHENTICATION) private AuthenticationOrigin authentication; public Account() { String creationDate = TimeUtils.getTime(); + // Default 1 year Calendar cal = Calendar.getInstance(); cal.setTime(TimeUtils.toDate(creationDate)); cal.add(Calendar.YEAR, +1); String expirationDate = TimeUtils.getTime(cal.getTime()); - this.creationDate = creationDate; this.expirationDate = expirationDate; + this.password = new Password(); + this.failedAttempts = 0; this.authentication = null; } - public Account(String creationDate, String expirationDate, AuthenticationOrigin authentication) { + public Account(String expirationDate, Password password, int failedAttempts, AuthenticationOrigin authentication) { this.expirationDate = expirationDate; - this.creationDate = creationDate; + this.password = password; + this.failedAttempts = failedAttempts; this.authentication = authentication; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Account{"); - sb.append("creationDate='").append(creationDate).append('\''); - sb.append(", expirationDate='").append(expirationDate).append('\''); - sb.append(", authentication='").append(authentication).append('\''); + sb.append("expirationDate='").append(expirationDate).append('\''); + sb.append(", password=").append(password); + sb.append(", failedAttempts=").append(failedAttempts); + sb.append(", authentication=").append(authentication); sb.append('}'); return sb.toString(); } @@ -78,12 +83,21 @@ public Account setExpirationDate(String expirationDate) { return this; } - public String getCreationDate() { - return creationDate; + public Password getPassword() { + return password; + } + + public Account setPassword(Password password) { + this.password = password; + return this; + } + + public int getFailedAttempts() { + return failedAttempts; } - public Account setCreationDate(String creationDate) { - this.creationDate = creationDate; + public Account setFailedAttempts(int failedAttempts) { + this.failedAttempts = failedAttempts; return this; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java new file mode 100644 index 00000000000..6cc9d5f338d --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java @@ -0,0 +1,48 @@ +package org.opencb.opencga.core.models.user; + +import org.opencb.commons.annotations.DataField; +import org.opencb.opencga.core.api.FieldConstants; + +public class Password { + + @DataField(id = "expirationDate", since = "3.2.1", description = FieldConstants.INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE_DESCRIPTION) + private String expirationDate; + + @DataField(id = "lastChangeDate", since = "3.2.1", description = FieldConstants.INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE_DESCRIPTION) + private String lastChangeDate; + + public Password() { + } + + public Password(String expirationDate, String lastChangeDate) { + this.expirationDate = expirationDate; + this.lastChangeDate = lastChangeDate; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Password{"); + sb.append("expirationDate='").append(expirationDate).append('\''); + sb.append(", lastChangeDate='").append(lastChangeDate).append('\''); + sb.append('}'); + return sb.toString(); + } + + public String getExpirationDate() { + return expirationDate; + } + + public Password setExpirationDate(String expirationDate) { + this.expirationDate = expirationDate; + return this; + } + + public String getLastChangeDate() { + return lastChangeDate; + } + + public Password setLastChangeDate(String lastChangeDate) { + this.lastChangeDate = lastChangeDate; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java index b4d3ef26c02..8694320cee2 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java @@ -16,6 +16,7 @@ package org.opencb.opencga.core.models.user; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.opencb.commons.annotations.DataClass; import org.opencb.commons.annotations.DataField; import org.opencb.commons.datastore.core.ObjectMap; @@ -49,14 +50,11 @@ public class User { @DataField(id = "organization", indexed = true, description = FieldConstants.USER_ORGANIZATION) private String organization; - @DataField(id = "account", indexed = true, description = FieldConstants.USER_ACCOUNT) - private Account account; + @DataField(id = "creationDate", since = "3.2.1", description = FieldConstants.GENERIC_CREATION_DATE_DESCRIPTION) + private String creationDate; - /** - * An object describing the internal information of the User. This is managed by OpenCGA. - * - * @apiNote Internal - */ + @DataField(id = "modificationDate", since = "3.2.1", description = FieldConstants.GENERIC_MODIFICATION_DATE_DESCRIPTION) + private String modificationDate; @DataField(id = "internal", indexed = true, description = FieldConstants.GENERIC_INTERNAL) private UserInternal internal; @@ -89,22 +87,21 @@ public class User { public User() { } - public User(String id, Account account) { - this(id, id, null, null, account, new UserInternal(new UserStatus()), null, Collections.emptyList(), Collections.emptyMap(), + public User(String id) { + this(id, id, null, null, null, null, new UserInternal(new UserStatus()), null, Collections.emptyMap(), new LinkedList<>(), Collections.emptyMap()); } public User(String id, String name, String email, String organization, UserInternal internal) { - this(id, name, email, organization, null, internal, null, new ArrayList<>(), new HashMap<>(), new LinkedList<>(), new HashMap<>()); + this(id, name, email, organization, null, null, internal, null, new HashMap<>(), new LinkedList<>(), new HashMap<>()); } - public User(String id, String name, String email, String organization, Account account, UserInternal internal, UserQuota quota, - List projects, Map configs, List filters, Map attributes) { + public User(String id, String name, String email, String organization, UserInternal internal, UserQuota quota, List projects, + Map configs, List filters, Map attributes) { this.id = id; this.name = name; this.email = email; this.organization = organization; - this.account = account != null ? account : new Account(); this.internal = internal; this.quota = quota; this.projects = projects; @@ -113,6 +110,22 @@ public User(String id, String name, String email, String organization, Account a this.attributes = attributes; } + public User(String id, String name, String email, String organization, String creationDate, String modificationDate, + UserInternal internal, UserQuota quota, Map configs, List filters, + Map attributes) { + this.id = id; + this.name = name; + this.email = email; + this.organization = organization; + this.creationDate = creationDate; + this.modificationDate = modificationDate; + this.internal = internal; + this.quota = quota; + this.configs = configs; + this.filters = filters; + this.attributes = attributes; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("User{"); @@ -120,7 +133,8 @@ public String toString() { sb.append(", name='").append(name).append('\''); sb.append(", email='").append(email).append('\''); sb.append(", organization='").append(organization).append('\''); - sb.append(", account=").append(account); + sb.append(", creationDate='").append(creationDate).append('\''); + sb.append(", modificationDate='").append(modificationDate).append('\''); sb.append(", internal=").append(internal); sb.append(", quota=").append(quota); sb.append(", projects=").append(projects); @@ -167,12 +181,34 @@ public User setOrganization(String organization) { return this; } + public String getCreationDate() { + return creationDate; + } + + public User setCreationDate(String creationDate) { + this.creationDate = creationDate; + return this; + } + + public String getModificationDate() { + return modificationDate; + } + + public User setModificationDate(String modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + @JsonIgnore + @Deprecated public Account getAccount() { - return account; + return getInternal().getAccount(); } + @JsonIgnore + @Deprecated public User setAccount(Account account) { - this.account = account; + getInternal().setAccount(account); return this; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/UserInternal.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/UserInternal.java index 329db613b5b..55a75709bd1 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/UserInternal.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/UserInternal.java @@ -16,32 +16,41 @@ package org.opencb.opencga.core.models.user; +import org.opencb.commons.annotations.DataField; +import org.opencb.opencga.core.api.FieldConstants; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.models.common.Internal; public class UserInternal extends Internal { + @DataField(id = "status", description = FieldConstants.INTERNAL_STATUS_DESCRIPTION) private UserStatus status; - private int failedAttempts; + + @DataField(id = "account", since = "3.2.1", description = FieldConstants.USER_ACCOUNT) + private Account account; public UserInternal() { } public UserInternal(UserStatus status) { - this(TimeUtils.getTime(), TimeUtils.getTime(), status); + this(TimeUtils.getTime(), TimeUtils.getTime(), status, new Account()); + } + + public UserInternal(UserStatus status, Account account) { + this(TimeUtils.getTime(), TimeUtils.getTime(), status, account); } - public UserInternal(String registrationDate, String lastModified, UserStatus status) { + public UserInternal(String registrationDate, String lastModified, UserStatus status1, Account account) { super(null, registrationDate, lastModified); - this.status = status; - this.failedAttempts = 0; + this.status = status1; + this.account = account; } @Override public String toString() { final StringBuilder sb = new StringBuilder("UserInternal{"); sb.append("status=").append(status); - sb.append(", failedAttempts=").append(failedAttempts); + sb.append(", account=").append(account); sb.append(", registrationDate='").append(registrationDate).append('\''); sb.append(", lastModified='").append(lastModified).append('\''); sb.append('}'); @@ -57,12 +66,13 @@ public UserInternal setStatus(UserStatus status) { return this; } - public int getFailedAttempts() { - return failedAttempts; + public Account getAccount() { + return account; } - public UserInternal setFailedAttempts(int failedAttempts) { - this.failedAttempts = failedAttempts; + public UserInternal setAccount(Account account) { + this.account = account; return this; } + } diff --git a/pom.xml b/pom.xml index 84e170213b8..fd542d22621 100644 --- a/pom.xml +++ b/pom.xml @@ -1369,7 +1369,7 @@ opencga LOCAL - 5 + 5 https://ws.opencb.org/opencga-prod From 7c8520961279439b774c3c03c3fc515f77999fc6 Mon Sep 17 00:00:00 2001 From: pfurio Date: Wed, 24 Jul 2024 11:26:33 +0200 Subject: [PATCH 03/10] core: rename lastChangeDate for lastModified, #TASK-6494 --- .../MoveUserAccountToInternalMigration.java | 7 ++- .../opencga/catalog/db/api/UserDBAdaptor.java | 3 +- .../db/mongodb/UserMongoDBAdaptor.java | 2 +- .../db/mongodb/converters/UserConverter.java | 54 ++++++++++++++++++- .../opencga/catalog/managers/UserManager.java | 6 +-- .../opencga/core/api/FieldConstants.java | 2 +- .../opencga/core/models/user/Password.java | 18 +++---- .../opencb/opencga/core/models/user/User.java | 11 ++-- .../src/main/resources/configuration.yml | 2 +- 9 files changed, 80 insertions(+), 25 deletions(-) diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java index 64a824ec8ed..68f2cc00e7c 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/MoveUserAccountToInternalMigration.java @@ -30,17 +30,20 @@ protected void run() throws Exception { Document internal = document.get("internal", Document.class); internal.put("account", account); - updateDocument.getSet().put("expirationDate", internal.get("lastModified")); + updateDocument.getSet().put("modificationDate", internal.get("lastModified")); updateDocument.getSet().put("creationDate", account.get("creationDate")); account.remove("creationDate"); Document password = new Document() .append("expirationDate", null) - .append("lastChangedDate", internal.get("lastModified")); + .append("lastModified", internal.get("lastModified")); account.put("password", password); account.put("failedAttempts", internal.get("failedAttempts")); internal.remove("failedAttempts"); + updateDocument.getSet().put("internal", internal); + updateDocument.getUnset().add("account"); + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), updateDocument.toFinalUpdateDocument())); }); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java index bc25060061e..8c67639017c 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java @@ -120,6 +120,7 @@ enum QueryParams implements QueryParam { ORGANIZATION("organization", TEXT_ARRAY, ""), CREATION_DATE("creationDate", TEXT_ARRAY, ""), MODIFICATION_DATE("modificationDate", TEXT_ARRAY, ""), + DEPRECATED_ACCOUNT("account", OBJECT, ""), // Deprecated since 3.2.1 #TASK-6494 TODO: Remove in future releases INTERNAL("internal", OBJECT, ""), INTERNAL_STATUS_ID("internal.status.id", TEXT, ""), INTERNAL_STATUS_DATE("internal.status.date", TEXT, ""), @@ -129,7 +130,7 @@ enum QueryParams implements QueryParam { INTERNAL_ACCOUNT_CREATION_DATE("internal.account.creationDate", TEXT, ""), INTERNAL_ACCOUNT_EXPIRATION_DATE("internal.account.expirationDate", TEXT, ""), INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE("internal.account.password.expirationDate", TEXT, ""), - INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE("internal.account.password.lastChangeDate", TEXT, ""), + INTERNAL_ACCOUNT_PASSWORD_LAST_MODIFIED("internal.account.password.lastModified", TEXT, ""), QUOTA("quota", OBJECT, ""), ATTRIBUTES("attributes", TEXT, ""), // "Format: where is [<|<=|>|>=|==|!=|~|!~]" diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 581ed6f1620..76bc3bd9926 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -172,7 +172,7 @@ public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, St String encryptedPassword = encryptPassword(newPassword); updateDocument.getSet().put(PRIVATE_PASSWORD, encryptedPassword); updateDocument.getPush().put(ARCHIVE_PASSWORD, encryptedPassword); - updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE.key(), TimeUtils.getTime()); + updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_LAST_MODIFIED.key(), TimeUtils.getTime()); if (configuration.getAccount().getPasswordExpirationDays() > 0) { Date date = TimeUtils.addDaysToCurrentDate(configuration.getAccount().getPasswordExpirationDays()); String stringDate = TimeUtils.getTime(date); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java index 32420556a73..837349b6b8a 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/UserConverter.java @@ -18,27 +18,77 @@ import org.apache.avro.generic.GenericRecord; import org.bson.Document; +import org.opencb.opencga.catalog.db.api.UserDBAdaptor; import org.opencb.opencga.core.models.common.mixins.GenericRecordAvroJsonMixin; import org.opencb.opencga.core.models.user.User; +import org.opencb.opencga.core.models.user.UserInternal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Created by pfurio on 19/01/16. */ public class UserConverter extends OpenCgaMongoConverter { + protected static Logger logger = LoggerFactory.getLogger(UserConverter.class); + public UserConverter() { super(User.class); getObjectMapper().addMixIn(GenericRecord.class, GenericRecordAvroJsonMixin.class); } + @Override + public Document convertToStorageType(User object) { + Document userDocument = super.convertToStorageType(object); + removeDeprecatedAccountObject(userDocument); + return userDocument; + } + @Override public User convertToDataModelType(Document document) { User user = super.convertToDataModelType(document); + + restoreFromDeprecatedAccountObject(user); + addToDeprecatedAccountObject(user); + + return user; + } + + /** + * Remove 'account' object from the User document so it is no longer stored in the database. + * Remove after a few releases. + * + * @param userDocument User document. + */ + @Deprecated + private void removeDeprecatedAccountObject(Document userDocument) { + userDocument.remove(UserDBAdaptor.QueryParams.DEPRECATED_ACCOUNT.key()); + } + + /** + * Restores information from the account object to the corresponding internal.account object. + * Added to maintain backwards compatibility with the deprecated account object in TASK-6494 (v3.2.1) + * Remove after a few releases. + * + * @param user User object. + */ + @Deprecated + private void restoreFromDeprecatedAccountObject(User user) { + if (user.getAccount() != null) { + if (user.getInternal() == null) { + user.setInternal(new UserInternal()); + } + user.getInternal().setAccount(user.getAccount()); + logger.warn("Restoring user account information from deprecated account object to internal.account object. " + + "Please, run 'opencga-admin.sh migration run'."); + } + } + + private void addToDeprecatedAccountObject(User user) { // Add account to deprecated place - if (user.getInternal() != null && user.getInternal().getAccount() != null) { + if (user.getInternal() != null && user.getInternal().getAccount() != null && user.getAccount() == null) { user.setAccount(user.getInternal().getAccount()); } - return user; } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java index 9fa16ae9d64..8070d177233 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java @@ -62,8 +62,8 @@ */ public class UserManager extends AbstractManager { - static final QueryOptions INCLUDE_INTERNAL = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( - UserDBAdaptor.QueryParams.ID.key(), UserDBAdaptor.QueryParams.INTERNAL.key())); + static final QueryOptions INCLUDE_INTERNAL = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.ID.key(), + UserDBAdaptor.QueryParams.INTERNAL.key(), UserDBAdaptor.QueryParams.DEPRECATED_ACCOUNT.key())); protected static Logger logger = LoggerFactory.getLogger(UserManager.class); private final CatalogIOManager catalogIOManager; private final AuthenticationFactory authenticationFactory; @@ -171,7 +171,7 @@ public OpenCGAResult create(User user, String password, String token) thro // Set password expiration if (AuthenticationOrigin.AuthenticationType.OPENCGA.name().equals(account.getAuthentication().getId())) { - account.getPassword().setLastChangeDate(TimeUtils.getTime()); + account.getPassword().setLastModified(TimeUtils.getTime()); } if (!AuthenticationOrigin.AuthenticationType.OPENCGA.name().equals(account.getAuthentication().getId()) || configuration.getAccount().getPasswordExpirationDays() <= 0) { diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java b/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java index d4f3142bc1d..c5aaf9dadf9 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java @@ -446,7 +446,7 @@ public class FieldConstants { + " in successfully, this field is automatically reset to 0."; public static final String INTERNAL_ACCOUNT_PASSWORD_DESCRIPTION = "Object containing the last time the password was changed and the" + " expiration date."; - public static final String INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE_DESCRIPTION = "Date the user's password was last changed. This " + public static final String INTERNAL_ACCOUNT_PASSWORD_LAST_MODIFIED_DESCRIPTION = "Date the user's password was last changed. This " + "field will be null if the user account origin is different from OpenCGA."; public static final String INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE_DESCRIPTION = "Date the user's password expires. This field will" + " be null if the user account origin is different from OpenCGA and the passwordExpiration feature is disabled."; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java index 6cc9d5f338d..5b375936bd3 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/Password.java @@ -8,22 +8,22 @@ public class Password { @DataField(id = "expirationDate", since = "3.2.1", description = FieldConstants.INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE_DESCRIPTION) private String expirationDate; - @DataField(id = "lastChangeDate", since = "3.2.1", description = FieldConstants.INTERNAL_ACCOUNT_PASSWORD_LAST_CHANGE_DATE_DESCRIPTION) - private String lastChangeDate; + @DataField(id = "lastModified", since = "3.2.1", description = FieldConstants.INTERNAL_ACCOUNT_PASSWORD_LAST_MODIFIED_DESCRIPTION) + private String lastModified; public Password() { } - public Password(String expirationDate, String lastChangeDate) { + public Password(String expirationDate, String lastModified) { this.expirationDate = expirationDate; - this.lastChangeDate = lastChangeDate; + this.lastModified = lastModified; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Password{"); sb.append("expirationDate='").append(expirationDate).append('\''); - sb.append(", lastChangeDate='").append(lastChangeDate).append('\''); + sb.append(", lastModified='").append(lastModified).append('\''); sb.append('}'); return sb.toString(); } @@ -37,12 +37,12 @@ public Password setExpirationDate(String expirationDate) { return this; } - public String getLastChangeDate() { - return lastChangeDate; + public String getLastModified() { + return lastModified; } - public Password setLastChangeDate(String lastChangeDate) { - this.lastChangeDate = lastChangeDate; + public Password setLastModified(String lastModified) { + this.lastModified = lastModified; return this; } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java index 8694320cee2..98273a80528 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/User.java @@ -16,7 +16,6 @@ package org.opencb.opencga.core.models.user; -import com.fasterxml.jackson.annotation.JsonIgnore; import org.opencb.commons.annotations.DataClass; import org.opencb.commons.annotations.DataField; import org.opencb.commons.datastore.core.ObjectMap; @@ -56,6 +55,10 @@ public class User { @DataField(id = "modificationDate", since = "3.2.1", description = FieldConstants.GENERIC_MODIFICATION_DATE_DESCRIPTION) private String modificationDate; + @DataField(id = "account", description = FieldConstants.USER_ACCOUNT) + @Deprecated + private Account account; + @DataField(id = "internal", indexed = true, description = FieldConstants.GENERIC_INTERNAL) private UserInternal internal; @@ -199,16 +202,14 @@ public User setModificationDate(String modificationDate) { return this; } - @JsonIgnore @Deprecated public Account getAccount() { - return getInternal().getAccount(); + return account; } - @JsonIgnore @Deprecated public User setAccount(Account account) { - getInternal().setAccount(account); + this.account = account; return this; } diff --git a/opencga-core/src/main/resources/configuration.yml b/opencga-core/src/main/resources/configuration.yml index e3661d0167a..4d16f4aa68d 100644 --- a/opencga-core/src/main/resources/configuration.yml +++ b/opencga-core/src/main/resources/configuration.yml @@ -7,7 +7,7 @@ workspace: ${OPENCGA.USER.WORKSPACE} jobDir: ${OPENCGA.USER.WORKSPACE}/jobs # Maximum number of login attempts before banning a user account -maxLoginAttempts: ${OPENCGA.MAX_LOGIN_ATTEMPTS} +maxLoginAttempts: ${OPENCGA.ACCOUNT.MAX_LOGIN_ATTEMPTS} panel: host: "http://resources.opencb.org/opencb/opencga/disease-panels" From 4d2dba5e36b609f5f23e8e72e6723e04fe0fc4e9 Mon Sep 17 00:00:00 2001 From: pfurio Date: Tue, 6 Aug 2024 13:34:58 +0200 Subject: [PATCH 04/10] core: update configuration.yml, #TASK-6494 --- opencga-core/src/main/resources/configuration.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/opencga-core/src/main/resources/configuration.yml b/opencga-core/src/main/resources/configuration.yml index 4d16f4aa68d..3d283d3ed24 100644 --- a/opencga-core/src/main/resources/configuration.yml +++ b/opencga-core/src/main/resources/configuration.yml @@ -7,7 +7,9 @@ workspace: ${OPENCGA.USER.WORKSPACE} jobDir: ${OPENCGA.USER.WORKSPACE}/jobs # Maximum number of login attempts before banning a user account -maxLoginAttempts: ${OPENCGA.ACCOUNT.MAX_LOGIN_ATTEMPTS} +account: + maxLoginAttempts: ${OPENCGA.ACCOUNT.MAX_LOGIN_ATTEMPTS} + passwordExpirationDays: 0 panel: host: "http://resources.opencb.org/opencb/opencga/disease-panels" From ebaef56fcbe65a0b75b57226a80126f00a5882ba Mon Sep 17 00:00:00 2001 From: pfurio Date: Thu, 8 Aug 2024 16:41:09 +0200 Subject: [PATCH 05/10] catalog: add salt to passwords, #TASK-6494 --- .../OrganizationsCommandExecutor.java | 1 - .../options/OrganizationsCommandOptions.java | 3 - ....java => AddPasswordHistoryMigration.java} | 31 +-- .../authorization/AuthorizationDBAdaptor.java | 24 +-- .../opencga/catalog/db/DBAdaptorFactory.java | 5 +- .../db/api/AnnotationSetDBAdaptor.java | 17 +- .../db/api/ClinicalAnalysisDBAdaptor.java | 3 +- .../catalog/db/api/CohortDBAdaptor.java | 3 +- .../catalog/db/api/FamilyDBAdaptor.java | 2 +- .../opencga/catalog/db/api/FileDBAdaptor.java | 13 +- .../catalog/db/api/IndividualDBAdaptor.java | 2 +- .../db/api/InterpretationDBAdaptor.java | 4 +- .../opencga/catalog/db/api/JobDBAdaptor.java | 3 +- .../opencga/catalog/db/api/NoteDBAdaptor.java | 3 +- .../catalog/db/api/OrganizationDBAdaptor.java | 4 +- .../catalog/db/api/PanelDBAdaptor.java | 6 +- .../catalog/db/api/ProjectDBAdaptor.java | 4 +- .../catalog/db/api/SampleDBAdaptor.java | 8 +- .../catalog/db/api/StudyDBAdaptor.java | 27 +-- .../opencga/catalog/db/api/UserDBAdaptor.java | 12 +- .../db/mongodb/AnnotationMongoDBAdaptor.java | 11 +- .../mongodb/AuthorizationMongoDBAdaptor.java | 17 +- .../ClinicalAnalysisMongoDBAdaptor.java | 9 +- .../db/mongodb/CohortMongoDBAdaptor.java | 8 +- .../db/mongodb/FamilyMongoDBAdaptor.java | 11 +- .../db/mongodb/FileMongoDBAdaptor.java | 13 +- .../db/mongodb/IndividualMongoDBAdaptor.java | 10 +- .../mongodb/InterpretationMongoDBAdaptor.java | 12 +- .../catalog/db/mongodb/JobMongoDBAdaptor.java | 11 +- .../catalog/db/mongodb/MongoDBAdaptor.java | 15 +- .../db/mongodb/MongoDBAdaptorFactory.java | 4 +- .../db/mongodb/NoteMongoDBAdaptor.java | 8 +- .../mongodb/OrganizationMongoDBAdaptor.java | 6 +- .../db/mongodb/PanelMongoDBAdaptor.java | 15 +- .../db/mongodb/ProjectMongoDBAdaptor.java | 12 +- .../db/mongodb/SampleMongoDBAdaptor.java | 14 +- .../db/mongodb/StudyMongoDBAdaptor.java | 27 +-- .../db/mongodb/UserMongoDBAdaptor.java | 195 ++++++++++++------ .../opencga/catalog/managers/NoteManager.java | 2 +- .../catalog/managers/OrganizationManager.java | 9 +- .../mongodb/IndividualMongoDBAdaptorTest.java | 5 +- .../db/mongodb/JobMongoDBAdaptorTest.java | 8 +- .../db/mongodb/SampleMongoDBAdaptorTest.java | 6 +- .../db/mongodb/StudyMongoDBAdaptorTest.java | 14 +- .../db/mongodb/UserMongoDBAdaptorTest.java | 2 +- .../catalog/managers/UserManagerTest.java | 4 +- .../user/OrganizationUserUpdateParams.java | 51 ++++- 47 files changed, 362 insertions(+), 312 deletions(-) rename opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/{AddPasswordHistory.java => AddPasswordHistoryMigration.java} (62%) diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java index 68a4eb5dc0d..1294b1397e7 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java @@ -301,7 +301,6 @@ private RestResponse updateUser() throws Exception { putNestedIfNotNull(beanParams, "quota.cpuUsage", commandOptions.quotaCpuUsage, true); putNestedIfNotNull(beanParams, "quota.maxDisk", commandOptions.quotaMaxDisk, true); putNestedIfNotNull(beanParams, "quota.maxCpu", commandOptions.quotaMaxCpu, true); - putNestedIfNotEmpty(beanParams, "account.expirationDate", commandOptions.accountExpirationDate, true); putNestedMapIfNotEmpty(beanParams, "attributes", commandOptions.attributes, true); organizationUserUpdateParams = JacksonUtils.getDefaultObjectMapper().copy() diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java index 7b60a3059b2..0f9f2a18c49 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java @@ -305,9 +305,6 @@ public class UpdateUserCommandOptions { @Parameter(names = {"--quota-max-cpu"}, description = "The body web service maxCpu parameter", required = false, arity = 1) public Integer quotaMaxCpu; - @Parameter(names = {"--account-expiration-date"}, description = "The body web service expirationDate parameter", required = false, arity = 1) - public String accountExpirationDate; - @DynamicParameter(names = {"--attributes"}, description = "The body web service attributes parameter. Use: --attributes key=value", required = false) public java.util.Map attributes = new HashMap<>(); //Dynamic parameters must be initialized; diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistoryMigration.java similarity index 62% rename from opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java rename to opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistoryMigration.java index d0fb6af2d12..f016e564c77 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistory.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_1/AddPasswordHistoryMigration.java @@ -3,37 +3,40 @@ import com.mongodb.client.model.Filters; import com.mongodb.client.model.Projections; import com.mongodb.client.model.UpdateOneModel; -import org.apache.commons.lang3.StringUtils; +import org.bson.Document; import org.bson.conversions.Bson; import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor; import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; import org.opencb.opencga.catalog.migration.Migration; import org.opencb.opencga.catalog.migration.MigrationTool; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.Collections; + +import static org.opencb.opencga.catalog.db.mongodb.UserMongoDBAdaptor.*; @Migration(id = "add_archivePasswords_array", description = "Add password history #6494", version = "3.2.1", language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240723) -public class AddPasswordHistory extends MigrationTool { +public class AddPasswordHistoryMigration extends MigrationTool { @Override protected void run() throws Exception { - Bson query = Filters.exists("_archivePasswords", false); - Bson projection = Projections.include("_password"); + Bson query = Filters.exists(PRIVATE_PASSWORD_ARCHIVE, false); + Bson projection = Projections.include(PRIVATE_PASSWORD); migrateCollection(Arrays.asList(OrganizationMongoDBAdaptorFactory.USER_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_USER_COLLECTION), query, projection, (document, bulk) -> { - MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); - - // Add _archivePasswords String currentPassword = document.getString("_password"); - List archivePasswords = new ArrayList<>(); - if (StringUtils.isNotEmpty(currentPassword)) { - archivePasswords.add(currentPassword); - } - updateDocument.getSet().put("_archivePasswords", archivePasswords); + + Document passwordDoc = new Document() + .append(HASH, currentPassword) + .append(SALT, ""); + Document privatePassword = new Document(); + privatePassword.put(CURRENT, passwordDoc); + privatePassword.put(ARCHIVE, Collections.singletonList(passwordDoc)); + + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + updateDocument.getSet().put(PRIVATE_PASSWORD, privatePassword); bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), updateDocument.toFinalUpdateDocument())); }); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authorization/AuthorizationDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authorization/AuthorizationDBAdaptor.java index c86787e84df..09c142e68e9 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authorization/AuthorizationDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authorization/AuthorizationDBAdaptor.java @@ -16,10 +16,8 @@ package org.opencb.opencga.catalog.auth.authorization; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.models.Acl; import org.opencb.opencga.core.models.AclEntryList; import org.opencb.opencga.core.models.common.Enums; @@ -80,27 +78,21 @@ > OpenCGAResult> get(List resourceIds, L */ OpenCGAResult removeFromStudy(long studyId, String member, Enums.Resource entry) throws CatalogException; - OpenCGAResult setToMembers(long studyId, List members, - List aclParams) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult setToMembers(long studyId, List members, List aclParams) + throws CatalogException; // Special method only to set acls in study - OpenCGAResult setToMembers(List studyIds, List members, List permissions) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult setToMembers(List studyIds, List members, List permissions) throws CatalogException; - OpenCGAResult addToMembers(long studyId, List members, - List aclParams) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult addToMembers(long studyId, List members, List aclParams) + throws CatalogException; // Special method only to add acls in study - OpenCGAResult addToMembers(List studyIds, List members, List permissions) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult addToMembers(List studyIds, List members, List permissions) throws CatalogException; - OpenCGAResult removeFromMembers(List members, List aclParams) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult removeFromMembers(List members, List aclParams) throws CatalogException; - OpenCGAResult resetMembersFromAllEntries(long studyId, List members) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult resetMembersFromAllEntries(long studyId, List members) throws CatalogException; OpenCGAResult setAcls(List resourceIds, AclEntryList aclEntryList, Enums.Resource resource) throws CatalogDBException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/DBAdaptorFactory.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/DBAdaptorFactory.java index 5f3367d4d1c..883943f1a4b 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/DBAdaptorFactory.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/DBAdaptorFactory.java @@ -19,10 +19,8 @@ import org.apache.commons.lang3.StringUtils; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.opencga.catalog.db.api.*; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.config.Admin; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.models.organizations.Organization; @@ -83,8 +81,7 @@ default String getCatalogDatabase(String prefix, String organization) { MetaDBAdaptor getCatalogMetaDBAdaptor(String organization) throws CatalogDBException; - OpenCGAResult createOrganization(Organization organization, QueryOptions options, String userId) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult createOrganization(Organization organization, QueryOptions options, String userId) throws CatalogException; void deleteOrganization(Organization organization) throws CatalogDBException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/AnnotationSetDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/AnnotationSetDBAdaptor.java index a06f3762b4d..ccca18225c9 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/AnnotationSetDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/AnnotationSetDBAdaptor.java @@ -21,6 +21,7 @@ import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.study.Variable; @@ -62,12 +63,10 @@ OpenCGAResult update(Query query, ObjectMap parameters, List variab * @param variableSetId variable set id to identify the annotations that will add a new annotation. * @param variable new variable that will be added. * @return a OpenCGAResult object. - * @throws CatalogDBException if the variable could not be added to an existing annotationSet. - * @throws CatalogParameterException if there is any unexpected parameter. - * @throws CatalogAuthorizationException if the operation is not authorized. + * @throws CatalogException if the variable could not be added to an existing annotationSet, there is any unexpected parameter or + * the operation is not authorized. */ - OpenCGAResult addVariableToAnnotations(long studyUid, long variableSetId, Variable variable) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult addVariableToAnnotations(long studyUid, long variableSetId, Variable variable) throws CatalogException; // /** // * This method will rename the id of all the annotations corresponding to the variableSetId changing oldName per newName. @@ -88,12 +87,10 @@ OpenCGAResult addVariableToAnnotations(long studyUid, long variableSetId, Variab * @param variableSetId variable set id for which the annotationSets have to delete the annotation. * @param annotationName Annotation name. * @return a OpenCGAResult object. - * @throws CatalogDBException when there is an error in the database. - * @throws CatalogParameterException if there is any unexpected parameter. - * @throws CatalogAuthorizationException if the operation is not authorized. + * @throws CatalogException when there is an error in the database, there is any unexpected parameter or the operation is not + * authorized. */ - OpenCGAResult removeAnnotationField(long studyUid, long variableSetId, String annotationName) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult removeAnnotationField(long studyUid, long variableSetId, String annotationName) throws CatalogException; /** * Makes a groupBy to obtain the different values that every annotation has and the total number of each. diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java index 04f1aeafbe4..4fd3c2f9a3b 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java @@ -235,8 +235,7 @@ default void checkId(long clinicalAnalysisId) throws CatalogDBException, Catalog OpenCGAResult nativeInsert(Map clinicalAnalysis, String userId) throws CatalogDBException; OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, List variableSetList, - List clinicalAuditList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + List clinicalAuditList, QueryOptions options) throws CatalogException; OpenCGAResult update(long id, ObjectMap parameters, List variableSetList, List clinicalAuditList, QueryOptions queryOptions) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/CohortDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/CohortDBAdaptor.java index d8b6f82182e..c95d006161d 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/CohortDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/CohortDBAdaptor.java @@ -133,8 +133,7 @@ default void checkId(long cohortId) throws CatalogDBException, CatalogParameterE OpenCGAResult nativeInsert(Map cohort, String userId) throws CatalogDBException; - OpenCGAResult insert(long studyId, Cohort cohort, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(long studyId, Cohort cohort, List variableSetList, QueryOptions options) throws CatalogException; OpenCGAResult get(long cohortId, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FamilyDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FamilyDBAdaptor.java index da321435f29..fe9fd976e64 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FamilyDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FamilyDBAdaptor.java @@ -149,7 +149,7 @@ default void checkId(long familyId) throws CatalogDBException, CatalogParameterE OpenCGAResult nativeInsert(Map family, String userId) throws CatalogDBException; OpenCGAResult insert(long studyId, Family family, List members, List variableSetList, - QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + QueryOptions options) throws CatalogException; OpenCGAResult get(long familyId, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FileDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FileDBAdaptor.java index 2ffe6fd1ee9..a341840a6bf 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FileDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/FileDBAdaptor.java @@ -233,13 +233,10 @@ default void checkId(long fileId) throws CatalogDBException, CatalogParameterExc * @param variableSetList Variable set list. * @param options Options to filter the output that will be returned after the insertion of the file. * @return A OpenCGAResult object containing the time spent. - * @throws CatalogDBException when the file could not be inserted due to different reasons. - * @throws CatalogParameterException if there is any formatting error. - * @throws CatalogAuthorizationException if the user is not authorised to perform the query. + * @throws CatalogException when the file could not be inserted due to any formatting error or the user is not authorised. */ OpenCGAResult insert(long studyId, File file, List existingSamples, List nonExistingSamples, - List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + List variableSetList, QueryOptions options) throws CatalogException; /*** * Inserts the passed file in the database. @@ -252,13 +249,11 @@ OpenCGAResult insert(long studyId, File file, List existingSamples, List * @param variableSetList Variable set list. * @param options Options to filter the output that will be returned after the insertion of the file. * @return A OpenCGAResult object containing the time spent. - * @throws CatalogDBException when the file could not be inserted due to different reasons. - * @throws CatalogParameterException if there is any formatting error. - * @throws CatalogAuthorizationException if the user is not authorised to perform the query. + * @throws CatalogException when the file could not be inserted due any formatting error or the user is not authorised. */ OpenCGAResult insertWithVirtualFile(long studyId, File file, File virtualFile, List existingSamples, List nonExistingSamples, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + throws CatalogException; /*** * Retrieves the file from the database containing the fileId given. diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/IndividualDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/IndividualDBAdaptor.java index d55e1019e0e..b6dbc94b861 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/IndividualDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/IndividualDBAdaptor.java @@ -163,7 +163,7 @@ default void checkId(long individualId) throws CatalogDBException, CatalogParame OpenCGAResult nativeInsert(Map individual, String userId) throws CatalogDBException; OpenCGAResult insert(long studyId, Individual individual, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + throws CatalogException; OpenCGAResult get(long individualId, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java index 8c95202e0de..519e25fa3eb 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java @@ -24,6 +24,7 @@ import org.opencb.commons.datastore.core.QueryParam; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.core.api.ParamConstants; @@ -135,8 +136,7 @@ default void checkId(long interpretationId) throws CatalogDBException, CatalogPa OpenCGAResult nativeInsert(Map interpretation, String userId) throws CatalogDBException; OpenCGAResult insert(long studyId, Interpretation interpretation, ParamUtils.SaveInterpretationAs action, - List clinicalAuditList) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + List clinicalAuditList) throws CatalogException; OpenCGAResult update(long uid, ObjectMap parameters, List clinicalAuditList, ParamUtils.SaveInterpretationAs action, QueryOptions queryOptions) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/JobDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/JobDBAdaptor.java index a6016da7441..ebbc7b62143 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/JobDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/JobDBAdaptor.java @@ -54,8 +54,7 @@ default void checkId(long jobId) throws CatalogDBException, CatalogParameterExce OpenCGAResult nativeInsert(Map job, String userId) throws CatalogDBException; - OpenCGAResult insert(long studyId, Job job, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(long studyId, Job job, QueryOptions options) throws CatalogException; default OpenCGAResult restore(Query query, QueryOptions queryOptions) throws CatalogDBException { //return updateStatus(query, new Job.JobStatus(Job.JobStatus.PREPARED)); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/NoteDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/NoteDBAdaptor.java index 34d3495407d..eeecd6d55df 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/NoteDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/NoteDBAdaptor.java @@ -6,6 +6,7 @@ import org.opencb.commons.datastore.core.QueryParam; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.models.notes.Note; import org.opencb.opencga.core.response.OpenCGAResult; @@ -16,7 +17,7 @@ public interface NoteDBAdaptor extends DBAdaptor { - OpenCGAResult insert(Note note) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(Note note) throws CatalogException; default OpenCGAResult get(long noteUid, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/OrganizationDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/OrganizationDBAdaptor.java index d8d8e8a0a51..93e65c63121 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/OrganizationDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/OrganizationDBAdaptor.java @@ -5,6 +5,7 @@ import org.opencb.commons.datastore.core.QueryParam; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.models.organizations.Organization; import org.opencb.opencga.core.response.OpenCGAResult; @@ -98,8 +99,7 @@ public static QueryParams getParam(String key) { // // OpenCGAResult nativeInsert(Map project, String userId) throws CatalogDBException; // - OpenCGAResult insert(Organization organization, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(Organization organization, QueryOptions options) throws CatalogException; OpenCGAResult get(String userId, QueryOptions options) throws CatalogDBException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/PanelDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/PanelDBAdaptor.java index a6ce18d5a2f..63bdd0d5e18 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/PanelDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/PanelDBAdaptor.java @@ -153,11 +153,9 @@ default void checkUid(long panelUid) throws CatalogDBException, CatalogParameter } } - OpenCGAResult insert(long studyUid, List panelList) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(long studyUid, List panelList) throws CatalogException; - OpenCGAResult insert(long studyId, Panel panel, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(long studyId, Panel panel, QueryOptions options) throws CatalogException; OpenCGAResult get(long panelId, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ProjectDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ProjectDBAdaptor.java index fcdfba9034d..1ff667bdbac 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ProjectDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ProjectDBAdaptor.java @@ -23,6 +23,7 @@ import org.opencb.commons.datastore.core.QueryParam; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.models.project.Project; import org.opencb.opencga.core.models.study.StudyPermissions; @@ -133,8 +134,7 @@ default void checkId(long projectId) throws CatalogDBException { OpenCGAResult nativeInsert(Map project, String userId) throws CatalogDBException; - OpenCGAResult insert(Project project, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(Project project, QueryOptions options) throws CatalogException; OpenCGAResult get(long project, QueryOptions options) throws CatalogDBException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/SampleDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/SampleDBAdaptor.java index b9f0b5b1b36..485ab7b10dd 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/SampleDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/SampleDBAdaptor.java @@ -63,7 +63,7 @@ default void checkId(long sampleId) throws CatalogDBException, CatalogParameterE OpenCGAResult nativeInsert(Map sample, String userId) throws CatalogDBException; OpenCGAResult insert(long studyId, Sample sample, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + throws CatalogException; OpenCGAResult get(long sampleId, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; @@ -86,13 +86,11 @@ OpenCGAResult updateProjectRelease(long studyId, int release) */ OpenCGAResult unmarkPermissionRule(long studyId, String permissionRuleId) throws CatalogException; - default OpenCGAResult setRgaIndexes(long studyUid, RgaIndex rgaIndex) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + default OpenCGAResult setRgaIndexes(long studyUid, RgaIndex rgaIndex) throws CatalogException { return setRgaIndexes(studyUid, Collections.emptyList(), rgaIndex); } - OpenCGAResult setRgaIndexes(long studyUid, List sampleUids, RgaIndex rgaIndex) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult setRgaIndexes(long studyUid, List sampleUids, RgaIndex rgaIndex) throws CatalogException; enum QueryParams implements QueryParam { ID("id", TEXT, ""), diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/StudyDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/StudyDBAdaptor.java index b4e0aea1d2e..0afd3f255d4 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/StudyDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/StudyDBAdaptor.java @@ -25,6 +25,7 @@ import org.opencb.commons.datastore.core.QueryParam; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.core.models.common.Enums; @@ -249,8 +250,7 @@ OpenCGAResult setUsersToGroup(long studyId, String groupId, List */ OpenCGAResult removeUsersFromGroup(long studyId, String groupId, List members) throws CatalogDBException; - OpenCGAResult removeUsersFromAllGroups(long studyId, List users) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult removeUsersFromAllGroups(long studyId, List users) throws CatalogException; /** * Delete a group. @@ -273,12 +273,9 @@ OpenCGAResult removeUsersFromAllGroups(long studyId, List users) * @param groupList List containing possible groups that are synced and where the user should be added to. * @param authOrigin Authentication origin of the synced groups. * @return OpenCGAResult object. - * @throws CatalogDBException CatalogDBException - * @throws CatalogParameterException CatalogParameterException - * @throws CatalogAuthorizationException CatalogAuthorizationException + * @throws CatalogException CatalogException */ - OpenCGAResult resyncUserWithSyncedGroups(String user, List groupList, String authOrigin) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult resyncUserWithSyncedGroups(String user, List groupList, String authOrigin) throws CatalogException; /** * ADD or REMOVE user to list of provided groups. @@ -288,13 +285,10 @@ OpenCGAResult resyncUserWithSyncedGroups(String user, List groupL * @param groupList List of group ids. * @param action Update action [ADD, REMOVE] * @return OpenCGAResult object. - * @throws CatalogDBException CatalogDBException - * @throws CatalogParameterException CatalogParameterException - * @throws CatalogAuthorizationException CatalogAuthorizationException + * @throws CatalogException CatalogException */ - OpenCGAResult updateUserFromGroups(String user, List studyUids, List groupList, - ParamUtils.AddRemoveAction action) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult updateUserFromGroups(String user, List studyUids, List groupList, ParamUtils.AddRemoveAction action) + throws CatalogException; /** * Create the permission rule to the list of permission rules defined for the entry in the studyId. @@ -381,13 +375,13 @@ default void checkVariableSetExists(String variableSetId, long studyId) throws C OpenCGAResult createVariableSet(long studyId, VariableSet variableSet) throws CatalogDBException; OpenCGAResult addFieldToVariableSet(long studyUid, long variableSetId, Variable variable, String user) - throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException; + throws CatalogException; OpenCGAResult renameFieldVariableSet(long variableSetId, String oldName, String newName, String user) throws CatalogDBException, CatalogAuthorizationException; OpenCGAResult removeFieldFromVariableSet(long studyUid, long variableSetId, String name, String user) - throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException; + throws CatalogException; OpenCGAResult getVariableSet(long variableSetUid, QueryOptions options) throws CatalogDBException; @@ -411,8 +405,7 @@ OpenCGAResult getVariableSet(long variableSetId, QueryOptions optio OpenCGAResult getVariableSets(Query query, QueryOptions queryOptions, String user) throws CatalogDBException, CatalogAuthorizationException; - OpenCGAResult deleteVariableSet(long studyUid, VariableSet variableSet, boolean force) - throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException; + OpenCGAResult deleteVariableSet(long studyUid, VariableSet variableSet, boolean force) throws CatalogException; void updateDiskUsage(ClientSession clientSession, long studyId, long size) throws CatalogDBException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java index 8c67639017c..52b0022f533 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java @@ -22,10 +22,7 @@ import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.commons.datastore.core.QueryParam; -import org.opencb.opencga.catalog.exceptions.CatalogAuthenticationException; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; -import org.opencb.opencga.catalog.exceptions.CatalogDBException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; +import org.opencb.opencga.catalog.exceptions.*; import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.models.user.UserFilter; import org.opencb.opencga.core.response.OpenCGAResult; @@ -75,7 +72,7 @@ default void checkIds(List userIds) throws CatalogDBException, CatalogPa void authenticate(String userId, String password) throws CatalogDBException, CatalogAuthenticationException; OpenCGAResult insert(User user, String password, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + throws CatalogException; OpenCGAResult get(String userId, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; @@ -97,9 +94,10 @@ OpenCGAResult delete(String userId, QueryOptions queryOptions) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; OpenCGAResult changePassword(String userId, String oldPassword, String newPassword) - throws CatalogDBException, CatalogAuthenticationException; + throws CatalogException; - OpenCGAResult resetPassword(String userId, String email, String newCryptPass) throws CatalogDBException; + OpenCGAResult resetPassword(String userId, String email, String newCryptPass) + throws CatalogException; // Config operations OpenCGAResult setConfig(String userId, String name, Map config) throws CatalogDBException; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java index d1e48be9331..02ce5649729 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java @@ -31,6 +31,7 @@ import org.opencb.opencga.catalog.db.mongodb.converters.AnnotationConverter; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.AnnotationUtils; import org.opencb.opencga.catalog.utils.Constants; @@ -687,8 +688,7 @@ private List getNewAnnotationList(List annotationSetLis return annotationList; } - public OpenCGAResult addVariableToAnnotations(long studyUid, long variableSetId, Variable variable) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult addVariableToAnnotations(long studyUid, long variableSetId, Variable variable) throws CatalogException { long startTime = startQuery(); // We generate the generic document that should be inserted @@ -764,12 +764,9 @@ public OpenCGAResult addVariableToAnnotations(long studyUid, long variableSetId, * @param variableSetId Variable set id. * @param fieldId Field id corresponds with the variable name whose annotations have to be removed. * @return A OpenCGAResult object. - * @throws CatalogDBException if there is any unexpected error. - * @throws CatalogParameterException if there is any unexpected parameter. - * @throws CatalogAuthorizationException if the operation is not authorized. + * @throws CatalogException if there is any unexpected error or parameter, or if the operation is not authorized. */ - public OpenCGAResult removeAnnotationField(long studyUid, long variableSetId, String fieldId) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult removeAnnotationField(long studyUid, long variableSetId, String fieldId) throws CatalogException { long startTime = startQuery(); UpdateDocument updateDocument = new UpdateDocument(); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java index 445c1c6047a..ac6dd7af9fe 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java @@ -34,10 +34,8 @@ import org.opencb.opencga.catalog.auth.authorization.AuthorizationManager; import org.opencb.opencga.catalog.auth.authorization.CatalogAuthorizationManager; import org.opencb.opencga.catalog.db.api.StudyDBAdaptor; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.api.ParamConstants; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.Configuration; @@ -578,7 +576,7 @@ public OpenCGAResult removeFromStudy(long studyId, String member, Enums.Resou @Override public OpenCGAResult setToMembers(long studyId, List members, List aclParams) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { return runTransaction(clientSession -> { long startTime = startQuery(); @@ -598,8 +596,7 @@ public OpenCGAResult setToMembers(long studyId, List members, List studyIds, List members, List permissions) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult setToMembers(List studyIds, List members, List permissions) throws CatalogException { return runTransaction(clientSession -> { long startTime = startQuery(); for (Long studyId : studyIds) { @@ -652,7 +649,7 @@ private void setToMembers(List resourceIds, List members, List members, List aclParams) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { return runTransaction(clientSession -> { long startTime = startQuery(); addToMembersGroupInStudy(studyId, members, clientSession); @@ -696,8 +693,7 @@ private void addToMembers(List resourceIds, List members, List studyIds, List members, List permissions) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult addToMembers(List studyIds, List members, List permissions) throws CatalogException { return runTransaction((clientSession) -> { long startTime = startQuery(); for (Long studyId : studyIds) { @@ -724,7 +720,7 @@ private void addToMembersGroupInStudy(long studyId, List members, Client @Override public OpenCGAResult removeFromMembers(List members, List aclParams) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { return runTransaction(clientSession -> { long startTime = startQuery(); @@ -766,8 +762,7 @@ private void removeFromMembers(ClientSession clientSession, List resourceI } @Override - public OpenCGAResult resetMembersFromAllEntries(long studyId, List members) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult resetMembersFromAllEntries(long studyId, List members) throws CatalogException { if (members == null || members.isEmpty()) { throw new CatalogDBException("Missing 'members' array."); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java index ec066ba4fc6..08216439ba5 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java @@ -256,7 +256,7 @@ public OpenCGAResult update(long uid, ObjectMap parameters, List va try { return runTransaction(clientSession -> transactionalUpdate(clientSession, result.first(), parameters, variableSetList, clinicalAuditList, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update clinical analysis {}: {}", clinicalAnalysisId, e.getMessage(), e); throw new CatalogDBException("Could not update clinical analysis " + clinicalAnalysisId + ": " + e.getMessage(), e.getCause()); } @@ -684,7 +684,7 @@ public OpenCGAResult delete(ClinicalAnalysis clinicalAnalysis, List privateDelete(clientSession, clinicalAnalysis, clinicalAuditList)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete Clinical Analysis {}: {}", clinicalAnalysis.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete Clinical Analysis " + clinicalAnalysis.getId() + ": " + e.getMessage(), e.getCause()); @@ -702,7 +702,7 @@ public OpenCGAResult delete(Query query, List c try { result.append(runTransaction(clientSession -> privateDelete(clientSession, clinicalAnalysis, clinicalAuditList))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete Clinical Analysis {}: {}", clinicalAnalysis.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, clinicalAnalysis.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -1048,8 +1048,7 @@ public OpenCGAResult nativeInsert(Map clinicalAnalysis, String u @Override public OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, List variableSetList, - List clinicalAuditList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + List clinicalAuditList, QueryOptions options) throws CatalogException { try { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/CohortMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/CohortMongoDBAdaptor.java index 7f25b1ee7b9..6b948a722ba 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/CohortMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/CohortMongoDBAdaptor.java @@ -96,7 +96,7 @@ public OpenCGAResult nativeInsert(Map cohort, String userId) thr @Override public OpenCGAResult insert(long studyId, Cohort cohort, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { try { return runTransaction(clientSession -> { long startTime = startQuery(); @@ -275,7 +275,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, List try { result.append(runTransaction(clientSession -> transactionalUpdate(clientSession, cohort, parameters, variableSetList, queryOptions))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update cohort {}: {}", cohort.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, cohort.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -545,7 +545,7 @@ public OpenCGAResult delete(Cohort cohort) throws CatalogDBException, CatalogPar throw new CatalogDBException("Could not find cohort " + cohort.getId() + " with uid " + cohort.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete cohort {}: {}", cohort.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete cohort '" + cohort.getId() + "': " + e.getMessage(), e.getCause()); } @@ -561,7 +561,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException, CatalogParam String cohortId = cohort.getString(QueryParams.ID.key()); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, cohort))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete cohort {}: {}", cohortId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, cohortId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FamilyMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FamilyMongoDBAdaptor.java index 9e8c35d00ab..97bfd92a671 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FamilyMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FamilyMongoDBAdaptor.java @@ -115,8 +115,7 @@ public OpenCGAResult nativeInsert(Map family, String userId) thr @Override public OpenCGAResult insert(long studyId, Family family, List members, List variableSetList, - QueryOptions options) throws CatalogDBException, CatalogParameterException, - CatalogAuthorizationException { + QueryOptions options) throws CatalogException { try { AtomicReference familyCopy = new AtomicReference<>(); OpenCGAResult result = runTransaction(clientSession -> { @@ -333,7 +332,7 @@ public OpenCGAResult update(long familyUid, ObjectMap parameters, List transactionalUpdate(clientSession, familyDataResult.first(), parameters, variableSetList, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update family {}: {}", familyDataResult.first().getId(), e.getMessage(), e); throw new CatalogDBException("Could not update family " + familyDataResult.first().getId() + ": " + e.getMessage(), e.getCause()); @@ -368,7 +367,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, List try { result.append(runTransaction(clientSession -> transactionalUpdate(clientSession, family, parameters, variableSetList, queryOptions))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update family {}: {}", family.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, family.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -784,7 +783,7 @@ public OpenCGAResult delete(Family family) throws CatalogDBException, CatalogPar throw new CatalogDBException("Could not find family " + family.getId() + " with uid " + family.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete family {}: {}", family.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete family " + family.getId() + ": " + e.getMessage(), e.getCause()); } @@ -801,7 +800,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException, CatalogParam String familyId = family.getString(QueryParams.ID.key()); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, family))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete family {}: {}", familyId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, familyId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FileMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FileMongoDBAdaptor.java index f214620bf39..0f8383a9905 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FileMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/FileMongoDBAdaptor.java @@ -127,8 +127,7 @@ public OpenCGAResult nativeInsert(Map file, String userId) throw @Override public OpenCGAResult insert(long studyId, File file, List existingSamples, List nonExistingSamples, - List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + List variableSetList, QueryOptions options) throws CatalogException { return runTransaction( (clientSession) -> { long tmpStartTime = startQuery(); @@ -144,7 +143,7 @@ public OpenCGAResult insert(long studyId, File file, List existingSample @Override public OpenCGAResult insertWithVirtualFile(long studyId, File file, File virtualFile, List existingSamples, List nonExistingSamples, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { return runTransaction( (clientSession) -> { long tmpStartTime = startQuery(); @@ -344,7 +343,7 @@ public OpenCGAResult update(long fileUid, ObjectMap parameters, List transactionalUpdate(clientSession, fileDataResult.first(), parameters, variableSetList, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update file {}: {}", fileDataResult.first().getPath(), e.getMessage(), e); throw new CatalogDBException("Could not update file " + fileDataResult.first().getPath() + ": " + e.getMessage(), e.getCause()); } @@ -370,7 +369,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, List try { result.append(runTransaction(clientSession -> transactionalUpdate(clientSession, file, parameters, variableSetList, queryOptions))); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update file {}: {}", file.getPath(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, file.getPath(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -931,7 +930,7 @@ public OpenCGAResult delete(File file, String status) try { return runTransaction(clientSession -> privateDelete(clientSession, fileDocument, status)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete file {}: {}", file.getPath(), e.getMessage(), e); throw new CatalogDBException("Could not delete file " + file.getPath() + ": " + e.getMessage(), e.getCause()); } @@ -962,7 +961,7 @@ public OpenCGAResult delete(Query query, String status) Document fileDocument = iterator.next(); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, fileDocument, status))); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete file {}: {}", fileDocument.getString(QueryParams.PATH.key()), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, fileDocument.getString(QueryParams.ID.key()), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java index 13dbb40741c..03a6704af17 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java @@ -119,7 +119,7 @@ public OpenCGAResult nativeInsert(Map individual, String userId) @Override public OpenCGAResult insert(long studyId, Individual individual, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { try { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); @@ -329,7 +329,7 @@ public OpenCGAResult update(long individualUid, ObjectMap parameters, List transactionalUpdate(clientSession, individualUid, parameters, variableSetList, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { throw new CatalogDBException("Could not update individual: " + e.getMessage(), e.getCause()); } } @@ -363,7 +363,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, List try { result.append(runTransaction(clientSession -> transactionalUpdate(clientSession, individual, parameters, variableSetList, queryOptions))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update individual {}: {}", individual.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, individual.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -1051,7 +1051,7 @@ public OpenCGAResult delete(Individual individual) throws CatalogDBException, Ca throw new CatalogDBException("Could not find individual " + individual.getId() + " with uid " + individual.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete individual {}: {}", individual.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete individual " + individual.getId() + ": " + e.getMessage(), e); } @@ -1068,7 +1068,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException, CatalogParam String individualId = individual.getString(QueryParams.ID.key()); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, individual))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete individual {}: {}", individualId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, individualId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java index 3d78516dd55..f15a2ac5739 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java @@ -40,6 +40,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.InterpretationCatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.managers.ClinicalAnalysisManager; import org.opencb.opencga.catalog.utils.Constants; @@ -120,8 +121,7 @@ public OpenCGAResult nativeInsert(Map interpretation, String use @Override public OpenCGAResult insert(long studyId, Interpretation interpretation, ParamUtils.SaveInterpretationAs action, - List clinicalAuditList) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + List clinicalAuditList) throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting interpretation insert transaction for interpretation id '{}'", interpretation.getId()); @@ -635,7 +635,7 @@ public OpenCGAResult update(long uid, ObjectMap parameters, List try { return runTransaction(clientSession -> update(clientSession, interpretation.first(), parameters, clinicalAuditList, action, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update interpretation {}: {}", interpretationId, e.getMessage(), e); throw new CatalogDBException("Could not update interpretation " + interpretationId + ": " + e.getMessage(), e.getCause()); } @@ -654,7 +654,7 @@ public OpenCGAResult revert(long id, int previousVersion, List c return delete(clientSession, interpretation, clinicalAuditList, clinicalResult.first()); }); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete interpretation {}: {}", interpretationId, e.getMessage(), e); throw new CatalogDBException("Could not delete interpretation " + interpretation.getId() + ": " + e.getMessage(), e.getCause()); } @@ -852,7 +852,7 @@ public OpenCGAResult delete(Query query, List cli return delete(clientSession, interpretation, clinicalAuditList, clinicalResult.first()); })); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete interpretation {}: {}", interpretationId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, interpretationId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptor.java index 53c9a5f157e..d89e0020f93 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptor.java @@ -100,8 +100,7 @@ public OpenCGAResult nativeInsert(Map job, String userId) throws } @Override - public OpenCGAResult insert(long studyId, Job job, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(long studyId, Job job, QueryOptions options) throws CatalogException { try { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); @@ -228,7 +227,7 @@ public OpenCGAResult update(long jobUid, ObjectMap parameters, QueryOptions quer try { return runTransaction(session -> privateUpdate(session, dataResult.first(), parameters, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update job {}: {}", dataResult.first().getId(), e.getMessage(), e); throw new CatalogDBException("Could not update job " + dataResult.first().getId() + ": " + e.getMessage(), e.getCause()); } @@ -254,7 +253,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions quer Job job = iterator.next(); try { result.append(runTransaction(session -> privateUpdate(session, job, parameters, queryOptions))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update job {}: {}", job.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, job.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -306,7 +305,7 @@ public OpenCGAResult delete(Job job) throws CatalogDBException, CatalogParameter throw new CatalogDBException("Could not find job " + job.getId() + " with uid " + job.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete job {}: {}", job.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete job " + job.getId() + ": " + e.getMessage(), e.getCause()); } @@ -322,7 +321,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException, CatalogParam String jobId = job.getString(QueryParams.ID.key()); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, job))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete job {}: {}", jobId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, jobId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java index 7f41e38411d..10e84541343 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java @@ -93,16 +93,15 @@ public MongoDBAdaptor(Configuration configuration, Logger logger) { } public interface TransactionBodyWithException { - T execute(ClientSession session) throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException; + T execute(ClientSession session) throws CatalogException; } - protected T runTransaction(TransactionBodyWithException body) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + protected T runTransaction(TransactionBodyWithException body) throws CatalogException { return runTransaction(body, null); } protected T runTransaction(TransactionBodyWithException inputBody, Consumer onException) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { ClientSession session = dbAdaptorFactory.getMongoDataStore().startSession(); try { TransactionBodyWithException body; @@ -124,7 +123,7 @@ protected T runTransaction(TransactionBodyWithException inputBody, Consum return session.withTransaction(() -> { try { return body.execute(session); - } catch (CatalogDBException | CatalogAuthorizationException | CatalogParameterException e) { + } catch (CatalogException e) { throw new CatalogDBRuntimeException(e); } }); @@ -147,6 +146,12 @@ protected T runTransaction(TransactionBodyWithException inputBody, Consum onException.accept(cause); } throw cause; + } else if (e.getCause() instanceof CatalogAuthenticationException) { + CatalogAuthenticationException cause = (CatalogAuthenticationException) e.getCause(); + if (onException != null) { + onException.accept(cause); + } + throw cause; } else { throw e; } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorFactory.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorFactory.java index 621c537cddd..e262c3d3595 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorFactory.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorFactory.java @@ -27,10 +27,8 @@ import org.opencb.commons.datastore.mongodb.MongoDataStoreManager; import org.opencb.opencga.catalog.db.DBAdaptorFactory; import org.opencb.opencga.catalog.db.api.*; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.io.IOManagerFactory; import org.opencb.opencga.catalog.managers.NoteManager; import org.opencb.opencga.core.api.ParamConstants; @@ -261,7 +259,7 @@ public MetaDBAdaptor getCatalogMetaDBAdaptor(String organizationId) throws Catal @Override public OpenCGAResult createOrganization(Organization organization, QueryOptions options, String userId) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { OrganizationMongoDBAdaptorFactory orgFactory = getOrganizationMongoDBAdaptorFactory(organization.getId(), false); if (orgFactory != null && orgFactory.isCatalogDBReady()) { throw new CatalogDBException("Organization '" + organization.getId() + "' already exists."); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/NoteMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/NoteMongoDBAdaptor.java index 820f15ed2f7..0b953919713 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/NoteMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/NoteMongoDBAdaptor.java @@ -14,6 +14,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.CatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.Constants; import org.opencb.opencga.catalog.utils.ParamUtils; @@ -51,8 +52,7 @@ public NoteMongoDBAdaptor(MongoDBCollection noteCollection, MongoDBCollection ar } @Override - public OpenCGAResult insert(Note note) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(Note note) throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting note insert transaction for note id '{}'", note.getId()); @@ -142,7 +142,7 @@ public OpenCGAResult update(long uid, ObjectMap parameters, QueryOptions queryOp throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { try { return runTransaction(clientSession -> privateUpdate(clientSession, uid, parameters, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update note: {}", e.getMessage(), e); throw new CatalogDBException("Could not update note: " + e.getMessage(), e.getCause()); } @@ -262,7 +262,7 @@ public OpenCGAResult delete(Note note) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { try { return runTransaction(clientSession -> privateDelete(clientSession, note)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { throw new CatalogDBException("Could not delete note " + note.getId() + ": " + e.getMessage(), e); } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptor.java index aa090f498d1..b971f5a5740 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptor.java @@ -17,6 +17,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.OrganizationCatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.managers.OrganizationManager; import org.opencb.opencga.catalog.utils.Constants; @@ -52,8 +53,7 @@ public OrganizationMongoDBAdaptor(MongoDBCollection organizationCollection, Conf } @Override - public OpenCGAResult insert(Organization organization, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(Organization organization, QueryOptions options) throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting organization insert transaction for organization id '{}'", organization.getId()); @@ -124,7 +124,7 @@ public OpenCGAResult update(String organizationId, ObjectMap param try { QueryOptions options = queryOptions != null ? new QueryOptions(queryOptions) : QueryOptions.empty(); return runTransaction(clientSession -> privateUpdate(clientSession, organizationId, parameters, options)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update organization {}: {}", organizationId, e.getMessage(), e); throw new CatalogDBException("Could not update organization " + organizationId + ": " + e.getMessage(), e.getCause()); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/PanelMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/PanelMongoDBAdaptor.java index d82535b9351..fcc8f32fd6f 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/PanelMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/PanelMongoDBAdaptor.java @@ -33,6 +33,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.CatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.Constants; import org.opencb.opencga.catalog.utils.UuidUtils; @@ -87,8 +88,7 @@ public MongoDBCollection getPanelArchiveCollection() { } @Override - public OpenCGAResult insert(long studyUid, List panelList) throws CatalogDBException, CatalogParameterException, - CatalogAuthorizationException { + public OpenCGAResult insert(long studyUid, List panelList) throws CatalogException { if (panelList == null || panelList.isEmpty()) { throw new CatalogDBException("Missing panel list"); } @@ -108,8 +108,7 @@ public OpenCGAResult insert(long studyUid, List panelList) throws Catalog } @Override - public OpenCGAResult insert(long studyUid, Panel panel, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(long studyUid, Panel panel, QueryOptions options) throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting insert transaction of panel id '{}'", panel.getId()); @@ -291,7 +290,7 @@ public OpenCGAResult update(long panelUid, ObjectMap parameters, QueryOptions qu try { return runTransaction(clientSession -> privateUpdate(clientSession, dataResult.first(), parameters, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update panel {}: {}", dataResult.first().getId(), e.getMessage(), e); throw new CatalogDBException("Could not update panel '" + dataResult.first().getId() + "': " + e.getMessage(), e.getCause()); } @@ -317,7 +316,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions quer Panel panel = iterator.next(); try { result.append(runTransaction(clientSession -> privateUpdate(clientSession, panel, parameters, queryOptions))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update panel {}: {}", panel.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, panel.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -464,7 +463,7 @@ public OpenCGAResult delete(Panel panel) throws CatalogDBException, CatalogParam throw new CatalogDBException("Could not find panel " + panel.getId() + " with uid " + panel.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete panel {}: {}", panel.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete panel '" + panel.getId() + "': " + e.getMessage(), e.getCause()); } @@ -480,7 +479,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException, CatalogParam String panelId = panel.getString(QueryParams.ID.key()); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, panel))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete panel {}: {}", panelId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, panelId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptor.java index 89d90aab932..3a91bc26284 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptor.java @@ -32,6 +32,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.ProjectCatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.FqnUtils; import org.opencb.opencga.catalog.utils.UuidUtils; @@ -82,8 +83,7 @@ public OpenCGAResult nativeInsert(Map project, String userId) th } @Override - public OpenCGAResult insert(Project project, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(Project project, QueryOptions options) throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting project insert transaction for project id '{}'", project.getId()); @@ -201,7 +201,7 @@ public OpenCGAResult update(long projectUid, ObjectMap parameters, QueryOptions try { return runTransaction(clientSession -> privateUpdate(clientSession, projectDataResult.first(), parameters)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update project {}: {}", projectDataResult.first().getId(), e.getMessage(), e); throw new CatalogDBException("Could not update project '" + projectDataResult.first().getId() + "': " + e.getMessage(), e.getCause()); @@ -220,7 +220,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions quer Project project = iterator.next(); try { result.append(runTransaction(clientSession -> privateUpdate(clientSession, project, parameters))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update project {}: {}", project.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, project.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -383,7 +383,7 @@ public OpenCGAResult delete(long id, QueryOptions queryOptions) throws CatalogDB public OpenCGAResult delete(Project project) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { try { return runTransaction(clientSession -> privateDelete(clientSession, project)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete project {}: {}", project.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete project '" + project.getId() + "': " + e.getMessage(), e.getCause()); } @@ -412,7 +412,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException { try { result.append(runTransaction(clientSession -> privateDelete(clientSession, project))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete project {}: {}", project.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, project.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptor.java index 198c9fce456..d9058193e7d 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptor.java @@ -39,6 +39,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.SampleCatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.managers.IndividualManager; import org.opencb.opencga.catalog.managers.SampleManager; @@ -199,7 +200,7 @@ Sample insert(ClientSession clientSession, long studyUid, Sample sample, List insert(long studyId, Sample sample, List variableSetList, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting sample insert transaction for sample id '{}'", sample.getId()); @@ -262,7 +263,7 @@ public OpenCGAResult update(long uid, ObjectMap parameters, List va try { return runTransaction(clientSession -> privateUpdate(clientSession, documentResult.first(), parameters, variableSetList, queryOptions)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update sample {}: {}", sampleId, e.getMessage(), e); throw new CatalogDBException("Could not update sample " + sampleId + ": " + e.getMessage(), e.getCause()); } @@ -297,7 +298,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, List try { result.append(runTransaction(clientSession -> privateUpdate(clientSession, sampleDocument, parameters, variableSetList, queryOptions))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update sample {}: {}", sampleId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, sampleId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -857,8 +858,7 @@ public OpenCGAResult unmarkPermissionRule(long studyId, String permissionRuleId) } @Override - public OpenCGAResult setRgaIndexes(long studyUid, List sampleUids, RgaIndex rgaIndex) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult setRgaIndexes(long studyUid, List sampleUids, RgaIndex rgaIndex) throws CatalogException { ObjectMap params; try { params = new ObjectMap(getDefaultObjectMapper().writeValueAsString(rgaIndex)); @@ -943,7 +943,7 @@ public OpenCGAResult delete(Sample sample) throws CatalogDBException, CatalogPar throw new CatalogDBException("Could not find sample " + sample.getId() + " with uid " + sample.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete sample {}: {}", sample.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete sample " + sample.getId() + ": " + e.getMessage(), e); } @@ -960,7 +960,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException { try { result.append(runTransaction(clientSession -> privateDelete(clientSession, sample))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete sample {}: {}", sampleId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, sampleId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptor.java index 5c6e0ff2035..c91fd4c3665 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptor.java @@ -38,6 +38,7 @@ import org.opencb.opencga.catalog.db.mongodb.iterators.StudyCatalogMongoDBIterator; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.Constants; import org.opencb.opencga.catalog.utils.FqnUtils; @@ -490,8 +491,7 @@ OpenCGAResult removeUsersFromAdminsGroup(ClientSession clientSession, Lis } @Override - public OpenCGAResult removeUsersFromAllGroups(long studyId, List users) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult removeUsersFromAllGroups(long studyId, List users) throws CatalogException { if (users == null || users.size() == 0) { throw new CatalogDBException("Unable to remove users from groups. List of users is empty"); } @@ -546,8 +546,7 @@ public OpenCGAResult syncGroup(long studyId, String groupId, Group.Sync s } @Override - public OpenCGAResult resyncUserWithSyncedGroups(String user, List groupList, String authOrigin) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult resyncUserWithSyncedGroups(String user, List groupList, String authOrigin) throws CatalogException { if (StringUtils.isEmpty(user)) { throw new CatalogDBException("Missing user field"); } @@ -600,8 +599,7 @@ public OpenCGAResult resyncUserWithSyncedGroups(String user, List @Override public OpenCGAResult updateUserFromGroups(String user, List studyUids, List groupList, - ParamUtils.AddRemoveAction action) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + ParamUtils.AddRemoveAction action) throws CatalogException { if (StringUtils.isEmpty(user)) { throw new CatalogParameterException("Missing user parameter"); @@ -820,7 +818,7 @@ public OpenCGAResult createVariableSet(long studyId, VariableSet va @Override public OpenCGAResult addFieldToVariableSet(long studyUid, long variableSetId, Variable variable, String user) - throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { + throws CatalogException { OpenCGAResult variableSet = getVariableSet(variableSetId, new QueryOptions(), user); checkVariableNotInVariableSet(variableSet.first(), variable.getId()); @@ -897,9 +895,7 @@ public OpenCGAResult renameFieldVariableSet(long variableSetId, Str @Override public OpenCGAResult removeFieldFromVariableSet(long studyUid, long variableSetId, String name, String user) - throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { - long startTime = startQuery(); - + throws CatalogException { OpenCGAResult variableSet = getVariableSet(variableSetId, new QueryOptions(), user); checkVariableInVariableSet(variableSet.first(), name); @@ -1167,8 +1163,7 @@ public OpenCGAResult getVariableSets(Query query, QueryOptions quer } @Override - public OpenCGAResult deleteVariableSet(long studyUid, VariableSet variableSet, boolean force) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult deleteVariableSet(long studyUid, VariableSet variableSet, boolean force) throws CatalogException { try { return runTransaction(clientSession -> { if (force) { @@ -1341,7 +1336,7 @@ public OpenCGAResult update(long studyUid, ObjectMap parameters, QueryOptions qu try { return runTransaction(clientSession -> privateUpdate(clientSession, studyResult.first(), parameters)); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not update study {}: {}", studyId, e.getMessage(), e); throw new CatalogDBException("Could not update study '" + studyId + "': " + e.getMessage(), e.getCause()); } @@ -1364,7 +1359,7 @@ public OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions quer Study study = iterator.next(); try { result.append(runTransaction(clientSession -> privateUpdate(clientSession, study, parameters))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not update study {}: {}", study.getId(), e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, study.getId(), e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); @@ -1478,7 +1473,7 @@ public OpenCGAResult delete(Study study) throws CatalogDBException, CatalogParam throw new CatalogDBException("Could not find study " + study.getId() + " with uid " + study.getUid()); } return runTransaction(clientSession -> privateDelete(clientSession, result.first())); - } catch (CatalogDBException e) { + } catch (CatalogException e) { logger.error("Could not delete study {}: {}", study.getId(), e.getMessage(), e); throw new CatalogDBException("Could not delete study " + study.getId() + ": " + e.getMessage(), e.getCause()); } @@ -1494,7 +1489,7 @@ public OpenCGAResult delete(Query query) throws CatalogDBException { String studyId = study.getString(QueryParams.ID.key()); try { result.append(runTransaction(clientSession -> privateDelete(clientSession, study))); - } catch (CatalogDBException | CatalogParameterException | CatalogAuthorizationException e) { + } catch (CatalogException e) { logger.error("Could not delete study {}: {}", studyId, e.getMessage(), e); result.getEvents().add(new Event(Event.Type.ERROR, studyId, e.getMessage())); result.setNumMatches(result.getNumMatches() + 1); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 76bc3bd9926..775b6cd3b2c 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -18,6 +18,7 @@ import com.mongodb.client.ClientSession; import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; import com.mongodb.client.model.Updates; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.NotImplementedException; @@ -37,13 +38,12 @@ import org.opencb.opencga.catalog.db.api.UserDBAdaptor; import org.opencb.opencga.catalog.db.mongodb.converters.UserConverter; import org.opencb.opencga.catalog.db.mongodb.iterators.CatalogMongoDBIterator; -import org.opencb.opencga.catalog.exceptions.CatalogAuthenticationException; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; -import org.opencb.opencga.catalog.exceptions.CatalogDBException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; +import org.opencb.opencga.catalog.exceptions.*; import org.opencb.opencga.catalog.managers.StudyManager; import org.opencb.opencga.catalog.utils.ParamUtils; +import org.opencb.opencga.core.common.PasswordUtils; import org.opencb.opencga.core.common.TimeUtils; +import org.opencb.opencga.core.config.AuthenticationOrigin; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.models.common.InternalStatus; import org.opencb.opencga.core.models.project.Project; @@ -73,8 +73,22 @@ public class UserMongoDBAdaptor extends CatalogMongoDBAdaptor implements UserDBA private final MongoDBCollection deletedUserCollection; private UserConverter userConverter; - private static final String PRIVATE_PASSWORD = "_password"; - private static final String ARCHIVE_PASSWORD = "_archivePasswords"; + // --- Password constants --- + public static final String HASH = "hash"; + public static final String SALT = "salt"; + + public static final String PRIVATE_PASSWORD = "_password"; + + public static final String CURRENT = "current"; + private static final String PRIVATE_PASSWORD_CURRENT = "_password." + CURRENT; + private static final String PRIVATE_PASSWORD_CURRENT_HASH = PRIVATE_PASSWORD_CURRENT + "." + HASH; + private static final String PRIVATE_PASSWORD_CURRENT_SALT = PRIVATE_PASSWORD_CURRENT + "." + SALT; + + public static final String ARCHIVE = "archive"; + public static final String PRIVATE_PASSWORD_ARCHIVE = "_password." + ARCHIVE; + private static final String PRIVATE_PASSWORD_ARCHIVE_HASH = PRIVATE_PASSWORD_ARCHIVE + "." + HASH; + private static final String PRIVATE_PASSWORD_ARCHIVE_SALT = PRIVATE_PASSWORD_ARCHIVE + "." + SALT; + // -------------------------- public UserMongoDBAdaptor(MongoDBCollection userCollection, MongoDBCollection deletedUserCollection, Configuration configuration, OrganizationMongoDBAdaptorFactory dbAdaptorFactory) { @@ -96,8 +110,7 @@ boolean exists(ClientSession clientSession, String userId) throws CatalogDBExcep } @Override - public OpenCGAResult insert(User user, String password, QueryOptions options) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(User user, String password, QueryOptions options) throws CatalogException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); @@ -120,8 +133,18 @@ private void insert(ClientSession clientSession, User user, String password) thr Document userDocument = userConverter.convertToStorageType(user); userDocument.append(ID, user.getId()); - userDocument.append(PRIVATE_PASSWORD, encryptPassword(password)); - userDocument.append(ARCHIVE_PASSWORD, Collections.singletonList(encryptPassword(password))); + + Document privatePassword = new Document(); + if (StringUtils.isNotEmpty(password)) { + String salt = PasswordUtils.getStrongRandomPassword(); + String hash = encryptPassword(password + salt); + Document passwordDoc = new Document() + .append(HASH, hash) + .append(SALT, salt); + privatePassword.put(CURRENT, passwordDoc); + privatePassword.put(ARCHIVE, Collections.singletonList(passwordDoc)); + } + userDocument.put(PRIVATE_PASSWORD, privatePassword); userCollection.insert(clientSession, userDocument, null); } @@ -134,78 +157,118 @@ public OpenCGAResult get(String userId, QueryOptions options) } @Override - public OpenCGAResult changePassword(String userId, String oldPassword, String newPassword) - throws CatalogDBException, CatalogAuthenticationException { + public OpenCGAResult changePassword(String userId, String oldPassword, String newPassword) throws CatalogException { return setPassword(userId, oldPassword, newPassword); } @Override - public void authenticate(String userId, String password) throws CatalogAuthenticationException { - Document bson; - try { - bson = new Document() - .append(ID, userId) - .append(PRIVATE_PASSWORD, encryptPassword(password)); - } catch (CatalogDBException e) { - throw new CatalogAuthenticationException("Could not encrypt password: " + e.getMessage(), e); + public void authenticate(String userId, String password) throws CatalogDBException, CatalogAuthenticationException { + Bson query = Filters.and( + Filters.eq(QueryParams.ID.key(), userId), + Filters.eq(INTERNAL_ACCOUNT_AUTHENTICATION_ID.key(), AuthenticationOrigin.AuthenticationType.OPENCGA) + ); + Bson projection = Projections.include(PRIVATE_PASSWORD); + DataResult dataResult = userCollection.find(query, projection, QueryOptions.empty()); + if (dataResult.getNumResults() == 0) { + throw new CatalogDBException("User " + userId + " not found"); + } + Document userDocument = dataResult.first(); + Document rootPasswordDoc = userDocument.get(PRIVATE_PASSWORD, Document.class); + if (rootPasswordDoc == null) { + throw new CatalogDBException("Critical error. User '" + userId + "' does not have any password set. Please, contact" + + " with the developers."); } - if (userCollection.count(bson).getNumMatches() == 0) { - throw CatalogAuthenticationException.incorrectUserOrPassword("Internal"); + Document passwordDoc = rootPasswordDoc.get(CURRENT, Document.class); + if (passwordDoc == null) { + throw new CatalogDBException("Critical error. User '" + userId + "' does not have any password set. Please, contact" + + " with the developers."); + } + + String salt = passwordDoc.getString(SALT); + String hash = encryptPassword(password + salt); + if (!hash.equals(passwordDoc.getString(HASH))) { + throw CatalogAuthenticationException.incorrectUserOrPassword(AuthenticationOrigin.AuthenticationType.OPENCGA.name()); } } @Override - public OpenCGAResult resetPassword(String userId, String email, String newPassword) throws CatalogDBException { + public OpenCGAResult resetPassword(String userId, String email, String newPassword) throws CatalogException { return setPassword(userId, null, newPassword); } - public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, String newPassword) throws CatalogDBException { - List queryFilter = new ArrayList<>(); - queryFilter.add(Filters.eq(QueryParams.ID.key(), userId)); - queryFilter.add(Filters.ne(ARCHIVE_PASSWORD, encryptPassword(newPassword))); - if (StringUtils.isNotEmpty(oldPassword)) { - queryFilter.add(Filters.eq(PRIVATE_PASSWORD, encryptPassword(oldPassword))); - } - Bson query = Filters.and(queryFilter); + public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, String newPassword) throws CatalogException { + String prefixErrorMsg = "Could not update the password. "; + return runTransaction(clientSession -> { + // 1. Obtain archived passwords + Bson query = Filters.eq(QueryParams.ID.key(), userId); + Bson projection = Projections.include(PRIVATE_PASSWORD); + DataResult userQueryResult = userCollection.find(clientSession, query, projection, QueryOptions.empty()); + if (userQueryResult.getNumResults() == 0) { + throw new CatalogDBException(prefixErrorMsg + "User " + userId + " not found."); + } + Document userDoc = userQueryResult.first(); + Document passwordDoc = userDoc.get(PRIVATE_PASSWORD, Document.class); + + // 1.1. Check oldPassword + if (StringUtils.isNotEmpty(oldPassword)) { + Document currentPasswordDoc = passwordDoc.get(CURRENT, Document.class); + String currentSalt = currentPasswordDoc.getString(SALT); + String currentHash = encryptPassword(oldPassword + currentSalt); + if (!currentHash.equals(currentPasswordDoc.getString(HASH))) { + throw new CatalogAuthenticationException(prefixErrorMsg + "Please, verify that the current password is correct."); + } + } - UpdateDocument updateDocument = new UpdateDocument(); - String encryptedPassword = encryptPassword(newPassword); - updateDocument.getSet().put(PRIVATE_PASSWORD, encryptedPassword); - updateDocument.getPush().put(ARCHIVE_PASSWORD, encryptedPassword); - updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_LAST_MODIFIED.key(), TimeUtils.getTime()); - if (configuration.getAccount().getPasswordExpirationDays() > 0) { - Date date = TimeUtils.addDaysToCurrentDate(configuration.getAccount().getPasswordExpirationDays()); - String stringDate = TimeUtils.getTime(date); - updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE.key(), stringDate); - } - Document update = updateDocument.toFinalUpdateDocument(); + // 2. Calculate all possible hashValues with new password + Set hashValues = new HashSet<>(); + List saltValues = passwordDoc.getList(ARCHIVE, Document.class).stream() + .map(document -> document.getString(SALT)) + .collect(Collectors.toList()); + for (String saltValue : saltValues) { + hashValues.add(encryptPassword(newPassword + saltValue)); + } - logger.debug("Change password: query '{}'; update: '{}'", query.toBsonDocument(), update); - DataResult result = userCollection.update(query, update, null); - if (result.getNumUpdated() == 0) { - if (result.getNumMatches() == 0) { - Query userQuery = new Query(QueryParams.ID.key(), userId); - OpenCGAResult queryResult = nativeGet(userQuery, - new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(PRIVATE_PASSWORD, ARCHIVE_PASSWORD))); - if (queryResult.getNumResults() == 0) { - throw new CatalogDBException("Could not update the password. User not found."); - } - Document userDocument = queryResult.first(); - if (StringUtils.isNotEmpty(oldPassword)) { - String dbPassword = userDocument.getString(PRIVATE_PASSWORD); - if (!encryptPassword(oldPassword).equals(dbPassword)) { - throw new CatalogDBException("Could not update the password. Please, verify that the current password is correct."); - } - } - List archivePassword = userDocument.getList(ARCHIVE_PASSWORD, String.class); - if (archivePassword.contains(encryptedPassword)) { - throw new CatalogDBException("Could not update the password. The new password has already been used. Please, use" - + " a different one."); + // 3. Check new password has not been used before + for (Document document : passwordDoc.getList(ARCHIVE, Document.class)) { + String hashValue = document.getString(HASH); + if (hashValues.contains(hashValue)) { + throw new CatalogAuthenticationException(prefixErrorMsg + "The new password has already been used." + + " Please, use a different one."); } } - throw new CatalogDBException("Could not update the password. Please, verify that the current password is correct."); - } - return new OpenCGAResult(result); + + // 4. Generate new salt for current password + String newSalt = PasswordUtils.getStrongRandomPassword(); + String newHash = encryptPassword(newPassword + newSalt); + + // 5. Generate update document + UpdateDocument updateDocument = new UpdateDocument(); + // add to current + updateDocument.getSet().put(PRIVATE_PASSWORD_CURRENT_HASH, newHash); + updateDocument.getSet().put(PRIVATE_PASSWORD_CURRENT_SALT, newSalt); + + // add to archive + Document document = new Document() + .append(HASH, newHash) + .append(SALT, newSalt); + updateDocument.getPush().put(PRIVATE_PASSWORD_ARCHIVE, document); + + updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_LAST_MODIFIED.key(), TimeUtils.getTime()); + if (configuration.getAccount().getPasswordExpirationDays() > 0) { + Date date = TimeUtils.addDaysToCurrentDate(configuration.getAccount().getPasswordExpirationDays()); + String stringDate = TimeUtils.getTime(date); + updateDocument.getSet().put(INTERNAL_ACCOUNT_PASSWORD_EXPIRATION_DATE.key(), stringDate); + } + Document update = updateDocument.toFinalUpdateDocument(); + + logger.debug("Change password: query '{}'; update: '{}'", query.toBsonDocument(), update); + DataResult result = userCollection.update(clientSession, query, update, null); + if (result.getNumUpdated() == 0) { + throw new CatalogAuthenticationException("Could not update the password. Please, verify that the current password is" + + " correct."); + } + return new OpenCGAResult(result); + }, e -> logger.error("User {}: {}", userId, e.getMessage())); } @Override diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java index 4628126dc51..f32c8422dec 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/NoteManager.java @@ -303,7 +303,7 @@ private OpenCGAResult update(long noteUid, NoteUpdateParams noteUpdatePara updateMap.put(NoteDBAdaptor.QueryParams.USER_ID.key(), tokenPayload.getUserId()); OpenCGAResult update = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).update(noteUid, updateMap, - QueryOptions.empty()); + options); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { // Fetch updated note OpenCGAResult result = getCatalogDBAdaptorFactory().getCatalogNoteDBAdaptor(organizationId).get(noteUid, options); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java index 2612ea7f633..20ec12a7f2b 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java @@ -327,9 +327,6 @@ public OpenCGAResult updateUser(@Nullable String organizationId, String us throw new CatalogException("Max CPU cannot be negative"); } } - if (updateParams.getAccount() != null && StringUtils.isNotEmpty(updateParams.getAccount().getExpirationDate())) { - ParamUtils.checkDateIsNotExpired(updateParams.getAccount().getExpirationDate(), "expirationDate"); - } ObjectMap updateMap; try { @@ -337,6 +334,12 @@ public OpenCGAResult updateUser(@Nullable String organizationId, String us } catch (JsonProcessingException e) { throw new CatalogException("Could not parse OrganizationUserUpdateParams object: " + e.getMessage(), e); } + + if (updateParams.getInternal() != null && updateParams.getInternal().getAccount() != null + && StringUtils.isNotEmpty(updateParams.getInternal().getAccount().getExpirationDate())) { + ParamUtils.checkDateIsNotExpired(updateParams.getInternal().getAccount().getExpirationDate(), "expirationDate"); + } + OpenCGAResult updateResult = getUserDBAdaptor(myOrganizationId).update(userId, updateMap); auditManager.auditUpdate(myOrganizationId, tokenPayload.getUserId(myOrganizationId), Enums.Resource.USER, userId, "", "", "", auditParams, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptorTest.java index 4cae5cd565b..8882260fabc 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptorTest.java @@ -26,9 +26,8 @@ import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.opencga.catalog.db.api.IndividualDBAdaptor; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; +import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.core.models.individual.Individual; import org.opencb.opencga.core.models.individual.IndividualInternal; import org.opencb.opencga.core.models.individual.IndividualPopulation; @@ -187,7 +186,7 @@ public void testModifyIndividualNegativeFatherId() throws Exception { } @Test - public void testAvoidDuplicatedSamples() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void testAvoidDuplicatedSamples() throws CatalogException { dbAdaptorFactory.getCatalogSampleDBAdaptor(organizationId).insert(studyUid, new Sample().setId("sample1").setInternal(SampleInternal.init()), Collections.emptyList(), QueryOptions.empty()); Sample sample1 = getSample(studyUid, "sample1"); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptorTest.java index 9c6d82a4c79..a382282764d 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/JobMongoDBAdaptorTest.java @@ -60,7 +60,7 @@ private Job getNewJob(String id) { } @Test - public void createJobTest() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void createJobTest() throws CatalogException { Job job = getNewJob("jobName1"); System.out.println(catalogJobDBAdaptor.insert(studyUid, job, null)); @@ -120,7 +120,7 @@ public void getJobTest() throws CatalogException { } @Test - public void testSortResultsPriorityAndCreationDate() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void testSortResultsPriorityAndCreationDate() throws CatalogException { Date startDate = TimeUtils.getDate(); // Create 100 jobs @@ -176,7 +176,7 @@ public void testSortResultsPriorityAndCreationDate() throws CatalogDBException, // } @Test - public void getJobsOrderedByDate() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void getJobsOrderedByDate() throws CatalogException { // Job with current date Job job1 = getNewJob("job1"); @@ -250,7 +250,7 @@ public void updateInputAndOutputFiles() throws Exception { } @Test - public void groupByStatus() throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { + public void groupByStatus() throws CatalogException { for (int i = 0; i < 10; i++) { Enums.ExecutionStatus status = new Enums.ExecutionStatus(); if (i < 5) { diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptorTest.java index 5488bc6a545..fa908630690 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/SampleMongoDBAdaptorTest.java @@ -27,10 +27,8 @@ import org.opencb.opencga.catalog.db.api.CohortDBAdaptor; import org.opencb.opencga.catalog.db.api.FileDBAdaptor; import org.opencb.opencga.catalog.db.api.SampleDBAdaptor; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.managers.SampleManager; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.models.cohort.Cohort; @@ -175,7 +173,7 @@ public class SampleMongoDBAdaptorTest extends AbstractMongoDBAdaptorTest { // } @Test - public void searchByOntology() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void searchByOntology() throws CatalogException { List ontologyList = Arrays.asList( new Phenotype("hpo:123", "One hpo term", "hpo", Phenotype.Status.UNKNOWN), new Phenotype("hpo:456", "Another hpo term", "hpo", Phenotype.Status.UNKNOWN), @@ -387,7 +385,7 @@ public void caseInsensitiveSearchTest() throws Exception { // Test if we can search for samples of an individual @Test - public void getSampleWithIndividual() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void getSampleWithIndividual() throws CatalogException { QueryOptions queryOptions = new QueryOptions(); // We create a new sample with the individual diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptorTest.java index 697a77d894f..f81f28b37a6 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/StudyMongoDBAdaptorTest.java @@ -20,10 +20,8 @@ import org.junit.experimental.categories.Category; import org.opencb.commons.datastore.core.DataResult; import org.opencb.commons.datastore.core.QueryOptions; -import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; -import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.utils.FqnUtils; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.core.api.ParamConstants; @@ -112,7 +110,7 @@ public void createVariableSetTest() throws CatalogDBException { } @Test - public void testRemoveFieldFromVariableSet() throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { + public void testRemoveFieldFromVariableSet() throws CatalogException { DataResult variableSetDataResult = createExampleVariableSet("VARSET_1", false); DataResult result = catalogStudyDBAdaptor.removeFieldFromVariableSet(5L, variableSetDataResult.first().getUid(), "NAME", orgAdminUserId1); @@ -165,7 +163,7 @@ public void testRemoveFieldFromVariableSet() throws CatalogDBException, CatalogA * @throws CatalogDBException */ @Test - public void addFieldToVariableSetTest1() throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { + public void addFieldToVariableSetTest1() throws CatalogException { DataResult varset1 = createExampleVariableSet("VARSET_1", false); createExampleVariableSet("VARSET_2", true); Variable variable = new Variable("NAM", "", Variable.VariableType.STRING, "", true, false, Collections.emptyList(), null, 0, "", "", null, @@ -191,7 +189,7 @@ public void addFieldToVariableSetTest1() throws CatalogDBException, CatalogAutho * @throws CatalogDBException */ @Test - public void addFieldToVariableSetTest2() throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { + public void addFieldToVariableSetTest2() throws CatalogException { Variable variable = new Variable("NAM", "", Variable.VariableType.STRING, "", true, false, Collections.emptyList(), null, 0, "", "", null, Collections.emptyMap()); thrown.expect(CatalogDBException.class); @@ -208,7 +206,7 @@ public void createGroup() throws CatalogDBException { } @Test - public void removeUsersFromAllGroups() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void removeUsersFromAllGroups() throws CatalogException { catalogStudyDBAdaptor.createGroup(studyUid, new Group("name1", Arrays.asList(normalUserId1, normalUserId2))); catalogStudyDBAdaptor.createGroup(studyUid, new Group("name2", Arrays.asList(normalUserId1, normalUserId2, normalUserId3))); catalogStudyDBAdaptor.createGroup(studyUid, new Group("name3", Arrays.asList(normalUserId1, normalUserId3))); @@ -221,7 +219,7 @@ public void removeUsersFromAllGroups() throws CatalogDBException, CatalogParamet } @Test - public void resyncUserWithSyncedGroups() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void resyncUserWithSyncedGroups() throws CatalogException { // We create synced groups and not synced groups in study studyUid Group group = new Group("@notSyncedGroup", Arrays.asList(normalUserId1, normalUserId2, normalUserId3)); catalogStudyDBAdaptor.createGroup(studyUid, group); @@ -293,7 +291,7 @@ public void resyncUserWithSyncedGroups() throws CatalogDBException, CatalogParam } @Test - public void updateUserToGroups() throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public void updateUserToGroups() throws CatalogException { // We create synced groups and not synced groups in study studyUid Group group = new Group("@notSyncedGroup", Collections.emptyList()); catalogStudyDBAdaptor.createGroup(studyUid, group); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptorTest.java index a007c100b0f..8e4571d86ea 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptorTest.java @@ -100,7 +100,7 @@ public void getUserTest() throws CatalogDBException, CatalogParameterException, } @Test - public void changePasswordTest() throws CatalogDBException, CatalogAuthenticationException { + public void changePasswordTest() throws CatalogException { DataResult result = catalogUserDBAdaptor.changePassword(normalUserId1, TestParamConstants.PASSWORD, "1234"); assertEquals(1, result.getNumUpdated()); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java index 7bfda8c5261..f23295fbd60 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/UserManagerTest.java @@ -438,7 +438,7 @@ public void testModifyUser() throws CatalogException, InterruptedException, IOEx assertEquals(userPost.getEmail(), newEmail); catalogManager.getUserManager().login(organizationId, orgOwnerUserId, newPassword); - CatalogDBException exception = assertThrows(CatalogDBException.class, + CatalogAuthenticationException exception = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().changePassword(organizationId, orgOwnerUserId, newPassword, TestParamConstants.PASSWORD)); assertTrue(exception.getMessage().contains("The new password has already been used")); @@ -513,7 +513,7 @@ public void changePasswordTest() throws CatalogException { catalogManager.getUserManager().changePassword(organizationId, normalUserId1, TestParamConstants.PASSWORD, newPassword); catalogManager.getUserManager().login(organizationId, normalUserId1, newPassword); - CatalogDBException exception = assertThrows(CatalogDBException.class, + CatalogAuthenticationException exception = assertThrows(CatalogAuthenticationException.class, () -> catalogManager.getUserManager().changePassword(organizationId, normalUserId1, TestParamConstants.PASSWORD, newPassword)); assertTrue(exception.getMessage().contains("verify that the current password is correct")); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/OrganizationUserUpdateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/OrganizationUserUpdateParams.java index ce30fd63c41..938ebd6dc7f 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/user/OrganizationUserUpdateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/user/OrganizationUserUpdateParams.java @@ -11,16 +11,16 @@ public class OrganizationUserUpdateParams extends UserUpdateParams { private UserQuota quota; - private Account account; + private Internal internal; private Map attributes; public OrganizationUserUpdateParams() { } - public OrganizationUserUpdateParams(String name, String email, UserQuota quota, Account account, Map attributes) { + public OrganizationUserUpdateParams(String name, String email, UserQuota quota, Internal internal, Map attributes) { super(name, email); this.quota = quota; - this.account = account; + this.internal = internal; this.attributes = attributes; } @@ -33,7 +33,7 @@ public ObjectMap getUpdateMap() throws JsonProcessingException { public String toString() { final StringBuilder sb = new StringBuilder("OrganizationUserUpdateParams{"); sb.append("quota=").append(quota); - sb.append(", account=").append(account); + sb.append(", internal=").append(internal); sb.append(", attributes=").append(attributes); sb.append('}'); return sb.toString(); @@ -48,12 +48,27 @@ public OrganizationUserUpdateParams setQuota(UserQuota quota) { return this; } + @Deprecated + @JsonIgnore public Account getAccount() { - return account; + return getInternal().getAccount(); } + @Deprecated public OrganizationUserUpdateParams setAccount(Account account) { - this.account = account; + if (internal == null) { + internal = new Internal(); + } + internal.setAccount(account); + return this; + } + + public Internal getInternal() { + return internal; + } + + public OrganizationUserUpdateParams setInternal(Internal internal) { + this.internal = internal; return this; } @@ -78,6 +93,30 @@ public OrganizationUserUpdateParams setEmail(String email) { return this; } + public static class Internal { + private Account account; + + public Internal() { + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Internal{"); + sb.append("account=").append(account); + sb.append('}'); + return sb.toString(); + } + + public Account getAccount() { + return account; + } + + public Internal setAccount(Account account) { + this.account = account; + return this; + } + } + public static class Account { private String expirationDate; From f5c19954585b9a1fef164fd29b468a51882921a0 Mon Sep 17 00:00:00 2001 From: pfurio Date: Fri, 9 Aug 2024 12:11:14 +0200 Subject: [PATCH 06/10] catalog: backwards compatibility, #TASK-6494 --- .../opencga/catalog/db/api/UserDBAdaptor.java | 1 + .../db/mongodb/UserMongoDBAdaptor.java | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java index 52b0022f533..84efa64aea2 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/UserDBAdaptor.java @@ -119,6 +119,7 @@ enum QueryParams implements QueryParam { CREATION_DATE("creationDate", TEXT_ARRAY, ""), MODIFICATION_DATE("modificationDate", TEXT_ARRAY, ""), DEPRECATED_ACCOUNT("account", OBJECT, ""), // Deprecated since 3.2.1 #TASK-6494 TODO: Remove in future releases + DEPRECATED_ACCOUNT_AUTHENTICATION_ID("account.authentication.id", TEXT, ""), // Deprecated since 3.2.1 #TASK-6494 INTERNAL("internal", OBJECT, ""), INTERNAL_STATUS_ID("internal.status.id", TEXT, ""), INTERNAL_STATUS_DATE("internal.status.date", TEXT, ""), diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 775b6cd3b2c..940e5d264f9 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -41,6 +41,7 @@ import org.opencb.opencga.catalog.exceptions.*; import org.opencb.opencga.catalog.managers.StudyManager; import org.opencb.opencga.catalog.utils.ParamUtils; +import org.opencb.opencga.core.api.ParamConstants; import org.opencb.opencga.core.common.PasswordUtils; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.AuthenticationOrigin; @@ -165,7 +166,11 @@ public OpenCGAResult changePassword(String userId, String oldPassword, String ne public void authenticate(String userId, String password) throws CatalogDBException, CatalogAuthenticationException { Bson query = Filters.and( Filters.eq(QueryParams.ID.key(), userId), - Filters.eq(INTERNAL_ACCOUNT_AUTHENTICATION_ID.key(), AuthenticationOrigin.AuthenticationType.OPENCGA) + // TODO: Deprecated. Remove Filters.or using the deprecated account authentication id + Filters.or( + Filters.eq(DEPRECATED_ACCOUNT_AUTHENTICATION_ID.key(), AuthenticationOrigin.AuthenticationType.OPENCGA), + Filters.eq(INTERNAL_ACCOUNT_AUTHENTICATION_ID.key(), AuthenticationOrigin.AuthenticationType.OPENCGA) + ) ); Bson projection = Projections.include(PRIVATE_PASSWORD); DataResult dataResult = userCollection.find(query, projection, QueryOptions.empty()); @@ -173,7 +178,25 @@ public void authenticate(String userId, String password) throws CatalogDBExcepti throw new CatalogDBException("User " + userId + " not found"); } Document userDocument = dataResult.first(); - Document rootPasswordDoc = userDocument.get(PRIVATE_PASSWORD, Document.class); + Object rootPasswordObject = userDocument.get(PRIVATE_PASSWORD); + Document rootPasswordDoc; + // TODO: Remove this block of code in the future when all users have been migrated + if (rootPasswordObject instanceof String) { + if (ParamConstants.OPENCGA_USER_ID.equals(userId)) { + logger.warn("User {} is using the deprecated password format. Please, migrate your code as soon as possible.", userId); + if (!encryptPassword(password).equals(rootPasswordObject)) { + throw CatalogAuthenticationException.incorrectUserOrPassword(AuthenticationOrigin.AuthenticationType.OPENCGA.name()); + } + return; + } else { + throw new CatalogDBException("User '" + userId + "' is using the deprecated password format. Please, ask your" + + " administrator to run the pending migrations to fix this issue."); + } + } else { + rootPasswordDoc = (Document) rootPasswordObject; + } + // TODO: End of block of code to remove (and replace using commented code below) +// Document rootPasswordDoc = userDocument.get(PRIVATE_PASSWORD, Document.class); if (rootPasswordDoc == null) { throw new CatalogDBException("Critical error. User '" + userId + "' does not have any password set. Please, contact" + " with the developers."); From 85f58f37d6575506915bb1bf203a58de056789d6 Mon Sep 17 00:00:00 2001 From: pfurio Date: Fri, 9 Aug 2024 12:25:24 +0200 Subject: [PATCH 07/10] catalog: increase random salt length to 32, #TASK-6494 --- .../opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java | 4 ++-- .../java/org/opencb/opencga/core/common/PasswordUtils.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 940e5d264f9..2375ddc03f2 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -137,7 +137,7 @@ private void insert(ClientSession clientSession, User user, String password) thr Document privatePassword = new Document(); if (StringUtils.isNotEmpty(password)) { - String salt = PasswordUtils.getStrongRandomPassword(); + String salt = PasswordUtils.getStrongRandomSalt(); String hash = encryptPassword(password + salt); Document passwordDoc = new Document() .append(HASH, hash) @@ -261,7 +261,7 @@ public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, St } // 4. Generate new salt for current password - String newSalt = PasswordUtils.getStrongRandomPassword(); + String newSalt = PasswordUtils.getStrongRandomSalt(); String newHash = encryptPassword(newPassword + newSalt); // 5. Generate update document diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java b/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java index d0e102cebed..e6e99ed2768 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java @@ -29,6 +29,10 @@ public static String getStrongRandomPassword() { return getStrongRandomPassword(DEFAULT_PASSWORD_LENGTH); } + public static String getStrongRandomSalt() { + return getStrongRandomPassword(32); + } + public static String getStrongRandomPassword(int length) { CharacterRule upper = new CharacterRule(EnglishCharacterData.UpperCase); CharacterRule lower = new CharacterRule(EnglishCharacterData.LowerCase); From 893787ca74c58fc23107dea10ac80c96706f3cfe Mon Sep 17 00:00:00 2001 From: pfurio Date: Fri, 9 Aug 2024 12:28:31 +0200 Subject: [PATCH 08/10] core: add constant variable for the salt lenght, #TASK-6494 --- .../java/org/opencb/opencga/core/common/PasswordUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java b/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java index e6e99ed2768..91fb20b8455 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/common/PasswordUtils.java @@ -10,6 +10,7 @@ public class PasswordUtils { public static final int MIN_STRONG_PASSWORD_LENGTH = 8; public static final int DEFAULT_PASSWORD_LENGTH = 10; + public static final int DEFAULT_SALT_LENGTH = 32; public static final String PASSWORD_REQUIREMENT = "Password must contain at least " + MIN_STRONG_PASSWORD_LENGTH + " characters, including at least one uppercase letter, one lowercase letter, one digit and one special character."; @@ -30,7 +31,7 @@ public static String getStrongRandomPassword() { } public static String getStrongRandomSalt() { - return getStrongRandomPassword(32); + return getStrongRandomPassword(DEFAULT_SALT_LENGTH); } public static String getStrongRandomPassword(int length) { From 759a7c64a4f4d6115bfb27d94729b979bfa60659 Mon Sep 17 00:00:00 2001 From: pfurio Date: Fri, 9 Aug 2024 16:41:45 +0200 Subject: [PATCH 09/10] catalog: add salt to encryptPassword method, #TASK-6494 --- .../db/mongodb/UserMongoDBAdaptor.java | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 2375ddc03f2..62d83109679 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -138,7 +138,7 @@ private void insert(ClientSession clientSession, User user, String password) thr Document privatePassword = new Document(); if (StringUtils.isNotEmpty(password)) { String salt = PasswordUtils.getStrongRandomSalt(); - String hash = encryptPassword(password + salt); + String hash = encryptPassword(password, salt); Document passwordDoc = new Document() .append(HASH, hash) .append(SALT, salt); @@ -184,7 +184,7 @@ public void authenticate(String userId, String password) throws CatalogDBExcepti if (rootPasswordObject instanceof String) { if (ParamConstants.OPENCGA_USER_ID.equals(userId)) { logger.warn("User {} is using the deprecated password format. Please, migrate your code as soon as possible.", userId); - if (!encryptPassword(password).equals(rootPasswordObject)) { + if (!encryptPassword(password, "").equals(rootPasswordObject)) { throw CatalogAuthenticationException.incorrectUserOrPassword(AuthenticationOrigin.AuthenticationType.OPENCGA.name()); } return; @@ -208,7 +208,7 @@ public void authenticate(String userId, String password) throws CatalogDBExcepti } String salt = passwordDoc.getString(SALT); - String hash = encryptPassword(password + salt); + String hash = encryptPassword(password, salt); if (!hash.equals(passwordDoc.getString(HASH))) { throw CatalogAuthenticationException.incorrectUserOrPassword(AuthenticationOrigin.AuthenticationType.OPENCGA.name()); } @@ -236,7 +236,7 @@ public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, St if (StringUtils.isNotEmpty(oldPassword)) { Document currentPasswordDoc = passwordDoc.get(CURRENT, Document.class); String currentSalt = currentPasswordDoc.getString(SALT); - String currentHash = encryptPassword(oldPassword + currentSalt); + String currentHash = encryptPassword(oldPassword, currentSalt); if (!currentHash.equals(currentPasswordDoc.getString(HASH))) { throw new CatalogAuthenticationException(prefixErrorMsg + "Please, verify that the current password is correct."); } @@ -248,7 +248,7 @@ public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, St .map(document -> document.getString(SALT)) .collect(Collectors.toList()); for (String saltValue : saltValues) { - hashValues.add(encryptPassword(newPassword + saltValue)); + hashValues.add(encryptPassword(newPassword, saltValue)); } // 3. Check new password has not been used before @@ -262,7 +262,7 @@ public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, St // 4. Generate new salt for current password String newSalt = PasswordUtils.getStrongRandomSalt(); - String newHash = encryptPassword(newPassword + newSalt); + String newHash = encryptPassword(newPassword, newSalt); // 5. Generate update document UpdateDocument updateDocument = new UpdateDocument(); @@ -739,18 +739,10 @@ public void forEach(Query query, Consumer action, QueryOptions o } } - public static void main(String[] args) throws CatalogDBException { - System.out.println(encryptPassword("admin")); - } - - private static String encryptPassword(String password) throws CatalogDBException { + private static String encryptPassword(String password, String salt) throws CatalogDBException { if (StringUtils.isNotEmpty(password)) { - if (password.matches("^[a-fA-F0-9]{40}$")) { - // Password already cyphered - return password; - } try { - return CryptoUtils.sha1(password); + return CryptoUtils.sha1(password + salt); } catch (NoSuchAlgorithmException e) { throw new CatalogDBException("Could not encrypt password", e); } From fdc4d89207e86ebf123584696d09b863285cac9b Mon Sep 17 00:00:00 2001 From: pfurio Date: Mon, 19 Aug 2024 09:39:35 +0200 Subject: [PATCH 10/10] catalog: simplify code, #TASK-6494 --- .../db/mongodb/UserMongoDBAdaptor.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java index 62d83109679..24c71463e32 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/UserMongoDBAdaptor.java @@ -242,29 +242,22 @@ public OpenCGAResult setPassword(String userId, @Nullable String oldPassword, St } } - // 2. Calculate all possible hashValues with new password - Set hashValues = new HashSet<>(); - List saltValues = passwordDoc.getList(ARCHIVE, Document.class).stream() - .map(document -> document.getString(SALT)) - .collect(Collectors.toList()); - for (String saltValue : saltValues) { - hashValues.add(encryptPassword(newPassword, saltValue)); - } - - // 3. Check new password has not been used before + // 2. Check new password has not been used before for (Document document : passwordDoc.getList(ARCHIVE, Document.class)) { String hashValue = document.getString(HASH); - if (hashValues.contains(hashValue)) { + String saltValue = document.getString(SALT); + String encryptedPassword = encryptPassword(newPassword, saltValue); + if (encryptedPassword.equals(hashValue)) { throw new CatalogAuthenticationException(prefixErrorMsg + "The new password has already been used." + " Please, use a different one."); } } - // 4. Generate new salt for current password + // 3. Generate new salt for current password String newSalt = PasswordUtils.getStrongRandomSalt(); String newHash = encryptPassword(newPassword, newSalt); - // 5. Generate update document + // 4. Generate update document UpdateDocument updateDocument = new UpdateDocument(); // add to current updateDocument.getSet().put(PRIVATE_PASSWORD_CURRENT_HASH, newHash);