GEODE-77: Implement Authenticator interface in class GMSAuthenticator with unit tests.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/0a70d514 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/0a70d514 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/0a70d514 Branch: refs/heads/feature/GEODE-77 Commit: 0a70d5140277b366be4d0b9607a5e68936837c2f Parents: 52f8ce6 Author: Qihong Chen <qc...@pivotal.io> Authored: Thu Aug 13 09:55:33 2015 -0700 Committer: Qihong Chen <qc...@pivotal.io> Committed: Thu Aug 13 09:55:33 2015 -0700 ---------------------------------------------------------------------- .../internal/InternalDistributedSystem.java | 1 + .../internal/membership/gms/Services.java | 22 +- .../membership/gms/auth/GMSAuthenticator.java | 155 +- .../gms/interfaces/Authenticator.java | 2 +- .../membership/gms/membership/GMSJoinLeave.java | 2356 +++++++++--------- .../gemfire/internal/i18n/LocalizedStrings.java | 9 +- .../gms/auth/GMSAuthenticatorJUnitTest.java | 300 +++ 7 files changed, 1651 insertions(+), 1194 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0a70d514/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/InternalDistributedSystem.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/InternalDistributedSystem.java b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/InternalDistributedSystem.java index d03f558..8a4e20a 100644 --- a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/InternalDistributedSystem.java +++ b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/InternalDistributedSystem.java @@ -564,6 +564,7 @@ public final class InternalDistributedSystem this.securityLogWriter.fine("SecurityLogWriter is created."); } + Services.setLogWriter(this.logWriter); Services.setSecurityLogWriter(this.securityLogWriter); this.clock = new DSClock(this.isLoner); http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0a70d514/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/Services.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/Services.java b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/Services.java index 79830b9..8a27cf0 100755 --- a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/Services.java +++ b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/Services.java @@ -36,6 +36,7 @@ public class Services { private static final ThreadGroup threadGroup = LoggingThreadGroup.createThreadGroup("Membership", logger); + private static InternalLogWriter staticLogWriter; private static InternalLogWriter staticSecurityLogWriter; final private Manager manager; @@ -48,6 +49,7 @@ public class Services { final private DMStats stats; final private Stopper cancelCriterion; + private InternalLogWriter logWriter; private InternalLogWriter securityLogWriter; private Timer timer = new Timer("Membership Timer", true); @@ -95,6 +97,8 @@ public class Services { // TODO fix this so that IDS doesn't know about Services securityLogWriter = staticSecurityLogWriter; staticSecurityLogWriter = null; + logWriter = staticLogWriter; + staticLogWriter = null; this.auth.init(this); this.messenger.init(this); this.manager.init(this); @@ -154,12 +158,20 @@ public class Services { this.manager.stop(); this.timer.cancel(); } - - public static void setSecurityLogWriter(InternalLogWriter writer) { - staticSecurityLogWriter = writer; + + public static void setLogWriter(InternalLogWriter writer) { + staticLogWriter = writer; } - - public LogWriter getSecurityLogWriter() { + + public static void setSecurityLogWriter(InternalLogWriter securityWriter) { + staticSecurityLogWriter = securityWriter; + } + + public InternalLogWriter getLogWriter() { + return this.logWriter; + } + + public InternalLogWriter getSecurityLogWriter() { return this.securityLogWriter; } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0a70d514/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java index c008171..7e7072d 100755 --- a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java +++ b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/auth/GMSAuthenticator.java @@ -1,17 +1,42 @@ package com.gemstone.gemfire.distributed.internal.membership.gms.auth; +import com.gemstone.gemfire.LogWriter; +import com.gemstone.gemfire.distributed.DistributedMember; import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember; import com.gemstone.gemfire.distributed.internal.membership.NetView; import com.gemstone.gemfire.distributed.internal.membership.gms.Services; import com.gemstone.gemfire.distributed.internal.membership.gms.interfaces.Authenticator; +import com.gemstone.gemfire.internal.ClassLoadUtil; +import com.gemstone.gemfire.internal.logging.InternalLogWriter; +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; + +// static messages +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.HandShake_AUTHENTICATOR_INSTANCE_COULD_NOT_BE_OBTAINED; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHENTICATOR_OBJECT; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHINITIALIZE_METHOD_0; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.AUTH_PEER_AUTHENTICATION_FAILED_WITH_EXCEPTION; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.AUTH_PEER_AUTHENTICATION_FAILED; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.AUTH_PEER_AUTHENTICATION_MISSING_CREDENTIALS; +import static com.gemstone.gemfire.internal.i18n.LocalizedStrings.AUTH_FAILED_TO_ACQUIRE_AUTHINITIALIZE_INSTANCE; +import static com.gemstone.gemfire.distributed.internal.DistributionConfig.SECURITY_PEER_AUTH_INIT_NAME; +import static com.gemstone.gemfire.distributed.internal.DistributionConfig.SECURITY_PEER_AUTHENTICATOR_NAME; + public class GMSAuthenticator implements Authenticator { + private Services services; + @Override public void init(Services s) { - // TODO Auto-generated method stub - + this.services = s; } @Override @@ -62,17 +87,129 @@ public class GMSAuthenticator implements Authenticator { } + /** + * Authenticate peer member with authenticator class defined by property + * "security-peer-authenticator". + * @param member the member to be authenticated + * @param credentials the credentials used in authentication + * @return null if authentication succeed (including no authenticator case), + * otherwise, return failure message + * @throws AuthenticationFailedException + * this will be removed since return string is used for failure + */ @Override - public String authenticate(InternalDistributedMember m, Object credentials) - throws AuthenticationFailedException { - // TODO Auto-generated method stub - return null; + public String authenticate(InternalDistributedMember member, Object credentials) + throws AuthenticationFailedException { + return authenticate(member, credentials, securityProps, services.getJoinLeave().getMemberID()); + } + + // for unit test + /* package */ String authenticate( + DistributedMember member, Object credentials, Properties secProps, DistributedMember localMember) + throws AuthenticationFailedException { + + String authMethod = secProps.getProperty(SECURITY_PEER_AUTHENTICATOR_NAME); + if (authMethod == null || authMethod.length() == 0) { + return null; + } + + InternalLogWriter securityLogWriter = services.getSecurityLogWriter(); + String failMsg = null; + if (credentials != null) { + try { + invokeAuthenticator(authMethod, member, credentials); + } catch (Exception ex) { + securityLogWriter.warning( + AUTH_PEER_AUTHENTICATION_FAILED_WITH_EXCEPTION, + new Object[] {member, authMethod, ex.getLocalizedMessage()}, ex); + failMsg = AUTH_PEER_AUTHENTICATION_FAILED.toLocalizedString(localMember); + } + } else { // No credentials - need to send failure message + securityLogWriter.warning( + AUTH_PEER_AUTHENTICATION_MISSING_CREDENTIALS, new Object[] {member, authMethod}); + failMsg = AUTH_PEER_AUTHENTICATION_MISSING_CREDENTIALS.toLocalizedString(member, authMethod); + } + return failMsg; } + /* package */ Principal invokeAuthenticator(String authMethod, DistributedMember member, Object credentials) + throws AuthenticationFailedException { + com.gemstone.gemfire.security.Authenticator auth = null; + try { + Method getter = ClassLoadUtil.methodFromName(authMethod); + auth = (com.gemstone.gemfire.security.Authenticator) getter.invoke(null, (Object[]) null); + if (auth == null) + throw new AuthenticationFailedException( + HandShake_AUTHENTICATOR_INSTANCE_COULD_NOT_BE_OBTAINED.toLocalizedString()); + + LogWriter logWriter = services.getLogWriter(); + LogWriter securityLogWriter = services.getSecurityLogWriter(); + auth.init(securityProps, logWriter, securityLogWriter); + return auth.authenticate((Properties) credentials, member); + } catch (GemFireSecurityException gse) { + throw gse; + } catch (Exception ex) { + throw new AuthenticationFailedException( + HandShake_FAILED_TO_ACQUIRE_AUTHENTICATOR_OBJECT.toLocalizedString(), ex); + } finally { + if (auth != null) auth.close(); + } + } + + /** + * Get credential object for the given GemFire distributed member + * @param member the target distributed member + * @return the credential object + */ @Override - public Object getCredentials() { - // TODO Auto-generated method stub - return null; + public Object getCredentials(InternalDistributedMember member) { + return getCredentials(member, securityProps); + } + + // for unit test + /* package */ Properties getCredentials(DistributedMember member, Properties secProps) { + Properties credentials = null; + String authMethod = secProps.getProperty(SECURITY_PEER_AUTH_INIT_NAME); + 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)); + + try { + LogWriter logWriter = services.getLogWriter(); + LogWriter securityLogWriter = services.getSecurityLogWriter(); + auth.init(logWriter, securityLogWriter); + credentials = auth.getCredentials(secProps, member, true); + } finally { + auth.close(); + } + } + } catch (GemFireSecurityException gse) { + throw gse; + } catch (Exception ex) { + throw new AuthenticationRequiredException( + HandShake_FAILED_TO_ACQUIRE_AUTHINITIALIZE_METHOD_0.toLocalizedString(authMethod), ex); + } + return credentials; + } + + private final static String secPrefix = "gemfire.sys.security-"; + private final static int gemfireSysPrefixLen = "gemfire.sys.".length(); + private Properties securityProps = getSecurityProps(); + + Properties getSecurityProps() { + Properties props = new Properties(); + Set keys = System.getProperties().keySet(); + for (Object key: keys) { + String propKey = (String) key; + if (propKey.startsWith(secPrefix)) { + props.setProperty(propKey.substring(gemfireSysPrefixLen), System.getProperty(propKey)); + } + } + return props; } @Override http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0a70d514/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/interfaces/Authenticator.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/interfaces/Authenticator.java b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/interfaces/Authenticator.java index fa45ff3..596b265 100755 --- a/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/interfaces/Authenticator.java +++ b/gemfire-core/src/main/java/com/gemstone/gemfire/distributed/internal/membership/gms/interfaces/Authenticator.java @@ -7,5 +7,5 @@ public interface Authenticator extends Service { String authenticate(InternalDistributedMember m, Object credentials) throws AuthenticationFailedException; - Object getCredentials(); + Object getCredentials(InternalDistributedMember m); }