diff --git a/opencga-analysis/src/test/java/org/opencb/opencga/analysis/alignment/AlignmentAnalysisTest.java b/opencga-analysis/src/test/java/org/opencb/opencga/analysis/alignment/AlignmentAnalysisTest.java index b855a379b08..cfe6e49b45e 100644 --- a/opencga-analysis/src/test/java/org/opencb/opencga/analysis/alignment/AlignmentAnalysisTest.java +++ b/opencga-analysis/src/test/java/org/opencb/opencga/analysis/alignment/AlignmentAnalysisTest.java @@ -38,7 +38,9 @@ import org.opencb.opencga.core.models.alignment.AlignmentGeneCoverageStatsParams; import org.opencb.opencga.core.models.file.File; import org.opencb.opencga.core.models.file.FileLinkParams; -import org.opencb.opencga.core.models.user.Account; +import org.opencb.opencga.core.models.organizations.OrganizationCreateParams; +import org.opencb.opencga.core.models.organizations.OrganizationUpdateParams; +import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.testclassification.duration.MediumTests; import org.opencb.opencga.storage.core.StorageEngineFactory; import org.opencb.opencga.storage.core.variant.VariantStorageEngine; @@ -218,8 +220,11 @@ public static void afterClass() { opencga.after(); } - public void setUpCatalogManager() throws IOException, CatalogException { - catalogManager.getUserManager().create(USER, "User Name", "mail@ebi.ac.uk", PASSWORD, "", null, Account.AccountType.FULL, opencga.getAdminToken()); + public void setUpCatalogManager() throws CatalogException { + catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId("test"), null, opencga.getAdminToken()); + catalogManager.getUserManager().create("test", new User().setId(USER).setName("User Name").setEmail("mail@ebi.ac.uk"), PASSWORD, opencga.getAdminToken()); + catalogManager.getOrganizationManager().update("test", new OrganizationUpdateParams().setOwner(USER), null, opencga.getAdminToken()); + token = catalogManager.getUserManager().login("user", PASSWORD).getToken(); String projectId = catalogManager.getProjectManager().create(PROJECT, "Project about some genomes", "", "Homo sapiens", diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/AdminCliOptionsParser.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/AdminCliOptionsParser.java index 28787847b65..1811f2ecbb9 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/AdminCliOptionsParser.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/AdminCliOptionsParser.java @@ -383,9 +383,6 @@ public class InstallCatalogCommandOptions extends CatalogDatabaseCommandOptions @Parameter(names = {"--email"}, description = "Administrator e-mail", arity = 1) public String email; - @Parameter(names = {"--organization"}, description = "Administrator organization", arity = 1) - public String organization; - @Parameter(names = {"--secret-key"}, description = "Secret key needed to authenticate through OpenCGA (JWT).") public String secretKey; diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/executors/CatalogCommandExecutor.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/executors/CatalogCommandExecutor.java index 12564ec4880..77817126f81 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/executors/CatalogCommandExecutor.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/admin/executors/CatalogCommandExecutor.java @@ -186,7 +186,7 @@ private void install() throws CatalogException { try (CatalogManager catalogManager = new CatalogManager(configuration)) { catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), commandOptions.commonOptions.adminPassword, - commandOptions.email, commandOptions.organization, commandOptions.force); + commandOptions.email, commandOptions.force); } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AuthenticationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AuthenticationManager.java index 569ee7de57a..d71c1e652a8 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AuthenticationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/AuthenticationManager.java @@ -20,6 +20,7 @@ import org.opencb.opencga.catalog.exceptions.CatalogAuthenticationException; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.core.api.ParamConstants; +import org.opencb.opencga.core.models.JwtPayload; import org.opencb.opencga.core.models.user.AuthenticationResponse; import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.response.OpenCGAResult; @@ -79,6 +80,14 @@ Key converStringToKeyObject(String keyString, String jcaAlgorithm) { */ public abstract AuthenticationResponse refreshToken(String refreshToken) throws CatalogAuthenticationException; + public JwtPayload getPayload(String token) throws CatalogAuthenticationException { + if (StringUtils.isEmpty(token) || "null".equalsIgnoreCase(token)) { + return new JwtPayload().setUserId(ParamConstants.ANONYMOUS_USER_ID); + } + + return jwtManager.getPayload(token); + } + /** * Obtains the userId corresponding to the token. * @@ -130,6 +139,16 @@ public String getUserId(String token) throws CatalogAuthenticationException { */ public abstract void newPassword(String userId, String newPassword) throws CatalogException; + /** + * Create a token for the user with default expiration time. + * + * @param user user. + * @return A token. + */ + public String createToken(User user) { + return createToken(user, Collections.emptyMap(), expiration); + } + /** * Create a token for the user with default expiration time. * @@ -172,6 +191,16 @@ public String createToken(String userId, Map claims) { */ public abstract String createToken(String userId, Map claims, long expiration); + /** + * Create a token for the user. + * + * @param user user. + * @param claims claims. + * @param expiration Expiration time in seconds. + * @return A token. + */ + public abstract String createToken(User user, Map claims, long expiration); + /** * Create a token for the user with no expiration time. * 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 06854118d47..3c4d27cf14e 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 @@ -408,6 +408,12 @@ public String createToken(String userId, Map claims, long expira throw new UnsupportedOperationException("Tokens are generated by Azure via authorization code or user-password"); } + @Override + public String createToken(User user, Map claims, long expiration) { + // Tokens are generated by Azure via authorization code or user-password + throw new UnsupportedOperationException("Tokens are generated by Azure via authorization code or user-password"); + } + @Override public String createNonExpiringToken(String userId, Map claims) { // Tokens are generated by Azure via authorization code or user-password 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 2f8f476f828..c47c752fe30 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 @@ -108,6 +108,11 @@ public String createToken(String userId, Map claims, long expira return jwtManager.createJWTToken(userId, claims, expiration); } + @Override + public String createToken(User user, Map claims, long expiration) { + return jwtManager.createJWTToken(user, claims, expiration); + } + @Override public String createNonExpiringToken(String userId, Map claims) { return jwtManager.createJWTToken(userId, claims, 0L); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/JwtManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/JwtManager.java index 15034dc866a..32965213720 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/JwtManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/auth/authentication/JwtManager.java @@ -18,6 +18,8 @@ import io.jsonwebtoken.*; import org.opencb.opencga.catalog.exceptions.CatalogAuthenticationException; +import org.opencb.opencga.core.models.JwtPayload; +import org.opencb.opencga.core.models.user.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -87,6 +89,27 @@ public String createJWTToken(String userId, long expiration) { return createJWTToken(userId, Collections.emptyMap(), expiration); } + public String createJWTToken(User user, Map claims, long expiration) { + long currentTime = System.currentTimeMillis(); + + JwtBuilder jwtBuilder = Jwts.builder(); + if (claims != null && !claims.isEmpty()) { + jwtBuilder.setClaims(claims); + } + jwtBuilder.setSubject(user.getId()) + .setIssuer(user.getOrganization()) + .setAudience("OpenCGA") + .setIssuedAt(new Date(currentTime)) + .signWith(privateKey, algorithm); + + // Set the expiration in number of seconds only if 'expiration' is greater than 0 + if (expiration > 0) { + jwtBuilder.setExpiration(new Date(currentTime + expiration * 1000L)); + } + + return jwtBuilder.compact(); + } + public String createJWTToken(String userId, Map claims, long expiration) { long currentTime = System.currentTimeMillis(); @@ -115,6 +138,11 @@ public void validateToken(String token, Key publicKey) throws CatalogAuthenticat parseClaims(token, publicKey); } + public JwtPayload getPayload(String token) throws CatalogAuthenticationException { + Claims body = parseClaims(token, publicKey).getBody(); + return new JwtPayload(body.getSubject(), body.getIssuer(), body.getAudience(), body.getIssuedAt(), body.getExpiration()); + } + public String getAudience(String token) throws CatalogAuthenticationException { return getAudience(token, this.publicKey); } 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 5d74c8c1f1b..0d73cc0faac 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 @@ -224,6 +224,11 @@ public String createToken(String userId, Map claims, long expira return jwtManager.createJWTToken(userId, claims, expiration); } + @Override + public String createToken(User user, Map claims, long expiration) { + return jwtManager.createJWTToken(user, claims, expiration); + } + @Override public String createNonExpiringToken(String userId, Map claims) { return jwtManager.createJWTToken(userId, claims, 0L); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/AbstractDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/AbstractDBAdaptor.java index af5ffcf4588..4187aca3582 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/AbstractDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/AbstractDBAdaptor.java @@ -16,17 +16,17 @@ package org.opencb.opencga.catalog.db; +import org.apache.commons.lang3.StringUtils; import org.opencb.commons.datastore.core.DataResult; import org.opencb.commons.datastore.core.Event; import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.opencga.catalog.db.api.DBIterator; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.response.OpenCGAResult; import org.slf4j.Logger; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; +import java.util.*; public abstract class AbstractDBAdaptor { @@ -101,6 +101,21 @@ protected void checkParameter(Object param, String name) throws CatalogDBExcepti } } + protected void checkUpdatedParams(ObjectMap parameters, List updateableKeys) throws CatalogParameterException { + Set keysToUpdate = parameters.keySet(); + Set updateableKeysSet = new HashSet<>(updateableKeys); + + List unexpectedKeys = new ArrayList<>(keysToUpdate.size()); + for (String key : keysToUpdate) { + if (!updateableKeysSet.contains(key)) { + unexpectedKeys.add(key); + } + } + if (!unexpectedKeys.isEmpty()) { + throw new CatalogParameterException("Unexpected fields passed to update: " + StringUtils.join(unexpectedKeys, ", ")); + } + } + public interface FilterOption { String getKey(); 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 86ccefa2653..cd00fc5344c 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 @@ -76,6 +76,8 @@ public interface DBAdaptorFactory extends AutoCloseable { MetaDBAdaptor getCatalogMetaDBAdaptor(); + OrganizationDBAdaptor getCatalogOrganizationDBAdaptor(); + UserDBAdaptor getCatalogUserDBAdaptor(); ProjectDBAdaptor getCatalogProjectDbAdaptor(); 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 94f3762c659..597e36069d7 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 @@ -1,10 +1,14 @@ package org.opencb.opencga.catalog.db.api; +import org.opencb.commons.datastore.core.ObjectMap; 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.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.models.organizations.Organization; +import org.opencb.opencga.core.response.OpenCGAResult; import java.util.HashMap; import java.util.Map; @@ -85,12 +89,14 @@ public static QueryParams getParam(String key) { // // OpenCGAResult nativeInsert(Map project, String userId) throws CatalogDBException; // -// OpenCGAResult insert(Project project, String userId, QueryOptions options) -// throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult insert(Organization organization, QueryOptions options) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; // // OpenCGAResult get(String userId, QueryOptions options) throws CatalogDBException; // -// OpenCGAResult get(long project, QueryOptions options) throws CatalogDBException; + OpenCGAResult get(long organization, QueryOptions options) throws CatalogDBException; + + OpenCGAResult get(Query query, QueryOptions options) throws CatalogDBException; // // OpenCGAResult incrementCurrentRelease(long projectId) throws CatalogDBException; // @@ -149,12 +155,12 @@ public static QueryParams getParam(String key) { // return queryResults; // } // -// OpenCGAResult update(long id, ObjectMap parameters, QueryOptions queryOptions) -// throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult update(long id, ObjectMap parameters, QueryOptions queryOptions) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; // // OpenCGAResult update(Query query, ObjectMap parameters, QueryOptions queryOptions) throws CatalogDBException; // -// OpenCGAResult delete(Project project) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; + OpenCGAResult delete(Organization organization) throws CatalogDBException; // // OpenCGAResult delete(Query query) throws CatalogDBException; // 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 ac605873666..905e8556307 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 @@ -136,7 +136,7 @@ default void checkId(long projectId) throws CatalogDBException { OpenCGAResult nativeInsert(Map project, String userId) throws CatalogDBException; - OpenCGAResult insert(Project project, String userId, QueryOptions options) + OpenCGAResult insert(String organizationId, Project project, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; OpenCGAResult get(String userId, QueryOptions options) throws CatalogDBException; 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 d16008639f8..331619d1359 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 @@ -29,6 +29,7 @@ import org.opencb.commons.datastore.mongodb.MongoDataStoreManager; import org.opencb.opencga.catalog.db.DBAdaptorFactory; import org.opencb.opencga.catalog.db.api.MigrationDBAdaptor; +import org.opencb.opencga.catalog.db.api.OrganizationDBAdaptor; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.core.config.Admin; @@ -271,7 +272,8 @@ public MetaMongoDBAdaptor getCatalogMetaDBAdaptor() { return metaDBAdaptor; } - public OrganizationMongoDBAdaptor getOrganizationDBAdaptor() { + @Override + public OrganizationDBAdaptor getCatalogOrganizationDBAdaptor() { return organizationDBAdaptor; } 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 c7486df7893..7001ac7d21e 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 @@ -1,20 +1,38 @@ package org.opencb.opencga.catalog.db.mongodb; import com.mongodb.client.ClientSession; +import com.mongodb.client.model.Filters; +import org.apache.commons.lang3.StringUtils; import org.bson.Document; -import org.opencb.commons.datastore.core.Query; -import org.opencb.commons.datastore.core.QueryOptions; +import org.bson.conversions.Bson; +import org.opencb.commons.datastore.core.*; import org.opencb.commons.datastore.mongodb.MongoDBCollection; import org.opencb.commons.datastore.mongodb.MongoDBIterator; import org.opencb.opencga.catalog.db.api.DBIterator; import org.opencb.opencga.catalog.db.api.OrganizationDBAdaptor; import org.opencb.opencga.catalog.db.mongodb.converters.OrganizationConverter; -import org.opencb.opencga.catalog.db.mongodb.iterators.ProjectCatalogMongoDBIterator; +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.CatalogParameterException; +import org.opencb.opencga.catalog.managers.OrganizationManager; +import org.opencb.opencga.catalog.utils.Constants; +import org.opencb.opencga.catalog.utils.ParamUtils; +import org.opencb.opencga.catalog.utils.UuidUtils; +import org.opencb.opencga.core.api.ParamConstants; +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.organizations.Organization; +import org.opencb.opencga.core.response.OpenCGAResult; import org.slf4j.LoggerFactory; +import java.util.*; + +import static org.opencb.opencga.catalog.db.api.ClinicalAnalysisDBAdaptor.QueryParams.MODIFICATION_DATE; +import static org.opencb.opencga.catalog.db.mongodb.MongoDBUtils.filterMapParams; +import static org.opencb.opencga.catalog.db.mongodb.MongoDBUtils.filterStringParams; + public class OrganizationMongoDBAdaptor extends MongoDBAdaptor implements OrganizationDBAdaptor { private final MongoDBCollection organizationCollection; @@ -23,13 +41,229 @@ public class OrganizationMongoDBAdaptor extends MongoDBAdaptor implements Organi public OrganizationMongoDBAdaptor(MongoDBCollection organizationCollection, MongoDBCollection deletedOrganizationCollection, Configuration configuration, MongoDBAdaptorFactory dbAdaptorFactory) { - super(configuration, LoggerFactory.getLogger(ProjectMongoDBAdaptor.class)); + super(configuration, LoggerFactory.getLogger(OrganizationMongoDBAdaptor.class)); this.dbAdaptorFactory = dbAdaptorFactory; this.organizationCollection = organizationCollection; this.deletedOrganizationCollection = deletedOrganizationCollection; this.organizationConverter = new OrganizationConverter(); } + @Override + public OpenCGAResult insert(Organization organization, QueryOptions options) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + return runTransaction(clientSession -> { + long tmpStartTime = startQuery(); + logger.debug("Starting organization insert transaction for organization id '{}'", organization.getId()); + insert(clientSession, organization); + return endWrite(tmpStartTime, 1, 1, 0, 0, null); + }, e -> logger.error("Could not create sample {}: {}", organization.getId(), e.getMessage())); + } + + Organization insert(ClientSession clientSession, Organization organization) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + + if (StringUtils.isEmpty(organization.getId())) { + throw new CatalogDBException("Missing organization id"); + } + + // Check the organization does not exist + List filterList = new ArrayList<>(); + filterList.add(Filters.eq(QueryParams.ID.key(), organization.getId())); + + Bson bson = Filters.and(filterList); + DataResult count = organizationCollection.count(clientSession, bson); + if (count.getNumMatches() > 0) { + throw new CatalogDBException("Organization { id: '" + organization.getId() + "'} already exists."); + } + + long organizationUid = getNewUid(); + organization.setUid(organizationUid); + if (StringUtils.isEmpty(organization.getUuid())) { + organization.setUuid(UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.ORGANIZATION)); + } + + Document organizationObject = organizationConverter.convertToStorageType(organization); + + // Versioning private parameters + organizationObject.put(PRIVATE_CREATION_DATE, StringUtils.isNotEmpty(organization.getCreationDate()) + ? TimeUtils.toDate(organization.getCreationDate()) : TimeUtils.getDate()); + organizationObject.put(PRIVATE_MODIFICATION_DATE, StringUtils.isNotEmpty(organization.getModificationDate()) + ? TimeUtils.toDate(organization.getModificationDate()) : TimeUtils.getDate()); + + logger.debug("Inserting organization '{}' ({})...", organization.getId(), organization.getUid()); + organizationCollection.insert(clientSession, organizationObject, null); + logger.debug("Organization '{}' successfully inserted", organization.getId()); + + return organization; + } + + @Override + public OpenCGAResult get(long organizationUid, QueryOptions options) throws CatalogDBException { + Query query = new Query(QueryParams.UID.key(), organizationUid); + return get(query, options); + } + + @Override + public OpenCGAResult get(Query query, QueryOptions options) throws CatalogDBException { + return get(null, query, options); + } + + @Override + public OpenCGAResult update(long organizationUid, ObjectMap parameters, QueryOptions queryOptions) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + QueryOptions options = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(QueryParams.ID.key(), QueryParams.UID.key())); + OpenCGAResult organizationResult = get(organizationUid, options); + + if (organizationResult.getNumResults() == 0) { + throw new CatalogDBException("Could not update organization. Organization uid '" + organizationUid + "' not found."); + } + + try { + return runTransaction(clientSession -> privateUpdate(clientSession, organizationResult.first(), parameters, queryOptions)); + } catch (CatalogDBException e) { + logger.error("Could not update organization {}: {}", organizationResult.first().getId(), e.getMessage(), e); + throw new CatalogDBException("Could not update organization " + organizationResult.first().getId() + ": " + e.getMessage(), + e.getCause()); + } + } + + private OpenCGAResult privateUpdate(ClientSession clientSession, Organization organization, ObjectMap parameters, + QueryOptions queryOptions) throws CatalogParameterException, CatalogDBException { + long tmpStartTime = startQuery(); + + UpdateDocument updateDocument = getValidatedUpdateParams(parameters, queryOptions); + Document organizationUpdate = updateDocument.toFinalUpdateDocument(); + + Query tmpQuery = new Query(QueryParams.UID.key(), organization.getUid()); + Bson queryBson = parseQuery(tmpQuery); + + if (organizationUpdate.isEmpty()) { + if (!parameters.isEmpty()) { + logger.error("Non-processed update parameters: {}", parameters.keySet()); + throw new CatalogDBException("Update could not be performed. Some fields could not be processed."); + } + throw new CatalogDBException("Nothing to be updated"); + } + + List events = new ArrayList<>(); + logger.debug("Update organization. Query: {}, Update: {}", queryBson.toBsonDocument(), organizationUpdate.toBsonDocument()); + + DataResult updateResult = organizationCollection.update(clientSession, queryBson, organizationUpdate, null); + + if (updateResult.getNumMatches() == 0) { + throw new CatalogDBException("Organization not found"); + } + if (updateResult.getNumUpdated() == 0) { + events.add(new Event(Event.Type.WARNING, organization.getId(), "Organization was already updated")); + } + logger.debug("Organization {} successfully updated", organization.getId()); + + + return endWrite(tmpStartTime, 1, 1, events); + } + + private UpdateDocument getValidatedUpdateParams(ObjectMap parameters, QueryOptions queryOptions) + throws CatalogParameterException, CatalogDBException { + checkUpdatedParams(parameters, Arrays.asList(QueryParams.NAME.key(), QueryParams.DOMAIN.key(), QueryParams.OWNER.key(), + QueryParams.CREATION_DATE.key(), QueryParams.MODIFICATION_DATE.key(), QueryParams.ADMINS.key(), + QueryParams.AUTHENTICATION_ORIGINS.key(), QueryParams.ATTRIBUTES.key())); + + UpdateDocument document = new UpdateDocument(); + + String[] acceptedParams = { + QueryParams.NAME.key(), QueryParams.DOMAIN.key(), QueryParams.OWNER.key(), + }; + filterStringParams(parameters, document.getSet(), acceptedParams); + + if (StringUtils.isNotEmpty(parameters.getString(QueryParams.CREATION_DATE.key()))) { + String time = parameters.getString(QueryParams.CREATION_DATE.key()); + Date date = TimeUtils.toDate(time); + document.getSet().put(QueryParams.CREATION_DATE.key(), time); + document.getSet().put(PRIVATE_CREATION_DATE, date); + } + if (StringUtils.isNotEmpty(parameters.getString(MODIFICATION_DATE.key()))) { + String time = parameters.getString(QueryParams.MODIFICATION_DATE.key()); + Date date = TimeUtils.toDate(time); + document.getSet().put(QueryParams.MODIFICATION_DATE.key(), time); + document.getSet().put(PRIVATE_MODIFICATION_DATE, date); + } + + // Check admins exist. + if (parameters.containsKey(QueryParams.ADMINS.key())) { + List adminList = parameters.getAsStringList(QueryParams.ADMINS.key()); + + Map actionMap = queryOptions.getMap(Constants.ACTIONS, new HashMap<>()); + ParamUtils.BasicUpdateAction operation = ParamUtils.BasicUpdateAction.from(actionMap, QueryParams.ADMINS.key(), + ParamUtils.BasicUpdateAction.ADD); + if (ParamUtils.BasicUpdateAction.SET.equals(operation) || !adminList.isEmpty()) { + switch (operation) { + case SET: + document.getSet().put(QueryParams.ADMINS.key(), adminList); + break; + case REMOVE: + document.getPullAll().put(QueryParams.ADMINS.key(), adminList); + break; + case ADD: + document.getAddToSet().put(QueryParams.ADMINS.key(), adminList); + break; + default: + throw new IllegalArgumentException("Unknown operation " + operation); + } + } + } + + if (parameters.containsKey(QueryParams.AUTHENTICATION_ORIGINS.key())) { + List authenticationOrigins = parameters.getAsList(QueryParams.AUTHENTICATION_ORIGINS.key(), + AuthenticationOrigin.class); + List authenticationOriginDocumentList = organizationConverter.convertAuthenticationOrigins(authenticationOrigins); + + Map actionMap = queryOptions.getMap(Constants.ACTIONS, new HashMap<>()); + ParamUtils.BasicUpdateAction operation = ParamUtils.BasicUpdateAction.from(actionMap, QueryParams.AUTHENTICATION_ORIGINS.key(), + ParamUtils.BasicUpdateAction.ADD); + switch (operation) { + case SET: + document.getSet().put(QueryParams.AUTHENTICATION_ORIGINS.key(), authenticationOriginDocumentList); + break; + case REMOVE: + document.getPullAll().put(QueryParams.AUTHENTICATION_ORIGINS.key(), authenticationOriginDocumentList); + break; + case ADD: + document.getAddToSet().put(QueryParams.AUTHENTICATION_ORIGINS.key(), authenticationOriginDocumentList); + break; + default: + throw new IllegalArgumentException("Unknown operation " + operation); + } + } + + String[] acceptedMapParams = {QueryParams.ATTRIBUTES.key(), }; + filterMapParams(parameters, document.getSet(), acceptedMapParams); + + if (!document.toFinalUpdateDocument().isEmpty()) { + String time = TimeUtils.getTime(); + if (StringUtils.isEmpty(parameters.getString(MODIFICATION_DATE.key()))) { + // Update modificationDate param + Date date = TimeUtils.toDate(time); + document.getSet().put(QueryParams.MODIFICATION_DATE.key(), time); + document.getSet().put(PRIVATE_MODIFICATION_DATE, date); + } + document.getSet().put(INTERNAL_LAST_MODIFIED, time); + } + + return document; + } + + OpenCGAResult get(ClientSession clientSession, Query query, QueryOptions options) throws CatalogDBException { + long startTime = startQuery(); + try (DBIterator dbIterator = iterator(clientSession, query, options)) { + return endQuery(startTime, dbIterator); + } + } + + @Override + public OpenCGAResult delete(Organization organization) throws CatalogDBException { + return null; + } + @Override public DBIterator iterator(Query query, QueryOptions options) throws CatalogDBException { return iterator(null, query, options); @@ -37,10 +271,76 @@ public DBIterator iterator(Query query, QueryOptions options) thro public DBIterator iterator(ClientSession clientSession, Query query, QueryOptions options) throws CatalogDBException { MongoDBIterator mongoCursor = getMongoCursor(clientSession, query, options); - return new ProjectCatalogMongoDBIterator<>(mongoCursor, clientSession, organizationConverter, dbAdaptorFactory, options, null); + return new OrganizationCatalogMongoDBIterator<>(mongoCursor, clientSession, organizationConverter, dbAdaptorFactory, options, null); } - private MongoDBIterator getMongoCursor(ClientSession clientSession, Query query, QueryOptions options) { - return null; + private MongoDBIterator getMongoCursor(ClientSession clientSession, Query query, QueryOptions options) + throws CatalogDBException { + Query finalQuery = new Query(query); + + QueryOptions qOptions; + if (options != null) { + qOptions = new QueryOptions(options); + } else { + qOptions = new QueryOptions(); + } + qOptions = filterQueryOptions(qOptions, OrganizationManager.INCLUDE_ORGANIZATION_IDS.getAsStringList(QueryOptions.INCLUDE)); + + Bson bson = parseQuery(finalQuery); + MongoDBCollection collection = getQueryCollection(finalQuery, organizationCollection, null, deletedOrganizationCollection); + logger.debug("Organization query: {}", bson.toBsonDocument()); + return collection.iterator(clientSession, bson, null, null, qOptions); + } + + private Bson parseQuery(Query query) throws CatalogDBException { + List andBsonList = new ArrayList<>(); + + Query queryCopy = new Query(query); + queryCopy.remove(ParamConstants.DELETED_PARAM); + + for (Map.Entry entry : queryCopy.entrySet()) { + String key = entry.getKey().split("\\.")[0]; + QueryParams queryParam = QueryParams.getParam(entry.getKey()) != null ? QueryParams.getParam(entry.getKey()) + : QueryParams.getParam(key); + if (queryParam == null) { + throw new CatalogDBException("Unexpected parameter " + entry.getKey() + ". The parameter does not exist or cannot be " + + "queried for."); + } + try { + switch (queryParam) { + case UID: + addAutoOrQuery(PRIVATE_UID, queryParam.key(), queryCopy, queryParam.type(), andBsonList); + break; + case CREATION_DATE: + addAutoOrQuery(PRIVATE_CREATION_DATE, queryParam.key(), queryCopy, queryParam.type(), andBsonList); + break; + case MODIFICATION_DATE: + addAutoOrQuery(PRIVATE_MODIFICATION_DATE, queryParam.key(), query, queryParam.type(), andBsonList); + break; + case ID: + case UUID: + case NAME: + case DOMAIN: + case OWNER: + case ADMINS: + addAutoOrQuery(queryParam.key(), queryParam.key(), queryCopy, queryParam.type(), andBsonList); + break; + default: + throw new CatalogDBException("Cannot query by parameter " + queryParam.key()); + } + } catch (Exception e) { + if (e instanceof CatalogDBException) { + throw e; + } else { + throw new CatalogDBException("Error parsing query : " + queryCopy.toJson(), e); + } + } + } + + if (andBsonList.size() > 0) { + return Filters.and(andBsonList); + } else { + return new Document(); + } } } 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 297ff31f27e..fa73854de1b 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 @@ -62,22 +62,22 @@ */ public class ProjectMongoDBAdaptor extends MongoDBAdaptor implements ProjectDBAdaptor { - private final MongoDBCollection userCollection; + private final MongoDBCollection projectCollection; private final MongoDBCollection deletedUserCollection; private ProjectConverter projectConverter; - public ProjectMongoDBAdaptor(MongoDBCollection userCollection, MongoDBCollection deletedUserCollection, Configuration configuration, + public ProjectMongoDBAdaptor(MongoDBCollection projectCollection, MongoDBCollection deletedUserCollection, Configuration configuration, MongoDBAdaptorFactory dbAdaptorFactory) { super(configuration, LoggerFactory.getLogger(ProjectMongoDBAdaptor.class)); this.dbAdaptorFactory = dbAdaptorFactory; - this.userCollection = userCollection; + this.projectCollection = projectCollection; this.deletedUserCollection = deletedUserCollection; this.projectConverter = new ProjectConverter(); } @Override public boolean exists(long projectId) { - DataResult count = userCollection.count(new Document(UserDBAdaptor.QueryParams.PROJECTS_UID.key(), projectId)); + DataResult count = projectCollection.count(new Document(UserDBAdaptor.QueryParams.PROJECTS_UID.key(), projectId)); return count.getNumMatches() != 0; } @@ -88,7 +88,7 @@ public OpenCGAResult nativeInsert(Map project, String userId) th Bson update = Updates.push("projects", getMongoDBDocument(project, "project")); //Update object - DataResult result = userCollection.update(query, update, null); + DataResult result = projectCollection.update(query, update, null); if (result.getNumInserted() == 0) { // Check if the project has been inserted throw new CatalogDBException("Project {" + project.get(QueryParams.ID.key()) + "\"} already exists for this user"); } @@ -96,34 +96,33 @@ public OpenCGAResult nativeInsert(Map project, String userId) th } @Override - public OpenCGAResult insert(Project project, String userId, QueryOptions options) + public OpenCGAResult insert(String organizationId, Project project, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting project insert transaction for project id '{}'", project.getId()); - insert(clientSession, project, userId); + insert(clientSession, organizationId, project); return endWrite(tmpStartTime, 1, 1, 0, 0, null); }, e -> logger.error("Could not create project {}: {}", project.getId(), e.getMessage())); } - Project insert(ClientSession clientSession, Project project, String userId) - throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + Project insert(ClientSession clientSession, String organizationId, Project project) throws CatalogDBException, + CatalogParameterException, CatalogAuthorizationException { if (project.getStudies() != null && !project.getStudies().isEmpty()) { throw new CatalogParameterException("Creating project and studies in a single transaction is forbidden"); } project.setStudies(Collections.emptyList()); - Bson countQuery = Filters.and(Filters.eq(UserDBAdaptor.QueryParams.ID.key(), userId), - Filters.eq(UserDBAdaptor.QueryParams.PROJECTS_ID.key(), project.getId())); - DataResult count = userCollection.count(clientSession, countQuery); + Bson countQuery = Filters.eq(QueryParams.ID.key(), project.getId()); + DataResult count = projectCollection.count(clientSession, countQuery); if (count.getNumMatches() != 0) { - throw new CatalogDBException("Project {id:\"" + project.getId() + "\"} already exists for this user"); + throw new CatalogDBException("Project {id:\"" + project.getId() + "\"} already exists in this organization"); } long projectUid = getNewUid(); project.setUid(projectUid); - project.setFqn(userId + "@" + project.getId()); + project.setFqn(organizationId + "@" + project.getId()); if (StringUtils.isEmpty(project.getUuid())) { project.setUuid(UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.PROJECT)); } @@ -134,14 +133,7 @@ Project insert(ClientSession clientSession, Project project, String userId) projectDocument.put(PRIVATE_MODIFICATION_DATE, StringUtils.isNotEmpty(project.getModificationDate()) ? TimeUtils.toDate(project.getModificationDate()) : TimeUtils.getDate()); - Bson update = Updates.push("projects", projectDocument); - - //Update object - Bson query = Filters.eq(UserDBAdaptor.QueryParams.ID.key(), userId); - - logger.debug("Inserting project. Query: {}, update: {}", query.toBsonDocument(), update.toBsonDocument()); - userCollection.update(clientSession, query, update, null); - + projectCollection.insert(clientSession, projectDocument, null); return project; } @@ -151,7 +143,7 @@ public OpenCGAResult incrementCurrentRelease(long projectId) throws CatalogDBExc Query query = new Query(QueryParams.UID.key(), projectId); Bson update = new Document("$inc", new Document("projects.$." + QueryParams.CURRENT_RELEASE.key(), 1)); - DataResult updateQR = userCollection.update(parseQuery(query), update, null); + DataResult updateQR = projectCollection.update(parseQuery(query), update, null); if (updateQR == null || updateQR.getNumMatches() == 0) { throw new CatalogDBException("Could not increment release number. Project id " + projectId + " not found"); } else if (updateQR.getNumUpdated() == 0) { @@ -174,7 +166,7 @@ private void editId(ClientSession clientSession, String owner, long projectUid, .append("projects.$." + QueryParams.ID.key(), newId) .append("projects.$." + QueryParams.FQN.key(), owner + "@" + newId) ); - DataResult result = userCollection.update(clientSession, query, update, null); + DataResult result = projectCollection.update(clientSession, query, update, null); if (result.getNumUpdated() == 0) { //Check if the the project id was modified throw new CatalogDBException("Project {id:\"" + newId + "\"} already exists"); } @@ -197,7 +189,7 @@ public long getId(final String userId, final String projectIdStr) throws Catalog Filters.eq(UserDBAdaptor.QueryParams.ID.key(), userId) ); Bson projection = Projections.elemMatch("projects", Filters.eq(QueryParams.ID.key(), projectId)); - DataResult queryResult = userCollection.find(filter, projection, null); + DataResult queryResult = projectCollection.find(filter, projection, null); User user = parseUser(queryResult); if (user == null || user.getProjects().isEmpty()) { return -1; @@ -215,7 +207,7 @@ public String getOwnerId(long projectId) throws CatalogDBException { Bson projection = Projections.include(UserDBAdaptor.QueryParams.ID.key()); // DataResult result = userCollection.find(query, projection, null); - DataResult result = userCollection.find(query, projection, null); + DataResult result = projectCollection.find(query, projection, null); if (result.getResults().isEmpty()) { throw CatalogDBException.uidNotFound("Project", projectId); @@ -227,7 +219,7 @@ public String getOwnerId(long projectId) throws CatalogDBException { @Override public OpenCGAResult count(Query query) throws CatalogDBException { Bson bson = parseQuery(query); - return new OpenCGAResult<>(userCollection.count(bson)); + return new OpenCGAResult<>(projectCollection.count(bson)); } @Override @@ -238,7 +230,7 @@ public OpenCGAResult count(Query query, String user, StudyPermissions.Perm @Override public OpenCGAResult distinct(Query query, String field) throws CatalogDBException { Bson bson = parseQuery(query); - return new OpenCGAResult(userCollection.distinct(field, bson)); + return new OpenCGAResult(projectCollection.distinct(field, bson)); } @Override @@ -311,7 +303,7 @@ OpenCGAResult privateUpdate(ClientSession clientSession, Project project Bson finalQuery = parseQuery(tmpQuery); logger.debug("Update project. Query: {}, update: {}", finalQuery.toBsonDocument(), updates.toBsonDocument()); - DataResult result = userCollection.update(clientSession, finalQuery, updates, null); + DataResult result = projectCollection.update(clientSession, finalQuery, updates, null); if (result.getNumMatches() == 0) { throw new CatalogDBException("Project " + project.getId() + " not found"); @@ -499,7 +491,7 @@ OpenCGAResult privateDelete(ClientSession clientSession, Project projec logger.debug("Delete project {}: Query: {}, update: {}", project.getId(), bsonQuery.toBsonDocument(), updateDocument.toBsonDocument()); - DataResult result = userCollection.update(clientSession, bsonQuery, updateDocument, QueryOptions.empty()); + DataResult result = projectCollection.update(clientSession, bsonQuery, updateDocument, QueryOptions.empty()); if (result.getNumMatches() == 0) { throw new CatalogDBException("Project " + project.getId() + " not found"); @@ -797,7 +789,7 @@ private MongoDBIterator getMongoCursor(ClientSession clientSession, Qu logger.debug("Get project: Aggregate : {}", aggregate.toBsonDocument()); } - return userCollection.iterator(clientSession, aggregates, qOptions); + return projectCollection.iterator(clientSession, aggregates, qOptions); } @Override diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/OrganizationConverter.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/OrganizationConverter.java index e0670ecab85..32d57d5b37d 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/OrganizationConverter.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/OrganizationConverter.java @@ -2,9 +2,16 @@ import org.apache.avro.generic.GenericRecord; import org.bson.Document; +import org.opencb.opencga.catalog.db.mongodb.MongoDBUtils; +import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.core.config.AuthenticationOrigin; import org.opencb.opencga.core.models.common.mixins.GenericRecordAvroJsonMixin; import org.opencb.opencga.core.models.organizations.Organization; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + public class OrganizationConverter extends OpenCgaMongoConverter { public OrganizationConverter() { @@ -18,4 +25,17 @@ public Document convertToStorageType(Organization object) { document.put("uid", document.getInteger("uid").longValue()); return document; } + + public List convertAuthenticationOrigins(List authenticationOriginList) throws CatalogDBException { + if (authenticationOriginList == null || authenticationOriginList.isEmpty()) { + return Collections.emptyList(); + } + List authenticationOriginDocumentList = new ArrayList<>(authenticationOriginList.size()); + for (AuthenticationOrigin authenticationOrigin : authenticationOriginList) { + Document authOriginDocument = MongoDBUtils.getMongoDBDocument(authenticationOrigin, "AuthenticationOrigin"); + authenticationOriginDocumentList.add(authOriginDocument); + } + return authenticationOriginDocumentList; + + } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/OrganizationCatalogMongoDBIterator.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/OrganizationCatalogMongoDBIterator.java index ef161f79012..080a3ade907 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/OrganizationCatalogMongoDBIterator.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/OrganizationCatalogMongoDBIterator.java @@ -73,7 +73,7 @@ private void fetchNextBatch() { // Get next BUFFER_SIZE documents int counter = 0; while (mongoCursor.hasNext() && counter < BUFFER_SIZE) { - Document organizationDocument = mongoCursor.next().get("organizations", Document.class); + Document organizationDocument = mongoCursor.next(); organizationListBuffer.add(organizationDocument); counter++; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/io/CatalogIOManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/io/CatalogIOManager.java index 551476b874b..7ddad50db0a 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/io/CatalogIOManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/io/CatalogIOManager.java @@ -24,16 +24,19 @@ import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Path; import java.nio.file.Paths; public class CatalogIOManager { /** * OpenCGA folders are created in the ROOTDIR. + * OPENCGA_ORGANIZATIONS_FOLDER contains organization workspaces organized by 'organizationUid' * OPENCGA_USERS_FOLDER contains users workspaces organized by 'userId' * OPENCGA_ANONYMOUS_USERS_FOLDER contains anonymous users workspaces organized by 'randomStringId' * OPENCGA_BIN_FOLDER contains all packaged binaries delivered within OpenCGA */ + private static final String OPENCGA_ORGANIZATIONS_FOLDER = "orgs/"; private static final String OPENCGA_USERS_FOLDER = "users/"; private static final String OPENCGA_ANONYMOUS_USERS_FOLDER = "anonymous/"; private static final String OPENCGA_BIN_FOLDER = "bin/"; @@ -43,8 +46,9 @@ public class CatalogIOManager { * USER_PROJECTS_FOLDER this folder stores all the projects with the studies and files * USER_BIN_FOLDER contains user specific binaries */ - protected static final String USER_PROJECTS_FOLDER = "projects/"; - protected static final String USER_BIN_FOLDER = "bin/"; + protected static final String ORGANIZATION_USERS_FOLDER = "users/"; + protected static final String ORGANIZATION_PROJECTS_FOLDER = "projects/"; + protected static final String ORGANIZATION_BIN_FOLDER = "bin/"; protected static Logger logger = LoggerFactory.getLogger(CatalogIOManager.class); protected URI rootDir; private URI jobDir; @@ -67,8 +71,8 @@ public void createDefaultOpenCGAFolders() throws CatalogIOException { } ioManager.checkDirectoryUri(rootDir, true); - if (!ioManager.exists(getUsersUri())) { - ioManager.createDirectory(getUsersUri()); + if (!ioManager.exists(getOrganizationsUri())) { + ioManager.createDirectory(getOrganizationsUri()); } if (!ioManager.exists(rootDir.resolve(OPENCGA_ANONYMOUS_USERS_FOLDER))) { @@ -90,21 +94,30 @@ protected void checkParam(String param) throws CatalogIOException { } } - public URI getUsersUri() { - return Paths.get(rootDir).resolve(OPENCGA_USERS_FOLDER).toUri(); + public URI getOrganizationsUri() { + return Paths.get(rootDir).resolve(OPENCGA_ORGANIZATIONS_FOLDER).toUri(); } - public URI getUserUri(String userId) throws CatalogIOException { + public URI getOrganizationsUri(String organizationUid) throws CatalogIOException { + checkParam(organizationUid); + return Paths.get(getOrganizationsUri()).resolve(organizationUid.endsWith("/") ? organizationUid : (organizationUid + "/")).toUri(); + } + + public URI getUsersUri(String organizationId) { + return Paths.get(getOrganizationsUri()).resolve(organizationId).resolve(OPENCGA_USERS_FOLDER).toUri(); + } + + public URI getUserUri(String organizationId, String userId) throws CatalogIOException { checkParam(userId); - return Paths.get(getUsersUri()).resolve(userId.endsWith("/") ? userId : (userId + "/")).toUri(); + return Paths.get(getUsersUri(organizationId)).resolve(userId.endsWith("/") ? userId : (userId + "/")).toUri(); } - public URI getProjectsUri(String userId) throws CatalogIOException { - return Paths.get(getUserUri(userId)).resolve(USER_PROJECTS_FOLDER).toUri(); + public URI getProjectsUri(String organizationUid) throws CatalogIOException { + return Paths.get(getOrganizationsUri(organizationUid)).resolve(ORGANIZATION_PROJECTS_FOLDER).toUri(); } - public URI getProjectUri(String userId, String projectId) throws CatalogIOException { - return Paths.get(getProjectsUri(userId)).resolve(projectId.endsWith("/") ? projectId : (projectId + "/")).toUri(); + public URI getProjectUri(String organizationUid, String projectId) throws CatalogIOException { + return Paths.get(getProjectsUri(organizationUid)).resolve(projectId.endsWith("/") ? projectId : (projectId + "/")).toUri(); } private URI getStudyUri(String userId, String projectId, String studyId) throws CatalogIOException { @@ -112,18 +125,47 @@ private URI getStudyUri(String userId, String projectId, String studyId) throws return Paths.get(getProjectUri(userId, projectId)).resolve(studyId.endsWith("/") ? studyId : (studyId + "/")).toUri(); } - public URI createUser(String userId) throws CatalogIOException { + public URI createOrganization(String organizationUid) throws CatalogIOException { + checkParam(organizationUid); + + URI organizationsUri = getOrganizationsUri(); + ioManager.checkDirectoryUri(organizationsUri, true); + + URI organizationUri = getOrganizationsUri(organizationUid); + Path organizationPath = Paths.get(organizationUri); + try { + if (!ioManager.exists(organizationUri)) { + ioManager.createDirectory(organizationUri); + ioManager.createDirectory(organizationPath.resolve(CatalogIOManager.ORGANIZATION_PROJECTS_FOLDER).toUri()); + ioManager.createDirectory(organizationPath.resolve(CatalogIOManager.ORGANIZATION_BIN_FOLDER).toUri()); + ioManager.createDirectory(organizationPath.resolve(CatalogIOManager.ORGANIZATION_USERS_FOLDER).toUri()); + + return organizationUri; + } + } catch (CatalogIOException e) { + throw e; + } + return null; + } + + public void deleteOrganization(String organization) throws CatalogIOException { + URI organizationsUri = getOrganizationsUri(organization); + ioManager.checkUriExists(organizationsUri); + ioManager.deleteDirectory(organizationsUri); + } + + public URI createUser(String organizationId, String userId) throws CatalogIOException { checkParam(userId); - URI usersUri = getUsersUri(); + URI usersUri = getUsersUri(organizationId); ioManager.checkDirectoryUri(usersUri, true); - URI userPath = getUserUri(userId); + URI userPath = getUserUri(organizationId, userId); try { if (!ioManager.exists(userPath)) { ioManager.createDirectory(userPath); - ioManager.createDirectory(Paths.get(userPath).resolve(CatalogIOManager.USER_PROJECTS_FOLDER).toUri()); - ioManager.createDirectory(Paths.get(userPath).resolve(CatalogIOManager.USER_BIN_FOLDER).toUri()); + ioManager.createDirectory(Paths.get(userPath).resolve(CatalogIOManager.ORGANIZATION_PROJECTS_FOLDER).toUri()); + ioManager.createDirectory(Paths.get(userPath).resolve(CatalogIOManager.ORGANIZATION_BIN_FOLDER).toUri()); return userPath; } @@ -133,16 +175,16 @@ public URI createUser(String userId) throws CatalogIOException { return null; } - public void deleteUser(String userId) throws CatalogIOException { - URI userUri = getUserUri(userId); + public void deleteUser(String organizationId, String userId) throws CatalogIOException { + URI userUri = getUserUri(organizationId, userId); ioManager.checkUriExists(userUri); ioManager.deleteDirectory(userUri); } - public URI createProject(String userId, String projectId) throws CatalogIOException { + public URI createProject(String organizationUid, String projectId) throws CatalogIOException { checkParam(projectId); - URI projectUri = getProjectUri(userId, projectId); + URI projectUri = getProjectUri(organizationUid, projectId); try { if (!ioManager.exists(projectUri)) { projectUri = ioManager.createDirectory(projectUri, true); 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 5f12e37db83..8ef1e024af5 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 @@ -54,6 +54,7 @@ public abstract class AbstractManager { protected Configuration configuration; protected final DBAdaptorFactory catalogDBAdaptorFactory; + protected final OrganizationDBAdaptor organizationDBAdaptor; protected final UserDBAdaptor userDBAdaptor; protected final ProjectDBAdaptor projectDBAdaptor; protected final StudyDBAdaptor studyDBAdaptor; @@ -81,6 +82,7 @@ public abstract class AbstractManager { this.authorizationManager = authorizationManager; this.auditManager = auditManager; this.configuration = configuration; + this.organizationDBAdaptor = catalogDBAdaptorFactory.getCatalogOrganizationDBAdaptor(); this.userDBAdaptor = catalogDBAdaptorFactory.getCatalogUserDBAdaptor(); this.studyDBAdaptor = catalogDBAdaptorFactory.getCatalogStudyDBAdaptor(); this.fileDBAdaptor = catalogDBAdaptorFactory.getCatalogFileDBAdaptor(); 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 8811832480d..488a1c0f872 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 @@ -37,6 +37,9 @@ import org.opencb.opencga.core.common.UriUtils; import org.opencb.opencga.core.config.Admin; import org.opencb.opencga.core.config.Configuration; +import org.opencb.opencga.core.models.organizations.OrganizationCreateParams; +import org.opencb.opencga.core.models.organizations.OrganizationUpdateParams; +import org.opencb.opencga.core.models.project.ProjectCreateParams; import org.opencb.opencga.core.models.study.Study; import org.opencb.opencga.core.models.user.Account; import org.opencb.opencga.core.models.user.User; @@ -49,8 +52,7 @@ import java.nio.file.Paths; import static org.opencb.opencga.catalog.managers.AbstractManager.OPENCGA; -import static org.opencb.opencga.core.api.ParamConstants.ADMIN_PROJECT; -import static org.opencb.opencga.core.api.ParamConstants.ADMIN_STUDY; +import static org.opencb.opencga.core.api.ParamConstants.*; public class CatalogManager implements AutoCloseable { @@ -61,6 +63,7 @@ public class CatalogManager implements AutoCloseable { private CatalogIOManager catalogIOManager; private AdminManager adminManager; + private OrganizationManager organizationManager; private UserManager userManager; private ProjectManager projectManager; private StudyManager studyManager; @@ -105,6 +108,8 @@ private void configureManagers(Configuration configuration) throws CatalogExcept migrationManager = new MigrationManager(this, catalogDBAdaptorFactory, configuration); adminManager = new AdminManager(authorizationManager, auditManager, this, catalogDBAdaptorFactory, catalogIOManager, configuration); + organizationManager = new OrganizationManager(authorizationManager, auditManager, this, catalogDBAdaptorFactory, catalogIOManager, + configuration); userManager = new UserManager(authorizationManager, auditManager, this, catalogDBAdaptorFactory, catalogIOManager, configuration); projectManager = new ProjectManager(authorizationManager, auditManager, this, catalogDBAdaptorFactory, catalogIOManager, configuration); @@ -171,12 +176,11 @@ public boolean existsCatalogDB() { return catalogDBAdaptorFactory.isCatalogDBReady(); } - public void installCatalogDB(String secretKey, String password, String email, String organization, boolean force) - throws CatalogException { - installCatalogDB(secretKey, password, email, organization, force, false); + public void installCatalogDB(String secretKey, String password, String email, boolean force) throws CatalogException { + installCatalogDB(secretKey, password, email, force, false); } - public void installCatalogDB(String secretKey, String password, String email, String organization, boolean force, boolean test) + public void installCatalogDB(String secretKey, String password, String email, boolean force, boolean test) throws CatalogException { if (existsCatalogDB()) { if (force) { @@ -198,7 +202,7 @@ public void installCatalogDB(String secretKey, String password, String email, St try { logger.info("Installing database {} in {}", getCatalogDatabase(), configuration.getCatalog().getDatabase().getHosts()); - privateInstall(secretKey, password, email, organization, test); + privateInstall(secretKey, password, email, test); String token = userManager.loginAsAdmin(password).getToken(); installIndexes(token); } catch (Exception e) { @@ -211,8 +215,7 @@ public void installCatalogDB(String secretKey, String password, String email, St } } - private void privateInstall(String secretKey, String password, String email, String organization, boolean test) - throws CatalogException { + private void privateInstall(String secretKey, String password, String email, boolean test) throws CatalogException { if (existsCatalogDB()) { throw new CatalogException("Nothing to install. There already exists a catalog database"); } @@ -230,13 +233,17 @@ private void privateInstall(String secretKey, String password, String email, Str catalogDBAdaptorFactory.initialiseMetaCollection(configuration.getAdmin()); catalogIOManager.createDefaultOpenCGAFolders(); + organizationManager.create(new OrganizationCreateParams(ADMIN_ORGANIZATION, ADMIN_ORGANIZATION, "", null, null, null, null), + QueryOptions.empty(), null); User user = new User(OPENCGA, new Account().setType(Account.AccountType.ADMINISTRATOR).setExpirationDate("")) .setEmail(StringUtils.isEmpty(email) ? "opencga@admin.com" : email) - .setOrganization(organization); + .setOrganization(ADMIN_ORGANIZATION); userManager.create(user, password, null); - String token = userManager.login(OPENCGA, password).getToken(); - projectManager.create(ADMIN_PROJECT, ADMIN_PROJECT, "Default project", "", "", "", null, token); + + // Add OPENCGA as owner of ADMIN_ORGANIZATION + organizationManager.update(ADMIN_ORGANIZATION, new OrganizationUpdateParams().setOwner(OPENCGA), QueryOptions.empty(), token); + projectManager.create(new ProjectCreateParams().setId(ADMIN_PROJECT).setDescription("Default project"), null, token); studyManager.create(ADMIN_PROJECT, new Study().setId(ADMIN_STUDY).setDescription("Default study"), QueryOptions.empty(), token); // Skip old available migrations @@ -314,6 +321,10 @@ public AdminManager getAdminManager() { return adminManager; } + public OrganizationManager getOrganizationManager() { + return organizationManager; + } + public UserManager getUserManager() { return userManager; } 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 08325a8dbb7..1ddad567156 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 @@ -1,12 +1,46 @@ package org.opencb.opencga.catalog.managers; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.commons.collections4.CollectionUtils; +import org.opencb.commons.datastore.core.Event; +import org.opencb.commons.datastore.core.ObjectMap; +import org.opencb.commons.datastore.core.Query; +import org.opencb.commons.datastore.core.QueryOptions; +import org.opencb.commons.utils.ListUtils; import org.opencb.opencga.catalog.auth.authorization.AuthorizationManager; import org.opencb.opencga.catalog.db.DBAdaptorFactory; +import org.opencb.opencga.catalog.db.api.OrganizationDBAdaptor; +import org.opencb.opencga.catalog.exceptions.CatalogException; +import org.opencb.opencga.catalog.exceptions.CatalogIOException; +import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.io.CatalogIOManager; +import org.opencb.opencga.catalog.utils.ParamUtils; +import org.opencb.opencga.catalog.utils.UuidUtils; +import org.opencb.opencga.core.api.ParamConstants; +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.organizations.Organization; +import org.opencb.opencga.core.models.organizations.OrganizationCreateParams; +import org.opencb.opencga.core.models.organizations.OrganizationUpdateParams; +import org.opencb.opencga.core.response.OpenCGAResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Function; public class OrganizationManager extends AbstractManager { + public static final QueryOptions INCLUDE_ORGANIZATION_IDS = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( + OrganizationDBAdaptor.QueryParams.ID.key(), OrganizationDBAdaptor.QueryParams.UID.key(), + OrganizationDBAdaptor.QueryParams.UUID.key())); + public static final QueryOptions INCLUDE_ORGANIZATION_ADMINS = keepFieldsInQueryOptions(INCLUDE_ORGANIZATION_IDS, + Arrays.asList(OrganizationDBAdaptor.QueryParams.OWNER.key(), OrganizationDBAdaptor.QueryParams.ADMINS.key())); + protected static Logger logger = LoggerFactory.getLogger(OrganizationManager.class); private final CatalogIOManager catalogIOManager; OrganizationManager(AuthorizationManager authorizationManager, AuditManager auditManager, CatalogManager catalogManager, @@ -15,8 +49,197 @@ public class OrganizationManager extends AbstractManager { this.catalogIOManager = catalogIOManager; } - + OpenCGAResult internalGet(String organizationId, QueryOptions options, String user) throws CatalogException { + return internalGet(Collections.singletonList(organizationId), null, options, user, false); + } + + OpenCGAResult internalGet(List organizationList, @Nullable Query query, QueryOptions options, String user, + boolean ignoreException) throws CatalogException { + if (CollectionUtils.isEmpty(organizationList)) { + throw new CatalogException("Missing organization entries."); + } + List uniqueList = ListUtils.unique(organizationList); + + QueryOptions queryOptions = new QueryOptions(ParamUtils.defaultObject(options, QueryOptions::new)); + + Query queryCopy = query == null ? new Query() : new Query(query); + + OrganizationDBAdaptor.QueryParams idQueryParam = getFieldFilter(uniqueList); + queryCopy.put(idQueryParam.key(), uniqueList); + + if (!authorizationManager.isInstallationAdministrator(user)) { + // Only admins and owner are allowed to see the organizations + queryCopy.put(OrganizationDBAdaptor.QueryParams.ADMINS.key(), user); + } + + // Ensure the field by which we are querying for will be kept in the results + queryOptions = keepFieldInQueryOptions(queryOptions, idQueryParam.key()); + + OpenCGAResult organizationDataResult = organizationDBAdaptor.get(queryCopy, queryOptions); + + Function organizationStringFunction = Organization::getId; + if (idQueryParam.equals(OrganizationDBAdaptor.QueryParams.UUID)) { + organizationStringFunction = Organization::getUuid; + } + + if (ignoreException || organizationDataResult.getNumResults() == uniqueList.size()) { + return organizationDataResult; + } + + List missingOrganizations = new ArrayList<>(organizationList.size()); + for (Organization organization : organizationDataResult.getResults()) { + if (!uniqueList.contains(organizationStringFunction.apply(organization))) { + missingOrganizations.add(organizationStringFunction.apply(organization)); + } + } + + throw CatalogException.notFound("organizations", missingOrganizations); + } + + OrganizationDBAdaptor.QueryParams getFieldFilter(List idList) throws CatalogException { + OrganizationDBAdaptor.QueryParams idQueryParam = null; + for (String entry : idList) { + OrganizationDBAdaptor.QueryParams param = OrganizationDBAdaptor.QueryParams.ID; + if (UuidUtils.isOpenCgaUuid(entry)) { + param = OrganizationDBAdaptor.QueryParams.UUID; + } + if (idQueryParam == null) { + idQueryParam = param; + } + if (idQueryParam != param) { + throw new CatalogException("Found uuids and ids in the same query. Please, choose one or do two different queries."); + } + } + return idQueryParam; + } + + public OpenCGAResult create(OrganizationCreateParams organizationCreateParams, QueryOptions options, String token) + throws CatalogException { + String userId = this.catalogManager.getUserManager().getUserId(token); + + ObjectMap auditParams = new ObjectMap() + .append("organizationCreateParams", organizationCreateParams) + .append("options", options) + .append("token", token); + + options = ParamUtils.defaultObject(options, QueryOptions::new); + OpenCGAResult queryResult; + Organization organization; + try { + // The first time we create the ADMIN_ORGANIZATION as there are no users yet, we should not check anything + if (!ParamConstants.ADMIN_ORGANIZATION.equals(organizationCreateParams.getId())) { + //Only the OpenCGA administrator can create an organization + authorizationManager.checkIsInstallationAdministrator(userId); + } + ParamUtils.checkObj(organizationCreateParams, "organizationCreateParams"); + + organization = organizationCreateParams.toOrganization(); + validateOrganizationForCreation(organization); + + queryResult = organizationDBAdaptor.insert(organization, options); + if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { + OpenCGAResult result = organizationDBAdaptor.get(organization.getUid(), options); + organization = result.first(); + // Fetch created organization + queryResult.setResults(result.getResults()); + } + } catch (CatalogException e) { + auditManager.auditCreate(userId, Enums.Resource.ORGANIZATION, organizationCreateParams.getId(), "", "", "", auditParams, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); + throw e; + } + + try { + catalogIOManager.createOrganization(Long.toString(organization.getUid())); + } catch (CatalogIOException e) { + auditManager.auditCreate(userId, Enums.Resource.ORGANIZATION, organization.getId(), "", "", "", auditParams, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); + try { + organizationDBAdaptor.delete(organization); + } catch (Exception e1) { + logger.error("Error deleting organization from catalog after failing creating the folder in the filesystem", e1); + throw e; + } + throw e; + } + auditManager.auditCreate(userId, Enums.Resource.ORGANIZATION, organization.getId(), organization.getUuid(), "", "", auditParams, + new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); + + return queryResult; + } + + public OpenCGAResult update(String organizationId, OrganizationUpdateParams updateParams, QueryOptions options, + String token) throws CatalogException { + JwtPayload payload = catalogManager.getUserManager().getTokenPayload(token); + + ObjectMap updateMap; + try { + updateMap = updateParams != null ? updateParams.getUpdateMap() : null; + } catch (JsonProcessingException e) { + throw new CatalogException("Could not parse OrganizationUpdateParams object: " + e.getMessage(), e); + } + + ObjectMap auditParams = new ObjectMap() + .append("organizationId", organizationId) + .append("updateParams", updateMap) + .append("options", options) + .append("token", token); + + OpenCGAResult result = OpenCGAResult.empty(Organization.class); + String organizationUuid = ""; + try { + OpenCGAResult internalResult = internalGet(Collections.singletonList(organizationId), null, + INCLUDE_ORGANIZATION_ADMINS, payload.getUserId(), false); + if (internalResult.getNumResults() == 0) { + throw new CatalogException("Organization '" + organizationId + "' not found"); + } + Organization organization = internalResult.first(); + + // We set the proper values for the audit + organizationId = organization.getId(); + organizationUuid = organization.getUuid(); + + OpenCGAResult updateResult = organizationDBAdaptor.update(organization.getUid(), updateMap, options); + result.append(updateResult); + + auditManager.auditUpdate(payload.getUserId(), Enums.Resource.ORGANIZATION, organization.getId(), organization.getUuid(), "", "", + auditParams, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); + } catch (CatalogException e) { + Event event = new Event(Event.Type.ERROR, organizationId, e.getMessage()); + result.getEvents().add(event); + result.setNumErrors(result.getNumErrors() + 1); + + logger.error("Cannot update organization {}: {}", organizationId, e.getMessage()); + auditManager.auditUpdate(payload.getUserId(), Enums.Resource.ORGANIZATION, organizationId, organizationUuid, "", "", + auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); + throw e; + } + return result; + } + + private void validateOrganizationForCreation(Organization organization) throws CatalogParameterException { + ParamUtils.checkParameter(organization.getId(), OrganizationDBAdaptor.QueryParams.ID.key()); + + organization.setUuid(UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.ORGANIZATION)); + organization.setName(ParamUtils.defaultString(organization.getName(), organization.getId())); + organization.setDomain(ParamUtils.defaultString(organization.getDomain(), "")); + organization.setCreationDate(ParamUtils.checkDateOrGetCurrentDate(organization.getCreationDate(), + OrganizationDBAdaptor.QueryParams.CREATION_DATE.key())); + organization.setModificationDate(ParamUtils.checkDateOrGetCurrentDate(organization.getModificationDate(), + OrganizationDBAdaptor.QueryParams.MODIFICATION_DATE.key())); + organization.setAdmins(Collections.emptyList()); + organization.setProjects(Collections.emptyList()); + + if (CollectionUtils.isNotEmpty(organization.getAuthenticationOrigins())) { + for (AuthenticationOrigin authenticationOrigin : organization.getAuthenticationOrigins()) { + ParamUtils.checkParameter(authenticationOrigin.getId(), "AuthenticationOrigin id"); + } + } else { + organization.setAuthenticationOrigins(Collections.emptyList()); + } + organization.setAttributes(ParamUtils.defaultObject(organization.getAttributes(), HashMap::new)); + } } 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 249d14ab057..72eb35b67a1 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 @@ -22,7 +22,6 @@ import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; -import org.opencb.commons.datastore.core.result.Error; import org.opencb.commons.utils.ListUtils; import org.opencb.opencga.catalog.auth.authorization.AuthorizationManager; import org.opencb.opencga.catalog.db.DBAdaptorFactory; @@ -36,14 +35,15 @@ import org.opencb.opencga.core.cellbase.CellBaseValidator; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.config.storage.CellBaseConfiguration; +import org.opencb.opencga.core.models.JwtPayload; import org.opencb.opencga.core.models.audit.AuditRecord; import org.opencb.opencga.core.models.cohort.Cohort; import org.opencb.opencga.core.models.common.Enums; import org.opencb.opencga.core.models.individual.Individual; +import org.opencb.opencga.core.models.organizations.Organization; import org.opencb.opencga.core.models.project.*; import org.opencb.opencga.core.models.sample.Sample; 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; @@ -222,9 +222,9 @@ public OpenCGAResult create(String id, String name, String description, public OpenCGAResult create(ProjectCreateParams projectCreateParams, QueryOptions options, String token) throws CatalogException { - //Only the user can create a project - String userId = this.catalogManager.getUserManager().getUserId(token); - if (userId.isEmpty()) { + // Only the organization owner or the administrators can create a project + JwtPayload payload = this.catalogManager.getUserManager().getTokenPayload(token); + if (payload.getUserId().isEmpty()) { throw new CatalogException("The token introduced does not correspond to any registered user."); } @@ -236,54 +236,42 @@ public OpenCGAResult create(ProjectCreateParams projectCreateParams, Qu options = ParamUtils.defaultObject(options, QueryOptions::new); OpenCGAResult queryResult; Project project; + Organization organization; try { - ParamUtils.checkObj(projectCreateParams, "ProjectCreateParams"); - - // Check that the account type is not guest - OpenCGAResult user = userDBAdaptor.get(userId, QueryOptions.empty()); - if (user.getNumResults() == 0) { - throw new CatalogException("Internal error happened. Could not find user " + userId); - } - - if (Account.AccountType.FULL != user.first().getAccount().getType()) { - if (user.first().getAccount().getType() == Account.AccountType.ADMINISTRATOR) { - // Check it is the first project - if (user.first().getProjects() != null && !user.first().getProjects().isEmpty()) { - String errorMsg = "Cannot create more projects for ADMINISTRATOR user '" + user.first().getId() + "'."; - auditManager.auditCreate(userId, Enums.Resource.PROJECT, projectCreateParams.getId(), "", "", "", auditParams, - new AuditRecord.Status(AuditRecord.Status.Result.ERROR, new Error(0, "", errorMsg))); - throw new CatalogException(errorMsg); - } - } else { - - String errorMsg = "User " + userId + " is not authorized to create new projects. Only users with " - + Account.AccountType.FULL + " accounts are allowed to do so."; - auditManager.auditCreate(userId, Enums.Resource.PROJECT, projectCreateParams.getId(), "", "", "", auditParams, - new AuditRecord.Status(AuditRecord.Status.Result.ERROR, new Error(0, "", errorMsg))); - throw new CatalogException(errorMsg); - } - } + // To ensure only an organization admin can create the project, we add it to the query object + Query organizationQuery = new Query(OrganizationDBAdaptor.QueryParams.ADMINS.key(), payload.getUserId()); + organization = catalogManager.getOrganizationManager().internalGet(Collections.singletonList(payload.getOrganization()), + organizationQuery, OrganizationManager.INCLUDE_ORGANIZATION_IDS, payload.getUserId(), false).first(); + } catch (CatalogException e) { + String message = "Only the organization owner or the administrators can create a project"; + CatalogException e1 = new CatalogException(message, e); + auditManager.auditCreate(payload.getUserId(), Enums.Resource.PROJECT, projectCreateParams.getId(), "", "", "", auditParams, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e1.getError())); + throw e1; + } + try { + ParamUtils.checkObj(projectCreateParams, "ProjectCreateParams"); project = projectCreateParams.toProject(); - validateProjectForCreation(project, user.first()); + validateProjectForCreation(project); - queryResult = projectDBAdaptor.insert(project, userId, options); - OpenCGAResult result = getProject(userId, project.getUuid(), options); + queryResult = projectDBAdaptor.insert(organization.getId(), project, options); + OpenCGAResult result = getProject(organization.getId(), project.getUuid(), options); project = result.first(); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { // Fetch created project queryResult.setResults(result.getResults()); } } catch (CatalogException e) { - auditManager.auditCreate(userId, Enums.Resource.PROJECT, projectCreateParams.getId(), "", "", "", auditParams, + auditManager.auditCreate(payload.getUserId(), Enums.Resource.PROJECT, projectCreateParams.getId(), "", "", "", auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); throw e; } try { - catalogIOManager.createProject(userId, Long.toString(project.getUid())); + catalogIOManager.createProject(Long.toString(organization.getUid()), Long.toString(project.getUid())); } catch (CatalogIOException e) { - auditManager.auditCreate(userId, Enums.Resource.PROJECT, project.getId(), "", "", "", auditParams, + auditManager.auditCreate(payload.getUserId(), Enums.Resource.PROJECT, project.getId(), "", "", "", auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); try { projectDBAdaptor.delete(project); @@ -293,13 +281,13 @@ public OpenCGAResult create(ProjectCreateParams projectCreateParams, Qu } throw e; } - auditManager.auditCreate(userId, Enums.Resource.PROJECT, project.getId(), project.getUuid(), "", "", auditParams, + auditManager.auditCreate(payload.getUserId(), Enums.Resource.PROJECT, project.getId(), project.getUuid(), "", "", auditParams, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); return queryResult; } - private void validateProjectForCreation(Project project, User user) throws CatalogParameterException { + private void validateProjectForCreation(Project project) throws CatalogParameterException { ParamUtils.checkParameter(project.getId(), ProjectDBAdaptor.QueryParams.ID.key()); project.setName(ParamUtils.defaultString(project.getName(), project.getId())); project.setDescription(ParamUtils.defaultString(project.getDescription(), "")); @@ -311,28 +299,21 @@ private void validateProjectForCreation(Project project, User user) throws Catal project.setInternal(ProjectInternal.init()); project.setAttributes(ParamUtils.defaultObject(project.getAttributes(), HashMap::new)); - if (user.getAccount().getType() == Account.AccountType.ADMINISTRATOR) { - // Do not validate organism nor CellBase for admin account - } else { - if (project.getOrganism() == null || StringUtils.isEmpty(project.getOrganism().getAssembly()) - || StringUtils.isEmpty(project.getOrganism().getScientificName())) { - throw new CatalogParameterException("Missing mandatory organism information"); - } - try { - CellBaseConfiguration cellBaseConfiguration = ParamUtils.defaultObject(project.getCellbase(), - new CellBaseConfiguration(ParamConstants.CELLBASE_URL, ParamConstants.CELLBASE_VERSION)); - cellBaseConfiguration = CellBaseValidator.validate(cellBaseConfiguration, - project.getOrganism().getScientificName(), - project.getOrganism().getAssembly(), true); - project.setCellbase(cellBaseConfiguration); - } catch (IOException e) { - throw new CatalogParameterException(e); - } + if (project.getOrganism() == null || StringUtils.isEmpty(project.getOrganism().getAssembly()) + || StringUtils.isEmpty(project.getOrganism().getScientificName())) { + throw new CatalogParameterException("Missing mandatory organism information"); + } + try { + CellBaseConfiguration cellBaseConfiguration = ParamUtils.defaultObject(project.getCellbase(), + new CellBaseConfiguration(ParamConstants.CELLBASE_URL, ParamConstants.CELLBASE_VERSION)); + cellBaseConfiguration = CellBaseValidator.validate(cellBaseConfiguration, project.getOrganism().getScientificName(), + project.getOrganism().getAssembly(), true); + project.setCellbase(cellBaseConfiguration); + } catch (IOException e) { + throw new CatalogParameterException(e); } - project.setUuid(UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.PROJECT)); - if (project.getStudies() != null && !project.getStudies().isEmpty()) { throw new CatalogParameterException("Creating project and studies in a single transaction is forbidden"); } 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 a789f25b443..db7a0cdfa17 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 @@ -41,8 +41,10 @@ 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.organizations.Organization; import org.opencb.opencga.core.models.project.Project; import org.opencb.opencga.core.models.study.Group; import org.opencb.opencga.core.models.study.GroupUpdateParams; @@ -153,7 +155,7 @@ public void changePassword(String userId, String oldPassword, String newPassword } } - public OpenCGAResult create(User user, String password, @Nullable String token) throws CatalogException { + public OpenCGAResult create(String organizationId, User user, String password, @Nullable String token) throws CatalogException { // Check if the users can be registered publicly or just the admin. ObjectMap auditParams = new ObjectMap("user", user); @@ -212,7 +214,7 @@ public OpenCGAResult create(User user, String password, @Nullable String t throw new CatalogException("Creating user and projects in a single transaction is forbidden"); } - catalogIOManager.createUser(user.getId()); + catalogIOManager.createUser(organizationId, user.getId()); userDBAdaptor.insert(user, password, QueryOptions.empty()); auditManager.auditCreate(userId, Enums.Resource.USER, user.getId(), "", "", "", auditParams, @@ -222,7 +224,92 @@ public OpenCGAResult create(User user, String password, @Nullable String t } catch (CatalogIOException | CatalogDBException e) { if (userDBAdaptor.exists(user.getId())) { logger.error("ERROR! DELETING USER! " + user.getId()); - catalogIOManager.deleteUser(user.getId()); + catalogIOManager.deleteUser(organizationId, user.getId()); + } + + auditManager.auditCreate(userId, Enums.Resource.USER, user.getId(), "", "", "", auditParams, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); + + throw e; + } + } + + public OpenCGAResult create(User user, String password, @Nullable String token) throws CatalogException { + // Check if the users can be registered publicly or just the admin. + ObjectMap auditParams = new ObjectMap("user", user); + + // Initialise fields + ParamUtils.checkObj(user, "User"); + ParamUtils.checkValidUserId(user.getId()); + ParamUtils.checkParameter(user.getName(), "name"); + user.setEmail(ParamUtils.defaultString(user.getEmail(), "")); + if (StringUtils.isNotEmpty(user.getEmail())) { + checkEmail(user.getEmail()); + } + user.setOrganization(ParamUtils.defaultObject(user.getOrganization(), "")); + ParamUtils.checkObj(user.getAccount(), "account"); + user.getAccount().setType(ParamUtils.defaultObject(user.getAccount().getType(), Account.AccountType.GUEST)); + user.getAccount().setCreationDate(TimeUtils.getTime()); + user.getAccount().setExpirationDate(ParamUtils.defaultString(user.getAccount().getExpirationDate(), "")); + user.setInternal(new UserInternal(new UserStatus(UserStatus.READY))); + user.setQuota(ParamUtils.defaultObject(user.getQuota(), UserQuota::new)); + user.setProjects(ParamUtils.defaultObject(user.getProjects(), Collections::emptyList)); + user.setSharedProjects(ParamUtils.defaultObject(user.getSharedProjects(), 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)); + + if (StringUtils.isEmpty(password)) { + // The authentication origin must be different than internal + Set authOrigins = configuration.getAuthentication().getAuthenticationOrigins() + .stream() + .map(AuthenticationOrigin::getId) + .collect(Collectors.toSet()); + if (!authOrigins.contains(user.getAccount().getAuthentication().getId())) { + throw new CatalogException("Unknown authentication origin id '" + user.getAccount().getAuthentication() + "'"); + } + } else { + user.getAccount().setAuthentication(new Account.AuthenticationOrigin(INTERNAL_AUTHORIZATION, false)); + } + + String userId = OPENCGA; + Organization organization; + if (OPENCGA.equals(user.getId())) { + organization = catalogManager.getOrganizationManager().internalGet(ParamConstants.ADMIN_ORGANIZATION, + OrganizationManager.INCLUDE_ORGANIZATION_ADMINS, userId).first(); + } else { + JwtPayload payload = authenticationManagerMap.get(INTERNAL_AUTHORIZATION).getPayload(token); + organization = catalogManager.getOrganizationManager().internalGet(ParamConstants.ADMIN_ORGANIZATION, + OrganizationManager.INCLUDE_ORGANIZATION_ADMINS, payload.getUserId()).first(); + if (!OPENCGA.equals(payload.getUserId())) { + // Check owner or admin is trying to create a new user for the organization + if (!payload.getOrganization().equals(user.getOrganization())) { + throw new CatalogException("Owner or admins can only create new users inside the organization"); + } + } + } + + checkUserExists(user.getId()); + + try { + if (StringUtils.isNotEmpty(password) && !PasswordUtils.isStrongPassword(password)) { + throw new CatalogException("Invalid password. Check password strength for user " + user.getId()); + } + if (user.getProjects() != null && !user.getProjects().isEmpty()) { + throw new CatalogException("Creating user and projects in a single transaction is forbidden"); + } + + catalogIOManager.createUser(Long.toString(organization.getUid()), user.getId()); + userDBAdaptor.insert(user, password, QueryOptions.empty()); + + auditManager.auditCreate(userId, Enums.Resource.USER, user.getId(), "", "", "", auditParams, + new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); + + return userDBAdaptor.get(user.getId(), QueryOptions.empty()); + } catch (CatalogIOException | CatalogDBException e) { + if (userDBAdaptor.exists(user.getId())) { + logger.error("ERROR! DELETING USER! " + user.getId()); + catalogIOManager.deleteUser(user.getOrganization(), user.getId()); } auditManager.auditCreate(userId, Enums.Resource.USER, user.getId(), "", "", "", auditParams, @@ -801,6 +888,76 @@ public AuthenticationResponse loginAsAdmin(String password) throws CatalogExcept return login(OPENCGA, password); } + public AuthenticationResponse login(String organizationId, String username, String password) throws CatalogException { + ParamUtils.checkParameter(organizationId, "organizationId"); + ParamUtils.checkParameter(username, "userId"); + ParamUtils.checkParameter(password, "password"); + + String authId = null; + AuthenticationResponse response = null; + + OpenCGAResult userOpenCGAResult = userDBAdaptor.get(username, INCLUDE_ACCOUNT); + if (userOpenCGAResult.getNumResults() == 1) { + authId = userOpenCGAResult.first().getAccount().getAuthentication().getId(); + if (!authenticationManagerMap.containsKey(authId)) { + throw new CatalogException("Could not authenticate user '" + username + "'. The authentication origin '" + authId + + "' could not be found."); + } + try { + response = authenticationManagerMap.get(authId).authenticate(username, password); + } catch (CatalogAuthenticationException e) { + auditManager.auditUser(username, Enums.Action.LOGIN, username, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); + throw e; + } + } else { + // We attempt to login the user with the different authentication managers + for (Map.Entry entry : authenticationManagerMap.entrySet()) { + AuthenticationManager authenticationManager = entry.getValue(); + try { + response = authenticationManager.authenticate(username, password); + authId = entry.getKey(); + break; + } catch (CatalogAuthenticationException e) { + logger.debug("Attempted authentication failed with {} for user '{}'\n{}", entry.getKey(), username, e.getMessage(), e); + } + } + } + + if (response == null) { + auditManager.auditUser(username, Enums.Action.LOGIN, username, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, new Error(0, "", "Incorrect user or password."))); + throw CatalogAuthenticationException.incorrectUserOrPassword(); + } + + auditManager.auditUser(username, Enums.Action.LOGIN, username, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); + String userId = authenticationManagerMap.get(authId).getUserId(response.getToken()); + if (!INTERNAL_AUTHORIZATION.equals(authId)) { + // External authorization + try { + // If the user is not registered, an exception will be raised + userDBAdaptor.checkId(userId); + } catch (CatalogDBException e) { + // The user does not exist so we register it + User user = authenticationManagerMap.get(authId).getRemoteUserInformation(Collections.singletonList(userId)).get(0); + // Generate a root token to be able to create the user even if the installation is private + String rootToken = authenticationManagerMap.get(INTERNAL_AUTHORIZATION).createToken(OPENCGA); + create(user, null, rootToken); + } + + try { + List remoteGroups = authenticationManagerMap.get(authId).getRemoteGroups(response.getToken()); + + // Resync synced groups of user in OpenCGA + studyDBAdaptor.resyncUserWithSyncedGroups(userId, remoteGroups, authId); + } catch (CatalogException e) { + logger.error("Could not update synced groups for user '" + userId + "'\n" + e.getMessage(), e); + } + } + + return response; + } + public AuthenticationResponse login(String username, String password) throws CatalogException { ParamUtils.checkParameter(username, "userId"); ParamUtils.checkParameter(password, "password"); @@ -1394,6 +1551,26 @@ private String getCatalogUserId(String userId, String token) throws CatalogExcep } } + /** + * Get the token payload. + * + * @param token Token + * @return The token payload. + * @throws CatalogException when the token has expired. + */ + public JwtPayload getTokenPayload(String token) throws CatalogException { + for (Map.Entry entry : authenticationManagerMap.entrySet()) { + AuthenticationManager authenticationManager = entry.getValue(); + try { + return authenticationManager.getPayload(token); + } catch (Exception e) { + logger.debug("Could not get payload from token using authentication manager '{}'. {}", entry.getKey(), e.getMessage(), e); + } + } + // We make this call again to get the original exception + return authenticationManagerMap.get(INTERNAL_AUTHORIZATION).getPayload(token); + } + /** * Get the userId from the sessionId. * diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/CatalogDemo.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/CatalogDemo.java index 91708265ca4..3d2331d6eda 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/CatalogDemo.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/CatalogDemo.java @@ -47,7 +47,7 @@ private CatalogDemo() { public static void createDemoDatabase(CatalogManager catalogManager, String adminPassword, boolean force) throws CatalogException { catalogManager.installCatalogDB(catalogManager.getConfiguration().getAdmin().getSecretKey(), adminPassword, "opencga@admin.com", - "", force); + force); try { populateDatabase(catalogManager); } catch (IOException e) { diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/UuidUtils.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/UuidUtils.java index fe30716cadd..bcd545bb70a 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/UuidUtils.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/utils/UuidUtils.java @@ -48,7 +48,8 @@ public enum Entity { JOB(8), CLINICAL(9), PANEL(10), - INTERPRETATION(11); + INTERPRETATION(11), + ORGANIZATION(12); private final int mask; diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/auth/authorization/CatalogAuthorizationManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/auth/authorization/CatalogAuthorizationManagerTest.java index 01121cbe2d3..837c17c85f8 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/auth/authorization/CatalogAuthorizationManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/auth/authorization/CatalogAuthorizationManagerTest.java @@ -136,7 +136,7 @@ public void before() throws Exception { CatalogManagerExternalResource.clearCatalog(configuration); catalogManager = new CatalogManager(configuration); - catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), TestParamConstants.ADMIN_PASSWORD, "opencga@admin.com", "", true, true); + catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), TestParamConstants.ADMIN_PASSWORD, "opencga@admin.com", true, true); opencgaToken = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); fileManager = catalogManager.getFileManager(); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorTest.java index ee8d9848e20..4ad06bb24fd 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptorTest.java @@ -179,9 +179,9 @@ public void initDefaultCatalogDB() throws CatalogException { user1 = new User("jcoll", "Jacobo Coll", "jcoll@ebi", "", null, new UserInternal(new UserStatus()), new UserQuota(-1, -1, -1, -1), Collections.emptyList(), Collections.emptyList(), new HashMap<>(), new LinkedList<>(), new HashMap<>()); catalogUserDBAdaptor.insert(user1, "1234", null); - catalogProjectDBAdaptor.insert(new Project("P1", "project", "", null, 1, ProjectInternal.init()), "jcoll", null); - catalogProjectDBAdaptor.insert(new Project("P2", "project", "", null, 1, ProjectInternal.init()), "jcoll", null); - catalogProjectDBAdaptor.insert(new Project("P3", "project", "", null, 1, ProjectInternal.init()), "jcoll", null); + catalogProjectDBAdaptor.insert("jcoll", new Project("P1", "project", "", null, 1, ProjectInternal.init()), null); + catalogProjectDBAdaptor.insert("jcoll", new Project("P2", "project", "", null, 1, ProjectInternal.init()), null); + catalogProjectDBAdaptor.insert("jcoll", new Project("P3", "project", "", null, 1, ProjectInternal.init()), null); user2 = new User("jmmut", "Jose Miguel", "jmmut@ebi", "ACME", new UserInternal(new UserStatus())); catalogUserDBAdaptor.insert(user2, "1111", null); @@ -189,9 +189,9 @@ public void initDefaultCatalogDB() throws CatalogException { user3 = new User("imedina", "Nacho", "nacho@gmail", "SPAIN", null, new UserInternal(new UserStatus()), new UserQuota(-1, -1, -1, -1), Collections.emptyList(), Collections.emptyList(), new HashMap<>(), new LinkedList<>(), new HashMap<>()); catalogUserDBAdaptor.insert(user3, "2222", null); - catalogProjectDBAdaptor.insert(new Project("pr1", "90 GigaGenomes", TimeUtils.getTime(), TimeUtils.getTime(), "very long description", null, null, + catalogProjectDBAdaptor.insert("imedina", new Project("pr1", "90 GigaGenomes", TimeUtils.getTime(), TimeUtils.getTime(), "very long description", null, null, Collections.emptyList(), 1, ProjectInternal.init(), Collections.emptyMap() - ), "imedina", null); + ), null); catalogStudyDBAdaptor.insert(catalogProjectDBAdaptor.get(new Query(ProjectDBAdaptor.QueryParams.ID.key(), "pr1"), null).first(), new Study("name", "Study name", "ph1", TimeUtils.getTime(), TimeUtils.getTime(), "", null, null, null, 0, Arrays.asList(new Group("@members", Collections.emptyList())), Arrays.asList( @@ -208,8 +208,8 @@ public void initDefaultCatalogDB() throws CatalogException { new HashMap<>()); catalogUserDBAdaptor.insert(user4, "pfuriopass", null); - catalogProjectDBAdaptor.insert(new Project("pr", "lncRNAs", TimeUtils.getTime(), TimeUtils.getTime(), "My description", null, null, - Collections.emptyList(), 1, ProjectInternal.init(), Collections.emptyMap()), "pfurio", null); + catalogProjectDBAdaptor.insert("pfurio", new Project("pr", "lncRNAs", TimeUtils.getTime(), TimeUtils.getTime(), "My description", null, null, + Collections.emptyList(), 1, ProjectInternal.init(), Collections.emptyMap()), null); catalogStudyDBAdaptor.insert(catalogProjectDBAdaptor.get(new Query(ProjectDBAdaptor.QueryParams.ID.key(), "pr"), null).first(), new Study("spongeScan", "spongeScan", "sponges", TimeUtils.getTime(), TimeUtils.getTime(), "", null, null, null, 0, Arrays.asList(new Group("@members", Collections.emptyList())), Arrays.asList( diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptorTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptorTest.java index b9c0fb05755..1f2c1cd4d6f 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptorTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/db/mongodb/ProjectMongoDBAdaptorTest.java @@ -41,15 +41,15 @@ public class ProjectMongoDBAdaptorTest extends MongoDBAdaptorTest { @Test public void createProjectTest() throws CatalogException, JsonProcessingException { Project p = new Project("1000G", "Project about some genomes", "", "", "Cool", null, 1, ProjectInternal.init()); - System.out.println(catalogProjectDBAdaptor.insert(p, user1.getId(), null)); + System.out.println(catalogProjectDBAdaptor.insert(user1.getId(), p, null)); p = new Project("2000G", "Project about some more genomes", "", "", "Cool", null, 1, ProjectInternal.init()); - System.out.println(catalogProjectDBAdaptor.insert(p, user1.getId(), null)); + System.out.println(catalogProjectDBAdaptor.insert(user1.getId(), p, null)); p = new Project("pmp", "Project management project", "", "", "it is a system", null, 1, ProjectInternal.init()); - System.out.println(catalogProjectDBAdaptor.insert(p, user2.getId(), null)); - System.out.println(catalogProjectDBAdaptor.insert(p, user1.getId(), null)); + System.out.println(catalogProjectDBAdaptor.insert(user2.getId(), p, null)); + System.out.println(catalogProjectDBAdaptor.insert(user1.getId(), p, null)); try { - System.out.println(catalogProjectDBAdaptor.insert(p, user1.getId(), null)); + System.out.println(catalogProjectDBAdaptor.insert(user1.getId(), p, null)); fail("Expected \"projectAlias already exists\" exception"); } catch (CatalogDBException e) { System.out.println(e); @@ -131,9 +131,9 @@ public void getAllProjects() throws CatalogDBException { */ @Test public void renameProjectTest() throws CatalogException { - catalogProjectDBAdaptor.insert(new Project("p1", "project1", null, null, "Cool", null, 1, ProjectInternal.init()), user1.getId(), null); + catalogProjectDBAdaptor.insert(user1.getId(), new Project("p1", "project1", null, null, "Cool", null, 1, ProjectInternal.init()), null); Project p1 = getProject(user1.getId(), "p1"); - catalogProjectDBAdaptor.insert(new Project("p2", "project2", null, null, "Cool", null, 1, ProjectInternal.init()), user1.getId(), null); + catalogProjectDBAdaptor.insert(user1.getId(), new Project("p2", "project2", null, null, "Cool", null, 1, ProjectInternal.init()), null); Project p2 = getProject(user1.getId(), "p2"); catalogProjectDBAdaptor.update(p1.getUid(), new ObjectMap(ProjectDBAdaptor.QueryParams.ID.key(), "newpmp"), QueryOptions.empty()); @@ -154,9 +154,9 @@ public void renameProjectTest() throws CatalogException { @Test public void test() throws Exception { - catalogProjectDBAdaptor.insert(new Project("p1", "project1", null, null, "Cool", null, 1, ProjectInternal.init()), user1.getId(), null); + catalogProjectDBAdaptor.insert(user1.getId(), new Project("p1", "project1", null, null, "Cool", null, 1, ProjectInternal.init()), null); Project p1 = getProject(user1.getId(), "p1"); - catalogProjectDBAdaptor.insert(new Project("p2", "project2", null, null, "Cool", null, 1, ProjectInternal.init()), user1.getId(), null); + catalogProjectDBAdaptor.insert(user1.getId(), new Project("p2", "project2", null, null, "Cool", null, 1, ProjectInternal.init()), null); Project p2 = getProject(user1.getId(), "p2"); catalogProjectDBAdaptor.update(p1.getUid(), new ObjectMap(ProjectDBAdaptor.QueryParams.CELLBASE.key(), diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/io/CatalogIOManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/io/CatalogIOManagerTest.java index d5d400a047d..11341106e64 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/io/CatalogIOManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/io/CatalogIOManagerTest.java @@ -59,23 +59,25 @@ public void before() throws Exception { @Test public void testCreateAccount() throws Exception { + String organizationId = "opencb"; String userId = "imedina"; - URI userUri = ioManager.createUser(userId); + URI userUri = ioManager.createUser(organizationId, userId); Path userPath = Paths.get(userUri); assertTrue(Files.exists(userPath)); assertEquals(tmpOutdir.resolve("users/" + userId).toAbsolutePath().toString(), userUri.getPath()); - ioManager.deleteUser(userId); + ioManager.deleteUser(organizationId, userId); assertFalse(Files.exists(userPath)); } @Test public void testCreateStudy() throws Exception { + String organizationId = "opencb"; String userId = "imedina"; String projectId = "1000g"; - Path userPath = Paths.get(ioManager.createUser(userId)); + Path userPath = Paths.get(ioManager.createUser(organizationId, userId)); Path projectPath = Paths.get(ioManager.createProject(userId, projectId)); assertTrue(Files.exists(projectPath)); 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 d29de6b553a..e71696593d8 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 @@ -32,6 +32,8 @@ import org.opencb.opencga.core.models.file.File; import org.opencb.opencga.core.models.file.FileCreateParams; import org.opencb.opencga.core.models.file.FileUpdateParams; +import org.opencb.opencga.core.models.organizations.OrganizationCreateParams; +import org.opencb.opencga.core.models.organizations.OrganizationUpdateParams; import org.opencb.opencga.core.models.sample.Sample; import org.opencb.opencga.core.models.study.Study; import org.opencb.opencga.core.models.study.Variable; @@ -93,10 +95,14 @@ public void setUp() throws Exception { public void setUpCatalogManager(CatalogManager catalogManager) throws IOException, CatalogException { opencgaToken = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); + catalogManager.getOrganizationManager().create(new OrganizationCreateParams().setId("test_org"), null, opencgaToken); + catalogManager.getUserManager().create("user", "User Name", "mail@ebi.ac.uk", TestParamConstants.PASSWORD, "", null, Account.AccountType.FULL, opencgaToken); catalogManager.getUserManager().create("user2", "User2 Name", "mail2@ebi.ac.uk", TestParamConstants.PASSWORD, "", null, Account.AccountType.FULL, opencgaToken); catalogManager.getUserManager().create("user3", "User3 Name", "user.2@e.mail", TestParamConstants.PASSWORD, "ACME", null, Account.AccountType.FULL, opencgaToken); + catalogManager.getOrganizationManager().update("test_org", new OrganizationUpdateParams().setOwner("user").setAdmins(Arrays.asList("user2", "user3")), null, opencgaToken); + token = catalogManager.getUserManager().login("user", TestParamConstants.PASSWORD).getToken(); sessionIdUser2 = catalogManager.getUserManager().login("user2", TestParamConstants.PASSWORD).getToken(); sessionIdUser3 = catalogManager.getUserManager().login("user3", TestParamConstants.PASSWORD).getToken(); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerExternalResource.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerExternalResource.java index 2e79d7a0151..a8e4ac7f96c 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerExternalResource.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/CatalogManagerExternalResource.java @@ -86,8 +86,7 @@ public void before() throws Exception { } configuration.getAdmin().setSecretKey(PasswordUtils.getStrongRandomPassword(JwtManager.SECRET_KEY_MIN_LENGTH)); catalogManager = new CatalogManager(configuration); - catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), TestParamConstants.ADMIN_PASSWORD, "opencga@admin.com", "", - true, true); + catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), TestParamConstants.ADMIN_PASSWORD, "opencga@admin.com", true, true); catalogManager.close(); // FIXME!! Should not need to create again the catalogManager // Have to create again the CatalogManager, as it has a random "secretKey" inside diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/utils/CatalogFileUtilsTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/utils/CatalogFileUtilsTest.java index 4a51358bb53..6d31de83b9e 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/utils/CatalogFileUtilsTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/utils/CatalogFileUtilsTest.java @@ -75,7 +75,7 @@ public void before() throws CatalogException, IOException, URISyntaxException { CatalogManagerExternalResource.clearCatalog(configuration); catalogManager = new CatalogManager(configuration); - catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), TestParamConstants.ADMIN_PASSWORD, "opencga@admin.com", "", true, true); + catalogManager.installCatalogDB(configuration.getAdmin().getSecretKey(), TestParamConstants.ADMIN_PASSWORD, "opencga@admin.com", true, true); String opencgaToken = catalogManager.getUserManager().loginAsAdmin(TestParamConstants.ADMIN_PASSWORD).getToken(); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java b/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java index b65214a9ba4..45ff1e1cc4b 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java @@ -116,6 +116,7 @@ public class ParamConstants { // --------------------------------------------- public static final String PROJECT_STUDY_SEPARATOR = ":"; public static final String OPENCGA_USER_ID = "opencga"; + public static final String ADMIN_ORGANIZATION = "opencga"; public static final String ADMIN_PROJECT = "admin"; public static final String ADMIN_STUDY = "admin"; public static final String ADMIN_STUDY_FQN = diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/JwtPayload.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/JwtPayload.java new file mode 100644 index 00000000000..130d25ac533 --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/JwtPayload.java @@ -0,0 +1,80 @@ +package org.opencb.opencga.core.models; + +import java.util.Date; + +public class JwtPayload { + + private String userId; + private String organization; + private String audience; // Recipients of the JWT token. + private Date issuedAt; // Time when the JWT was issued. + private Date expirationTime; // Expiration time of the JWT. + + public JwtPayload() { + } + + public JwtPayload(String userId, String organization, String audience, Date issuedAt, Date expirationTime) { + this.userId = userId; + this.organization = organization; + this.audience = audience; + this.issuedAt = issuedAt; + this.expirationTime = expirationTime; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("JwtPayload{"); + sb.append("userId='").append(userId).append('\''); + sb.append(", organization='").append(organization).append('\''); + sb.append(", audience='").append(audience).append('\''); + sb.append(", issuedAt=").append(issuedAt); + sb.append(", expirationTime=").append(expirationTime); + sb.append('}'); + return sb.toString(); + } + + public String getUserId() { + return userId; + } + + public JwtPayload setUserId(String userId) { + this.userId = userId; + return this; + } + + public String getOrganization() { + return organization; + } + + public JwtPayload setOrganization(String organization) { + this.organization = organization; + return this; + } + + public String getAudience() { + return audience; + } + + public JwtPayload setAudience(String audience) { + this.audience = audience; + return this; + } + + public Date getIssuedAt() { + return issuedAt; + } + + public JwtPayload setIssuedAt(Date issuedAt) { + this.issuedAt = issuedAt; + return this; + } + + public Date getExpirationTime() { + return expirationTime; + } + + public JwtPayload setExpirationTime(Date expirationTime) { + this.expirationTime = expirationTime; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/admin/InstallationParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/admin/InstallationParams.java index 39afad5dc53..69e1f08736b 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/admin/InstallationParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/admin/InstallationParams.java @@ -21,16 +21,14 @@ public class InstallationParams { private String secretKey; private String password; private String email; - private String organization; public InstallationParams() { } - public InstallationParams(String secretKey, String password, String email, String organization) { + public InstallationParams(String secretKey, String password, String email) { this.secretKey = secretKey; this.password = password; this.email = email; - this.organization = organization; } @Override @@ -39,7 +37,6 @@ public String toString() { sb.append("secretKey='").append(secretKey).append('\''); sb.append(", password='").append(password).append('\''); sb.append(", email='").append(email).append('\''); - sb.append(", organization='").append(organization).append('\''); sb.append('}'); return sb.toString(); } @@ -71,12 +68,4 @@ public InstallationParams setEmail(String email) { return this; } - public String getOrganization() { - return organization; - } - - public InstallationParams setOrganization(String organization) { - this.organization = organization; - return this; - } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/Enums.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/Enums.java index 764a07b409c..5ad6d48c29f 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/Enums.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/Enums.java @@ -60,6 +60,7 @@ public Resource getResource() { public enum Resource { AUDIT, + ORGANIZATION, USER, PROJECT, STUDY, diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/Organization.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/Organization.java index 3d3eca18b37..9185fa706bd 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/Organization.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/Organization.java @@ -52,6 +52,21 @@ public class Organization extends PrivateFields { public Organization() { } + public Organization(String id, String name, String domain, String owner, List admins, String creationDate, + String modificationDate, List projects, List authenticationOrigins, + Map attributes) { + this.id = id; + this.name = name; + this.domain = domain; + this.owner = owner; + this.admins = admins; + this.creationDate = creationDate; + this.modificationDate = modificationDate; + this.projects = projects; + this.authenticationOrigins = authenticationOrigins; + this.attributes = attributes; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("Organization{"); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/OrganizationCreateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/OrganizationCreateParams.java new file mode 100644 index 00000000000..88f86cf8e9a --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/OrganizationCreateParams.java @@ -0,0 +1,134 @@ +package org.opencb.opencga.core.models.organizations; + +import org.opencb.commons.annotations.DataField; +import org.opencb.opencga.core.api.FieldConstants; +import org.opencb.opencga.core.config.AuthenticationOrigin; + +import java.util.List; +import java.util.Map; + +public class OrganizationCreateParams { + + @DataField(id = "id", required = true, indexed = true, unique = true, immutable = true, + description = FieldConstants.ORGANIZATION_ID_DESCRIPTION) + private String id; + + @DataField(id = "name", description = FieldConstants.ORGANIZATION_NAME_DESCRIPTION) + private String name; + + @DataField(id = "domain", description = FieldConstants.ORGANIZATION_DOMAIN_DESCRIPTION) + private String domain; + + @DataField(id = "creationDate", description = FieldConstants.GENERIC_CREATION_DATE_DESCRIPTION) + private String creationDate; + + @DataField(id = "modificationDate", description = FieldConstants.GENERIC_MODIFICATION_DATE_DESCRIPTION) + private String modificationDate; + + @DataField(id = "authenticationOrigins", description = FieldConstants.ORGANIZATION_AUTHENTICATION_ORIGINS_DESCRIPTION) + private List authenticationOrigins; + + @DataField(id = "attributes", description = FieldConstants.GENERIC_ATTRIBUTES_DESCRIPTION) + private Map attributes; + + public OrganizationCreateParams() { + } + + public OrganizationCreateParams(String id, String name, String domain, String creationDate, String modificationDate, + List authenticationOrigins, Map attributes) { + this.id = id; + this.name = name; + this.domain = domain; + this.creationDate = creationDate; + this.modificationDate = modificationDate; + this.authenticationOrigins = authenticationOrigins; + this.attributes = attributes; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("OrganizationCreateParams{"); + sb.append("id='").append(id).append('\''); + sb.append(", name='").append(name).append('\''); + sb.append(", domain='").append(domain).append('\''); + sb.append(", creationDate='").append(creationDate).append('\''); + sb.append(", modificationDate='").append(modificationDate).append('\''); + sb.append(", authenticationOrigins=").append(authenticationOrigins); + sb.append(", attributes=").append(attributes); + sb.append('}'); + return sb.toString(); + } + + public static OrganizationCreateParams of(Organization organization) { + return new OrganizationCreateParams(organization.getId(), organization.getName(), organization.getDomain(), + organization.getCreationDate(), organization.getModificationDate(),organization.getAuthenticationOrigins(), + organization.getAttributes()); + } + + public Organization toOrganization() { + return new Organization(id, name, domain, null, null, creationDate, modificationDate, null, authenticationOrigins, attributes); + } + + public String getId() { + return id; + } + + public OrganizationCreateParams setId(String id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public OrganizationCreateParams setName(String name) { + this.name = name; + return this; + } + + public String getDomain() { + return domain; + } + + public OrganizationCreateParams setDomain(String domain) { + this.domain = domain; + return this; + } + + public String getCreationDate() { + return creationDate; + } + + public OrganizationCreateParams setCreationDate(String creationDate) { + this.creationDate = creationDate; + return this; + } + + public String getModificationDate() { + return modificationDate; + } + + public OrganizationCreateParams setModificationDate(String modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + public List getAuthenticationOrigins() { + return authenticationOrigins; + } + + public OrganizationCreateParams setAuthenticationOrigins(List authenticationOrigins) { + this.authenticationOrigins = authenticationOrigins; + return this; + } + + public Map getAttributes() { + return attributes; + } + + public OrganizationCreateParams setAttributes(Map attributes) { + this.attributes = attributes; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/OrganizationUpdateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/OrganizationUpdateParams.java new file mode 100644 index 00000000000..e7e5ce28f9b --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/organizations/OrganizationUpdateParams.java @@ -0,0 +1,148 @@ +package org.opencb.opencga.core.models.organizations; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.opencb.commons.annotations.DataField; +import org.opencb.commons.datastore.core.ObjectMap; +import org.opencb.opencga.core.api.FieldConstants; +import org.opencb.opencga.core.config.AuthenticationOrigin; + +import java.util.List; +import java.util.Map; + +import static org.opencb.opencga.core.common.JacksonUtils.getUpdateObjectMapper; + +public class OrganizationUpdateParams { + + @DataField(id = "name", description = FieldConstants.ORGANIZATION_NAME_DESCRIPTION) + private String name; + + @DataField(id = "domain", description = FieldConstants.ORGANIZATION_DOMAIN_DESCRIPTION) + private String domain; + + @DataField(id = "owner", description = FieldConstants.ORGANIZATION_OWNER_DESCRIPTION) + private String owner; + + @DataField(id = "admins", description = FieldConstants.ORGANIZATION_ADMINS_DESCRIPTION) + private List admins; + + @DataField(id = "creationDate", description = FieldConstants.GENERIC_CREATION_DATE_DESCRIPTION) + private String creationDate; + + @DataField(id = "modificationDate", description = FieldConstants.GENERIC_MODIFICATION_DATE_DESCRIPTION) + private String modificationDate; + + @DataField(id = "authenticationOrigins", description = FieldConstants.ORGANIZATION_AUTHENTICATION_ORIGINS_DESCRIPTION) + private List authenticationOrigins; + + @DataField(id = "attributes", description = FieldConstants.GENERIC_ATTRIBUTES_DESCRIPTION) + private Map attributes; + + public OrganizationUpdateParams() { + } + + public OrganizationUpdateParams(String name, String domain, String owner, List admins, String creationDate, + String modificationDate, List authenticationOrigins, + Map attributes) { + this.name = name; + this.domain = domain; + this.owner = owner; + this.admins = admins; + this.creationDate = creationDate; + this.modificationDate = modificationDate; + this.authenticationOrigins = authenticationOrigins; + this.attributes = attributes; + } + + @JsonIgnore + public ObjectMap getUpdateMap() throws JsonProcessingException { + return new ObjectMap(getUpdateObjectMapper().writeValueAsString(this)); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("OrganizationUpdateParams{"); + sb.append("name='").append(name).append('\''); + sb.append(", domain='").append(domain).append('\''); + sb.append(", owner='").append(owner).append('\''); + sb.append(", admins=").append(admins); + sb.append(", creationDate='").append(creationDate).append('\''); + sb.append(", modificationDate='").append(modificationDate).append('\''); + sb.append(", authenticationOrigins=").append(authenticationOrigins); + sb.append(", attributes=").append(attributes); + sb.append('}'); + return sb.toString(); + } + + public String getName() { + return name; + } + + public OrganizationUpdateParams setName(String name) { + this.name = name; + return this; + } + + public String getDomain() { + return domain; + } + + public OrganizationUpdateParams setDomain(String domain) { + this.domain = domain; + return this; + } + + public String getOwner() { + return owner; + } + + public OrganizationUpdateParams setOwner(String owner) { + this.owner = owner; + return this; + } + + public List getAdmins() { + return admins; + } + + public OrganizationUpdateParams setAdmins(List admins) { + this.admins = admins; + return this; + } + + public String getCreationDate() { + return creationDate; + } + + public OrganizationUpdateParams setCreationDate(String creationDate) { + this.creationDate = creationDate; + return this; + } + + public String getModificationDate() { + return modificationDate; + } + + public OrganizationUpdateParams setModificationDate(String modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + public List getAuthenticationOrigins() { + return authenticationOrigins; + } + + public OrganizationUpdateParams setAuthenticationOrigins(List authenticationOrigins) { + this.authenticationOrigins = authenticationOrigins; + return this; + } + + public Map getAttributes() { + return attributes; + } + + public OrganizationUpdateParams setAttributes(Map attributes) { + this.attributes = attributes; + return this; + } +} diff --git a/opencga-server/src/main/java/org/opencb/opencga/server/rest/admin/AdminWSServer.java b/opencga-server/src/main/java/org/opencb/opencga/server/rest/admin/AdminWSServer.java index 835c9632af1..1af8626844b 100644 --- a/opencga-server/src/main/java/org/opencb/opencga/server/rest/admin/AdminWSServer.java +++ b/opencga-server/src/main/java/org/opencb/opencga/server/rest/admin/AdminWSServer.java @@ -280,13 +280,11 @@ public Response syncSolr(@ApiParam(value = "Collection to be indexed (file, samp + "secretKey: Secret key needed to authenticate through OpenCGA (JWT)
" + "password: Password that will be set to perform future administrative operations over OpenCGA
" + "email: Administrator's email address.
" - + "organization: Administrator's organization.
" + "
    ") public Response install( @ApiParam(value = "JSON containing the mandatory parameters", required = true) InstallationParams installParams) { try { - catalogManager.installCatalogDB(installParams.getSecretKey(), installParams.getPassword(), installParams.getEmail(), - installParams.getOrganization(), false); + catalogManager.installCatalogDB(installParams.getSecretKey(), installParams.getPassword(), installParams.getEmail(), false); return createOkResponse(DataResult.empty()); } catch (Exception e) { return createErrorResponse(e);