From 9b6efbd93a12c858a0d2643013217ec3d6c3a46d Mon Sep 17 00:00:00 2001 From: "Thomas Nelson Jr (arthurdent3) tn1381@att.com" Date: Mon, 16 Jul 2018 16:41:20 -0400 Subject: various Updates Q-api, triggers, conductor conditional updates. Bug fixes Change-Id: Iec392309787cd90f0a2827a2955399723640e800 Issue-ID: MUSIC-93 Signed-off-by: Thomas Nelson Jr (arthurdent3) tn1381@att.com --- src/main/java/org/onap/music/main/CachingUtil.java | 45 ++++++----- .../java/org/onap/music/main/CronJobManager.java | 91 ++++++++++++++++++++++ src/main/java/org/onap/music/main/MusicCore.java | 23 +----- src/main/java/org/onap/music/main/MusicUtil.java | 79 +++++++++++++------ .../org/onap/music/main/PropertiesListener.java | 8 +- 5 files changed, 173 insertions(+), 73 deletions(-) (limited to 'src/main/java/org/onap/music/main') diff --git a/src/main/java/org/onap/music/main/CachingUtil.java b/src/main/java/org/onap/music/main/CachingUtil.java index b34721bb..d3654118 100755 --- a/src/main/java/org/onap/music/main/CachingUtil.java +++ b/src/main/java/org/onap/music/main/CachingUtil.java @@ -33,6 +33,7 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.jcs.JCS; import org.apache.commons.jcs.access.CacheAccess; import org.codehaus.jackson.map.ObjectMapper; +import org.mindrot.jbcrypt.BCrypt; import org.onap.music.datastore.PreparedQueryObject; import org.onap.music.datastore.jsonobjects.AAFResponse; import org.onap.music.eelf.logging.EELFLoggerDelegate; @@ -101,8 +102,8 @@ public class CachingUtil implements Runnable { String keySpace = row.getString("application_name"); try { userAttempts.put(nameSpace, 0); - boolean aafRresponse = triggerAAF(nameSpace, userId, password); - if (aafRresponse) { + AAFResponse responseObj = triggerAAF(nameSpace, userId, password); + if (responseObj.getNs().size() > 0) { map = new HashMap<>(); map.put(userId, password); aafCache.put(nameSpace, map); @@ -133,9 +134,9 @@ public class CachingUtil implements Runnable { String keySpace) throws Exception { if (aafCache.get(nameSpace) != null) { - /* if (keySpace != null && !musicCache.get(keySpace).equals(nameSpace)) { + if (keySpace != null && !musicCache.get(keySpace).equals(nameSpace)) { logger.info(EELFLoggerDelegate.applicationLogger,"Create new application for the same namespace."); - } else */if (aafCache.get(nameSpace).get(userId).equals(password)) { + } else if (aafCache.get(nameSpace).get(userId).equals(password)) { logger.info(EELFLoggerDelegate.applicationLogger,"Authenticated with cache value.."); // reset invalid attempts to 0 userAttempts.put(nameSpace, 0); @@ -163,21 +164,20 @@ public class CachingUtil implements Runnable { } } - boolean aafRresponse = triggerAAF(nameSpace, userId, password); - if (aafRresponse) { - //TODO + AAFResponse responseObj = triggerAAF(nameSpace, userId, password); + if (responseObj.getNs().size() > 0) { //if (responseObj.getNs().get(0).getAdmin().contains(userId)) { - Map map = new HashMap<>(); - map.put(userId, password); - aafCache.put(nameSpace, map); + //Map map = new HashMap<>(); + //map.put(userId, password); + //aafCache.put(nameSpace, map); return true; //} } logger.info(EELFLoggerDelegate.applicationLogger,"Invalid user. Cache not updated"); - return aafRresponse; + return false; } - private static boolean triggerAAF(String nameSpace, String userId, String password) + private static AAFResponse triggerAAF(String nameSpace, String userId, String password) throws Exception { if (MusicUtil.getAafEndpointUrl() == null) { logger.error(EELFLoggerDelegate.errorLogger,"",AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR); @@ -195,9 +195,7 @@ public class CachingUtil implements Runnable { ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON) .header("Authorization", "Basic " + base64Creds) .header("content-type", "application/json").get(ClientResponse.class); - if(response.getStatus() == 200) - return true; - else if (response.getStatus() != 200) { + if (response.getStatus() != 200) { if (userAttempts.get(nameSpace) == null) userAttempts.put(nameSpace, 0); if ((Integer) userAttempts.get(nameSpace) >= 2) { @@ -212,14 +210,14 @@ public class CachingUtil implements Runnable { // TODO Allow for 2-3 times and forbid any attempt to trigger AAF with invalid values // for specific time. } - /*response.getHeaders().put(HttpHeaders.CONTENT_TYPE, + response.getHeaders().put(HttpHeaders.CONTENT_TYPE, Arrays.asList(MediaType.APPLICATION_JSON)); // AAFResponse output = response.getEntity(AAFResponse.class); response.bufferEntity(); String x = response.getEntity(String.class); - AAFResponse responseObj = new ObjectMapper().readValue(x, AAFResponse.class);*/ + AAFResponse responseObj = new ObjectMapper().readValue(x, AAFResponse.class); - return false; + return responseObj; } public static void updateMusicCache(String keyspace, String nameSpace) { @@ -352,7 +350,7 @@ public class CachingUtil implements Runnable { logger.error(EELFLoggerDelegate.errorLogger,"Application is not onboarded. Please contact admin."); resultMap.put("Exception", "Application is not onboarded. Please contact admin."); } else { - if(!(rs.getString("username").equals(userId)) || !(rs.getString("password").equals(password))) { + if(!(rs.getString("username").equals(userId)) || !(BCrypt.checkpw(password, rs.getString("password")))) { logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.AUTHENTICATIONERROR, ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR); logger.error(EELFLoggerDelegate.errorLogger,"Namespace, UserId and password doesn't match. namespace: "+ns+" and userId: "+userId); resultMap.put("Exception", "Namespace, UserId and password doesn't match. namespace: "+ns+" and userId: "+userId); @@ -365,13 +363,14 @@ public class CachingUtil implements Runnable { public static Map authenticateAIDUser(String nameSpace, String userId, String password, String keyspace) { Map resultMap = new HashMap<>(); + String pwd = null; if((musicCache.get(keyspace) != null) && (musicValidateCache.get(nameSpace) != null) && (musicValidateCache.get(nameSpace).containsKey(userId))) { if(!musicCache.get(keyspace).equals(nameSpace)) { resultMap.put("Exception", "Namespace and keyspace doesn't match"); return resultMap; } - if(!musicValidateCache.get(nameSpace).get(userId).equals(password)) { + if(!BCrypt.checkpw(password,musicValidateCache.get(nameSpace).get(userId))) { resultMap.put("Exception", "Namespace, userId and password doesn't match"); return resultMap; } @@ -399,7 +398,7 @@ public class CachingUtil implements Runnable { } else { String user = rs.getString("username"); - String pwd = rs.getString("password"); + pwd = rs.getString("password"); String ns = rs.getString("application_name"); if(!ns.equals(nameSpace)) { resultMap.put("Exception", "Namespace and keyspace doesn't match"); @@ -409,13 +408,13 @@ public class CachingUtil implements Runnable { resultMap.put("Exception", "Invalid userId :"+userId); return resultMap; } - if(!pwd.equals(password)) { + if(!BCrypt.checkpw(password, pwd)) { resultMap.put("Exception", "Invalid password"); return resultMap; } } CachingUtil.updateMusicCache(keyspace, nameSpace); - CachingUtil.updateMusicValidateCache(nameSpace, userId, password); + CachingUtil.updateMusicValidateCache(nameSpace, userId, pwd); return resultMap; } } diff --git a/src/main/java/org/onap/music/main/CronJobManager.java b/src/main/java/org/onap/music/main/CronJobManager.java index fb4a2ac3..5b7a8de4 100644 --- a/src/main/java/org/onap/music/main/CronJobManager.java +++ b/src/main/java/org/onap/music/main/CronJobManager.java @@ -21,6 +21,9 @@ */ package org.onap.music.main; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -28,6 +31,13 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.exceptions.MusicServiceException; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + @WebListener public class CronJobManager implements ServletContextListener { @@ -37,11 +47,92 @@ public class CronJobManager implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(new CachingUtil(), 0, 24, TimeUnit.HOURS); + PreparedQueryObject pQuery = new PreparedQueryObject(); + String consistency = MusicUtil.EVENTUAL; + pQuery.appendQueryString("CREATE TABLE IF NOT EXISTS admin.locks ( lock_id text PRIMARY KEY, ctime text)"); + try { + ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency); + } catch (MusicServiceException e1) { + e1.printStackTrace(); + } + + pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "select * from admin.locks"); + try { + ResultSet rs = MusicCore.get(pQuery); + Iterator it = rs.iterator(); + StringBuilder deleteKeys = new StringBuilder(); + Boolean expiredKeys = false; + while (it.hasNext()) { + Row row = (Row) it.next(); + String id = row.getString("lock_id"); + long ctime = Long.parseLong(row.getString("ctime")); + if(System.currentTimeMillis() >= ctime + 24 * 60 * 60 * 1000) { + expiredKeys = true; + String new_id = id.substring(1); + MusicCore.deleteLock(new_id); + deleteKeys.append(id).append(","); + } + else { + MusicUtil.zkNodeMap.put(id, ctime); + } + }; + if(expiredKeys) { + deleteKeys.deleteCharAt(deleteKeys.length()-1); + deleteKeysFromDB(deleteKeys); + } + } catch (MusicServiceException e) { + e.printStackTrace(); + } catch (MusicLockingException e) { + e.printStackTrace(); + } + + //Zookeeper cleanup + scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + Iterator> it = MusicUtil.zkNodeMap.entrySet().iterator(); + StringBuilder deleteKeys = new StringBuilder(); + Boolean expiredKeys = false; + while (it.hasNext()) { + Map.Entry pair = (Map.Entry)it.next(); + long ctime = pair.getValue(); + if (System.currentTimeMillis() >= ctime + 24 * 60 * 60 * 1000) { + try { + expiredKeys = true; + String id = pair.getKey(); + deleteKeys.append("'").append(id).append("'").append(","); + MusicCore.deleteLock(id.substring(1)); + MusicUtil.zkNodeMap.remove(id); + + } catch (MusicLockingException e) { + e.printStackTrace(); + } + } + } + if(expiredKeys) { + deleteKeys.deleteCharAt(deleteKeys.length()-1); + deleteKeysFromDB(deleteKeys); + } + } + } , 0, 24, TimeUnit.HOURS); } @Override public void contextDestroyed(ServletContextEvent event) { scheduler.shutdownNow(); } + + public void deleteKeysFromDB(StringBuilder deleteKeys) { + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "DELETE FROM admin.locks WHERE lock_id IN ("+deleteKeys+")"); + try { + MusicCore.nonKeyRelatedPut(pQuery, "eventual"); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/org/onap/music/main/MusicCore.java b/src/main/java/org/onap/music/main/MusicCore.java index 661d7adc..dfc93ccc 100644 --- a/src/main/java/org/onap/music/main/MusicCore.java +++ b/src/main/java/org/onap/music/main/MusicCore.java @@ -22,7 +22,6 @@ package org.onap.music.main; -import java.io.PrintWriter; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; @@ -294,10 +293,6 @@ public class MusicCore { logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: You already have the lock!"); return new ReturnType(ResultType.SUCCESS, "You already have the lock!"); } - if (currentMls.getLockStatus() != MusicLockState.LockStatus.UNLOCKED || currentMls.getLockHolder() != null) { - logger.info("In acquire lock: the previous lock has not been released yet! current mls:"+currentMls.toString()); - return new ReturnType(ResultType.FAILURE, "The previous lock has not been released yet."); - } } catch (NullPointerException e) { logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.INVALIDLOCK+lockId,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR); } @@ -515,14 +510,6 @@ public class MusicCore { public static void voluntaryReleaseLock(String lockId) throws MusicLockingException{ try { getLockingServiceHandle().unlockAndDeleteId(lockId); - String lockName = getLockNameFromId(lockId); - String lockHolder = null; - MusicLockState mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder); - try { - getLockingServiceHandle().setLockState(lockName, mls); - } catch (MusicLockingException e) { - logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.RELEASELOCK+lockId ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR); - } } catch (KeeperException.NoNodeException e) { // ??? No way } @@ -653,7 +640,6 @@ public class MusicCore { try { MusicLockState mls = getLockingServiceHandle() .getLockState(keyspaceName + "." + tableName + "." + primaryKey); - logger.info("Got MusicLockState object... :"+mls.toString()); if (mls.getLockHolder().equals(lockId) == true) { if (conditionInfo != null) try { @@ -678,7 +664,6 @@ public class MusicCore { "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n" + e.getMessage()); }catch(MusicLockingException ex){ - logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage()); return new ReturnType(ResultType.FAILURE,ex.getMessage()); } @@ -775,7 +760,7 @@ public class MusicCore { ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey, queryObject, lockId, conditionInfo); long criticalPutTime = System.currentTimeMillis(); - releaseLock(lockId, true); + voluntaryReleaseLock(lockId); long lockDeleteTime = System.currentTimeMillis(); String timingInfo = "|lock creation time:" + (lockCreationTime - start) + "|lock accquire time:" + (lockAcqTime - lockCreationTime) @@ -785,7 +770,7 @@ public class MusicCore { return criticalPutResult; } else { logger.info(EELFLoggerDelegate.applicationLogger,"unable to acquire lock, id " + lockId); - releaseLock(lockId, true);; + destroyLockRef(lockId); return lockAcqResult; } } @@ -855,10 +840,10 @@ public class MusicCore { logger.info(EELFLoggerDelegate.applicationLogger,"acquired lock with id " + lockId); ResultSet result = criticalGet(keyspaceName, tableName, primaryKey, queryObject, lockId); - releaseLock(lockId, true); + voluntaryReleaseLock(lockId); return result; } else { - releaseLock(lockId, true); + destroyLockRef(lockId); logger.info(EELFLoggerDelegate.applicationLogger,"unable to acquire lock, id " + lockId); return null; } diff --git a/src/main/java/org/onap/music/main/MusicUtil.java b/src/main/java/org/onap/music/main/MusicUtil.java index 20bb0a48..a161fd56 100755 --- a/src/main/java/org/onap/music/main/MusicUtil.java +++ b/src/main/java/org/onap/music/main/MusicUtil.java @@ -24,16 +24,25 @@ package org.onap.music.main; import java.io.File; import java.io.FileNotFoundException; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; +import java.util.StringTokenizer; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; + import org.onap.music.datastore.PreparedQueryObject; import org.onap.music.eelf.logging.EELFLoggerDelegate; + import com.datastax.driver.core.DataType; +import com.sun.jersey.core.util.Base64; /** * @author nelson24 @@ -58,6 +67,9 @@ public class MusicUtil { public static final String INSERT = "insert"; public static final String UPDATE = "update"; public static final String UPSERT = "upsert"; + public static final String USERID = "userId"; + public static final String PASSWORD = "password"; + public static final String AUTHORIZATION = "Authorization"; private static final String LOCALHOST = "localhost"; private static final String PROPERTIES_FILE = "/opt/app/music/etc/music.properties"; @@ -81,6 +93,7 @@ public class MusicUtil { private static String cassName = "cassandra"; private static String cassPwd; private static String aafEndpointUrl = null; + public static ConcurrentMap zkNodeMap = new ConcurrentHashMap<>(); private MusicUtil() { throw new IllegalStateException("Utility Class"); @@ -402,7 +415,8 @@ public class MusicUtil { MusicUtil.cassPwd = cassPwd; } - public static String convertToCQLDataType(DataType type, Object valueObj) throws Exception { + @SuppressWarnings("unchecked") + public static String convertToCQLDataType(DataType type, Object valueObj) throws Exception { String value = ""; switch (type.getName()) { @@ -416,8 +430,7 @@ public class MusicUtil { value = "'" + valueString + "'"; break; case MAP: { - @SuppressWarnings("unchecked") - Map otMap = (Map) valueObj; + Map otMap = (Map) valueObj; value = "{" + jsonMaptoSqlString(otMap, ",") + "}"; break; } @@ -440,29 +453,34 @@ public class MusicUtil { public static Object convertToActualDataType(DataType colType, Object valueObj) throws Exception { String valueObjString = valueObj + ""; switch (colType.getName()) { - case UUID: - return UUID.fromString(valueObjString); - case VARINT: - return BigInteger.valueOf(Long.parseLong(valueObjString)); - case BIGINT: - return Long.parseLong(valueObjString); - case INT: - return Integer.parseInt(valueObjString); - case FLOAT: - return Float.parseFloat(valueObjString); - case DOUBLE: - return Double.parseDouble(valueObjString); - case BOOLEAN: - return Boolean.parseBoolean(valueObjString); - case MAP: - return (Map) valueObj; - case LIST: - return (List)valueObj; - default: - return valueObjString; + case UUID: + return UUID.fromString(valueObjString); + case VARINT: + return BigInteger.valueOf(Long.parseLong(valueObjString)); + case BIGINT: + return Long.parseLong(valueObjString); + case INT: + return Integer.parseInt(valueObjString); + case FLOAT: + return Float.parseFloat(valueObjString); + case DOUBLE: + return Double.parseDouble(valueObjString); + case BOOLEAN: + return Boolean.parseBoolean(valueObjString); + case MAP: + return (Map) valueObj; + case BLOB: + + default: + return valueObjString; } } + public static ByteBuffer convertToActualDataType(DataType colType, byte[] valueObj) { + ByteBuffer buffer = ByteBuffer.wrap(valueObj); + return buffer; + } + /** * * Utility function to parse json map into sql like string @@ -489,6 +507,7 @@ public class MusicUtil { return sqlString.toString(); } + @SuppressWarnings("unused") public static String buildVersion(String major, String minor, String patch) { if (minor != null) { major += "." + minor; @@ -530,8 +549,18 @@ public class MusicUtil { logger.info(EELFLoggerDelegate.applicationLogger,"Version In:" + versionIn); return response; } - - + public static Map extractBasicAuthentication(String authorization){ + + Map authValues = new HashMap<>(); + authorization = authorization.replaceFirst("Basic", ""); + String decoded = Base64.base64Decode(authorization); + StringTokenizer token = new StringTokenizer(decoded, ":"); + authValues.put(MusicUtil.USERID, token.nextToken().toString()); + authValues.put(MusicUtil.PASSWORD,token.nextToken()); + return authValues; + + } + } diff --git a/src/main/java/org/onap/music/main/PropertiesListener.java b/src/main/java/org/onap/music/main/PropertiesListener.java index afd35387..8b00e473 100755 --- a/src/main/java/org/onap/music/main/PropertiesListener.java +++ b/src/main/java/org/onap/music/main/PropertiesListener.java @@ -30,26 +30,22 @@ import java.util.Arrays; import java.util.Properties; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import javax.servlet.annotation.WebListener; import org.onap.music.eelf.logging.EELFLoggerDelegate; import org.onap.music.eelf.logging.format.AppMessages; import org.onap.music.eelf.logging.format.ErrorSeverity; import org.onap.music.eelf.logging.format.ErrorTypes; -@WebListener public class PropertiesListener implements ServletContextListener { private Properties prop; - private static EELFLoggerDelegate logger = - EELFLoggerDelegate.getLogger(PropertiesListener.class); + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(PropertiesListener.class); @Override public void contextInitialized(ServletContextEvent servletContextEvent) { prop = new Properties(); Properties projectProp = new Properties(); URL resource = getClass().getResource("/"); - String musicPropertiesFilePath = resource.getPath().replace("WEB-INF/classes/", - "WEB-INF/classes/project.properties"); + String musicPropertiesFilePath = resource.getPath().replace("WEB-INF/classes/","WEB-INF/classes/project.properties"); // Open the file try { -- cgit 1.2.3-korg