From 05e395c6ca27d4fcf6871e9c249c76c8ce61264e Mon Sep 17 00:00:00 2001 From: GANDHAM Date: Tue, 15 Oct 2019 09:16:11 -0500 Subject: Update shiro bundle & fix sidecar Issue-ID: AAF-111 Change-Id: Id22107054dc0081dc4c803c89f1d75713a083055 Signed-off-by: GANDHAM --- pom.xml | 2 +- shiro-osgi-bundle/pom.xml | 2 +- shiro/pom.xml | 2 +- .../onap/aaf/cadi/shiro/AAFAuthorizationInfo.java | 33 +++-- .../java/org/onap/aaf/cadi/shiro/AAFRealm.java | 85 ++++++++++-- .../onap/aaf/cadi/shiro/test/StandAloneTest.java | 147 +++++++++++++++++++++ sidecar/fproxy/pom.xml | 2 +- sidecar/pom.xml | 2 +- sidecar/rproxy/pom.xml | 2 +- sidecar/tproxy-config/pom.xml | 2 +- version.properties | 2 +- 11 files changed, 251 insertions(+), 30 deletions(-) create mode 100644 shiro/src/test/java/org/onap/aaf/cadi/shiro/test/StandAloneTest.java diff --git a/pom.xml b/pom.xml index 0f5b176..b20804f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.onap.aaf.cadi parent - 2.1.14-SNAPSHOT + 2.1.16-SNAPSHOT CADI Plugins Parent pom diff --git a/shiro-osgi-bundle/pom.xml b/shiro-osgi-bundle/pom.xml index fae026d..c7e0a16 100644 --- a/shiro-osgi-bundle/pom.xml +++ b/shiro-osgi-bundle/pom.xml @@ -22,7 +22,7 @@ org.onap.aaf.cadi parent - 2.1.14-SNAPSHOT + 2.1.16-SNAPSHOT .. diff --git a/shiro/pom.xml b/shiro/pom.xml index 81e9f5e..ab3f2db 100644 --- a/shiro/pom.xml +++ b/shiro/pom.xml @@ -22,7 +22,7 @@ org.onap.aaf.cadi parent - 2.1.14-SNAPSHOT + 2.1.16-SNAPSHOT .. 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 0035626..ac62778 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,6 +29,7 @@ import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.Permission; import org.onap.aaf.cadi.Access; import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.aaf.AAFPermission; /** * We treat "roles" and "permissions" in a similar way for first pass. @@ -41,16 +42,17 @@ public class AAFAuthorizationInfo implements AuthorizationInfo { private Access access; private Principal bait; - private List pond; - private ArrayList sPerms; - private ArrayList oPerms; + // Use these to save conversions + private List cPerms; + private List oPerms; + private List sPerms; - public AAFAuthorizationInfo(Access access, Principal bait, List pond) { + public AAFAuthorizationInfo(Access access, Principal bait) { this.access = access; this.bait = bait; - this.pond = pond; - sPerms=null; + cPerms=null; oPerms=null; + sPerms=null; } public Principal principal() { @@ -62,8 +64,12 @@ public class AAFAuthorizationInfo implements AuthorizationInfo { access.log(Level.DEBUG, "AAFAuthorizationInfo.getObjectPermissions"); synchronized(bait) { if(oPerms == null) { - oPerms = new ArrayList(); - for(final org.onap.aaf.cadi.Permission p : pond) { + oPerms = new ArrayList<>(); + if(cPerms==null) { + cPerms = new ArrayList<>(); + AAFRealm.singleton.authz.fishAll(bait, cPerms); + } + for(final org.onap.aaf.cadi.Permission p : cPerms) { oPerms.add(new AAFShiroPermission(p)); } } @@ -83,10 +89,13 @@ public class AAFAuthorizationInfo implements AuthorizationInfo { access.log(Level.DEBUG,"AAFAuthorizationInfo.getStringPermissions"); synchronized(bait) { if(sPerms == null) { - sPerms = new ArrayList(); - for(org.onap.aaf.cadi.Permission p : pond) { - sPerms.add(p.getKey().replace("|",":")); - access.printf(Level.INFO,"%s has %s",bait.getName(),p.getKey()); + sPerms = new ArrayList<>(); + if(cPerms==null) { + cPerms = new ArrayList<>(); + AAFRealm.singleton.authz.fishAll(bait,cPerms); + } + for(final org.onap.aaf.cadi.Permission p : cPerms) { + sPerms.add(p.getKey()); } } } 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 eb8bc60..d213b01 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 @@ -22,7 +22,6 @@ package org.onap.aaf.cadi.shiro; import java.io.IOException; import java.security.Principal; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -33,37 +32,48 @@ 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; import org.onap.aaf.cadi.CadiException; 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 static Singleton singleton = Singleton.singleton(); - private static class Singleton { - private AAFCon acon; - private AAFAuthn authn; + // Package on purpose + static Singleton singleton = Singleton.singleton(); + + public static class Singleton { + public AAFCon acon; + public AAFAuthn authn; + public AAFLurPerm authz; // private Set> supports; - private AAFLurPerm authz; + private MapBathConverter mbc; private Map idMap; private Singleton() { + logger.info("Creating AAFRealm.Singleton"); mbc = null; idMap = null; String cadi_prop_files = access.getProperty(Config.CADI_PROP_FILES); @@ -222,6 +232,7 @@ public class AAFRealm extends AuthorizingRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + logger.debug("AAFRealm.doGetAuthenticationInfo"); final UsernamePasswordToken upt = (UsernamePasswordToken)token; final String user = upt.getUsername(); String authUser = user; @@ -264,6 +275,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"); @@ -275,6 +287,7 @@ public class AAFRealm extends AuthorizingRealm { @Override protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + logger.debug("AAFRealm.doGetAuthorizationInfo"); Principal bait = (Principal)principals.getPrimaryPrincipal(); Principal newBait = bait; if(singleton.idMap!=null) { @@ -289,9 +302,7 @@ public class AAFRealm extends AuthorizingRealm { }; } } - List pond = new ArrayList<>(); - singleton.authz.fishAll(newBait,pond); - return new AAFAuthorizationInfo(singleton.access,bait,pond); + return new AAFAuthorizationInfo(singleton.access,newBait); } @Override @@ -306,4 +317,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)"); + 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 permissions, AuthorizationInfo info) { + logger.debug("AAFRealm.isPermitted(List,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); + } + } diff --git a/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/StandAloneTest.java b/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/StandAloneTest.java new file mode 100644 index 0000000..da026dd --- /dev/null +++ b/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/StandAloneTest.java @@ -0,0 +1,147 @@ + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.onap.aaf.cadi.shiro.test; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.IncorrectCredentialsException; +import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.authc.UnknownAccountException; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.config.Ini; +import org.apache.shiro.config.Ini.Section; +import org.apache.shiro.config.IniSecurityManagerFactory; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.session.Session; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.util.Factory; +import org.onap.aaf.cadi.shiro.AAFRealm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StandAloneTest { + + /** + * Simple Quickstart application, from Shiro, showing how to use Shiro's API. + * + * @since 0.9 RC2 + */ + private static final transient Logger log = LoggerFactory.getLogger(StandAloneTest.class); + + public static void main(String[] args) { + if(args.length<3) { + System.out.println("Usage: java StandAloneTest fqi ns passwd"); + } else { + + String user = args[0]; + String ns = args[1]; + String pass = args[2]; + + // The easiest way to create a Shiro SecurityManager with configured + // realms, users, roles and permissions is to use the simple INI config. + // We'll do that by using a factory that can ingest a .ini file and + // return a SecurityManager instance: + + Ini ini = new Ini(); + Section section = ini.addSection("main"); + section.put("aafRealm", "org.onap.aaf.cadi.shiro.AAFRealm"); + section.put("securityManager.realms","$aafRealm"); + /* + * Equivalent to shiro.ini + * + * [main] + * aafRealm=org.onap.aaf.cadi.shiro.AAFRealm + * securityManager.realms=$aafRealm + */ + Factory factory = new IniSecurityManagerFactory(ini); + + // Alternative: Use the shiro.ini file at the root of the classpath + // (file: and url: prefixes load from files and urls respectively): + // Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini"); + SecurityManager securityManager = factory.getInstance(); + + // for this simple example quickstart, make the SecurityManager + // accessible as a JVM singleton. Most applications wouldn't do this + // and instead rely on their container configuration or web.xml for + // webapps. That is outside the scope of this simple quickstart, so + // we'll just do the bare minimum so you can continue to get a feel + // for things. + SecurityUtils.setSecurityManager(securityManager); + + // Now that a simple Shiro environment is set up, let's see what you can do: + + // get the currently executing user: + Subject currentUser = SecurityUtils.getSubject(); + + // Do some stuff with a Session (no need for a web or EJB container!!!) + Session session = currentUser.getSession(); + session.setAttribute("someKey", "aValue"); + String value = (String) session.getAttribute("someKey"); + if (value.equals("aValue")) { + log.info("Retrieved the correct value! [" + value + "]"); + } + + for(int i=0;i<3;++i) { + // let's login the current user so we can check against roles and permissions: + if (!currentUser.isAuthenticated()) { + UsernamePasswordToken token = new UsernamePasswordToken(user,pass); + // UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); + token.setRememberMe(true); + try { + currentUser.login(token); + } catch (UnknownAccountException uae) { + log.info("There is no user with username of " + token.getPrincipal()); + } catch (IncorrectCredentialsException ice) { + log.info("Password for account " + token.getPrincipal() + " was incorrect!"); + } catch (LockedAccountException lae) { + log.info("The account for username " + token.getPrincipal() + " is locked. " + + "Please contact your administrator to unlock it."); + } + // ... catch more exceptions here (maybe custom ones specific to your application? + catch (AuthenticationException ae) { + //unexpected condition? error? + // AT&T doesn't allow specifics + log.info(ae.getMessage()); + } + } + + // Uncomment following to test calls after Cache is Cleared + // AAFRealm.Singleton.singleton().authz.clearAll(); + + //say who they are: + //print their identifying principal (in this case, a username): + log.info("User [" + currentUser.getPrincipal() + "] logged in successfully."); + + //test NS Write Access + String msg = String.format("You are %s in role %s.admin", + currentUser.hasRole(ns+".admin")?"":"not", + ns); + log.info(msg); + + //test a typed permission (not instance-level) + msg = String.format("You %s have write access into NS %s", + currentUser.isPermitted(ns+".access|*|*")?"":"do not", + ns); + log.info(msg); + } + //all done - log out! + currentUser.logout(); + } + } +} diff --git a/sidecar/fproxy/pom.xml b/sidecar/fproxy/pom.xml index a84ee98..5bb4445 100644 --- a/sidecar/fproxy/pom.xml +++ b/sidecar/fproxy/pom.xml @@ -24,7 +24,7 @@ org.onap.aaf.cadi.sidecar sidecar - 2.1.14-SNAPSHOT + 2.1.16-SNAPSHOT diff --git a/sidecar/pom.xml b/sidecar/pom.xml index b0df6f2..3dca6f1 100644 --- a/sidecar/pom.xml +++ b/sidecar/pom.xml @@ -20,7 +20,7 @@ org.onap.aaf.cadi parent - 2.1.14-SNAPSHOT + 2.1.16-SNAPSHOT .. 4.0.0 diff --git a/sidecar/rproxy/pom.xml b/sidecar/rproxy/pom.xml index 8e4ac38..1e5d5c2 100644 --- a/sidecar/rproxy/pom.xml +++ b/sidecar/rproxy/pom.xml @@ -24,7 +24,7 @@ org.onap.aaf.cadi.sidecar sidecar - 2.1.14-SNAPSHOT + 2.1.16-SNAPSHOT diff --git a/sidecar/tproxy-config/pom.xml b/sidecar/tproxy-config/pom.xml index d734322..1321955 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.14-SNAPSHOT + 2.1.16-SNAPSHOT tproxy-config diff --git a/version.properties b/version.properties index 9b2b66e..5e52b35 100644 --- a/version.properties +++ b/version.properties @@ -28,7 +28,7 @@ # This TAG 2.1.13 is here to help remember to change this file. Keep it up to date with the following "real" entries: major=2 minor=1 -patch=13 +patch=16 base_version=${major}.${minor}.${patch} -- cgit 1.2.3-korg