GEODE-1571: have auth-init accept either a constructor or a static factory method.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/d200d708 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/d200d708 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/d200d708 Branch: refs/heads/master Commit: d200d70845649d14b71dab67ee17826017194e80 Parents: 8341267 Author: Jinmei Liao <[email protected]> Authored: Wed Jul 13 16:30:21 2016 -0700 Committer: Jinmei Liao <[email protected]> Committed: Mon Jul 18 10:04:44 2016 -0700 ---------------------------------------------------------------------- .../membership/gms/auth/GMSAuthenticator.java | 24 +++---- .../internal/cache/tier/sockets/HandShake.java | 20 +++--- .../internal/security/GeodeSecurityUtil.java | 66 +++++++++++++++++--- .../security/shiro/CustomAuthRealm.java | 6 +- .../gemfire/security/AuthInitialize.java | 12 +++- .../apache/geode/security/GeodePermission.java | 21 +++++++ .../apache/geode/security/PostProcessor.java | 2 +- .../security/templates/SamplePostProcessor.java | 16 ++++- .../security/GeodeSecurityUtilTest.java | 41 ++++++++++-- 9 files changed, 163 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java b/geode-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java index b82fdb1..f16a722 100755 --- a/geode-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java @@ -16,6 +16,14 @@ */ package com.gemstone.gemfire.distributed.internal.membership.gms.auth; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.*; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.*; + +import java.lang.reflect.Method; +import java.security.Principal; +import java.util.Properties; +import java.util.Set; + import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.distributed.DistributedMember; import com.gemstone.gemfire.distributed.internal.DistributionConfig; @@ -26,19 +34,12 @@ import com.gemstone.gemfire.distributed.internal.membership.gms.interfaces.Authe import com.gemstone.gemfire.internal.ClassLoadUtil; import com.gemstone.gemfire.internal.i18n.LocalizedStrings; import com.gemstone.gemfire.internal.logging.InternalLogWriter; +import com.gemstone.gemfire.internal.security.GeodeSecurityUtil; import com.gemstone.gemfire.security.AuthInitialize; import com.gemstone.gemfire.security.AuthenticationFailedException; import com.gemstone.gemfire.security.AuthenticationRequiredException; import com.gemstone.gemfire.security.GemFireSecurityException; -import java.lang.reflect.Method; -import java.security.Principal; -import java.util.Properties; -import java.util.Set; - -import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.*; -import static com.gemstone.gemfire.distributed.ConfigurationProperties.*; - // static messages public class GMSAuthenticator implements Authenticator { @@ -195,12 +196,7 @@ public class GMSAuthenticator implements Authenticator { try { if (authMethod != null && authMethod.length() > 0) { - Method getter = ClassLoadUtil.methodFromName(authMethod); - AuthInitialize auth = (AuthInitialize)getter.invoke(null, (Object[]) null); - if (auth == null) { - throw new AuthenticationRequiredException(AUTH_FAILED_TO_ACQUIRE_AUTHINITIALIZE_INSTANCE.toLocalizedString(authMethod)); - } - + AuthInitialize auth = GeodeSecurityUtil.getObjectOfType(authMethod, AuthInitialize.class); try { LogWriter logWriter = services.getLogWriter(); LogWriter securityLogWriter = services.getSecurityLogWriter(); http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/com/gemstone/gemfire/internal/cache/tier/sockets/HandShake.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/cache/tier/sockets/HandShake.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/cache/tier/sockets/HandShake.java index a2951f5..c8aeacc 100755 --- a/geode-core/src/main/java/com/gemstone/gemfire/internal/cache/tier/sockets/HandShake.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/cache/tier/sockets/HandShake.java @@ -1599,19 +1599,13 @@ public class HandShake implements ClientHandShake Properties credentials = null; try { if (authInitMethod != null && authInitMethod.length() > 0) { - Method instanceGetter = ClassLoadUtil.methodFromName(authInitMethod); - AuthInitialize auth = (AuthInitialize)instanceGetter.invoke(null, - (Object[])null); - if (auth != null) { - auth.init(logWriter, - securityLogWriter); - try { - credentials = auth.getCredentials(securityProperties, server, - isPeer); - } - finally { - auth.close(); - } + AuthInitialize auth = GeodeSecurityUtil.getObjectOfType(authInitMethod, AuthInitialize.class); + auth.init(logWriter, securityLogWriter); + try { + credentials = auth.getCredentials(securityProperties, server, isPeer); + } + finally { + auth.close(); } } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtil.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtil.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtil.java index 8707a78..2962240 100644 --- a/geode-core/src/main/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtil.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtil.java @@ -19,13 +19,20 @@ package com.gemstone.gemfire.internal.security; import static com.gemstone.gemfire.distributed.ConfigurationProperties.*; +import java.lang.reflect.Method; import java.security.AccessController; import java.security.Principal; import java.util.Properties; import java.util.Set; import java.util.concurrent.Callable; +import org.apache.commons.lang.NullArgumentException; import org.apache.commons.lang.StringUtils; +import org.apache.geode.security.GeodePermission; +import org.apache.geode.security.GeodePermission.Operation; +import org.apache.geode.security.GeodePermission.Resource; +import org.apache.geode.security.PostProcessor; +import org.apache.geode.security.SecurityManager; import org.apache.logging.log4j.Logger; import org.apache.shiro.SecurityUtils; import org.apache.shiro.ShiroException; @@ -47,12 +54,7 @@ import com.gemstone.gemfire.internal.security.shiro.ShiroPrincipal; import com.gemstone.gemfire.management.internal.security.ResourceOperation; import com.gemstone.gemfire.security.AuthenticationFailedException; import com.gemstone.gemfire.security.GemFireSecurityException; -import org.apache.geode.security.GeodePermission; -import org.apache.geode.security.GeodePermission.Operation; -import org.apache.geode.security.GeodePermission.Resource; import com.gemstone.gemfire.security.NotAuthorizedException; -import org.apache.geode.security.PostProcessor; -import org.apache.geode.security.SecurityManager; public class GeodeSecurityUtil { @@ -310,7 +312,7 @@ public class GeodeSecurityUtil { // only set up shiro realm if user has implemented SecurityManager else if (!StringUtils.isBlank(securityConfig)) { - securityManager = getObjectOfType(securityConfig, SecurityManager.class); + securityManager = getObjectOfTypeFromClassName(securityConfig, SecurityManager.class); securityManager.init(securityProps); Realm realm = new CustomAuthRealm(securityManager); org.apache.shiro.mgt.SecurityManager shiroManager = new DefaultSecurityManager(realm); @@ -323,7 +325,7 @@ public class GeodeSecurityUtil { // this initializes the post processor String customPostProcessor = securityProps.getProperty(SECURITY_POST_PROCESSOR); if( !StringUtils.isBlank(customPostProcessor)) { - postProcessor = getObjectOfType(customPostProcessor, PostProcessor.class); + postProcessor = getObjectOfTypeFromClassName(customPostProcessor, PostProcessor.class); postProcessor.init(securityProps); } else{ @@ -367,7 +369,14 @@ public class GeodeSecurityUtil { } - public static <T> T getObjectOfType(String className, Class<T> expectedClazz) { + /** + * this method would never return null, it either throws an exception or returns an object + * @param className + * @param expectedClazz + * @param <T> + * @return + */ + public static <T> T getObjectOfTypeFromClassName(String className, Class<T> expectedClazz) { Class actualClass = null; try { actualClass = ClassLoadUtil.classFromName(className); @@ -389,6 +398,47 @@ public class GeodeSecurityUtil { return actualObject; } + /** + * this method would never return null, it either throws an exception or returns an object + * @param factoryMethodName + * @param expectedClazz + * @param <T> + * @return + */ + public static <T> T getObjectOfTypeFromFactoryMethod(String factoryMethodName, Class<T> expectedClazz){ + try { + Method factoryMethod = ClassLoadUtil.methodFromName(factoryMethodName); + T actualObject = (T)factoryMethod.invoke(null, (Object[])null); + + if(actualObject == null){ + throw new NullArgumentException("Factory method "+ factoryMethodName + " should not return null."); + } + + return actualObject; + } catch (Exception e) { + throw new GemFireSecurityException(e.toString(), e); + } + } + + /** + * this method would never return null, it either throws an exception or returns an object + * @param classOrMethod + * @param expectedClazz + * @param <T> + * @return an object of type expectedClazz. This method would never return null. It either returns an non-null + * object or throws exception. + */ + public static <T> T getObjectOfType(String classOrMethod, Class<T> expectedClazz) { + T object = null; + try{ + object = getObjectOfTypeFromClassName(classOrMethod, expectedClazz); + } + catch (Exception e){ + object = getObjectOfTypeFromFactoryMethod(classOrMethod, expectedClazz); + } + return object; + } + public static SecurityManager getSecurityManager(){ return securityManager; } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/com/gemstone/gemfire/internal/security/shiro/CustomAuthRealm.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/security/shiro/CustomAuthRealm.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/security/shiro/CustomAuthRealm.java index 3d6275b..db07fe0 100644 --- a/geode-core/src/main/java/com/gemstone/gemfire/internal/security/shiro/CustomAuthRealm.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/security/shiro/CustomAuthRealm.java @@ -19,6 +19,8 @@ package com.gemstone.gemfire.internal.security.shiro; import java.security.Principal; import java.util.Properties; +import org.apache.geode.security.GeodePermission; +import org.apache.geode.security.SecurityManager; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; @@ -31,8 +33,6 @@ import org.apache.shiro.subject.PrincipalCollection; import com.gemstone.gemfire.internal.security.GeodeSecurityUtil; import com.gemstone.gemfire.management.internal.security.ResourceConstants; -import org.apache.geode.security.SecurityManager; -import org.apache.geode.security.GeodePermission; public class CustomAuthRealm extends AuthorizingRealm{ @@ -45,7 +45,7 @@ public class CustomAuthRealm extends AuthorizingRealm{ } public CustomAuthRealm (String authenticatorFactory) { - this.securityManager = GeodeSecurityUtil.getObjectOfType(authenticatorFactory, SecurityManager.class); + this.securityManager = GeodeSecurityUtil.getObjectOfTypeFromClassName(authenticatorFactory, SecurityManager.class); } @Override http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/com/gemstone/gemfire/security/AuthInitialize.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/security/AuthInitialize.java b/geode-core/src/main/java/com/gemstone/gemfire/security/AuthInitialize.java index 400c665..e92772b 100644 --- a/geode-core/src/main/java/com/gemstone/gemfire/security/AuthInitialize.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/security/AuthInitialize.java @@ -23,6 +23,7 @@ import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.cache.CacheCallback; import com.gemstone.gemfire.distributed.DistributedMember; import com.gemstone.gemfire.distributed.DistributedSystem; +import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; // TODO Add example usage of this interface and configuration details /** @@ -49,11 +50,21 @@ public interface AuthInitialize extends CacheCallback { * * @throws AuthenticationFailedException * if some exception occurs during the initialization + * + * @deprecated since Geode 1.0, use init() */ public void init(LogWriter systemLogger, LogWriter securityLogger) throws AuthenticationFailedException; /** + * @since Geode 1.0. implement this method instead of init with logwriters. + * Implementation should use log4j instead of these loggers. + */ + default public void init(){ + GemFireCacheImpl cache = GemFireCacheImpl.getInstance(); + init(cache.getLogger(), cache.getSecurityLogger()); + } + /** * Initialize with the given set of security properties and return the * credentials for the peer/client as properties. * @@ -83,5 +94,4 @@ public interface AuthInitialize extends CacheCallback { public Properties getCredentials(Properties securityProps, DistributedMember server, boolean isPeer) throws AuthenticationFailedException; - } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/org/apache/geode/security/GeodePermission.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/security/GeodePermission.java b/geode-core/src/main/java/org/apache/geode/security/GeodePermission.java index 866b14e..0a777a8 100644 --- a/geode-core/src/main/java/org/apache/geode/security/GeodePermission.java +++ b/geode-core/src/main/java/org/apache/geode/security/GeodePermission.java @@ -19,6 +19,11 @@ package org.apache.geode.security; import org.apache.shiro.authz.permission.WildcardPermission; +/** + * GeodePermission defines the resource, the operation, the region and the key involved in the action to be authorized. + * + * It is passed to the SecurityManager for the implementation to decide whether to grant a user this permission or not. + */ public class GeodePermission extends WildcardPermission { public static String ALL_REGIONS = "*"; @@ -37,18 +42,34 @@ public class GeodePermission extends WildcardPermission { READ } + /** + * Returns the resource, could be either DATA or CLUSTER + * @return + */ public Resource getResource() { return resource; } + /** + * Returns the operation, could be either MANAGE, WRITE or READ + * @return + */ public Operation getOperation() { return operation; } + /** + * returns the regionName, could be "*", meaning all regions + * @return + */ public String getRegionName() { return regionName; } + /** + * returns the key, could be "*" meaning all keys. + * @return + */ public String getKey() { return key; } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/org/apache/geode/security/PostProcessor.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/security/PostProcessor.java b/geode-core/src/main/java/org/apache/geode/security/PostProcessor.java index 0f13b47..1a0e5de 100644 --- a/geode-core/src/main/java/org/apache/geode/security/PostProcessor.java +++ b/geode-core/src/main/java/org/apache/geode/security/PostProcessor.java @@ -44,7 +44,7 @@ public interface PostProcessor { * @param key * the key of the value that's been accessed. This could be null. * @param value - * the value, this could be null. + * the original value. The orginal value could be null as well. * @return * the value that will be returned to the requester */ http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/main/java/org/apache/geode/security/templates/SamplePostProcessor.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/security/templates/SamplePostProcessor.java b/geode-core/src/main/java/org/apache/geode/security/templates/SamplePostProcessor.java index 7e078da..8f61db7 100644 --- a/geode-core/src/main/java/org/apache/geode/security/templates/SamplePostProcessor.java +++ b/geode-core/src/main/java/org/apache/geode/security/templates/SamplePostProcessor.java @@ -22,14 +22,28 @@ import java.util.Properties; import org.apache.geode.security.PostProcessor; +/** + * This is example that implements PostProcessor + */ public class SamplePostProcessor implements PostProcessor{ - public static String MASK = "****"; @Override public void init(final Properties securityProps) { } + /** + * this simply modifies the value with all the parameter values + * @param principal + * The principal that's accessing the value + * @param regionName + * The region that's been accessed. This could be null. + * @param key + * the key of the value that's been accessed. This could be null. + * @param value + * the value, this could be null. + * @return + */ @Override public Object processRegionValue(Principal principal, String regionName, http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d200d708/geode-core/src/test/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtilTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtilTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtilTest.java index d1dd466..6c1f1f2 100644 --- a/geode-core/src/test/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtilTest.java +++ b/geode-core/src/test/java/com/gemstone/gemfire/internal/security/GeodeSecurityUtilTest.java @@ -18,22 +18,23 @@ package com.gemstone.gemfire.internal.security; import static org.assertj.core.api.Java6Assertions.*; +import static org.junit.Assert.assertNotNull; import org.junit.Test; import org.junit.experimental.categories.Category; import com.gemstone.gemfire.security.GemFireSecurityException; -import com.gemstone.gemfire.test.junit.categories.SecurityTest; import com.gemstone.gemfire.test.junit.categories.UnitTest; -@Category({ UnitTest.class, SecurityTest.class }) +@Category(UnitTest.class) public class GeodeSecurityUtilTest { @Test - public void testGetObject(){ + public void testGetObjectFromConstructor(){ String string = GeodeSecurityUtil.getObjectOfType(String.class.getName(), String.class); - + assertNotNull(string); CharSequence charSequence = GeodeSecurityUtil.getObjectOfType(String.class.getName(), CharSequence.class); + assertNotNull(charSequence); assertThatThrownBy(() -> GeodeSecurityUtil.getObjectOfType("com.abc.testString", String.class)).isInstanceOf(GemFireSecurityException.class); @@ -45,4 +46,36 @@ public class GeodeSecurityUtilTest { assertThatThrownBy(() -> GeodeSecurityUtil.getObjectOfType(" ", String.class)).isInstanceOf(GemFireSecurityException.class); } + + @Test + public void testGetObjectFromFactoryMethod(){ + String string = GeodeSecurityUtil.getObjectOfType(Factories.class.getName()+".getString", String.class); + assertNotNull(string); + CharSequence charSequence = GeodeSecurityUtil.getObjectOfType(Factories.class.getName()+".getString", String.class); + assertNotNull(charSequence); + + assertThatThrownBy(() -> GeodeSecurityUtil.getObjectOfType(Factories.class.getName()+".getStringNonStatic", String.class)) + .isInstanceOf(GemFireSecurityException.class); + + assertThatThrownBy(() -> GeodeSecurityUtil.getObjectOfType(Factories.class.getName()+".getNullString", String.class)) + .isInstanceOf(GemFireSecurityException.class); + } + + private static class Factories{ + public static String getString(){ + return new String(); + } + + public static String getNullString(){ + return null; + } + + public String getStringNonStatic(){ + return new String(); + } + + public static Boolean getBoolean(){ + return Boolean.TRUE; + } + } }
