Prepare for release 2.1.18
[aaf/cadi.git] / shiro / src / main / java / org / onap / aaf / cadi / shiro / AAFRealm.java
index 3577c13..818ec9e 100644 (file)
@@ -23,13 +23,17 @@ package org.onap.aaf.cadi.shiro;
 import java.io.IOException;
 import java.security.Principal;
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
 
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.AuthenticationInfo;
 import org.apache.shiro.authc.AuthenticationToken;
 import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.realm.AuthorizingRealm;
 import org.apache.shiro.subject.PrincipalCollection;
 import org.onap.aaf.cadi.Access.Level;
@@ -38,101 +42,234 @@ import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.Permission;
 import org.onap.aaf.cadi.PropAccess;
 import org.onap.aaf.cadi.Symm;
+import org.onap.aaf.cadi.aaf.AAFPermission;
 import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
 import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
 import org.onap.aaf.cadi.config.Config;
 import org.onap.aaf.cadi.filter.MapBathConverter;
 import org.onap.aaf.cadi.util.CSV;
+import org.onap.aaf.cadi.util.Split;
 import org.onap.aaf.misc.env.APIException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * Note: Shiro Realm document
+ * https://shiro.apache.org/realm.html
+ */
 
 public class AAFRealm extends AuthorizingRealm {
        public static final String AAF_REALM = "AAFRealm";
+       private static final Logger logger =  LoggerFactory.getLogger(AAFRealm.class);
        
-       private PropAccess access;
-       private AAFCon<?> acon;
-       private AAFAuthn<?> authn;
-       private HashSet<Class<? extends AuthenticationToken>> supports;
-       private AAFLurPerm authz;
-       private MapBathConverter mbc;
+       // Package on purpose
+       static Singleton singleton = Singleton.singleton();
        
+       public static class Singleton {
+               public AAFCon<?> acon;
+               public AAFAuthn<?> authn;
+               public AAFLurPerm authz;
+//             private Set<Class<? extends AuthenticationToken>> supports;
+               
+               private MapBathConverter mbc;
+               private Map<String,String> idMap;
+               private Singleton() {
+                       logger.info("Creating AAFRealm.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(access,csv));
+                                                       access.log(Level.INFO, "MapBathConversion enabled with file ",csv);
+                                                       idMap = Collections.synchronizedMap(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) {
+                                                       access.log(e);
+                                               }
+                                       }
+                               } catch (APIException | CadiException | LocatorException e) {
+                                       String msg = "Cannot initiate AAFRealm";
+                                       access.log(Level.ERROR,e,msg);
+                                       throw new RuntimeException(msg,e);
+                               }
+                       }
+                       
+                       // There is only one of these.  If there are more, put back 
+//                     supports = Collections.synchronizedSet(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.error(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.error(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 WARN:
+                                               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();
+                                       }
+                               }
+                               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;
-               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.INIT,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.printf(Level.INIT, "MapBathConversion enabled with file %s\n",csv);
-                                       } catch (IOException e) {
-                                               access.log(e);
-                                       }
-                               }
-                       } catch (APIException | CadiException | LocatorException e) {
-                               String msg = "Cannot initiate AAFRealm";
-                               access.log(Level.INIT,msg,e.getMessage());
-                               throw new RuntimeException(msg,e);
-                       }
-               }
-               supports = new HashSet<Class<? extends AuthenticationToken>>();
-               supports.add(UsernamePasswordToken.class);
-       }
 
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
-               access.log(Level.DEBUG, "AAFRealm.doGetAuthenticationInfo",token);
-               
+               logger.debug("AAFRealm.doGetAuthenticationInfo");
                final UsernamePasswordToken upt = (UsernamePasswordToken)token;
-               String user = upt.getUsername();
-               String password=new String(upt.getPassword());
-               if(mbc!=null) {
+               final String user = upt.getUsername();
+               String authUser = user; 
+               final String password=new String(upt.getPassword());
+               String authPassword = password;
+               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(':');
                                        if(colon>=0) {
-                                               user = bath.substring(0, colon);
-                                               password = bath.substring(colon+1);
+                                               authUser = bath.substring(0, colon);
+                                               authPassword = bath.substring(colon+1); 
                                        }
                                }
                        } catch (IOException e) {
-                               access.log(e);
-                       } 
+                               singleton.access.log(e);
+                       }
                }
                String err;
                try {
-                       err = authn.validate(user,password);
+                       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";
-                       access.log(e, err);
+                       singleton.access.log(e,"Credential cannot be validated");
                }
                
