diff options
author | Instrumental <jcgmisc@stl.gathman.org> | 2018-03-26 13:49:56 -0700 |
---|---|---|
committer | Instrumental <jcgmisc@stl.gathman.org> | 2018-03-26 13:50:07 -0700 |
commit | a20accc73189d8e5454cd26049c0e6fae75da16f (patch) | |
tree | 3526110a1f65591354eff6400383512df4828903 /cadi/shiro | |
parent | ac1e1ec76e9125206be91a2f32c7104c9392dc9a (diff) |
AT&T 2.0.19 Code drop, stage 2
Issue-ID: AAF-197
Change-Id: Ifc93308f52c10d6ad82e99cd3ff5ddb900bf219a
Signed-off-by: Instrumental <jcgmisc@stl.gathman.org>
Diffstat (limited to 'cadi/shiro')
8 files changed, 671 insertions, 0 deletions
diff --git a/cadi/shiro/.gitignore b/cadi/shiro/.gitignore new file mode 100644 index 00000000..cb0cea39 --- /dev/null +++ b/cadi/shiro/.gitignore @@ -0,0 +1,5 @@ +/bin/ +/target/ +/.project +/.classpath +/.settings diff --git a/cadi/shiro/pom.xml b/cadi/shiro/pom.xml new file mode 100644 index 00000000..07ff5ab5 --- /dev/null +++ b/cadi/shiro/pom.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2017 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==================================================== + * +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.onap.aaf.cadi</groupId> + <artifactId>parent</artifactId> + <version>1.5.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <modelVersion>4.0.0</modelVersion> + <name>AAF CADI Shiro Plugin</name> + <packaging>jar</packaging> + <artifactId>aaf-cadi-shiro</artifactId> + + <developers> + <developer> + <name>Jonathan Gathman</name> + <email>jonathan.gathman@att.com</email> + <organization>ATT</organization> + <roles> + <role>Architect</role> + <role>Lead Developer</role> + </roles> + </developer> + <developer> + <name>Gabe Maurer</name> + <email>gabe.maurer@att.com</email> + <organization>ATT</organization> + <roles> + <role>Developer</role> + </roles> + </developer> + <developer> + <name>Ian Howell</name> + <email>ian.howell@att.com</email> + <organization>ATT</organization> + <roles> + <role>Developer</role> + </roles> + </developer> + </developers> + + <dependencies> + <dependency> + <groupId>org.onap.aaf.cadi</groupId> + <artifactId>aaf-cadi-aaf</artifactId> + </dependency> + <dependency> + <groupId>org.apache.shiro</groupId> + <artifactId>shiro-core</artifactId> + <version>1.3.2</version> + </dependency> + </dependencies> + <build> + <plugins /> + </build> +</project> diff --git a/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java b/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthenticationInfo.java new file mode 100644 index 00000000..a1d304bd --- /dev/null +++ b/cadi/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<hash.length;++i) { + if(hash[i]!=newhash[i]) { + return false; + } + } + return true; + } + } + } + return false; + } + + private byte[] getSaltedCred(String password) { + byte[] pbytes = password.getBytes(); + ByteBuffer bb = ByteBuffer.allocate(pbytes.length+Integer.SIZE/8); + bb.asIntBuffer().put(salt); + bb.put(password.getBytes()); + try { + return Hash.hashSHA256(bb.array()); + } catch (NoSuchAlgorithmException e) { + return new byte[0]; // should never get here + } + } +} diff --git a/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java b/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java new file mode 100644 index 00000000..90935900 --- /dev/null +++ b/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFAuthorizationInfo.java @@ -0,0 +1,94 @@ +/** + * ============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.List; + +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; + +/** + * We treate "roles" and "permissions" in a similar way for first pass. + * + * @author jg1555 + * + */ +public class AAFAuthorizationInfo implements AuthorizationInfo { + private static final long serialVersionUID = -4805388954462426018L; + private Access access; + private Principal bait; + private List<org.onap.aaf.cadi.Permission> pond; + private ArrayList<String> sPerms; + private ArrayList<Permission> oPerms; + + public AAFAuthorizationInfo(Access access, Principal bait, List<org.onap.aaf.cadi.Permission> pond) { + this.access = access; + this.bait = bait; + this.pond = pond; + sPerms=null; + oPerms=null; + } + + public Principal principal() { + return bait; + } + + @Override + public Collection<Permission> getObjectPermissions() { + access.log(Level.DEBUG, "AAFAuthorizationInfo.getObjectPermissions"); + synchronized(bait) { + if(oPerms == null) { + oPerms = new ArrayList<Permission>(); + for(final org.onap.aaf.cadi.Permission p : pond) { + oPerms.add(new AAFShiroPermission(p)); + } + } + } + return oPerms; + } + + @Override + public Collection<String> getRoles() { + access.log(Level.DEBUG, "AAFAuthorizationInfo.getRoles"); + // Until we decide to make Roles available, tie into String based permissions. + return getStringPermissions(); + } + + @Override + public Collection<String> getStringPermissions() { + access.log(Level.DEBUG, "AAFAuthorizationInfo.getStringPermissions"); + synchronized(bait) { + if(sPerms == null) { + sPerms = new ArrayList<String>(); + for(org.onap.aaf.cadi.Permission p : pond) { + sPerms.add(p.getKey()); + } + } + } + return sPerms; + } + +} diff --git a/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java b/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFPrincipalCollection.java new file mode 100644 index 00000000..145968de --- /dev/null +++ b/cadi/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<String> realmSet; + private final Principal principal; + private List<Principal> list=null; + private Set<Principal> set=null; + + static { + realmSet = new HashSet<String>(); + 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<Principal> iterator() { + return null; + } + + @Override + public List<Principal> asList() { + if(list==null) { + list = new ArrayList<Principal>(); + } + list.add(principal); + return list; + } + + @Override + public Set<Principal> asSet() { + if(set==null) { + set = new HashSet<Principal>(); + } + set.add(principal); + return set; + } + + @SuppressWarnings("unchecked") + @Override + public <T> Collection<T> byType(Class<T> cls) { + Collection<T> coll = new ArrayList<T>(); + if(cls.isAssignableFrom(Principal.class)) { + coll.add((T)principal); + } + return coll; + } + + @Override + public Collection<Principal> fromRealm(String realm) { + if(AAFRealm.AAF_REALM.equals(realm)) { + return asList(); + } else { + return new ArrayList<Principal>(); + } + } + + @Override + public Principal getPrimaryPrincipal() { + return principal; + } + + @Override + public Set<String> getRealmNames() { + return realmSet; + } + + @Override + public boolean isEmpty() { + return principal==null; + } + + @SuppressWarnings("unchecked") + @Override + public <T> T oneByType(Class<T> cls) { + if(cls.isAssignableFrom(Principal.class)) { + return (T)principal; + } + return null; + } + +} diff --git a/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java b/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFRealm.java new file mode 100644 index 00000000..006547a9 --- /dev/null +++ b/cadi/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<Class<? extends AuthenticationToken>> 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<Class<? extends AuthenticationToken>>(); + 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<Permission> pond = new ArrayList<Permission>(); + 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/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFShiroPermission.java b/cadi/shiro/src/main/java/org/onap/aaf/cadi/shiro/AAFShiroPermission.java new file mode 100644 index 00000000..a348a045 --- /dev/null +++ b/cadi/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/cadi/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java b/cadi/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java new file mode 100644 index 00000000..156e54b4 --- /dev/null +++ b/cadi/shiro/src/test/java/org/onap/aaf/cadi/shiro/test/JU_AAFRealm.java @@ -0,0 +1,92 @@ +/** + * ============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 { + + @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<String>())); + + 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); + } + + } +} |