From 23c59fc7e51a04fd8b285c254ca9a8c25d2b64f1 Mon Sep 17 00:00:00 2001 From: Ryan Doherty Date: Thu, 8 Feb 2024 00:00:14 -0500 Subject: [PATCH] checkpoint commit --- .../conifer/templates/WDK/model-config.xml.j2 | 37 --- .../org/gusdb/wdk/jmx/mbeans/ModelConfig.java | 2 - .../org/gusdb/wdk/model/ModelXmlParser.java | 3 - .../java/org/gusdb/wdk/model/Utilities.java | 96 ++---- .../java/org/gusdb/wdk/model/WdkModel.java | 20 +- .../gusdb/wdk/model/WdkSqlScriptRunner.java | 5 +- .../gusdb/wdk/model/answer/AnswerValue.java | 2 +- .../gusdb/wdk/model/answer/TransformUtil.java | 2 +- .../gusdb/wdk/model/config/ModelConfig.java | 53 +--- .../model/config/ModelConfigAccountDB.java | 16 - .../wdk/model/config/ModelConfigBuilder.java | 11 - .../wdk/model/config/ModelConfigParser.java | 3 - .../model/query/param/AbstractEnumParam.java | 1 - .../query/param/FilterParamNewHandler.java | 14 +- .../wdk/model/test/ParamValuesFactory.java | 2 +- .../org/gusdb/wdk/model/test/QueryTester.java | 2 +- .../gusdb/wdk/model/test/RecordTester.java | 2 +- .../gusdb/wdk/model/test/SummaryTester.java | 2 +- .../model/test/sanity/tests/QuestionTest.java | 2 +- .../org/gusdb/wdk/model/user/BasicUser.java | 31 ++ .../gusdb/wdk/model/user/BearerTokenUser.java | 43 +-- .../java/org/gusdb/wdk/model/user/User.java | 201 +------------ .../org/gusdb/wdk/model/user/UserFactory.java | 280 +++++++----------- .../gusdb/wdk/model/user/WdkUserProperty.java | 32 -- .../wdk/session/WdkOAuthClientWrapper.java | 24 ++ .../wdk/service/filter/CheckLoginFilter.java | 24 +- .../service/formatter/ProjectFormatter.java | 3 +- .../wdk/service/formatter/UserFormatter.java | 4 +- .../request/user/UserCreationRequest.java | 4 +- .../request/user/UserDatasetShareRequest.java | 2 - .../request/user/UserProfileRequest.java | 20 +- .../wdk/service/service/SessionService.java | 21 +- .../service/service/user/ProfileService.java | 32 +- .../wdk/service/service/user/UserService.java | 2 +- .../service/user/UserUtilityServices.java | 5 +- 35 files changed, 270 insertions(+), 733 deletions(-) delete mode 100644 Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigAccountDB.java create mode 100644 Model/src/main/java/org/gusdb/wdk/model/user/BasicUser.java delete mode 100644 Model/src/main/java/org/gusdb/wdk/model/user/WdkUserProperty.java diff --git a/Model/lib/conifer/roles/conifer/templates/WDK/model-config.xml.j2 b/Model/lib/conifer/roles/conifer/templates/WDK/model-config.xml.j2 index e831a0dcc4..ebb2626861 100644 --- a/Model/lib/conifer/roles/conifer/templates/WDK/model-config.xml.j2 +++ b/Model/lib/conifer/roles/conifer/templates/WDK/model-config.xml.j2 @@ -29,9 +29,6 @@ site_vars file: {{ site_vars }} {% if modelconfig_useWeights is defined -%} assetsUrl="{{ modelconfig_useWeights }}" {% endif -%} - {% if modelconfig_secretKeyFile is defined -%} - secretKeyFile="{{ modelconfig_secretKeyFile }}" - {% endif -%} {% if modelconfig_blockedThreshold is defined -%} monitorBlockedThreads="{{ modelconfig_monitorBlockedThreads }}" {% endif -%} @@ -145,40 +142,6 @@ site_vars file: {{ site_vars }} {% endif -%} /> - - {% if modelconfig_userDatasetStoreConfig is defined -%} {{ modelconfig_userDatasetStoreConfig|indent }} {% endif -%} diff --git a/Model/src/main/java/org/gusdb/wdk/jmx/mbeans/ModelConfig.java b/Model/src/main/java/org/gusdb/wdk/jmx/mbeans/ModelConfig.java index d4ce7a0a72..b47b5abac6 100644 --- a/Model/src/main/java/org/gusdb/wdk/jmx/mbeans/ModelConfig.java +++ b/Model/src/main/java/org/gusdb/wdk/jmx/mbeans/ModelConfig.java @@ -24,7 +24,6 @@ protected void init() { org.gusdb.wdk.model.config.QueryMonitor queryMonitor = modelConfig.getQueryMonitor(); org.gusdb.wdk.model.config.ModelConfigUserDB modelConfigUserDB = modelConfig.getUserDB(); org.gusdb.wdk.model.config.ModelConfigAppDB modelConfigAppDB = modelConfig.getAppDB(); - org.gusdb.wdk.model.config.ModelConfigAccountDB modelConfigAccountDB = modelConfig.getAccountDB(); org.gusdb.wdk.model.config.ModelConfigUserDatasetStore modelConfigUserDatasetStore = modelConfig.getUserDatasetStoreConfig(); @@ -32,7 +31,6 @@ protected void init() { setValuesFromGetters("queryMonitor", queryMonitor); setValuesFromGetters("userDb", modelConfigUserDB); setValuesFromGetters("appDb", modelConfigAppDB); - setValuesFromGetters("accountDb", modelConfigAccountDB); setValuesFromGetters("userDatasetStore", modelConfigUserDatasetStore); } diff --git a/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java b/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java index 7f595e505b..c71218bf23 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java +++ b/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java @@ -436,9 +436,6 @@ private Map loadProperties(String projectId, URL modelPropURL, M if (!propMap.containsKey("USER_SCHEMA")) { propMap.put("USER_SCHEMA", config.getUserDB().getUserSchema()); } - if (!propMap.containsKey("ACCT_SCHEMA")) { - propMap.put("ACCT_SCHEMA", config.getAccountDB().getAccountSchema()); - } return propMap; } diff --git a/Model/src/main/java/org/gusdb/wdk/model/Utilities.java b/Model/src/main/java/org/gusdb/wdk/model/Utilities.java index c5c22e1dc5..921c68038f 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/Utilities.java +++ b/Model/src/main/java/org/gusdb/wdk/model/Utilities.java @@ -1,17 +1,11 @@ package org.gusdb.wdk.model; -import org.apache.log4j.Logger; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import javax.activation.DataHandler; -import javax.mail.*; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.sql.Clob; import java.sql.SQLException; import java.util.Date; @@ -22,6 +16,20 @@ import java.util.regex.Pattern; import java.util.stream.Stream; +import javax.activation.DataHandler; +import javax.mail.Address; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + +import org.apache.log4j.Logger; + /** * This class provided constants that are shared among different WDK model * classes. Furthermore, it also provides utility functions to send @@ -31,16 +39,10 @@ */ public class Utilities { - private static final Logger logger = Logger.getLogger(Utilities.class); + private static final Logger LOG = Logger.getLogger(Utilities.class); public static final int TRUNCATE_DEFAULT = 100; - /** - * The maximum size for parameter values that will be displayed in thr URL as - * plain values - */ - public static final int MAX_PARAM_VALUE_SIZE = 100; - /** * The maximum number of attributes used in sorting an answer */ @@ -56,10 +58,6 @@ public class Utilities { */ public static final String SYSTEM_PROPERTY_GUS_HOME = "GUS_HOME"; - public static final int MAXIMUM_RECORD_INSTANCES = 10000; - - public static final int DEFAULT_PAGE_SIZE = 20; - public static final int DEFAULT_SUMMARY_ATTRIBUTE_SIZE = 6; public static final int DEFAULT_WEIGHT = 10; @@ -71,8 +69,6 @@ public class Utilities { */ public static final int MAX_PK_COLUMN_COUNT = 4; - public static final int MAX_PK_COLUMN_VALUE_SIZE = 1999; - public static final String INTERNAL_PARAM_SET = "InternalParams"; public static final String INTERNAL_QUERY_SET = "InternalQueries"; public static final String INTERNAL_QUESTION_SET = "InternalQuestions"; @@ -99,12 +95,12 @@ public class Utilities { public static final String COLUMN_DIVIDER = ","; public static final String WDK_MODEL_KEY = "wdk_model"; - public static final String WDK_MODEL_BEAN_KEY = "wdkModel"; // cannot change this because of JSPs public static final String WDK_USER_KEY = "wdk_user"; - public static final String WDK_USER_BEAN_KEY = "wdkUser"; + public static final String BEARER_TOKEN_KEY = "bearer-token"; public static final String WDK_SERVICE_ENDPOINT_KEY = "wdkServiceEndpoint"; + /* * Inner class to act as a JAF DataSource to send HTML e-mail content */ @@ -164,22 +160,6 @@ public static String[] toArray(String data) { return data.trim().split("\\s+"); } - public static String fromArray(String[] data) { - return fromArray(data, ","); - } - - public static String fromArray(String[] data, String delimiter) { - if (data == null) - return null; - StringBuffer sb = new StringBuffer(); - for (String value : data) { - if (sb.length() > 0) - sb.append(delimiter); - sb.append(value); - } - return sb.toString(); - } - public static String parseValue(Object objValue) { if (objValue == null) return null; @@ -197,21 +177,6 @@ private static String parseClob(Clob clobValue) { } } - public static String[][] convertContent(String content) throws JSONException { - JSONArray jsResult = new JSONArray(content); - JSONArray jsRow = (JSONArray) jsResult.get(0); - String[][] result = new String[jsResult.length()][jsRow.length()]; - for (int row = 0; row < result.length; row++) { - jsRow = (JSONArray) jsResult.get(row); - for (int col = 0; col < result[row].length; col++) { - Object cell = jsRow.get(col); - result[row][col] = (cell == null || cell == JSONObject.NULL) ? null - : cell.toString(); - } - } - return result; - } - // sendEmail() method overloading: different number of parameters (max 8), different type for attachments // 7 parameters (missing bcc, datahandlers instead of attachments) @@ -258,7 +223,7 @@ public static void sendEmail(String smtpServer, String sendTos, String reply, String subject, String content, String ccAddresses, String bccAddresses, Attachment[] attachments) throws WdkModelException { - logger.debug("Sending message to: " + sendTos + ", bcc to: " + bccAddresses + + LOG.debug("Sending message to: " + sendTos + ", bcc to: " + bccAddresses + ",reply: " + reply + ", using SMPT: " + smtpServer); // create properties and get the session @@ -317,7 +282,6 @@ public static void sendEmail(String smtpServer, String sendTos, String reply, } } - public static byte[] readFile(File file) throws IOException { byte[] buffer = new byte[(int) file.length()]; InputStream stream = new FileInputStream(file); @@ -326,18 +290,6 @@ public static byte[] readFile(File file) throws IOException { return buffer; } - public static int createHashFromValueMap(Map map) { - StringBuilder buffer = new StringBuilder("{"); - for (S key : map.keySet()) { - if (buffer.length() > 1) { - buffer.append(";"); - } - buffer.append(key).append(":").append(map.get(key)); - } - buffer.append("}"); - return buffer.toString().hashCode(); - } - public static Map parseSortList(String sortList) throws WdkModelException { Map sortingMap = new LinkedHashMap(); String[] attrCombines = sortList.split(","); diff --git a/Model/src/main/java/org/gusdb/wdk/model/WdkModel.java b/Model/src/main/java/org/gusdb/wdk/model/WdkModel.java index bb30e38ac3..a87dbcfb2f 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/WdkModel.java +++ b/Model/src/main/java/org/gusdb/wdk/model/WdkModel.java @@ -23,7 +23,6 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import org.apache.log4j.Logger; @@ -38,13 +37,13 @@ import org.gusdb.fgputil.functional.FunctionalInterfaces.SupplierWithException; import org.gusdb.fgputil.runtime.InstanceManager; import org.gusdb.fgputil.runtime.Manageable; +import org.gusdb.wdk.model.user.User; import org.gusdb.wdk.model.analysis.StepAnalysis; import org.gusdb.wdk.model.analysis.StepAnalysisPlugins; import org.gusdb.wdk.model.answer.single.SingleRecordQuestion; import org.gusdb.wdk.model.columntool.ColumnToolBundleMap; import org.gusdb.wdk.model.columntool.DefaultColumnToolBundleRef; import org.gusdb.wdk.model.config.ModelConfig; -import org.gusdb.wdk.model.config.ModelConfigAccountDB; import org.gusdb.wdk.model.config.ModelConfigAppDB; import org.gusdb.wdk.model.config.ModelConfigUserDB; import org.gusdb.wdk.model.config.ModelConfigUserDatasetStore; @@ -69,7 +68,6 @@ import org.gusdb.wdk.model.user.BasketFactory; import org.gusdb.wdk.model.user.FavoriteFactory; import org.gusdb.wdk.model.user.StepFactory; -import org.gusdb.wdk.model.user.User; import org.gusdb.wdk.model.user.UserFactory; import org.gusdb.wdk.model.user.analysis.StepAnalysisFactory; import org.gusdb.wdk.model.user.analysis.StepAnalysisFactoryImpl; @@ -203,7 +201,6 @@ public static WdkModel construct(String projectId, String gusHome) throws WdkMod private ColumnToolBundleMap columnToolBundleMap = new ColumnToolBundleMap(); private String defaultColumnToolBundleRef; - private ReentrantLock systemUserLock = new ReentrantLock(); private User systemUser; private String buildNumber; @@ -551,14 +548,12 @@ public void configure(ModelConfig modelConfig) throws WdkModelException { ModelConfigAppDB appDbConfig = modelConfig.getAppDB(); ModelConfigUserDB userDbConfig = modelConfig.getUserDB(); - ModelConfigAccountDB accountDbConfig = modelConfig.getAccountDB(); ModelConfigUserDatasetStore udsConfig = modelConfig.getUserDatasetStoreConfig(); QueryLogger.initialize(modelConfig.getQueryMonitor()); appDb = new DatabaseInstance(appDbConfig, DB_INSTANCE_APP, true); userDb = new DatabaseInstance(userDbConfig, DB_INSTANCE_USER, true); - accountDb = new DatabaseInstance(accountDbConfig, DB_INSTANCE_ACCOUNT, true); // set true to avoid a broken dev irods at build time if ( udsConfig == null ) { @@ -599,6 +594,8 @@ public void configure(ModelConfig modelConfig) throws WdkModelException { new UnconfiguredStepAnalysisFactory(this) : new StepAnalysisFactoryImpl(this)); + systemUser = userFactory.createUnregisteredUser().getSecond(); + LOG.info("WDK Model configured."); } @@ -1360,17 +1357,6 @@ public String queryParamDisplayName(String paramName) { } public User getSystemUser() { - if (systemUser == null) { - try { - systemUserLock.lock(); - if (systemUser == null) { - systemUser = userFactory.createUnregistedUser(); - } - } - finally { - systemUserLock.unlock(); - } - } return systemUser; } diff --git a/Model/src/main/java/org/gusdb/wdk/model/WdkSqlScriptRunner.java b/Model/src/main/java/org/gusdb/wdk/model/WdkSqlScriptRunner.java index fc37486c44..8ee52be404 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/WdkSqlScriptRunner.java +++ b/Model/src/main/java/org/gusdb/wdk/model/WdkSqlScriptRunner.java @@ -22,11 +22,11 @@ */ public class WdkSqlScriptRunner { - private static enum DbType { APP, USER, ACCT } + private static enum DbType { APP, USER } public static void main(String[] args) { if (args.length != 3 && args.length != 5) { - System.err.println("USAGE: fgpJava " + WdkSqlScriptRunner.class.getName() + " [APP|USER|ACCT] [ ]"); + System.err.println("USAGE: fgpJava " + WdkSqlScriptRunner.class.getName() + " [APP|USER] [ ]"); System.exit(1); } BufferedReader sqlReader = null; @@ -46,7 +46,6 @@ public static void main(String[] args) { ModelConfigDB dbConfig = ( whichDb.equals(DbType.APP) ? modelConf.getAppDB() : whichDb.equals(DbType.USER) ? modelConf.getUserDB() : - whichDb.equals(DbType.ACCT) ? modelConf.getAccountDB() : null ); // should never happen; value already validated db = new DatabaseInstance(dbConfig); diff --git a/Model/src/main/java/org/gusdb/wdk/model/answer/AnswerValue.java b/Model/src/main/java/org/gusdb/wdk/model/answer/AnswerValue.java index 3024bda4f6..7974eb99f4 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/answer/AnswerValue.java +++ b/Model/src/main/java/org/gusdb/wdk/model/answer/AnswerValue.java @@ -53,9 +53,9 @@ import org.gusdb.wdk.model.record.Field; import org.gusdb.wdk.model.record.PrimaryKeyDefinition; import org.gusdb.wdk.model.record.PrimaryKeyIterator; -import org.gusdb.wdk.model.record.ResultSetPrimaryKeyIterator; import org.gusdb.wdk.model.record.RecordClass; import org.gusdb.wdk.model.record.RecordInstance; +import org.gusdb.wdk.model.record.ResultSetPrimaryKeyIterator; import org.gusdb.wdk.model.record.TableField; import org.gusdb.wdk.model.record.attribute.AttributeField; import org.gusdb.wdk.model.record.attribute.ColumnAttributeField; diff --git a/Model/src/main/java/org/gusdb/wdk/model/answer/TransformUtil.java b/Model/src/main/java/org/gusdb/wdk/model/answer/TransformUtil.java index 88e4ad740c..bbd855c512 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/answer/TransformUtil.java +++ b/Model/src/main/java/org/gusdb/wdk/model/answer/TransformUtil.java @@ -12,10 +12,10 @@ import org.gusdb.wdk.model.query.spec.QueryInstanceSpec; import org.gusdb.wdk.model.question.Question; import org.gusdb.wdk.model.user.Step; +import org.gusdb.wdk.model.user.StepContainer.ListStepContainer; import org.gusdb.wdk.model.user.Strategy; import org.gusdb.wdk.model.user.User; import org.gusdb.wdk.model.user.UserCache; -import org.gusdb.wdk.model.user.StepContainer.ListStepContainer; /** * Provides a utility to use transform questions to convert an answer value of diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java index 6409c37e1a..6bb84b1236 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java @@ -1,15 +1,10 @@ package org.gusdb.wdk.model.config; -import java.io.FileReader; -import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Optional; -import org.apache.log4j.Logger; -import org.gusdb.fgputil.EncryptionUtil; import org.gusdb.fgputil.FormatUtil; -import org.gusdb.fgputil.IoUtil; import org.gusdb.fgputil.Named.NamedObject; import org.gusdb.oauth2.client.KeyStoreTrustManager.KeyStoreConfig; import org.gusdb.oauth2.client.OAuthConfig; @@ -22,8 +17,6 @@ */ public class ModelConfig implements OAuthConfig, KeyStoreConfig { - private static final Logger LOG = Logger.getLogger(ModelConfig.class); - public static final String WSF_LOCAL = "local"; public enum AuthenticationMethod implements NamedObject { @@ -71,7 +64,6 @@ public String getName() { private final ModelConfigUserDB _userDB; private final ModelConfigAppDB _appDB; - private final ModelConfigAccountDB _accountDB; private final ModelConfigUserDatasetStore _userDatasetStoreConfig; @@ -83,17 +75,6 @@ public String getName() { private final String _projectId; private final Path _gusHome; - /** - * location of secret key file - */ - private final Optional _secretKeyFile; - - /** - * cached secret key; value is assigned at construction or as soon as the - * secretKeyFile is present and readable when the secret key is requested - */ - private String _secretKey; - /** * enable/disable weight feature in the steps. default enabled. */ @@ -148,7 +129,7 @@ public String getName() { public ModelConfig(String modelName, String projectId, Path gusHome, boolean caching, boolean useWeights, String paramRegex, Optional secretKeyFile, Path wdkTempDir, String webServiceUrl, String assetsUrl, String smtpServer, String supportEmail, List adminEmails, String emailSubject, - String emailContent, ModelConfigUserDB userDB, ModelConfigAppDB appDB, ModelConfigAccountDB accountDB, + String emailContent, ModelConfigUserDB userDB, ModelConfigAppDB appDB, ModelConfigUserDatasetStore userDatasetStoreConfig, QueryMonitor queryMonitor, boolean monitorBlockedThreads, int blockedThreshold, AuthenticationMethod authenticationMethod, String oauthUrl, String oauthClientId, String oauthClientSecret, String changePasswordUrl, @@ -165,7 +146,6 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac _paramRegex = paramRegex; // file locations - _secretKeyFile = secretKeyFile; _wdkTempDir = wdkTempDir; // network locations @@ -182,7 +162,6 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac // databases _userDB = userDB; _appDB = appDB; - _accountDB = accountDB; // user dataset config _userDatasetStoreConfig = userDatasetStoreConfig; @@ -204,9 +183,6 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac // SSL key store information _keyStoreFile = keyStoreFile; _keyStorePassPhrase = keyStorePassPhrase; - - // get secret key at object creation time if available - getSecretKey(); } /** @@ -295,33 +271,6 @@ public ModelConfigAppDB getAppDB() { return _appDB; } - /** - * @return the accountDB - */ - public ModelConfigAccountDB getAccountDB() { - return _accountDB; - } - - /** - * Returns a cached secret key, generated by encrypting the value in the - * configured secret key file. If the configured filename is null or the contents - * of the file cannot be read for any reason, null is returned. - * - * @return secret key - */ - public String getSecretKey() { - if (_secretKey == null && _secretKeyFile.isPresent()) { - try (FileReader in = new FileReader(_secretKeyFile.get().toFile())) { - _secretKey = EncryptionUtil.md5(IoUtil.readAllChars(in).strip()); - } - catch (IOException e) { - // log error but otherwise ignore so null is returned; problem may be remedied in the future - LOG.warn("Unable to read secret key value from file: " + _secretKeyFile, e); - } - } - return _secretKey; - } - /** * @return configured authentication method */ diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigAccountDB.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigAccountDB.java deleted file mode 100644 index 1b1b621b2f..0000000000 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigAccountDB.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.gusdb.wdk.model.config; - -import org.gusdb.fgputil.db.platform.DBPlatform; - -public class ModelConfigAccountDB extends ModelConfigDB { - - private String _accountSchema; - - public void setAccountSchema(String accountSchema) { - _accountSchema = DBPlatform.normalizeSchema(accountSchema); - } - - public String getAccountSchema() { - return _accountSchema; - } -} diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java index a94f09e3ba..ae414d5906 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java @@ -45,7 +45,6 @@ public class ModelConfigBuilder { // databases private ModelConfigUserDB _userDB; private ModelConfigAppDB _appDB; - private ModelConfigAccountDB _accountDB; // user dataset config private ModelConfigUserDatasetStore _userDatasetStoreConfig; @@ -91,7 +90,6 @@ public ModelConfig build() throws WdkModelException { assertNonNull("supportEmail", _supportEmail); assertNonNull("userDb", _userDB); assertNonNull("appDb", _appDB); - assertNonNull("accountDb", _accountDB); // TODO: should probably have a default stub for this to avoid NPEs //assertNonNull("userDatasetStoreConfig", _userDatasetStoreConfig); @@ -125,7 +123,6 @@ public ModelConfig build() throws WdkModelException { // databases _userDB, _appDB, - _accountDB, // user dataset config _userDatasetStoreConfig, @@ -248,14 +245,6 @@ public void setAppDB(ModelConfigAppDB appDB) { _appDB = appDB; } - /** - * @param accountDB - * the accountDB to set - */ - public void setAccountDB(ModelConfigAccountDB accountDB) { - _accountDB = accountDB; - } - /** * @param secretKeyFile * the secretKeyFile to set diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigParser.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigParser.java index ee874200ec..9a363d7f6e 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigParser.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigParser.java @@ -62,9 +62,6 @@ private static Digester configureDigester() { // load user db configureNode(digester, "modelConfig/userDb", ModelConfigUserDB.class, "setUserDB"); - // load user db - configureNode(digester, "modelConfig/accountDb", ModelConfigAccountDB.class, "setAccountDB"); - // userdatasetstore configureNode(digester, "modelConfig/userDatasetStore", ModelConfigUserDatasetStore.class, "setUserDatasetStore"); configureNode(digester, "modelConfig/userDatasetStore/property", WdkModelText.class, "addProperty"); diff --git a/Model/src/main/java/org/gusdb/wdk/model/query/param/AbstractEnumParam.java b/Model/src/main/java/org/gusdb/wdk/model/query/param/AbstractEnumParam.java index 0b26907dc3..dd65553168 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/query/param/AbstractEnumParam.java +++ b/Model/src/main/java/org/gusdb/wdk/model/query/param/AbstractEnumParam.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; - import java.util.LinkedHashMap; import java.util.List; import java.util.Map; diff --git a/Model/src/main/java/org/gusdb/wdk/model/query/param/FilterParamNewHandler.java b/Model/src/main/java/org/gusdb/wdk/model/query/param/FilterParamNewHandler.java index c76242921f..37147634f0 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/query/param/FilterParamNewHandler.java +++ b/Model/src/main/java/org/gusdb/wdk/model/query/param/FilterParamNewHandler.java @@ -1,19 +1,23 @@ package org.gusdb.wdk.model.query.param; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.gusdb.fgputil.EncryptionUtil; import org.gusdb.fgputil.MapBuilder; import org.gusdb.fgputil.validation.ValidObjectFactory.RunnableObj; import org.gusdb.wdk.model.WdkModel; import org.gusdb.wdk.model.WdkModelException; -import org.gusdb.wdk.model.query.*; +import org.gusdb.wdk.model.query.Column; +import org.gusdb.wdk.model.query.Query; +import org.gusdb.wdk.model.query.QueryInstance; +import org.gusdb.wdk.model.query.QuerySet; +import org.gusdb.wdk.model.query.SqlQuery; import org.gusdb.wdk.model.query.spec.QueryInstanceSpec; import org.gusdb.wdk.model.user.User; import org.json.JSONException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - /** * @author jerric */ diff --git a/Model/src/main/java/org/gusdb/wdk/model/test/ParamValuesFactory.java b/Model/src/main/java/org/gusdb/wdk/model/test/ParamValuesFactory.java index 06f0e87326..61658146af 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/test/ParamValuesFactory.java +++ b/Model/src/main/java/org/gusdb/wdk/model/test/ParamValuesFactory.java @@ -15,9 +15,9 @@ import org.gusdb.wdk.model.WdkModelException; import org.gusdb.wdk.model.query.Query; import org.gusdb.wdk.model.query.param.AbstractDependentParam; +import org.gusdb.wdk.model.query.param.AbstractEnumParam.SelectMode; import org.gusdb.wdk.model.query.param.Param; import org.gusdb.wdk.model.query.param.ParamValuesSet; -import org.gusdb.wdk.model.query.param.AbstractEnumParam.SelectMode; import org.gusdb.wdk.model.user.User; public class ParamValuesFactory { diff --git a/Model/src/main/java/org/gusdb/wdk/model/test/QueryTester.java b/Model/src/main/java/org/gusdb/wdk/model/test/QueryTester.java index 1d1210bd83..f03ae38d83 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/test/QueryTester.java +++ b/Model/src/main/java/org/gusdb/wdk/model/test/QueryTester.java @@ -4,9 +4,9 @@ import java.util.List; import java.util.Map; -import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionGroup; diff --git a/Model/src/main/java/org/gusdb/wdk/model/test/RecordTester.java b/Model/src/main/java/org/gusdb/wdk/model/test/RecordTester.java index ae5f34c53d..daf799317a 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/test/RecordTester.java +++ b/Model/src/main/java/org/gusdb/wdk/model/test/RecordTester.java @@ -3,9 +3,9 @@ import java.util.LinkedHashMap; import java.util.Map; -import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; diff --git a/Model/src/main/java/org/gusdb/wdk/model/test/SummaryTester.java b/Model/src/main/java/org/gusdb/wdk/model/test/SummaryTester.java index 132341d8e1..9eb1024d1c 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/test/SummaryTester.java +++ b/Model/src/main/java/org/gusdb/wdk/model/test/SummaryTester.java @@ -10,9 +10,9 @@ import java.util.Optional; import java.util.Properties; -import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; diff --git a/Model/src/main/java/org/gusdb/wdk/model/test/sanity/tests/QuestionTest.java b/Model/src/main/java/org/gusdb/wdk/model/test/sanity/tests/QuestionTest.java index 2a1b1d85c3..4c4153f124 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/test/sanity/tests/QuestionTest.java +++ b/Model/src/main/java/org/gusdb/wdk/model/test/sanity/tests/QuestionTest.java @@ -10,9 +10,9 @@ import org.gusdb.wdk.model.question.Question; import org.gusdb.wdk.model.record.RecordInstance; import org.gusdb.wdk.model.record.attribute.AttributeField; +import org.gusdb.wdk.model.test.sanity.RangeCountTestUtil; import org.gusdb.wdk.model.test.sanity.SanityTester.ElementTest; import org.gusdb.wdk.model.test.sanity.SanityTester.Statistics; -import org.gusdb.wdk.model.test.sanity.RangeCountTestUtil; import org.gusdb.wdk.model.test.sanity.TestResult; import org.gusdb.wdk.model.user.StepContainer; import org.gusdb.wdk.model.user.User; diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/BasicUser.java b/Model/src/main/java/org/gusdb/wdk/model/user/BasicUser.java new file mode 100644 index 0000000000..a7b877d7ba --- /dev/null +++ b/Model/src/main/java/org/gusdb/wdk/model/user/BasicUser.java @@ -0,0 +1,31 @@ +package org.gusdb.wdk.model.user; + +import org.gusdb.wdk.model.WdkModel; +import org.json.JSONObject; + +/** + * Represents a VEupathDB user + * + * @author rdoherty + */ +public class BasicUser extends org.gusdb.oauth2.client.veupathdb.BasicUser implements User { + + private final WdkModel _wdkModel; + + public BasicUser(WdkModel wdkModel, long userId, boolean isGuest, String signature, String stableId) { + super(userId, isGuest, signature, stableId); + _wdkModel = wdkModel; + } + + public BasicUser(WdkModel wdkModel, JSONObject json) { + super(json); + _wdkModel = wdkModel; + } + + @Override + public WdkModel getWdkModel() { + return _wdkModel; + } + + +} diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/BearerTokenUser.java b/Model/src/main/java/org/gusdb/wdk/model/user/BearerTokenUser.java index fb05a0ec48..040c3dc941 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/user/BearerTokenUser.java +++ b/Model/src/main/java/org/gusdb/wdk/model/user/BearerTokenUser.java @@ -1,51 +1,20 @@ package org.gusdb.wdk.model.user; -import org.apache.log4j.Logger; import org.gusdb.oauth2.client.ValidatedToken; -import org.gusdb.oauth2.shared.token.IdTokenFields; import org.gusdb.wdk.model.WdkModel; import org.gusdb.wdk.session.WdkOAuthClientWrapper; -import org.json.JSONObject; -public class BearerTokenUser extends User { +public class BearerTokenUser extends org.gusdb.oauth2.client.veupathdb.BearerTokenUser implements User { - private static final Logger LOG = Logger.getLogger(BearerTokenUser.class); - - private final WdkOAuthClientWrapper _client; - private final ValidatedToken _token; - private boolean _userInfoFetched = false; + private final WdkModel _wdkModel; public BearerTokenUser(WdkModel wdkModel, WdkOAuthClientWrapper client, ValidatedToken token) { - // parent constructor sets immutable fields provided on the token - super(wdkModel, - Long.valueOf(token.getUserId()), - token.isGuest(), - token.getTokenContents().get(IdTokenFields.signature.name(), String.class), - token.getTokenContents().get(IdTokenFields.preferred_username.name(), String.class)); - _client = client; - _token = token; + super(client.getOAuthClient(), client.getOAuthConfig().getOauthUrl(), token); + _wdkModel = wdkModel; } @Override - protected void fetchUserInfo() { - // return if already fetched - if (_userInfoFetched) return; - - LOG.info("User data fetch requested for user " + getUserId() + "; querying OAuth server."); - // fetch user info from OAuth server where it is stored (but only on demand, and only once for this object's lifetime) - JSONObject userInfo = _client.getUserData(_token); - - // set email (standard property but mutable so set on user profile and not token - setEmail(userInfo.getString(IdTokenFields.email.name())); - - // set other user properties found only on user profile object - for (WdkUserProperty userProp : User.USER_PROPERTIES.values()) { - userProp.setValue(this, userInfo.optString(userProp.getName(), null)); - } - - LOG.info("User data successfully fetched for " + getDisplayName() + " / " + getOrganization()); - _userInfoFetched = true; + public WdkModel getWdkModel() { + return _wdkModel; } - } - diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/User.java b/Model/src/main/java/org/gusdb/wdk/model/user/User.java index af44903e2c..266107cfdd 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/user/User.java +++ b/Model/src/main/java/org/gusdb/wdk/model/user/User.java @@ -1,185 +1,16 @@ -package org.gusdb.wdk.model.user; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.gusdb.fgputil.accountdb.UserPropertyName; -import org.gusdb.fgputil.functional.Functions; -import org.gusdb.wdk.model.WdkModel; - -/** - * Represents a WDK user. - * - * @author rdoherty - */ -public class User { - - public static final Map USER_PROPERTIES = createUserPropertyDefs(); - - private static Map createUserPropertyDefs() { - List userProps = List.of( - new WdkUserProperty("username", "Username", "username", false, false, false, User::getUsername, User::setUsername), - new WdkUserProperty("firstName", "First Name", "first_name", true, true, false, User::getFirstName, User::setFirstName), - new WdkUserProperty("middleName", "Middle Name", "middle_name", false, true, false, User::getMiddleName, User::setMiddleName), - new WdkUserProperty("lastName", "Last Name", "last_name", true, true, false, User::getLastName, User::setLastName), - new WdkUserProperty("organization", "Organization", "organization", true, true, false, User::getOrganization, User::setOrganization), - new WdkUserProperty("interests", "Interests", "interests", false, false, true, User::getInterests, User::setInterests) - ); - return Collections.unmodifiableMap(Functions.getMapFromValues(userProps, UserPropertyName::getName)); - } - - private final WdkModel _wdkModel; - - // immutable fields supplied by bearer token - private final long _userId; - private final boolean _isGuest; - private final String _signature; - private final String _stableId; - - // mutable fields that may need to be fetched - private String _email; // standard; not a user property - private String _username; - private String _firstName; - private String _middleName; - private String _lastName; - private String _organization; - private String _interests; - - public User(WdkModel wdkModel, long userId, boolean isGuest, String signature, String stableId) { - _wdkModel = wdkModel; - _userId = userId; - _isGuest = isGuest; - _signature = signature; - _stableId = stableId; - } - - public WdkModel getWdkModel() { - return _wdkModel; - } - - public long getUserId() { - return _userId; - } - - public boolean isGuest() { - return _isGuest; - } - - public String getSignature() { - return _signature; - } - - public String getStableId() { - return _stableId; - } - - protected void fetchUserInfo() { - // nothing to do in this base class; all info must be explicitly set - } - - public String getEmail() { - fetchUserInfo(); - return _email; - } - - public User setEmail(String email) { - _email = email; - return this; - } - - public String getUsername() { - fetchUserInfo(); - return _username; - } - - public User setUsername(String username) { - _username = username; - return this; - } - - public String getFirstName() { - fetchUserInfo(); - return _firstName; - } - - public User setFirstName(String firstName) { - _firstName = firstName; - return this; - } - - public String getMiddleName() { - fetchUserInfo(); - return _middleName; - } - - public User setMiddleName(String middleName) { - _middleName = middleName; - return this; - } - - public String getLastName() { - fetchUserInfo(); - return _lastName; - } - - public User setLastName(String lastName) { - _lastName = lastName; - return this; - } - - public String getOrganization() { - fetchUserInfo(); - return _organization; - } - - public User setOrganization(String organization) { - _organization = organization; - return this; - } - - public String getInterests() { - fetchUserInfo(); - return _interests; - } - - public User setInterests(String interests) { - _interests = interests; - return this; - } - - /** - * Provides a "pretty" display name for this user - * - * @return display name for this user - */ - public String getDisplayName() { - return isGuest() ? "WDK Guest" : ( - formatNamePart(getFirstName()) + - formatNamePart(getMiddleName()) + - formatNamePart(getLastName())).trim(); - } - - private static String formatNamePart(String namePart) { - return (namePart == null || namePart.isEmpty() ? "" : " " + namePart.trim()); - } - - @Override - public String toString() { - return "User #" + getUserId() + " - " + getEmail(); - } - - @Override - public int hashCode() { - return String.valueOf(getUserId()).hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof User)) { - return false; - } - return getUserId() == ((User)obj).getUserId(); - } - -} +package org.gusdb.wdk.model.user; + +import java.util.Collection; + +import org.gusdb.oauth2.client.veupathdb.UserProperty; +import org.gusdb.wdk.model.WdkModel; + +public interface User extends org.gusdb.oauth2.client.veupathdb.User { + + static Collection getPropertyDefs() { + return BasicUser.USER_PROPERTIES.values(); + } + + WdkModel getWdkModel(); + +} diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/UserFactory.java b/Model/src/main/java/org/gusdb/wdk/model/user/UserFactory.java index 5e1ce04f26..c815767749 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/user/UserFactory.java +++ b/Model/src/main/java/org/gusdb/wdk/model/user/UserFactory.java @@ -10,13 +10,18 @@ import org.apache.log4j.Logger; import org.gusdb.fgputil.MapBuilder; +import org.gusdb.fgputil.Tuples.ThreeTuple; +import org.gusdb.fgputil.Tuples.TwoTuple; import org.gusdb.fgputil.accountdb.AccountManager; import org.gusdb.fgputil.accountdb.UserProfile; import org.gusdb.fgputil.db.pool.DatabaseInstance; import org.gusdb.fgputil.db.runner.SQLRunner; +import org.gusdb.fgputil.db.runner.SQLRunnerException; import org.gusdb.fgputil.db.runner.SingleLongResultSetHandler; import org.gusdb.fgputil.db.runner.SingleLongResultSetHandler.Status; import org.gusdb.fgputil.events.Events; +import org.gusdb.oauth2.client.ValidatedToken; +import org.gusdb.oauth2.shared.IdTokenFields; import org.gusdb.wdk.events.UserProfileUpdateEvent; import org.gusdb.wdk.model.Utilities; import org.gusdb.wdk.model.WdkModel; @@ -24,7 +29,10 @@ import org.gusdb.wdk.model.WdkRuntimeException; import org.gusdb.wdk.model.WdkUserException; import org.gusdb.wdk.model.config.ModelConfig; -import org.gusdb.wdk.model.config.ModelConfigAccountDB; +import org.gusdb.wdk.session.WdkOAuthClientWrapper; +import org.json.JSONObject; + +import io.prometheus.client.Counter; /** * Manages persistence of user profile and preferences and creation and @@ -38,6 +46,11 @@ public class UserFactory { @SuppressWarnings("unused") private static Logger LOG = Logger.getLogger(UserFactory.class); + private static final Counter GUEST_CREATION_COUNTER = Counter.build() + .name("wdk_guest_creation_count") + .help("Number of guest users created by WDK services") + .register(); + // ------------------------------------------------------------------------- // database table and column definitions // ------------------------------------------------------------------------- @@ -54,23 +67,32 @@ public class UserFactory { static final String USER_SCHEMA_MACRO = "$$USER_SCHEMA$$"; private static final String IS_GUEST_VALUE_MACRO = "$$IS_GUEST$$"; - private static final String COUNT_USER_REF_BY_ID_SQL = - "select count(*)" + + // SQL and types to insert previously unknown user refs into the users table + private static final String INSERT_USER_REF_SQL = + "insert" + + " when not exists (select 1 from " + USER_SCHEMA_MACRO + TABLE_USERS + " where " + COL_USER_ID + " = ?)" + + " then" + + " into " + USER_SCHEMA_MACRO + TABLE_USERS + " (" + COL_USER_ID + "," + COL_IS_GUEST + "," + COL_FIRST_ACCESS +")" + + " select ?, " + IS_GUEST_VALUE_MACRO + ", ? from dual"; + + private static final Integer[] INSERT_USER_REF_PARAM_TYPES = { Types.BIGINT, Types.BIGINT, Types.TIMESTAMP }; + + // SQL and types to select user ref by ID + private static final String SELECT_USER_REF_BY_ID_SQL = + "select " + COL_USER_ID + ", " + COL_IS_GUEST + ", " + COL_FIRST_ACCESS + " from " + USER_SCHEMA_MACRO + TABLE_USERS + " where " + COL_USER_ID + " = ?"; - private static final Integer[] COUNT_USER_REF_BY_ID_PARAM_TYPES = { Types.BIGINT }; - private static final String INSERT_USER_REF_SQL = - "insert into " + USER_SCHEMA_MACRO + TABLE_USERS + - " (" + COL_USER_ID + "," + COL_IS_GUEST + "," + COL_FIRST_ACCESS +")" + - " values (?, " + IS_GUEST_VALUE_MACRO + ", ?)"; - private static final Integer[] INSERT_USER_REF_PARAM_TYPES = { Types.BIGINT, Types.TIMESTAMP }; + private static final Integer[] SELECT_USER_REF_BY_ID_PARAM_TYPES = { Types.BIGINT }; - private static final String SELECT_GUEST_USER_REF_BY_ID_SQL = - "select " + COL_FIRST_ACCESS + - " from " + USER_SCHEMA_MACRO + TABLE_USERS + - " where " + COL_IS_GUEST + " = " + IS_GUEST_VALUE_MACRO + " and " + COL_USER_ID + " = ?"; - private static final Integer[] SELECT_GUEST_USER_REF_BY_ID_PARAM_TYPES = { Types.BIGINT }; + private static class UserReference extends ThreeTuple { + public UserReference(Long userId, Boolean isGuest, Date firstAccess) { + super(userId, isGuest, firstAccess); + } + public Long getUserId() { return getFirst(); } + public Boolean isGuest() { return getSecond(); } + public Date getFirstAccess() { return getThird(); } + } // ------------------------------------------------------------------------- // the macros used by the registration email @@ -87,6 +109,7 @@ public class UserFactory { private final WdkModel _wdkModel; private final DatabaseInstance _userDb; private final String _userSchema; + private final WdkOAuthClientWrapper _client; // ------------------------------------------------------------------------- // constructor @@ -96,115 +119,51 @@ public UserFactory(WdkModel wdkModel) { // save model for populating new users _wdkModel = wdkModel; _userDb = wdkModel.getUserDb(); - ModelConfig modelConfig = wdkModel.getModelConfig(); - _userSchema = modelConfig.getUserDB().getUserSchema(); - ModelConfigAccountDB accountDbConfig = modelConfig.getAccountDB(); + _userSchema = wdkModel.getModelConfig().getUserDB().getUserSchema(); + _client = new WdkOAuthClientWrapper(wdkModel); } // ------------------------------------------------------------------------- // methods // ------------------------------------------------------------------------- - public User createUser(String email, - Map profileProperties) - throws WdkModelException, InvalidUsernameOrEmailException { - String dontEmailProp = _wdkModel.getProperties().get("DONT_EMAIL_NEW_USER"); - boolean sendWelcomeEmail = (dontEmailProp == null || !dontEmailProp.equals("true")); - return createUser(email, profileProperties, true, sendWelcomeEmail); - } - - public User createUser(String email, - Map profileProperties, - boolean addUserDbReference, boolean sendWelcomeEmail) - throws WdkModelException, InvalidUsernameOrEmailException { - try { - // check email for uniqueness and format - email = validateAndFormatEmail(email, _accountManager); - - // if user supplied a username, make sure it is unique - if (profileProperties.containsKey(AccountManager.USERNAME_PROPERTY_KEY)) { - String username = profileProperties.get(AccountManager.USERNAME_PROPERTY_KEY); - // check whether the username exists in the database already; if so, the operation fails - if (_accountManager.getUserProfileByUsername(username) != null) { - throw new InvalidUsernameOrEmailException("The username '" + username + "' is already in use. " + "Please choose another one."); - } - } - - // generate temporary password for user - String password = generateTemporaryPassword(); + public User createUser(String email, Map profileProperties) + throws WdkModelException, WdkUserException { - // add user to account DB - UserProfile profile = _accountManager.createAccount(email, password, profileProperties); + // contact OAuth server to create a new user with the passed props + TwoTuple userTuple = parseExpandedUserJson(_client.createUser(email, profileProperties)); + User user = userTuple.getFirst(); - // add user to this user DB (will be added to other user DBs as needed during login) - if (addUserDbReference) { - addUserReference(profile.getUserId(), false); - } - - // create new user object and add profile properties - User user = getUserFromProfile(profile); + // add user to this user DB (will be added to other user DBs as needed during login) + addUserReference(user); - // if needed, send user temporary password via email - if (sendWelcomeEmail) { - emailTemporaryPassword(user, password, _wdkModel.getModelConfig()); - } - - return user; - } - catch (WdkModelException | InvalidUsernameOrEmailException e) { - // do not wrap known exceptions - throw e; + // if needed, send user temporary password via email + if (isSendWelcomeEmail()) { + emailTemporaryPassword(user, userTuple.getSecond(), _wdkModel.getModelConfig()); } - catch (Exception e) { - // wrap unknown exceptions with WdkModelException - throw new WdkModelException("Could not completely create new user", e); - } - } - private User getUserFromProfile(UserProfile profile) { - if (profile == null) return null; - Map properties = profile.getProperties(); - return new User(_wdkModel, profile.getUserId(), - false, profile.getSignature(), profile.getStableId()) - .setEmail(profile.getEmail()) - .setFirstName(properties.get("firstName")) - .setMiddleName(properties.get("middleName")) - .setLastName(properties.get("lastName")) - .setOrganization(properties.get("organization")); - } + return user; - private void addUserReference(Long userId, boolean isGuest) { - Timestamp insertedOn = new Timestamp(new Date().getTime()); - String sql = INSERT_USER_REF_SQL - .replace(USER_SCHEMA_MACRO, _userSchema) - .replace(IS_GUEST_VALUE_MACRO, _userDb.getPlatform().convertBoolean(isGuest).toString()); - new SQLRunner(_userDb.getDataSource(), sql, "insert-user-ref") - .executeStatement(new Object[]{ userId, insertedOn }, INSERT_USER_REF_PARAM_TYPES); } - private boolean hasUserReference(long userId) { - String sql = COUNT_USER_REF_BY_ID_SQL.replace(USER_SCHEMA_MACRO, _userSchema); - SingleLongResultSetHandler handler = new SingleLongResultSetHandler(); - new SQLRunner(_userDb.getDataSource(), sql, "check-user-ref") - .executeQuery(new Object[]{ userId }, COUNT_USER_REF_BY_ID_PARAM_TYPES, handler); - if (handler.getStatus().equals(Status.NON_NULL_VALUE)) { - switch (handler.getRetrievedValue().intValue()) { - case 0: return false; - case 1: return true; - default: throw new IllegalStateException("More than one user reference in userDb for user " + userId); - } - } - throw new WdkRuntimeException("User reference count query did not return count for user id " + - userId + ". Status = " + handler.getStatus() + ", sql = " + sql); + private TwoTuple parseExpandedUserJson(JSONObject userJson) { + User user = new BasicUser(_wdkModel, + Long.valueOf(userJson.getString(IdTokenFields.sub.name())), + userJson.getBoolean(IdTokenFields.is_guest.name()), + userJson.getString(IdTokenFields.signature.name()), + userJson.getString(IdTokenFields.preferred_username.name()) + ); + user.setPropertyValues(userJson); + String password = userJson.getString(IdTokenFields.password.name()); + return new TwoTuple<>(user, password); } - private Date getGuestUserRefFirstAccess(long userId) { - String sql = SELECT_GUEST_USER_REF_BY_ID_SQL - .replace(USER_SCHEMA_MACRO, _userSchema) - .replace(IS_GUEST_VALUE_MACRO, _userDb.getPlatform().convertBoolean(true).toString()); - return new SQLRunner(_userDb.getDataSource(), sql, "get-guest-user-ref") - .executeQuery(new Object[]{ userId }, SELECT_GUEST_USER_REF_BY_ID_PARAM_TYPES, rs -> - !rs.next() ? null : new Date(rs.getTimestamp(COL_FIRST_ACCESS).getTime())); + /** + * @return whether or not WDK is configured to send a welcome email to new registered users (defaults to true) + */ + private boolean isSendWelcomeEmail() { + String dontEmailProp = _wdkModel.getProperties().get("DONT_EMAIL_NEW_USER"); + return dontEmailProp == null || !dontEmailProp.equals("true"); } private static void emailTemporaryPassword(User user, String password, @@ -226,73 +185,57 @@ private static void emailTemporaryPassword(User user, String password, Utilities.sendEmail(smtpServer, user.getEmail(), supportEmail, emailSubject, emailContent); } - // TODO: remove! This validation is now done on the OAuth server - private static String validateAndFormatEmail(String email, AccountManager accountMgr) throws InvalidUsernameOrEmailException { - // trim and validate passed email address and extract stable name - if (email == null) - throw new InvalidUsernameOrEmailException("The user's email cannot be empty."); - // format the info - email = AccountManager.trimAndLowercase(email); - if (email.isEmpty()) - throw new InvalidUsernameOrEmailException("The user's email cannot be empty."); - int atSignIndex = email.indexOf("@"); - if (atSignIndex < 1) // must be present and not the first char - throw new InvalidUsernameOrEmailException("The user's email address is invalid."); - // check whether the user exist in the database already; if email exists, the operation fails - if (accountMgr.getUserProfileByEmail(email) != null) - throw new InvalidUsernameOrEmailException("The email '" + email + "' has already been registered. " + "Please choose another."); - return email; - } - - private static String generateTemporaryPassword() { - // generate a random password of 8 characters long, the range will be - // [0-9A-Za-z] - StringBuilder buffer = new StringBuilder(); - Random rand = new Random(); - for (int i = 0; i < 8; i++) { - int value = rand.nextInt(36); - if (value < 10) { // number - buffer.append(value); - } else { // lower case letters - buffer.append((char) ('a' + value - 10)); - } - } - return buffer.toString(); - } - /** - * Create an unregistered user of the specified type and persist in the database - * - * @param userType unregistered user type to persist - * @return new unregistered user with remaining fields populated - * @throws WdkRuntimeException if unable to persist temporary user + * Adds a user reference row to the UserDB users table if one does not exist. + * Note is_guest and first_access are immutable fields and once set will not be + * changed by this code. + * + * @param user user to add + * @throws WdkModelException */ - public User createUnregistedUser() throws WdkRuntimeException { + public int addUserReference(User user) throws WdkModelException { try { - UserProfile profile = _accountManager.createGuestAccount("GUEST_"); - addUserReference(profile.getUserId(), true); - return new User(_wdkModel, profile.getUserId(), true, profile.getSignature(), profile.getStableId()).setEmail(profile.getEmail()); + long userId = user.getUserId(); + boolean isGuest = user.isGuest(); + Timestamp insertedOn = new Timestamp(new Date().getTime()); + String sql = INSERT_USER_REF_SQL + .replace(USER_SCHEMA_MACRO, _userSchema) + .replace(IS_GUEST_VALUE_MACRO, _userDb.getPlatform().convertBoolean(isGuest).toString()); + return new SQLRunner(_userDb.getDataSource(), sql, "insert-user-ref") + .executeUpdate(new Object[]{ userId, userId, insertedOn }, INSERT_USER_REF_PARAM_TYPES); } - catch (Exception e) { - throw new WdkRuntimeException("Unable to save temporary user", e); + catch (SQLRunnerException e) { + throw WdkModelException.translateFrom(e); } } - private User completeLogin(User user) { - if (user == null) - return user; - - // make sure user has reference in this user DB (needs to happen before merging) - if (!hasUserReference(user.getUserId())) { - addUserReference(user.getUserId(), false); + private Optional getUserReference(long userId) throws WdkModelException { + try { + String sql = SELECT_USER_REF_BY_ID_SQL.replace(USER_SCHEMA_MACRO, _userSchema); + return new SQLRunner(_userDb.getDataSource(), sql, "get-user-ref").executeQuery( + new Object[]{ userId }, + SELECT_USER_REF_BY_ID_PARAM_TYPES, + rs -> + !rs.next() + ? Optional.empty() + : Optional.of(new UserReference( + rs.getLong(COL_USER_ID), + rs.getBoolean(COL_IS_GUEST), + new Date(rs.getTimestamp(COL_FIRST_ACCESS).getTime())))); } + catch (SQLRunnerException e) { + throw WdkModelException.translateFrom(e); + } + } - // update user active timestamp - _accountManager.updateLastLogin(user.getUserId()); - - return user; + public TwoTuple createUnregisteredUser() { + ValidatedToken token = _client.getNewGuestToken(); + User user = new BearerTokenUser(_wdkModel, _client, token); + GUEST_CREATION_COUNTER.inc(); + return new TwoTuple<>(token, user); } + public User login(User guest, String email, String password) throws WdkUserException { // make sure the guest is really a guest @@ -434,15 +377,6 @@ public void resetPassword(String emailOrLoginName) throws WdkUserException, WdkM emailTemporaryPassword(user, newPassword, _wdkModel.getModelConfig()); } - public void changePassword(long userId, String newPassword) { - _accountManager.updatePassword(userId, newPassword); - } - // FIXME: should be atomic - public void insertUserToUserDb(User user) { - // make sure user has reference in this user DB (needs to happen before merging) - if (!hasUserReference(user.getUserId())) { - addUserReference(user.getUserId(), user.isGuest()); - } - } + } diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/WdkUserProperty.java b/Model/src/main/java/org/gusdb/wdk/model/user/WdkUserProperty.java deleted file mode 100644 index 276ed80c03..0000000000 --- a/Model/src/main/java/org/gusdb/wdk/model/user/WdkUserProperty.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.gusdb.wdk.model.user; - -import java.util.function.BiConsumer; -import java.util.function.Function; - -import org.gusdb.fgputil.accountdb.UserPropertyName; - -/** - * Convenience class to work around accountdb API and interface with WDK User class - */ -public class WdkUserProperty extends UserPropertyName { - - private final Function _getter; - private final BiConsumer _setter; - - public WdkUserProperty(String name, String displayName, String dbKey, boolean isRequired, boolean isPublic, boolean isMultiLine, Function getter, BiConsumer setter) { - UserPropertyName userProp = new UserPropertyName(name, dbKey, isRequired); - userProp.setDisplayName(displayName); - userProp.setPublic(isPublic); - userProp.setMultiLine(isMultiLine); - _getter = getter; - _setter = setter; - } - - public String getValue(User user) { - return _getter.apply(user); - } - - public void setValue(User user, String value) { - _setter.accept(user, value); - } -} diff --git a/Model/src/main/java/org/gusdb/wdk/session/WdkOAuthClientWrapper.java b/Model/src/main/java/org/gusdb/wdk/session/WdkOAuthClientWrapper.java index 52ea09d7bb..709b71f046 100644 --- a/Model/src/main/java/org/gusdb/wdk/session/WdkOAuthClientWrapper.java +++ b/Model/src/main/java/org/gusdb/wdk/session/WdkOAuthClientWrapper.java @@ -1,13 +1,18 @@ package org.gusdb.wdk.session; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; +import org.gusdb.oauth2.client.InvalidPropertiesException; import org.gusdb.oauth2.client.OAuthClient; import org.gusdb.oauth2.client.OAuthConfig; import org.gusdb.oauth2.client.ValidatedToken; +import org.gusdb.oauth2.shared.IdTokenFields; import org.gusdb.wdk.model.WdkModel; +import org.gusdb.wdk.model.WdkUserException; import org.json.JSONArray; import org.json.JSONObject; @@ -46,8 +51,27 @@ public List getUserData(List userIds) { } return users; } + public ValidatedToken getNewGuestToken() { return _client.getNewGuestToken(_config); } + public JSONObject createUser(String email, Map profileProperties) throws WdkUserException { + try { + Map allProps = new HashMap<>(profileProperties); + allProps.put(IdTokenFields.email.name(), email); + return _client.createNewUser(_config, allProps); + } + catch (InvalidPropertiesException e) { + throw new WdkUserException(e.getMessage()); + } + } + + public OAuthClient getOAuthClient() { + return _client; + } + + public OAuthConfig getOAuthConfig() { + return _config; + } } diff --git a/Service/src/main/java/org/gusdb/wdk/service/filter/CheckLoginFilter.java b/Service/src/main/java/org/gusdb/wdk/service/filter/CheckLoginFilter.java index 0358b6db1b..98ea9a7d9c 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/filter/CheckLoginFilter.java +++ b/Service/src/main/java/org/gusdb/wdk/service/filter/CheckLoginFilter.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; import org.glassfish.grizzly.http.server.Request; +import org.gusdb.fgputil.Tuples.TwoTuple; import org.gusdb.fgputil.web.ApplicationContext; import org.gusdb.fgputil.web.CookieBuilder; import org.gusdb.fgputil.web.RequestData; @@ -26,24 +27,19 @@ import org.gusdb.wdk.controller.ContextLookup; import org.gusdb.wdk.model.Utilities; import org.gusdb.wdk.model.WdkModel; +import org.gusdb.wdk.model.WdkRuntimeException; import org.gusdb.wdk.model.user.BearerTokenUser; import org.gusdb.wdk.model.user.User; +import org.gusdb.wdk.model.user.UserFactory; import org.gusdb.wdk.service.service.SessionService; import org.gusdb.wdk.service.service.SystemService; import org.gusdb.wdk.session.WdkOAuthClientWrapper; -import io.prometheus.client.Counter; - @Priority(30) public class CheckLoginFilter implements ContainerRequestFilter, ContainerResponseFilter { private static final Logger LOG = Logger.getLogger(CheckLoginFilter.class); - private static final Counter GUEST_CREATION_COUNTER = Counter.build() - .name("wdk_guest_creation_count") - .help("Number of guest users created by WDK services") - .register(); - private static final String TOKEN_COOKIE_VALUE_TO_SET = "tokenCookieValueToSet"; private static final String LEGACY_WDK_LOGIN_COOKIE_NAME = "wdk_check_auth"; @@ -83,26 +79,28 @@ public void filter(ContainerRequestContext requestContext) throws IOException { } else { // no credentials submitted; automatically create a guest to use on this request - token = oauth.getNewGuestToken(); - user = new BearerTokenUser(wdkModel, oauth, token); + UserFactory factory = wdkModel.getUserFactory(); + TwoTuple guestPair = factory.createUnregisteredUser(); + token = guestPair.getFirst(); + user = guestPair.getSecond(); LOG.info("Created new guest user [" + user.getUserId() + "] for request to path: /" + requestPath); - GUEST_CREATION_COUNTER.inc(); // set flag indicating that cookies should be added to response containing the new token requestContext.setProperty(TOKEN_COOKIE_VALUE_TO_SET, token.getTokenValue()); } // insert reference to this user into user DB for tracking and for foreign keys on other user DB tables - wdkModel.getUserFactory().insertUserToUserDb(user); + wdkModel.getUserFactory().addUserReference(user); - // set user on the request object for use by this request's processing + // set creds and user on the request object for use by this request's processing + request.setAttribute(Utilities.BEARER_TOKEN_KEY, token); request.setAttribute(Utilities.WDK_USER_KEY, user); } catch (Exception e) { // for now, log and let this go, deferring to legacy authentication LOG.error("Unable to authenticate with Authorization header " + rawToken, e); - throw e; + throw e instanceof RuntimeException ? (RuntimeException)e : new WdkRuntimeException(e); } } diff --git a/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java b/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java index ac12e63a1e..01bc586a59 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java +++ b/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java @@ -3,6 +3,7 @@ import java.util.Optional; import org.gusdb.fgputil.accountdb.UserPropertyName; +import org.gusdb.oauth2.client.veupathdb.UserProperty; import org.gusdb.wdk.core.api.JsonKeys; import org.gusdb.wdk.model.WdkModel; import org.gusdb.wdk.model.config.ModelConfig; @@ -50,7 +51,7 @@ public static JSONObject getWdkProjectInfo(WdkModel wdkModel, String serviceEndp // create profile property config sub-array JSONArray userProfileProps = new JSONArray(); - for (UserPropertyName prop : User.USER_PROPERTIES.values()) { + for (UserProperty prop : User.getPropertyDefs()) { userProfileProps.put(new JSONObject() .put(JsonKeys.NAME, prop.getName()) .put(JsonKeys.DISPLAY_NAME, prop.getDisplayName()) diff --git a/Service/src/main/java/org/gusdb/wdk/service/formatter/UserFormatter.java b/Service/src/main/java/org/gusdb/wdk/service/formatter/UserFormatter.java index 96f4e0a381..f4b89f0cf8 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/formatter/UserFormatter.java +++ b/Service/src/main/java/org/gusdb/wdk/service/formatter/UserFormatter.java @@ -2,10 +2,10 @@ import java.util.Optional; +import org.gusdb.oauth2.client.veupathdb.UserProperty; import org.gusdb.wdk.core.api.JsonKeys; import org.gusdb.wdk.model.user.User; import org.gusdb.wdk.model.user.UserPreferences; -import org.gusdb.wdk.model.user.WdkUserProperty; import org.json.JSONException; import org.json.JSONObject; @@ -44,7 +44,7 @@ public static JSONObject getUserJson(User user, boolean isOwner, private static JSONObject getPropertiesJson(User user, boolean isOwner) { JSONObject propsJson = new JSONObject(); - for (WdkUserProperty definedProperty : User.USER_PROPERTIES.values()) { + for (UserProperty definedProperty : User.getPropertyDefs()) { if (isOwner || definedProperty.isPublic()) { String key = definedProperty.getName(); String value = Optional.ofNullable(definedProperty.getValue(user)).orElse(""); diff --git a/Service/src/main/java/org/gusdb/wdk/service/request/user/UserCreationRequest.java b/Service/src/main/java/org/gusdb/wdk/service/request/user/UserCreationRequest.java index 96d5a6a96f..2d3e5f55f3 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/request/user/UserCreationRequest.java +++ b/Service/src/main/java/org/gusdb/wdk/service/request/user/UserCreationRequest.java @@ -1,8 +1,10 @@ package org.gusdb.wdk.service.request.user; +import java.util.Collection; import java.util.List; import org.gusdb.fgputil.accountdb.UserPropertyName; +import org.gusdb.oauth2.client.veupathdb.UserProperty; import org.gusdb.wdk.core.api.JsonKeys; import org.gusdb.wdk.service.request.exception.DataValidationException; import org.gusdb.wdk.service.request.exception.RequestMisformatException; @@ -15,7 +17,7 @@ public class UserCreationRequest { private final UserPreferencesRequest _globalPreferencesRequest; private final UserPreferencesRequest _projectPreferencesRequest; - public static UserCreationRequest createFromJson(JSONObject requestJson, List configuredProps) + public static UserCreationRequest createFromJson(JSONObject requestJson, Collection configuredProps) throws RequestMisformatException, DataValidationException { try { JSONObject userRequest = requestJson.getJSONObject(JsonKeys.USER); diff --git a/Service/src/main/java/org/gusdb/wdk/service/request/user/UserDatasetShareRequest.java b/Service/src/main/java/org/gusdb/wdk/service/request/user/UserDatasetShareRequest.java index e3a1968567..fafa4c742a 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/request/user/UserDatasetShareRequest.java +++ b/Service/src/main/java/org/gusdb/wdk/service/request/user/UserDatasetShareRequest.java @@ -15,7 +15,6 @@ import org.gusdb.fgputil.accountdb.AccountManager; import org.gusdb.wdk.model.WdkModel; import org.gusdb.wdk.model.config.ModelConfig; -import org.gusdb.wdk.model.config.ModelConfigAccountDB; import org.gusdb.wdk.service.request.exception.DataValidationException; import org.gusdb.wdk.service.request.exception.RequestMisformatException; import org.json.JSONArray; @@ -47,7 +46,6 @@ public class UserDatasetShareRequest { public UserDatasetShareRequest(WdkModel wdkModel) { ModelConfig modelConfig = wdkModel.getModelConfig(); - ModelConfigAccountDB accountDbConfig = modelConfig.getAccountDB(); _accountManager = new AccountManager(wdkModel.getAccountDb(), accountDbConfig.getAccountSchema(), accountDbConfig.getUserPropertyNames()); } diff --git a/Service/src/main/java/org/gusdb/wdk/service/request/user/UserProfileRequest.java b/Service/src/main/java/org/gusdb/wdk/service/request/user/UserProfileRequest.java index 9f810eee3d..42728cb8a5 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/request/user/UserProfileRequest.java +++ b/Service/src/main/java/org/gusdb/wdk/service/request/user/UserProfileRequest.java @@ -1,18 +1,18 @@ package org.gusdb.wdk.service.request.user; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import org.apache.log4j.Logger; import org.gusdb.fgputil.FormatUtil; import org.gusdb.fgputil.accountdb.UserProfile; -import org.gusdb.fgputil.accountdb.UserPropertyName; -import org.gusdb.fgputil.json.JsonUtil; import org.gusdb.fgputil.functional.Functions; +import org.gusdb.fgputil.json.JsonUtil; +import org.gusdb.oauth2.client.veupathdb.UserProperty; import org.gusdb.wdk.core.api.JsonKeys; import org.gusdb.wdk.service.request.exception.DataValidationException; import org.gusdb.wdk.service.request.exception.RequestMisformatException; @@ -70,7 +70,7 @@ public void setProfileMap(Map profileMap) { * @throws DataValidationException if data contained in request is invalid for another reason */ public static UserProfileRequest createFromJson(JSONObject json, - List configuredProps, boolean requireRequiredProperties) + Collection configuredProps, boolean requireRequiredProperties) throws RequestMisformatException, DataValidationException { try { UserProfileRequest request = new UserProfileRequest(); @@ -100,10 +100,8 @@ private static String validateEmail(JSONObject json, boolean isRequired) return email; } - private static Map getPropMap(List configuredProps) { - return Functions.getMapFromValues(configuredProps, new Function() { - @Override public String apply(UserPropertyName obj) { return obj.getName(); } - }); + private static Map getPropMap(Collection configuredProps) { + return Functions.getMapFromValues(configuredProps, UserProperty::getName); } /** @@ -117,7 +115,7 @@ private static Map getPropMap(List c * @throws DataValidationException if JSON format and types are ok, but further data validation fails */ private static Map parseProperties(JSONObject json, - Map configuredProps, boolean requireRequiredProperties) throws JSONException, DataValidationException { + Map configuredProps, boolean requireRequiredProperties) throws JSONException, DataValidationException { if (!json.has(JsonKeys.PROPERTIES)) { if (requireRequiredProperties) { throw new JSONException("'properties' property is required."); @@ -154,7 +152,7 @@ private static Map parseProperties(JSONObject json, } private static void validateRequiredPropsPresent(Map parsedProps, - Map configuredProps) throws DataValidationException { + Map configuredProps) throws DataValidationException { List missingProps = new ArrayList<>(); for (String propKey : configuredProps.keySet()) { if (!parsedProps.containsKey(propKey) && configuredProps.get(propKey).isRequired()) { @@ -167,7 +165,7 @@ private static void validateRequiredPropsPresent(Map parsedProps } private static void validateNonEmptyRequirement(Map parsedProps, - Map configuredProps) throws DataValidationException { + Map configuredProps) throws DataValidationException { // make sure any required (i.e. value must be non-empty) properties are not being modified to be empty List emptyRequiredValues = new ArrayList(); for (String propKey : configuredProps.keySet()) { diff --git a/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java b/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java index 4544ed0cfd..5cd709df20 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java +++ b/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java @@ -27,6 +27,7 @@ import org.gusdb.fgputil.web.SessionProxy; import org.gusdb.oauth2.client.ValidatedToken; import org.gusdb.wdk.core.api.JsonKeys; +import org.gusdb.wdk.events.NewUserEvent; import org.gusdb.wdk.model.Utilities; import org.gusdb.wdk.model.WdkModel; import org.gusdb.wdk.model.WdkModelException; @@ -113,8 +114,7 @@ public Response getOauthStateToken() throws WdkModelException { private static String generateStateToken(WdkModel wdkModel) throws WdkModelException { String saltedString = UUID.randomUUID() + ":::" + - String.valueOf(new Date().getTime()) + ":::" + - wdkModel.getModelConfig().getSecretKey(); + String.valueOf(new Date().getTime()); return EncryptionUtil.encrypt(saltedString); } @@ -165,7 +165,7 @@ public Response processOauthLogin( WdkOAuthClientWrapper client = new WdkOAuthClientWrapper(wdkModel); ValidatedToken bearerToken = client.getBearerTokenFromAuthCode(authCode, appUrl); User newUser = new BearerTokenUser(wdkModel, client, bearerToken); - wdkModel.getUserFactory().insertUserToUserDb(newUser); + wdkModel.getUserFactory().addUserReference(newUser); // transfer ownership from guest to logged-in user transferOwnership(oldUser, newUser, wdkModel); @@ -210,7 +210,7 @@ public Response processDbLogin(@HeaderParam(REFERRER_HEADER_KEY) String referrer WdkOAuthClientWrapper client = new WdkOAuthClientWrapper(wdkModel); ValidatedToken bearerToken = client.getBearerTokenFromCredentials(request.getEmail(), request.getPassword(), appUrl); User newUser = new BearerTokenUser(wdkModel, client, bearerToken); - wdkModel.getUserFactory().insertUserToUserDb(newUser); + wdkModel.getUserFactory().addUserReference(newUser); // transfer ownership from guest to logged-in user transferOwnership(oldUser, newUser, wdkModel); @@ -258,24 +258,19 @@ private Response getSuccessResponse(ValidatedToken bearerToken, User newUser, Us Events.triggerAndWait(new NewUserEvent(newUser, oldUser, session), new WdkRuntimeException("Unable to complete WDK user assignement.")); - // TODO: until client is updated, must still return WDK login cookie - LoginCookieFactory baker = new LoginCookieFactory(getWdkModel().getModelConfig().getSecretKey()); - CookieBuilder loginCookie = baker.createLoginCookie(newUser.getEmail()); - loginCookie.setMaxAge(EXPIRATION_3_YEARS_SECS); - // 3-year expiration (should change secret key before then) CookieBuilder bearerTokenCookie = new CookieBuilder( HttpHeaders.AUTHORIZATION, bearerToken.getTokenValue()); bearerTokenCookie.setMaxAge(EXPIRATION_3_YEARS_SECS); - redirectUrl = getSuccessRedirectUrl(redirectUrl, newUser, loginCookie, bearerTokenCookie); + redirectUrl = getSuccessRedirectUrl(redirectUrl, newUser, bearerTokenCookie); return (isRedirectResponse ? createRedirectResponse(redirectUrl) : createJsonResponse(true, null, redirectUrl) ) - .cookie(loginCookie.toJaxRsCookie(), bearerTokenCookie.toJaxRsCookie()) + .cookie(bearerTokenCookie.toJaxRsCookie()) .build(); } } @@ -288,7 +283,7 @@ private Response getSuccessResponse(ValidatedToken bearerToken, User newUser, Us * @param cookie login cookie to be sent to the browser * @return page user should be redirected to after successful login */ - protected String getSuccessRedirectUrl(String redirectUrl, User user, CookieBuilder cookie, CookieBuilder bearerTokenCookie) { + protected String getSuccessRedirectUrl(String redirectUrl, User user, CookieBuilder bearerTokenCookie) { return redirectUrl; } @@ -302,7 +297,7 @@ public Response processLogout() throws WdkModelException { // get a new session and add new guest user to it SessionProxy session = getSession(); - User newUser = getWdkModel().getUserFactory().createUnregistedUser(); + User newUser = getWdkModel().getUserFactory().createUnregisteredUser(); session.setAttribute(Utilities.WDK_USER_KEY, newUser); // throw new user event diff --git a/Service/src/main/java/org/gusdb/wdk/service/service/user/ProfileService.java b/Service/src/main/java/org/gusdb/wdk/service/service/user/ProfileService.java index 48fd2ef25d..f7c8c2a2ca 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/service/user/ProfileService.java +++ b/Service/src/main/java/org/gusdb/wdk/service/service/user/ProfileService.java @@ -1,15 +1,12 @@ package org.gusdb.wdk.service.service.user; -import java.util.List; import java.util.Map.Entry; import java.util.Optional; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; -import javax.ws.rs.ForbiddenException; import javax.ws.rs.GET; import javax.ws.rs.PUT; -import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; @@ -17,13 +14,11 @@ import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; -import org.gusdb.fgputil.accountdb.UserPropertyName; import org.gusdb.fgputil.web.LoginCookieFactory; import org.gusdb.wdk.model.Utilities; import org.gusdb.wdk.model.WdkModelException; import org.gusdb.wdk.model.user.InvalidUsernameOrEmailException; import org.gusdb.wdk.model.user.User; -import org.gusdb.wdk.model.user.UserFactory; import org.gusdb.wdk.model.user.UserPreferenceFactory; import org.gusdb.wdk.model.user.UserPreferences; import org.gusdb.wdk.service.UserBundle; @@ -32,7 +27,6 @@ import org.gusdb.wdk.service.request.exception.ConflictException; import org.gusdb.wdk.service.request.exception.DataValidationException; import org.gusdb.wdk.service.request.exception.RequestMisformatException; -import org.gusdb.wdk.service.request.user.PasswordChangeRequest; import org.gusdb.wdk.service.request.user.UserProfileRequest; import org.json.JSONException; import org.json.JSONObject; @@ -120,7 +114,7 @@ public Response updateUserProfile(String body) try { User user = getPrivateRegisteredUser(); UserProfileRequest request = UserProfileRequest.createFromJson( - new JSONObject(body), getPropertiesConfig(), false); + new JSONObject(body), User.USER_PROPERTIES, false); NewCookie loginCookie = processEmail(user, request.getEmail()); // overwrite any provided properties if (request.getEmail() != null) { @@ -149,30 +143,6 @@ private Response getProfileUpdateResponse(NewCookie loginCookie) { Response.noContent().cookie(loginCookie).build(); } - @PUT - @Path("password") - @Consumes(MediaType.APPLICATION_JSON) - public Response changeUserPassword(String body) - throws WdkModelException, DataValidationException { - User user = getPrivateRegisteredUser(); - try { - JSONObject json = new JSONObject(body); - PasswordChangeRequest request = PasswordChangeRequest.createFromJson(json); - UserFactory userMgr = getWdkModel().getUserFactory(); - if (userMgr.isCorrectPassword(user.getEmail(), request.getOldPassword())) { - userMgr.changePassword(user.getUserId(), request.getNewPassword()); - return Response.noContent().build(); - } - else { - // user submitted wrong old password, permission denied - throw new ForbiddenException("Old password specified is not correct."); - } - } - catch (JSONException | RequestMisformatException e) { - throw new BadRequestException(e); - } - } - /** * Ensures that a new email address, if provided, does not duplicate that of another account. If * the new email passes validation, a new cookie is returned to be used for authentication following the diff --git a/Service/src/main/java/org/gusdb/wdk/service/service/user/UserService.java b/Service/src/main/java/org/gusdb/wdk/service/service/user/UserService.java index 400e3fa959..005df36dc5 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/service/user/UserService.java +++ b/Service/src/main/java/org/gusdb/wdk/service/service/user/UserService.java @@ -6,8 +6,8 @@ import javax.ws.rs.PathParam; import org.gusdb.fgputil.FormatUtil; -import org.gusdb.fgputil.validation.ValidationLevel; import org.gusdb.fgputil.validation.ValidObjectFactory.RunnableObj; +import org.gusdb.fgputil.validation.ValidationLevel; import org.gusdb.wdk.model.WdkModelException; import org.gusdb.wdk.model.user.Step; import org.gusdb.wdk.model.user.User; diff --git a/Service/src/main/java/org/gusdb/wdk/service/service/user/UserUtilityServices.java b/Service/src/main/java/org/gusdb/wdk/service/service/user/UserUtilityServices.java index 1d643076e8..706b98a3c4 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/service/user/UserUtilityServices.java +++ b/Service/src/main/java/org/gusdb/wdk/service/service/user/UserUtilityServices.java @@ -1,5 +1,6 @@ package org.gusdb.wdk.service.service.user; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -18,10 +19,10 @@ import org.gusdb.fgputil.json.JsonIterators; import org.gusdb.fgputil.json.JsonType; import org.gusdb.fgputil.json.JsonType.ValueType; +import org.gusdb.oauth2.client.veupathdb.UserProperty; import org.gusdb.wdk.core.api.JsonKeys; import org.gusdb.wdk.model.WdkModelException; import org.gusdb.wdk.model.WdkUserException; -import org.gusdb.wdk.model.config.ModelConfigAccountDB; import org.gusdb.wdk.model.user.InvalidUsernameOrEmailException; import org.gusdb.wdk.model.user.User; import org.gusdb.wdk.model.user.UserFactory; @@ -58,7 +59,7 @@ public class UserUtilityServices extends AbstractWdkService { public Response createNewUser(String body) throws RequestMisformatException, DataValidationException, WdkModelException { try { JSONObject requestJson = new JSONObject(body); - List configuredUserProps = getWdkModel().getModelConfig().getAccountDB().getUserPropertyNames(); + Collection configuredUserProps = User.getPropertyDefs(); UserCreationRequest request = UserCreationRequest.createFromJson(requestJson, configuredUserProps); // create the user, saving to DB