Add Multi-Realm class handling
Also, improve Logging
Issue-ID: AAF-771
Change-Id: I4cf286b5c474596f5e824e5204598cf0c1bb014c
Signed-off-by: Instrumental <jonathan.gathman@att.com>
diff --git a/pom.xml b/pom.xml
index 07b98f9..c88f47a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.aaf.cadi</groupId>
<artifactId>parent</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
<name>CADI Plugins Parent</name>
<packaging>pom</packaging>
@@ -214,6 +214,14 @@
<version>${cadi.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-core</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+
+
+
<!--
<dependency>
diff --git a/shiro-osgi-bundle/pom.xml b/shiro-osgi-bundle/pom.xml
index 3a8647e..7d90542 100644
--- a/shiro-osgi-bundle/pom.xml
+++ b/shiro-osgi-bundle/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.aaf.cadi</groupId>
<artifactId>parent</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
diff --git a/shiro/pom.xml b/shiro/pom.xml
index 09078cc..6488034 100644
--- a/shiro/pom.xml
+++ b/shiro/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.aaf.cadi</groupId>
<artifactId>parent</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
@@ -90,18 +90,22 @@
<groupId>org.onap.aaf.authz</groupId>
<artifactId>aaf-cadi-aaf</artifactId>
</dependency>
- <!--<dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-core</artifactId>
- <version>1.4.0</version>
- </dependency> -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
- <version>1.3.2</version>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
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.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 @@
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 @@
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<hash.length;++i) {
if(hash[i]!=newhash[i]) {
@@ -77,6 +75,8 @@
return true;
}
}
+ } else {
+ access.printf(Level.ERROR, "AAFAuthenticationInfo received non-AAF token %s (%s)",atoken.getPrincipal(),atoken.getClass().getName());
}
return false;
}
diff --git a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java
index 4b0993b..fc0f4ff 100644
--- a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java
+++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java
@@ -29,8 +29,6 @@
import org.apache.shiro.authz.Permission;
import org.onap.aaf.cadi.Access;
import org.onap.aaf.cadi.Access.Level;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* We treat "roles" and "permissions" in a similar way for first pass.
@@ -41,8 +39,6 @@
public class AAFAuthorizationInfo implements AuthorizationInfo {
private static final long serialVersionUID = -4805388954462426018L;
- final static Logger logger = LoggerFactory.getLogger(AAFAuthorizationInfo.class);
-
private Access access;
private Principal bait;
private List<org.onap.aaf.cadi.Permission> pond;
@@ -55,7 +51,6 @@
this.pond = pond;
sPerms=null;
oPerms=null;
-
}
public Principal principal() {
@@ -64,7 +59,7 @@
@Override
public Collection<Permission> getObjectPermissions() {
-// logger.info("AAFAuthorizationInfo.getObjectPermissions");
+ access.log(Level.DEBUG, "AAFAuthorizationInfo.getObjectPermissions");
synchronized(bait) {
if(oPerms == null) {
oPerms = new ArrayList<Permission>();
@@ -73,29 +68,25 @@
}
}
}
-
-
return oPerms;
}
@Override
public Collection<String> 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<String> getStringPermissions() {
-
-// logger.info("AAFAuthorizationInfo.getStringPermissions");
+ access.log(Level.INFO,"AAFAuthorizationInfo.getStringPermissions");
synchronized(bait) {
if(sPerms == null) {
sPerms = new ArrayList<String>();
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.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<String> realmSet;
private final Principal principal;
private List<Principal> 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.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<Class<? extends AuthenticationToken>> supports;
- private AAFLurPerm authz;
- private MapBathConverter mbc;
- private Map<String,String> idMap;
-
+ private static class Singleton {
+ private AAFCon<?> acon;
+ private AAFAuthn<?> authn;
+ private Set<Class<? extends AuthenticationToken>> supports;
+ private AAFLurPerm authz;
+ private MapBathConverter mbc;
+ private Map<String,String> 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<String,String>();
+ // Load
+ for(Entry<String, String> 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);
+ }
+ }
+ idMap.put(oldID,newID);
+
+ }
+ } catch (IOException e) {
+ access.log(e);
+ }
+ }
+ } catch (APIException | CadiException | LocatorException e) {
+ String msg = "Cannot initiate AAFRealm";
+ access.log(Level.ERROR,e,msg);
+ throw new RuntimeException(msg,e);
+ }
+ }
+ supports = new ConcurrentSkipListSet<>();
+ 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.
*
*/
- 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<String,String>();
- // Load
- for(Entry<String, String> 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);
- }
- }
- idMap.put(oldID,newID);
-
- }
- } catch (IOException e) {
- logger.info(e.getMessage(), e);
- }
- }
- } catch (APIException | CadiException | LocatorException e) {
- String msg = "Cannot initiate AAFRealm";
- logger.info(msg + " "+ e.getMessage(), e);
- throw new RuntimeException(msg,e);
- }
- }
- supports = new HashSet<Class<? extends AuthenticationToken>>();
- supports.add(UsernamePasswordToken.class);
- }
@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 @@
}
}
} 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 @@
if(ai instanceof AAFAuthenticationInfo) {
if(!((AAFAuthenticationInfo)ai).matches(atoken)) {
throw new AuthenticationException("Credentials do not match");
-
}
} else {
@@ -198,9 +285,9 @@
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 @@
}
}
List<Permission> 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.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 @@
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<String>()));
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 @@
<parent>
<groupId>org.onap.aaf.cadi.sidecar</groupId>
<artifactId>sidecar</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
</parent>
<artifactId>fproxy</artifactId>
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 @@
<parent>
<groupId>org.onap.aaf.cadi</groupId>
<artifactId>parent</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
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 @@
<parent>
<groupId>org.onap.aaf.cadi.sidecar</groupId>
<artifactId>sidecar</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
</parent>
<artifactId>rproxy</artifactId>
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 @@
<parent>
<groupId>org.onap.aaf.cadi.sidecar</groupId>
<artifactId>sidecar</artifactId>
- <version>2.1.12-SNAPSHOT</version>
+ <version>2.1.13-SNAPSHOT</version>
</parent>
<artifactId>tproxy-config</artifactId>