-               if(err != null) {
-                       access.log(Level.DEBUG, err);
-                       throw new AuthenticationException(err);
-               }
-
            return new AAFAuthenticationInfo(
-                       access,
+                       singleton.access,
                        user,
                        password
            );
@@ -140,6 +277,7 @@ public class AAFRealm extends AuthorizingRealm {
 
        @Override
        protected void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)throws AuthenticationException {
+               logger.debug("AAFRealm.assertCredentialsMatch");
                if(ai instanceof AAFAuthenticationInfo) {
                        if(!((AAFAuthenticationInfo)ai).matches(atoken)) {
                                throw new AuthenticationException("Credentials do not match");
@@ -149,21 +287,33 @@ public class AAFRealm extends AuthorizingRealm {
                }
        }
 
-
        @Override
        protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
-               access.log(Level.DEBUG, "AAFRealm.doGetAuthenthorizationInfo");
+               logger.debug("AAFRealm.doGetAuthorizationInfo");
                Principal bait = (Principal)principals.getPrimaryPrincipal();
+               Principal newBait = bait;
+               if(singleton.idMap!=null) {
+                       final String newID = singleton.idMap.get(bait.getName());
+                       if(newID!=null) {
+                               singleton.access.printf(Level.INFO,"Successful authentication Translation %s to %s",bait.getName(), newID); 
+                               newBait = new Principal() {
+                                       @Override
+                                       public String getName() {
+                                               return newID;
+                                       }
+                               };
+                       }
+               }
                List<Permission> pond = new ArrayList<>();
-               authz.fishAll(bait,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());
+               // Only one was being loaded.  If more are needed uncomment the multi-class mode
+               return token instanceof UsernamePasswordToken;
+//             return singleton.supports.contains(token.getClass());
        }
 
        @Override
@@ -171,4 +321,58 @@ public class AAFRealm extends AuthorizingRealm {
                return AAF_REALM;
        }
 
+       private AAFPermission aafPerm(String permission) {
+               String[] pa = Split.splitTrim('|', permission);
+               switch(pa.length) {
+                       case 3:
+                               return new AAFPermission(null,pa[0],pa[1],pa[2]);
+                       case 4:
+                               return new AAFPermission(pa[0],pa[1],pa[2],pa[3]);
+                       default:
+                               return null;
+               }
+       }
+/*
+       @Override
+    public boolean isPermitted(PrincipalCollection principals, String permission) {
+               logger.debug("AAFRealm.isPermitted(principals,permission<String>)");
+               AAFPermission ap = aafPerm(permission);
+               if(ap!=null) {
+                       return singleton.authz.fish((Principal)principals.getPrimaryPrincipal(), ap);
+               }
+               return false;
+    }
+       
+       @Override
+       protected boolean isPermitted(org.apache.shiro.authz.Permission permission, AuthorizationInfo info) {
+               logger.debug("AAFRealm.isPermitted(shiro.Permission,AuthorizationInfo)");
+               if(info instanceof AAFAuthorizationInfo) {
+                       AAFPermission ap = aafPerm(permission.toString());
+                       if(ap!=null) {
+                               return singleton.authz.fish(((AAFAuthorizationInfo)info).principal(), ap);
+                       }
+                       return false;
+               }
+               return super.isPermitted(permission, info);
+       }
+
+       @Override
+       protected boolean[] isPermitted(List<org.apache.shiro.authz.Permission> permissions, AuthorizationInfo info) {
+               logger.debug("AAFRealm.isPermitted(List<shiro.Permission>,AuthorizationInfo)");
+               if(info instanceof AAFAuthorizationInfo) {
+                       boolean rv[] = new boolean[permissions.size()];
+                       int i=0;
+                       for(org.apache.shiro.authz.Permission sp : permissions) {
+                               AAFPermission ap = aafPerm(sp.toString());
+                               if(ap!=null) {
+                                       rv[i++]=singleton.authz.fish(((AAFAuthorizationInfo)info).principal(), ap);
+                               } else {
+                                       rv[i++]=false;
+                               }
+                       }
+                       return rv;
+               } 
+               return super.isPermitted(permissions, info);
+       }
+*/
 }