/* * Copyright (C) 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package apps.provisioning.config; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; /** * Maps the properties file to methods. */ public class ConfigData { private final String CACHED_USERNAMES = "accounts.UsernameGeneration.cachedUsernames"; private final Boolean CACHED_USERNAMES_DEFAULT = false; private final String CACHE_EXPIRATION_HOURS = "accounts.UsernameGeneration.cacheExpirationHours"; private final Integer CACHE_EXPIRATION_HOURS_DEFAULT = 24; private final Integer CACHE_EXPIRATION_HOURS_MIN = 1; private final String NUMBER_OF_SUGGESTIONS = "accounts.UsernameGeneration.numberOfSuggestions"; private final Integer NUMBER_OF_SUGGESTIONS_DEFAULT = 3; private final Integer NUMBER_OF_SUGGESTIONS_MIN = 1; private final Integer NUMBER_OF_SUGGESTIONS_MAX = 10; private final String PATTERNS = "accounts.UsernameGeneration.patterns"; private final String[] PATTERNS_DEFAULT = {"[firstname][lastname]", "[firstname].[lastname]", "[firstname]_[lastname]", "[C1_firstname][lastname]", "[firstname][C1_lastname]", "[C9_firstname][C9_lastname][#]"}; private final String SUGGESTED_USERNAMES_TIMEOUT = "accounts.UsernameGeneration.suggestedUsernamesTimeout"; private final int SUGGESTED_USERNAMES_TIMEOUT_DEFAULT = 120; // 2 minutes private final String AUTH_USER = "apis.GoogleAPIs.authUser"; private final String KEY_PATH = "apis.GoogleAPIs.keyPath"; private final String APP_NAME = "apis.GoogleAPIs.appName"; private final String DOMAIN = "apis.GoogleAPIs.domain"; private final String DOMAIN_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$"; private final String SERVICE_ACCOUNT_EMAIL = "apis.GoogleAPIs.serviceAccountEmail"; private final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; private final String DB_PATH = "db.h2.path"; private final String DB_PATH_DEFAULT = "./"; private final String DB_NAME = "db.h2.name"; private final String DB_NAME_DEFAULT = "usernames"; private final String USE_SSL = "security.ssl.useSSL"; private final Boolean USE_SSL_DEFAULT = false; private final String KEY_STORE_PATH = "security.ssl.keyStorePath"; private final String KEY_STORE_PASSWORD = "security.ssl.keyStorePassword"; private final String KEY_MANAGER_PASSWORD = "security.ssl.keyManagerPassword"; private final String[] ILLEGAL_CHARACTERS = {"/", "\n", "\r", "\t", "\0", "\f", "`", "?", "*", "\\", "<", ">", "|", "\"", ":"}; private final String ARRAY_SEPARATOR = ","; private static final Logger log = Logger.getLogger(ConfigData.class.getName()); private Properties properties; private Integer numberOfSuggestions; private String[] patterns; private String authUser; private String keyPath; private String serviceAccountEmail; private String appName; private String domain; private Boolean cacheUsernames; private Integer cacheExpirationHours; private String dbName; private String dbPath; private Boolean useSSL; private String keyStorePath; private String keyStorePassword; private String keyManagerPassword; private long suggestedUsernamesTimeout; public ConfigData(String configFilePath) throws FileNotFoundException, IOException, Exception { properties = new Properties(); properties.load(new FileInputStream(configFilePath)); parsePropertiesFile(); } /** * Checks that every property is set correctly. * * @throws Exception */ private void parsePropertiesFile() throws Exception { numberOfSuggestions = parseNumberOfSuggestions(); log.log(Level.INFO, "Number of suggestions: " + numberOfSuggestions); patterns = parsePatterns(); log.log(Level.INFO, "Patterns: " + patterns); authUser = parseAuthUser(); log.log(Level.INFO, "Auth user: " + authUser); keyPath = parseKeyPath(); log.log(Level.INFO, "Key path: " + keyPath); serviceAccountEmail = parseServiceAccountEmail(); log.log(Level.INFO, "Service account email: " + serviceAccountEmail); appName = parseAppName(); log.log(Level.INFO, "App name: " + appName); domain = parseDomain(); log.log(Level.INFO, "Domain: " + domain); suggestedUsernamesTimeout = parseSuggestedUsernamesTimeout(); log.log(Level.INFO, "Suggested usernames timeout: " + suggestedUsernamesTimeout); cacheUsernames = parseCacheUsernames(); log.log(Level.INFO, "Cached usernames: " + cacheUsernames); if (cacheUsernames) { cacheExpirationHours = parseCacheExpirationHours(); log.log(Level.INFO, "Cache expiration in hours: " + cacheExpirationHours); dbPath = parseDbPath(); log.log(Level.INFO, "Database path: " + dbPath); dbName = parseDbName(); log.log(Level.INFO, "Database name: " + dbName); } useSSL = parseUseSSL(); log.log(Level.INFO, "Uses SSL: " + useSSL); if (useSSL) { keyStorePath = parseKeyStorePath(); log.log(Level.INFO, "Key store path: " + keyStorePath); keyStorePassword = parseKeyStorePassword(); log.log(Level.INFO, "Key store password: " + keyStorePassword); keyManagerPassword = parseKeyManagerPassword(); log.log(Level.INFO, "Key manager password: " + keyManagerPassword); } } /** * Gets a property value from the properties object as String. * * @param key Property name to be retrieved. * @return The property requested as String. */ private String getString(String key) { String value = properties.getProperty(key); return value; } /** * Gets a property value from the properties object as String Array * * @param key Property name to be retrieved * @return The property requested as String array. */ private String[] getStringArray(String key) { String string = getString(key); if (string == null || string.isEmpty()) { return null; } return string.split(ARRAY_SEPARATOR); } /** * Gets a property value from the properties object as Boolean * * @param key Property name to be retrieved * @return The property requested as boolean. * @throws Exception */ private Boolean getBoolean(String key) throws Exception { String value = getString(key); if (value == null || value.isEmpty()) { return null; } value = value.toLowerCase(); if (value.equals("yes")) { return true; } else if (value.equals("no")) { return false; } else { throw new Exception("Only YES and NO options are allowed"); } } /** * Gets a property value from the properties object as Integer * * @param key Property name to be retrieved * @return The property requested as integer. * @throws NumberFormatException */ private Integer getInteger(String key) throws NumberFormatException { String value = getString(key); if (value == null || value.isEmpty()) { return null; } return Integer.parseInt(value); } /** * Parses the cachedUsernames property value. * * @return The cachedUsernames value from UsernameGeneration module. * @throws Exception */ private Boolean parseCacheUsernames() throws Exception { try { Boolean cachedUsernames = getBoolean(CACHED_USERNAMES); if (cachedUsernames == null) { log.log(Level.WARNING, "cachedUsernames set with the default value: " + CACHED_USERNAMES_DEFAULT); return CACHED_USERNAMES_DEFAULT; } return cachedUsernames; } catch (Exception e) { throw new Exception("Invalid value in " + CACHED_USERNAMES + "property."); } } /** * Gets the cachedUsernames property value. * * @return The cachedUsernames value from UsernameGeneration module. */ public Boolean getCacheUsernames() { return cacheUsernames; } /** * Parses the cacheExpirationHours property value. * * @return How long the cached information will be valid. * @throws Exception */ private Integer parseCacheExpirationHours() throws Exception { try { Integer cacheExpirationHours = getInteger(CACHE_EXPIRATION_HOURS); if (cacheExpirationHours == null) { return CACHE_EXPIRATION_HOURS_DEFAULT; } if (cacheExpirationHours < CACHE_EXPIRATION_HOURS_MIN) { throw new Exception("Expiration time is lower than minimum:" + NUMBER_OF_SUGGESTIONS_MIN); } return cacheExpirationHours; } catch (Exception e) { throw new Exception("Invalid value in " + CACHE_EXPIRATION_HOURS + " property."); } } /** * Parses the suggestedUsernamesTimeout property value. * * @return How long the suggested usernames will be suggested. * @throws Exception */ private Integer parseSuggestedUsernamesTimeout() throws Exception { try { Integer suggestedUsernamesTimeout = getInteger(SUGGESTED_USERNAMES_TIMEOUT); if (suggestedUsernamesTimeout == null) { return SUGGESTED_USERNAMES_TIMEOUT_DEFAULT; } return suggestedUsernamesTimeout; } catch (Exception e) { throw new Exception("Invalid value in " + SUGGESTED_USERNAMES_TIMEOUT + " property."); } } /** * Gets the cacheExpirationHours property value. * * @return How long the cached information will be valid. */ public Integer getCacheExpirationHours() { return cacheExpirationHours; } /** * Parses the numberOfSuggestions property value. * * @return Number of configured username suggestions. * @throws Exception */ private Integer parseNumberOfSuggestions() throws Exception { try { Integer numberOfSuggestions = getInteger(NUMBER_OF_SUGGESTIONS); if (numberOfSuggestions == null) { return NUMBER_OF_SUGGESTIONS_DEFAULT; } if (numberOfSuggestions < NUMBER_OF_SUGGESTIONS_MIN || numberOfSuggestions > NUMBER_OF_SUGGESTIONS_MAX) { throw new Exception("The number of suggestions value must be between " + NUMBER_OF_SUGGESTIONS_MIN + " and " + NUMBER_OF_SUGGESTIONS_MAX); } return numberOfSuggestions; } catch (Exception e) { throw new Exception("Invalid value in " + NUMBER_OF_SUGGESTIONS + " property."); } } /** * Gets the numberOfSuggestions property value. * * @return Number of configured username suggestions. */ public Integer getNumberOfSuggestions() { return numberOfSuggestions; } /** * Parses the patterns property value. * * @return The supported patterns as an array */ private String[] parsePatterns() { String[] patterns = getStringArray(PATTERNS); if (patterns == null) { log.log(Level.WARNING, "Pattern value set with the default value: " + PATTERNS_DEFAULT); return PATTERNS_DEFAULT; } return patterns; } /** * Gets the patterns property value. * * @return The supported patterns as an array */ public String[] getPatterns() { return patterns; } /** * Parses the authUser property value. * * @return The owner email of the project * @throws Exception */ private String parseAuthUser() throws Exception { String authUser = getString(AUTH_USER); if (authUser == null || authUser.isEmpty()) { throw new Exception("You must set " + AUTH_USER + " property."); } Pattern pattern = Pattern.compile(EMAIL_PATTERN); if (pattern.matcher(authUser).find()) { return authUser; } else { throw new Exception("Invalid value in " + AUTH_USER + " property"); } } /** * Gets the authUser property value. * * @return The owner email of the project */ public String getAuthUser() { return authUser; } /** * Parses the keyPath property value. * * @return The location of the P12 key file. * @throws FileNotFoundException * @throws Exception */ private String parseKeyPath() throws FileNotFoundException, Exception { String keyPath = getString(KEY_PATH); if (keyPath == null) { throw new Exception("You must set " + KEY_PATH + " property."); } File file = new File(keyPath); if (!file.exists()) { throw new FileNotFoundException("File declared in " + KEY_PATH + " doesn't exist."); } return keyPath; } /** * Gets the keyPath property value. * * @return The location of the P12 key file. */ public String getKeyPath() { return keyPath; } /** * Parses the serviceAccountEmail property value. * * @return The email generated for the service account credentials * @throws Exception */ private String parseServiceAccountEmail() throws Exception { String serviceAccountEmail = getString(SERVICE_ACCOUNT_EMAIL); if (serviceAccountEmail == null) { throw new Exception("You must set " + SERVICE_ACCOUNT_EMAIL + " property."); } Pattern pattern = Pattern.compile(EMAIL_PATTERN); if (pattern.matcher(serviceAccountEmail).find()) { return serviceAccountEmail; } else { throw new Exception("Invalid value in " + SERVICE_ACCOUNT_EMAIL + " property"); } } /** * Gets the serviceAccountEmail property value. * * @return The email generated for the service account credentials */ public String getServiceAccountEmail() { return serviceAccountEmail; } /** * Parses the appName property value. * * @return Application name * @throws Exception */ private String parseAppName() throws Exception { String appName = getString(APP_NAME); if (appName == null || appName.isEmpty()) { throw new Exception("You must set " + APP_NAME + " property."); } return appName; } /** * Gets the appName property value. * * @return Application name */ public String getAppName() { return appName; } /** * Parses the domain property value. * * @return Domain * @throws Exception */ private String parseDomain() throws Exception { String domain = getString(DOMAIN); if (domain == null || appName.isEmpty()) { throw new Exception("You must set " + DOMAIN + " property."); } Pattern pattern = Pattern.compile(DOMAIN_PATTERN); if (pattern.matcher(domain).find()) { return domain; } else { throw new Exception("Invalid value in " + DOMAIN + " property"); } } /** * Gets the domain property value. * * @return Domain */ public String getDomain() { return domain; } /** * Parses the database path value. * * @return Database path * @throws IOException */ private String parseDbPath() throws Exception { String dbPath = getString(DB_PATH); if (dbPath == null || dbPath.isEmpty()) { return DB_PATH_DEFAULT; } File path = new File(dbPath); if (!path.exists()) { throw new FileNotFoundException("The database path configured in " + DB_PATH + " must exist."); } if (!path.isDirectory()) { throw new Exception("The database path configured in " + DB_PATH + " must be a directory"); } return dbPath; } /** * Gets the database path value. * * @return Database path */ public String getDbPath() { return dbPath; } /** * Parses the database name value. * * @return Database name * @throws IOException */ private String parseDbName() throws Exception { String dbName = getString(DB_NAME); if (dbName == null || dbName.isEmpty()) { return DB_NAME_DEFAULT; } for (int i = 0; i < ILLEGAL_CHARACTERS.length; i++) { if (dbName.contains(ILLEGAL_CHARACTERS[i])) { throw new Exception("The database name has the following invalid character: " + ILLEGAL_CHARACTERS[i]); } } return dbName; } /** * Gets the database name value. * * @return Database name */ public String getDbName() { return dbName; } /** * Parses the useSSL property value. * * @return The useSSL value. * @throws Exception */ private Boolean parseUseSSL() throws Exception { try { Boolean useSSL = getBoolean(USE_SSL); if (useSSL == null) { log.log(Level.WARNING, "useSSL set with the default value: " + USE_SSL_DEFAULT); return USE_SSL_DEFAULT; } return useSSL; } catch (Exception e) { throw new Exception("Invalid value in " + USE_SSL + " property."); } } /** * Gets the useSSL property value. * * @return The useSSL value. */ public Boolean getUseSSL() { return useSSL; } /** * Parses the keyStorePath property value. * * @return The location of the key store file. * @throws FileNotFoundException * @throws Exception */ private String parseKeyStorePath() throws FileNotFoundException, Exception { String keyStorePath = getString(KEY_STORE_PATH); if (keyStorePath == null) { throw new Exception("You must set " + KEY_STORE_PATH + " property."); } File file = new File(keyStorePath); if (!file.exists()) { throw new FileNotFoundException("File declared in " + KEY_STORE_PATH + " doesn't exist."); } return keyStorePath; } /** * Gets the keyStorePath property value. * * @return The location of the key store file. */ public String getKeyStorePath() { return keyStorePath; } /** * Parses the keyStorePassword property value. * * @return Key store password * @throws Exception */ private String parseKeyStorePassword() throws Exception { String keyStorePassword = getString(KEY_STORE_PASSWORD); if (keyStorePassword == null) { throw new Exception("You must set " + KEY_STORE_PASSWORD + " property."); } return keyStorePassword; } /** * Gets the keyStorePassword property value. * * @return Key store password */ public String getKeyStorePassword() { return keyStorePassword; } /** * Parses the keyManagerPassword property value. * * @return Key manager password * @throws Exception */ private String parseKeyManagerPassword() throws Exception { String keyManagerPassword = getString(KEY_MANAGER_PASSWORD); if (keyManagerPassword == null) { throw new Exception("You must set " + KEY_MANAGER_PASSWORD + " property."); } return keyManagerPassword; } /** * Gets the keyManagerPassword property value. * * @return Key manager password */ public String getKeyManagerPassword() { return keyManagerPassword; } /** * @return The suggested usernames expiration timeout in seconds. A suggested username will remain * suggested for this amount of time (in seconds). */ public long getSuggestedUsernamesTimeout() { return suggestedUsernamesTimeout; } }