From a7f4def785c9e169ebcb4785d7561505e47f3fc0 Mon Sep 17 00:00:00 2001 From: Sai Gandham Date: Mon, 2 Jul 2018 22:37:37 -0500 Subject: Moving Shiro modules to cadi repo Issue-ID: AAF-380 Change-Id: If1029a16958335277ff38cdbe5662b0a14ea439f Signed-off-by: Sai Gandham --- shiro/.gitignore | 4 + shiro/pom.xml | 204 +++++++++++++++++++++ .../onap/aaf/cadi/shiro/AAFAuthenticationInfo.java | 90 +++++++++ .../onap/aaf/cadi/shiro/AAFAuthorizationInfo.java | 94 ++++++++++ .../aaf/cadi/shiro/AAFPrincipalCollection.java | 125 +++++++++++++ .../java/org/onap/aaf/cadi/shiro/AAFRealm.java | 142 ++++++++++++++ .../onap/aaf/cadi/shiro/AAFShiroPermission.java | 45 +++++ .../org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java | 93 ++++++++++ 8 files changed, 797 insertions(+) create mode 100644 shiro/.gitignore create mode 100644 shiro/pom.xml create mode 100644 shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java create mode 100644 shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java create mode 100644 shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java create mode 100644 shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java create mode 100644 shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFShiroPermission.java create mode 100644 shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java (limited to 'shiro') diff --git a/shiro/.gitignore b/shiro/.gitignore new file mode 100644 index 0000000..6028f0a --- /dev/null +++ b/shiro/.gitignore @@ -0,0 +1,4 @@ +/.classpath +/.settings/ +/target/ +/.project diff --git a/shiro/pom.xml b/shiro/pom.xml new file mode 100644 index 0000000..081313b --- /dev/null +++ b/shiro/pom.xml @@ -0,0 +1,204 @@ + + + + + org.onap.aaf.cadi + cadimiscparent + 2.1.2-SNAPSHOT + .. + + + 4.0.0 + AAF CADI Shiro Plugin + jar + aaf-cadi-shiro + + + + true + 0.7.7.201606060606 + 3.2 + jacoco + + target/code-coverage/jacoco-ut.exec + target/code-coverage/jacoco-it.exec + + **/gen/**,**/generated-sources/**,**/yang-gen**,**/pax/** + https://nexus.onap.org + /content/repositories/snapshots/ + /content/repositories/releases/ + /content/repositories/staging/ + /content/sites/site/org/onap/aaf/authz/${project.artifactId}/${project.version} + + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + Sai Gandham + sai.gandham@att.com + ATT + + Developer + + + + + + + org.onap.aaf.authz + aaf-cadi-aaf + + + + + org.apache.shiro + shiro-core + 1.3.2 + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + true + + ${nexusproxy} + 176c31dfe190a + ecomp-staging + + + + org.apache.maven.plugins + maven-deploy-plugin + + false + + + + org.jacoco + jacoco-maven-plugin + + + **/gen/** + **/generated-sources/** + **/yang-gen/** + **/pax/** + + + + + pre-unit-test + + prepare-agent + + + ${project.build.directory}/code-coverage/jacoco-ut.exec + surefireArgLine + + + + post-unit-test + test + + report + + + ${project.build.directory}/code-coverage/jacoco-ut.exec + ${project.reporting.outputDirectory}/jacoco-ut + + + + pre-integration-test + pre-integration-test + + prepare-agent + + + ${project.build.directory}/code-coverage/jacoco-it.exec + failsafeArgLine + + + + post-integration-test + post-integration-test + + report + + + ${project.build.directory}/code-coverage/jacoco-it.exec + ${project.reporting.outputDirectory}/jacoco-it + + + + + + + + + + + ecomp-releases + AAF Release Repository + ${nexusproxy}${releaseNexusPath} + + + ecomp-snapshots + AAF Snapshot Repository + ${nexusproxy}${snapshotNexusPath} + + + ecomp-site + dav:${nexusproxy}${sitePath} + + + 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 new file mode 100644 index 0000000..a1d304b --- /dev/null +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed 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. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.cadi.shiro; + +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +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.Hash; +import org.onap.aaf.cadi.Access.Level; + +public class AAFAuthenticationInfo implements AuthenticationInfo { + private static final long serialVersionUID = -1502704556864321020L; + // We assume that Shiro is doing Memory Only, and this salt is not needed cross process + private final static int salt = new SecureRandom().nextInt(); + + private final AAFPrincipalCollection apc; + private final byte[] hash; + private Access access; + + public AAFAuthenticationInfo(Access access, String username, String password) { + this.access = access; + apc = new AAFPrincipalCollection(username); + hash = getSaltedCred(password); + } + @Override + public byte[] getCredentials() { + access.log(Level.DEBUG, "AAFAuthenticationInfo.getCredentials"); + return hash; + } + + @Override + public PrincipalCollection getPrincipals() { + access.log(Level.DEBUG, "AAFAuthenticationInfo.getPrincipals"); + return apc; + } + + public boolean matches(AuthenticationToken atoken) { + if(atoken instanceof UsernamePasswordToken) { + UsernamePasswordToken upt = (UsernamePasswordToken)atoken; + if(apc.getPrimaryPrincipal().getName().equals(upt.getPrincipal())) { + byte[] newhash = getSaltedCred(new String(upt.getPassword())); + if(newhash.length==hash.length) { + for(int i=0;i pond; + private ArrayList sPerms; + private ArrayList oPerms; + + public AAFAuthorizationInfo(Access access, Principal bait, List pond) { + this.access = access; + this.bait = bait; + this.pond = pond; + sPerms=null; + oPerms=null; + } + + public Principal principal() { + return bait; + } + + @Override + public Collection getObjectPermissions() { + access.log(Level.DEBUG, "AAFAuthorizationInfo.getObjectPermissions"); + synchronized(bait) { + if(oPerms == null) { + oPerms = new ArrayList(); + for(final org.onap.aaf.cadi.Permission p : pond) { + oPerms.add(new AAFShiroPermission(p)); + } + } + } + return oPerms; + } + + @Override + public Collection getRoles() { + access.log(Level.DEBUG, "AAFAuthorizationInfo.getRoles"); + // Until we decide to make Roles available, tie into String based permissions. + return getStringPermissions(); + } + + @Override + public Collection getStringPermissions() { + 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()); + } + } + } + return sPerms; + } + +} 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 new file mode 100644 index 0000000..145968d --- /dev/null +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java @@ -0,0 +1,125 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed 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. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.cadi.shiro; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.shiro.subject.PrincipalCollection; + +public class AAFPrincipalCollection implements PrincipalCollection { + private static final long serialVersionUID = 558246013419818831L; + private static final Set realmSet; + private final Principal principal; + private List list=null; + private Set set=null; + + static { + realmSet = new HashSet(); + realmSet.add(AAFRealm.AAF_REALM); + } + + public AAFPrincipalCollection(Principal p) { + principal = p; + } + + public AAFPrincipalCollection(final String principalName) { + principal = new Principal() { + private final String name = principalName; + @Override + public String getName() { + return name; + } + }; + } + + @Override + public Iterator iterator() { + return null; + } + + @Override + public List asList() { + if(list==null) { + list = new ArrayList(); + } + list.add(principal); + return list; + } + + @Override + public Set asSet() { + if(set==null) { + set = new HashSet(); + } + set.add(principal); + return set; + } + + @SuppressWarnings("unchecked") + @Override + public Collection byType(Class cls) { + Collection coll = new ArrayList(); + if(cls.isAssignableFrom(Principal.class)) { + coll.add((T)principal); + } + return coll; + } + + @Override + public Collection fromRealm(String realm) { + if(AAFRealm.AAF_REALM.equals(realm)) { + return asList(); + } else { + return new ArrayList(); + } + } + + @Override + public Principal getPrimaryPrincipal() { + return principal; + } + + @Override + public Set getRealmNames() { + return realmSet; + } + + @Override + public boolean isEmpty() { + return principal==null; + } + + @SuppressWarnings("unchecked") + @Override + public T oneByType(Class cls) { + if(cls.isAssignableFrom(Principal.class)) { + return (T)principal; + } + return 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 new file mode 100644 index 0000000..006547a --- /dev/null +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java @@ -0,0 +1,142 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed 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. + * ============LICENSE_END==================================================== + * + */ +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.List; + +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.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.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.misc.env.APIException; + +public class AAFRealm extends AuthorizingRealm { + public static final String AAF_REALM = "AAFRealm"; + + private PropAccess access; + private AAFCon acon; + private AAFAuthn authn; + private HashSet> supports; + private AAFLurPerm authz; + + + /** + * + * 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 + 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); + } 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>(); + supports.add(UsernamePasswordToken.class); + } + + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + access.log(Level.DEBUG, "AAFRealm.doGetAuthenticationInfo",token); + + final UsernamePasswordToken upt = (UsernamePasswordToken)token; + String password=new String(upt.getPassword()); + String err; + try { + err = authn.validate(upt.getUsername(),password); + } catch (IOException|CadiException e) { + err = "Credential cannot be validated"; + access.log(e, err); + } + + if(err != null) { + access.log(Level.DEBUG, err); + throw new AuthenticationException(err); + } + + return new AAFAuthenticationInfo( + access, + upt.getUsername(), + password + ); + } + + @Override + protected void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)throws AuthenticationException { + if(ai instanceof AAFAuthenticationInfo) { + if(!((AAFAuthenticationInfo)ai).matches(atoken)) { + throw new AuthenticationException("Credentials do not match"); + } + } else { + throw new AuthenticationException("AuthenticationInfo is not an AAFAuthenticationInfo"); + } + } + + + @Override + protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + access.log(Level.DEBUG, "AAFRealm.doGetAuthenthorizationInfo"); + Principal bait = (Principal)principals.getPrimaryPrincipal(); + List pond = new ArrayList(); + authz.fishAll(bait,pond); + + return new AAFAuthorizationInfo(access,bait,pond); + + } + + @Override + public boolean supports(AuthenticationToken token) { + return supports.contains(token.getClass()); + } + + @Override + public String getName() { + return AAF_REALM; + } + +} diff --git a/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFShiroPermission.java b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFShiroPermission.java new file mode 100644 index 0000000..a348a04 --- /dev/null +++ b/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFShiroPermission.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed 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. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.cadi.shiro; + +import org.apache.shiro.authz.Permission; + +public class AAFShiroPermission implements Permission { + private org.onap.aaf.cadi.Permission perm; + public AAFShiroPermission(org.onap.aaf.cadi.Permission perm) { + this.perm = perm; + } + @Override + public boolean implies(Permission sp) { + if(sp instanceof AAFShiroPermission) { + if(perm.match(((AAFShiroPermission)sp).perm)){ + return true; + } + } + return false; + } + + @Override + public String toString() { + return perm.toString(); + } + +} 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 new file mode 100644 index 0000000..add449c --- /dev/null +++ b/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java @@ -0,0 +1,93 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed 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. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.cadi.shiro.test; + +import java.util.ArrayList; + +import org.apache.shiro.authc.AuthenticationInfo; +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 { + + // TODO: Ian - fix this test + // @Test + // public void test() { + // // NOTE This is a live test. This JUnit needs to be built with "Mock" + // try { + // System.setProperty(Config.CADI_PROP_FILES, "/opt/app/osaaf/etc/org.osaaf.common.props"); + // TestAAFRealm ar = new TestAAFRealm(); + + // UsernamePasswordToken upt = new UsernamePasswordToken("jonathan@people.osaaf.org", "new2You!"); + // AuthenticationInfo ani = ar.authn(upt); + + // AuthorizationInfo azi = ar.authz(ani.getPrincipals()); + // // Change this to something YOU have, Sai... + + // testAPerm(true,azi,"org.access","something","*"); + // testAPerm(false,azi,"org.accessX","something","*"); + // } catch (Throwable t) { + // t.printStackTrace(); + // Assert.fail(); + // } + // } + + private void testAPerm(boolean expect,AuthorizationInfo azi, String type, String instance, String action) { + + AAFShiroPermission testPerm = new AAFShiroPermission(new AAFPermission(type,instance,action,new ArrayList())); + + boolean any = false; + for(Permission p : azi.getObjectPermissions()) { + if(p.implies(testPerm)) { + any = true; + } + } + if(expect) { + Assert.assertTrue(any); + } else { + Assert.assertFalse(any); + } + + + } + + /** + * Note, have to create a derived class, because "doGet"... are protected + */ + private class TestAAFRealm extends AAFRealm { + public AuthenticationInfo authn(UsernamePasswordToken upt) { + return doGetAuthenticationInfo(upt); + } + public AuthorizationInfo authz(PrincipalCollection pc) { + return doGetAuthorizationInfo(pc); + } + + } +} -- cgit 1.2.3-korg