From 4a698c2e3d926fd69673eea8b15a78bc7770a29c Mon Sep 17 00:00:00 2001 From: Instrumental Date: Fri, 22 Feb 2019 13:52:58 -0600 Subject: Add Multi-Realm class handling Also, improve Logging Issue-ID: AAF-771 Change-Id: I4cf286b5c474596f5e824e5204598cf0c1bb014c Signed-off-by: Instrumental --- pom.xml | 10 +- shiro-osgi-bundle/pom.xml | 2 +- shiro/pom.xml | 18 +- .../onap/aaf/cadi/shiro/AAFAuthenticationInfo.java | 14 +- .../onap/aaf/cadi/shiro/AAFAuthorizationInfo.java | 17 +- .../aaf/cadi/shiro/AAFPrincipalCollection.java | 3 - .../java/org/onap/aaf/cadi/shiro/AAFRealm.java | 270 ++++++++++++++------- .../org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java | 8 +- sidecar/fproxy/pom.xml | 2 +- sidecar/pom.xml | 2 +- sidecar/rproxy/pom.xml | 2 +- sidecar/tproxy-config/pom.xml | 2 +- 12 files changed, 219 insertions(+), 131 deletions(-) diff --git a/pom.xml b/pom.xml index 07b98f9..c88f47a 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.onap.aaf.cadi parent - 2.1.12-SNAPSHOT + 2.1.13-SNAPSHOT CADI Plugins Parent pom @@ -214,6 +214,14 @@ ${cadi.version} + + org.apache.shiro + shiro-core + 1.3.2 + + + + org.apache.shiro shiro-core - 1.3.2 + + org.slf4j + slf4j-api + + + + ch.qos.logback + logback-classic + test + diff --git a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java index beb9707..99e387d 100644 --- a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java @@ -24,20 +24,17 @@ import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.PrincipalCollection; import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.Access.Level; import org.onap.aaf.cadi.Hash; public class AAFAuthenticationInfo implements AuthenticationInfo { private static final long serialVersionUID = -1502704556864321020L; - final static Logger logger = LoggerFactory.getLogger(AAFAuthenticationInfo.class); - // We assume that Shiro is doing Memory Only, and this salt is not needed cross process private final static int salt = new SecureRandom().nextInt(); @@ -50,15 +47,16 @@ public class AAFAuthenticationInfo implements AuthenticationInfo { apc = new AAFPrincipalCollection(username); hash = getSaltedCred(password); } + @Override public byte[] getCredentials() { -// logger.info("AAFAuthenticationInfo.getCredentials"); + access.log(Level.DEBUG, "AAFAuthenticationInfo.getCredentials"); return hash; } @Override public PrincipalCollection getPrincipals() { -// logger.info( "AAFAuthenticationInfo.getPrincipals"); + access.log(Level.DEBUG, "AAFAuthenticationInfo.getPrincipals"); return apc; } @@ -67,7 +65,7 @@ public class AAFAuthenticationInfo implements AuthenticationInfo { UsernamePasswordToken upt = (UsernamePasswordToken)atoken; if(apc.getPrimaryPrincipal().getName().equals(upt.getPrincipal())) { byte[] newhash = getSaltedCred(new String(upt.getPassword())); - logger.info("Successful authentication attempt by " +upt.getPrincipal()); + access.printf(Level.INFO,"Successful authentication attempt by %s",upt.getPrincipal()); if(newhash.length==hash.length) { for(int i=0;i pond; @@ -55,7 +51,6 @@ public class AAFAuthorizationInfo implements AuthorizationInfo { this.pond = pond; sPerms=null; oPerms=null; - } public Principal principal() { @@ -64,7 +59,7 @@ public class AAFAuthorizationInfo implements AuthorizationInfo { @Override public Collection getObjectPermissions() { -// logger.info("AAFAuthorizationInfo.getObjectPermissions"); + access.log(Level.DEBUG, "AAFAuthorizationInfo.getObjectPermissions"); synchronized(bait) { if(oPerms == null) { oPerms = new ArrayList(); @@ -73,29 +68,25 @@ public class AAFAuthorizationInfo implements AuthorizationInfo { } } } - - return oPerms; } @Override public Collection getRoles() { -// logger.info("AAFAuthorizationInfo.getRoles"); + access.log(Level.INFO,"AAFAuthorizationInfo.getRoles"); // Until we decide to make Roles available, tie into String based permissions. return getStringPermissions(); } @Override public Collection getStringPermissions() { - -// logger.info("AAFAuthorizationInfo.getStringPermissions"); + access.log(Level.INFO,"AAFAuthorizationInfo.getStringPermissions"); synchronized(bait) { if(sPerms == null) { sPerms = new ArrayList(); for(org.onap.aaf.cadi.Permission p : pond) { sPerms.add(p.getKey().replace("|",":")); - logger.info("the user has " +p.getKey()); - + access.printf(Level.INFO,"the user has %s",p.getKey()); } } } diff --git a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java index 15fad53..3998aa5 100644 --- a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java @@ -27,15 +27,12 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.shiro.subject.PrincipalCollection; public class AAFPrincipalCollection implements PrincipalCollection { private static final long serialVersionUID = 558246013419818831L; - private static final Logger logger = LoggerFactory.getLogger(AAFPrincipalCollection.class); private static final Set realmSet; private final Principal principal; private List list=null; diff --git a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java index 0fc962f..52bf354 100644 --- a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java @@ -21,17 +21,15 @@ package org.onap.aaf.cadi.shiro; import java.io.IOException; -import java.io.PrintStream; import java.security.Principal; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.TreeMap; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; - -import org.apache.log4j.PropertyConfigurator; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; @@ -55,93 +53,186 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AAFRealm extends AuthorizingRealm { - - final static Logger logger = LoggerFactory.getLogger(AAFRealm.class); - public static final String AAF_REALM = "AAFRealm"; + private static final Logger logger = LoggerFactory.getLogger(AAFRealm.class); + private static Singleton singleton = Singleton.singleton(); - private PropAccess access; - private AAFCon acon; - private AAFAuthn authn; - private HashSet> supports; - private AAFLurPerm authz; - private MapBathConverter mbc; - private Map idMap; - - - /** - * - * There appears to be no configuration objects or references available for CADI to start with. - * - */ - public AAFRealm () { - access = new PropAccess(); // pick up cadi_prop_files from VM_Args - mbc = null; - idMap = null; - String cadi_prop_files = access.getProperty(Config.CADI_PROP_FILES); - if(cadi_prop_files==null) { - String msg = Config.CADI_PROP_FILES + " in VM Args is required to initialize AAFRealm."; - logger.info(msg); - throw new RuntimeException(msg); - } else { - try { - acon = AAFCon.newInstance(access); - authn = acon.newAuthn(); - authz = acon.newLur(authn); - - final String csv = access.getProperty(Config.CADI_BATH_CONVERT); - if(csv!=null) { - try { - mbc = new MapBathConverter(access, new CSV(csv)); - logger.info("MapBathConversion enabled with file "+csv); - idMap = new TreeMap(); - // Load - for(Entry es : mbc.map().entrySet()) { - String oldID = es.getKey(); - if(oldID.startsWith("Basic ")) { - oldID = Symm.base64noSplit.decode(oldID.substring(6)); - int idx = oldID.indexOf(':'); - if(idx>=0) { - oldID = oldID.substring(0, idx); + private static class Singleton { + private AAFCon acon; + private AAFAuthn authn; + private Set> supports; + private AAFLurPerm authz; + private MapBathConverter mbc; + private Map idMap; + private Singleton() { + mbc = null; + idMap = null; + String cadi_prop_files = access.getProperty(Config.CADI_PROP_FILES); + if(cadi_prop_files==null) { + String msg = Config.CADI_PROP_FILES + " in VM Args is required to initialize AAFRealm."; + access.log(Level.INFO,msg); + throw new RuntimeException(msg); + } else { + try { + acon = AAFCon.newInstance(access); + authn = acon.newAuthn(); + authz = acon.newLur(authn); + + final String csv = access.getProperty(Config.CADI_BATH_CONVERT); + if(csv!=null) { + try { + mbc = new MapBathConverter(access, new CSV(csv)); + access.log(Level.INFO, "MapBathConversion enabled with file ",csv); + idMap = new ConcurrentHashMap(); + // Load + for(Entry es : mbc.map().entrySet()) { + String oldID = es.getKey(); + if(oldID.startsWith("Basic ")) { + oldID = Symm.base64noSplit.decode(oldID.substring(6)); + int idx = oldID.indexOf(':'); + if(idx>=0) { + oldID = oldID.substring(0, idx); + } } - } - String newID = es.getValue(); - if(newID.startsWith("Basic ")) { - newID = Symm.base64noSplit.decode(newID.substring(6)); - int idx = newID.indexOf(':'); - if(idx>=0) { - newID = newID.substring(0, idx); + String newID = es.getValue(); + if(newID.startsWith("Basic ")) { + newID = Symm.base64noSplit.decode(newID.substring(6)); + int idx = newID.indexOf(':'); + if(idx>=0) { + newID = newID.substring(0, idx); + } } + idMap.put(oldID,newID); + } - idMap.put(oldID,newID); - + } catch (IOException e) { + access.log(e); } - } catch (IOException e) { - logger.info(e.getMessage(), e); } + } catch (APIException | CadiException | LocatorException e) { + String msg = "Cannot initiate AAFRealm"; + access.log(Level.ERROR,e,msg); + throw new RuntimeException(msg,e); } - } catch (APIException | CadiException | LocatorException e) { - String msg = "Cannot initiate AAFRealm"; - logger.info(msg + " "+ e.getMessage(), e); - throw new RuntimeException(msg,e); } + supports = new ConcurrentSkipListSet<>(); + supports.add(UsernamePasswordToken.class); } - supports = new HashSet>(); - supports.add(UsernamePasswordToken.class); - } + + public static synchronized Singleton singleton() { + if(singleton==null) { + singleton = new Singleton(); + } + return singleton; + } + + // pick up cadi_prop_files from VM_Args + private final PropAccess access = new PropAccess() { + @Override + public void log(Exception e, Object... elements) { + logger.error(buildMsg(Level.ERROR, elements).toString(),e); + } + + @Override + public void log(Level level, Object... elements) { + if(willLog(level)) { + String str = buildMsg(level, elements).toString(); + switch(level) { + case WARN: + case AUDIT: + logger.warn(str); + break; + case DEBUG: + logger.debug(str); + break; + case ERROR: + logger.warn(str); + break; + case INFO: + case INIT: + logger.info(str); + break; + case NONE: + break; + case TRACE: + logger.trace(str); + break; + } + } + } + + @Override + public void printf(Level level, String fmt, Object... elements) { + if(willLog(level)) { + String str = String.format(fmt, elements); + switch(level) { + case WARN: + case AUDIT: + logger.warn(str); + break; + case DEBUG: + logger.debug(str); + break; + case ERROR: + logger.warn(str); + break; + case INFO: + case INIT: + logger.info(str); + break; + case NONE: + break; + case TRACE: + logger.trace(str); + break; + } + } + } + + @Override + public boolean willLog(Level level) { + if(super.willLog(level)) { + switch(level) { + case AUDIT: + return logger.isWarnEnabled(); + case DEBUG: + return logger.isDebugEnabled(); + case ERROR: + return logger.isErrorEnabled(); + case INFO: + case INIT: + return logger.isInfoEnabled(); + case NONE: + return false; + case TRACE: + return logger.isTraceEnabled(); + case WARN: + return logger.isWarnEnabled(); + + } + } + return false; + } + }; + } + + /** + * + * There appears to be no configuration objects or references available for CADI to start with. + * + */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { - logger.info("AAFRealm.doGetAuthenticationInfo :"+token); final UsernamePasswordToken upt = (UsernamePasswordToken)token; final String user = upt.getUsername(); String authUser = user; final String password=new String(upt.getPassword()); String authPassword = password; - if(mbc!=null) { + if(singleton.mbc!=null) { try { final String oldBath = "Basic " + Symm.base64noSplit.encode(user+':'+password); - String bath = mbc.convert(access, oldBath); + String bath = singleton.mbc.convert(singleton.access, oldBath); if(bath!=oldBath) { bath = Symm.base64noSplit.decode(bath.substring(6)); int colon = bath.indexOf(':'); @@ -151,26 +242,23 @@ public class AAFRealm extends AuthorizingRealm { } } } catch (IOException e) { - - logger.info(e.getMessage(), e); - + singleton.access.log(e); } } String err; try { - err = authn.validate(authUser,authPassword); + err = singleton.authn.validate(authUser,authPassword); + if(err != null) { + singleton.access.log(Level.INFO, err); + throw new AuthenticationException(err); + } + } catch (IOException e) { - err = "Credential cannot be validated"; - logger.info(e.getMessage(), e); + singleton.access.log(e,"Credential cannot be validated"); } - if(err != null) { - logger.info(err); - throw new AuthenticationException(err); - } - return new AAFAuthenticationInfo( - access, + singleton.access, user, password ); @@ -182,7 +270,6 @@ public class AAFRealm extends AuthorizingRealm { if(ai instanceof AAFAuthenticationInfo) { if(!((AAFAuthenticationInfo)ai).matches(atoken)) { throw new AuthenticationException("Credentials do not match"); - } } else { @@ -198,9 +285,9 @@ public class AAFRealm extends AuthorizingRealm { protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Principal bait = (Principal)principals.getPrimaryPrincipal(); Principal newBait = bait; - if(idMap!=null) { - final String newID = idMap.get(bait.getName()); - logger.info("Successful authentication attempt by " +bait.getName()); + if(singleton.idMap!=null) { + final String newID = singleton.idMap.get(bait.getName()); + singleton.access.printf(Level.INFO,"Successful authentication attempt by %s",bait.getName()); if(newID!=null) { newBait = new Principal() { @Override @@ -211,14 +298,13 @@ public class AAFRealm extends AuthorizingRealm { } } List pond = new ArrayList<>(); - authz.fishAll(newBait,pond); - return new AAFAuthorizationInfo(access,bait,pond); - + singleton.authz.fishAll(newBait,pond); + return new AAFAuthorizationInfo(singleton.access,bait,pond); } @Override public boolean supports(AuthenticationToken token) { - return supports.contains(token.getClass()); + return singleton.supports.contains(token.getClass()); } @Override diff --git a/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java b/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java index 281f8ad..f49ecb4 100644 --- a/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java +++ b/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java @@ -27,18 +27,20 @@ import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.Permission; import org.apache.shiro.subject.PrincipalCollection; +import org.junit.Test; import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.config.Config; import org.onap.aaf.cadi.shiro.AAFRealm; import org.onap.aaf.cadi.shiro.AAFShiroPermission; import junit.framework.Assert; public class JU_AAFRealm { -/* - @Test + public void test() { // NOTE This is a live test. This JUnit needs to be built with "Mock" before it can be // an official JUNIT + try { System.setProperty(Config.CADI_PROP_FILES, "/opt/app/osaaf/local/org.onap.aai.props"); TestAAFRealm ar = new TestAAFRealm(); @@ -61,7 +63,7 @@ public class JU_AAFRealm { Assert.fail(); } } - */ + private void testAPerm(boolean expect, AuthorizationInfo azi, String ns, String type, String instance, String action) { AAFShiroPermission testPerm = new AAFShiroPermission(new AAFPermission(ns,type,instance,action,new ArrayList())); diff --git a/sidecar/fproxy/pom.xml b/sidecar/fproxy/pom.xml index cebcafd..5ad8b38 100644 --- a/sidecar/fproxy/pom.xml +++ b/sidecar/fproxy/pom.xml @@ -24,7 +24,7 @@ org.onap.aaf.cadi.sidecar sidecar - 2.1.12-SNAPSHOT + 2.1.13-SNAPSHOT fproxy diff --git a/sidecar/pom.xml b/sidecar/pom.xml index 00daa15..0c9e5e3 100644 --- a/sidecar/pom.xml +++ b/sidecar/pom.xml @@ -20,7 +20,7 @@ org.onap.aaf.cadi parent - 2.1.12-SNAPSHOT + 2.1.13-SNAPSHOT .. 4.0.0 diff --git a/sidecar/rproxy/pom.xml b/sidecar/rproxy/pom.xml index 6a313c1..d1d7c22 100644 --- a/sidecar/rproxy/pom.xml +++ b/sidecar/rproxy/pom.xml @@ -24,7 +24,7 @@ org.onap.aaf.cadi.sidecar sidecar - 2.1.12-SNAPSHOT + 2.1.13-SNAPSHOT rproxy diff --git a/sidecar/tproxy-config/pom.xml b/sidecar/tproxy-config/pom.xml index 561f9fa..63643d3 100644 --- a/sidecar/tproxy-config/pom.xml +++ b/sidecar/tproxy-config/pom.xml @@ -24,7 +24,7 @@ org.onap.aaf.cadi.sidecar sidecar - 2.1.12-SNAPSHOT + 2.1.13-SNAPSHOT tproxy-config -- cgit 1.2.3-korg