Repository: incubator-geode Updated Branches: refs/heads/feature/GEODE-949-2 37b978c25 -> 3a0fe9550
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/DummyAuthorization.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/DummyAuthorization.java b/geode-core/src/test/java/templates/security/DummyAuthorization.java index 4c2bfec..896ccc5 100755 --- a/geode-core/src/test/java/templates/security/DummyAuthorization.java +++ b/geode-core/src/test/java/templates/security/DummyAuthorization.java @@ -16,6 +16,10 @@ */ package templates.security; +import java.security.Principal; +import java.util.HashSet; +import java.util.Set; + import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.operations.OperationContext; @@ -24,94 +28,95 @@ import com.gemstone.gemfire.distributed.DistributedMember; import com.gemstone.gemfire.security.AccessControl; import com.gemstone.gemfire.security.NotAuthorizedException; -import java.security.Principal; -import java.util.HashSet; -import java.util.Set; - /** - * A dummy implementation of the <code>AccessControl</code> interface that - * allows authorization depending on the format of the <code>Principal</code> + * A dummy implementation of the {@code AccessControl} interface that + * allows authorization depending on the format of the {@code Principal} * string. * - * @author Sumedh Wale * @since 5.5 */ public class DummyAuthorization implements AccessControl { private Set allowedOps; - - private DistributedMember remoteDistributedMember; - - private LogWriter logger; - - public static final OperationCode[] READER_OPS = { OperationCode.GET, - OperationCode.QUERY, OperationCode.EXECUTE_CQ, OperationCode.CLOSE_CQ, - OperationCode.STOP_CQ, OperationCode.REGISTER_INTEREST, - OperationCode.UNREGISTER_INTEREST, OperationCode.KEY_SET, - OperationCode.CONTAINS_KEY, OperationCode.EXECUTE_FUNCTION }; - - public static final OperationCode[] WRITER_OPS = { OperationCode.PUT, OperationCode.PUTALL, - OperationCode.DESTROY, OperationCode.INVALIDATE, OperationCode.REGION_CLEAR }; - - public DummyAuthorization() { - this.allowedOps = new HashSet(20); - } + private DistributedMember remoteMember; + private LogWriter securityLogWriter; + + public static final OperationCode[] READER_OPS = { + OperationCode.GET, + OperationCode.QUERY, + OperationCode.EXECUTE_CQ, + OperationCode.CLOSE_CQ, + OperationCode.STOP_CQ, + OperationCode.REGISTER_INTEREST, + OperationCode.UNREGISTER_INTEREST, + OperationCode.KEY_SET, + OperationCode.CONTAINS_KEY, + OperationCode.EXECUTE_FUNCTION }; + + public static final OperationCode[] WRITER_OPS = { + OperationCode.PUT, + OperationCode.PUTALL, + OperationCode.DESTROY, + OperationCode.INVALIDATE, + OperationCode.REGION_CLEAR }; public static AccessControl create() { return new DummyAuthorization(); } - private void addReaderOps() { - - for (int index = 0; index < READER_OPS.length; index++) { - this.allowedOps.add(READER_OPS[index]); - } + public DummyAuthorization() { + this.allowedOps = new HashSet(20); } - private void addWriterOps() { - - for (int index = 0; index < WRITER_OPS.length; index++) { - this.allowedOps.add(WRITER_OPS[index]); - } - } + @Override + public void init(final Principal principal, final DistributedMember remoteMember, final Cache cache) throws NotAuthorizedException { + if (principal != null) { - public void init(Principal principal, - DistributedMember remoteMember, - Cache cache) throws NotAuthorizedException { + final String name = principal.getName().toLowerCase(); - if (principal != null) { - String name = principal.getName().toLowerCase(); if (name != null) { - if (name.equals("root") || name.equals("admin") - || name.equals("administrator")) { + + if (name.equals("root") || name.equals("admin") || name.equals("administrator")) { addReaderOps(); addWriterOps(); this.allowedOps.add(OperationCode.REGION_CREATE); this.allowedOps.add(OperationCode.REGION_DESTROY); - } - else if (name.startsWith("writer")) { + + } else if (name.startsWith("writer")) { addWriterOps(); - } - else if (name.startsWith("reader")) { + + } else if (name.startsWith("reader")) { addReaderOps(); } + } } - this.remoteDistributedMember = remoteMember; - this.logger = cache.getSecurityLogger(); + + this.remoteMember = remoteMember; + this.securityLogWriter = cache.getSecurityLogger(); } + @Override public boolean authorizeOperation(String regionName, OperationContext context) { - - OperationCode opCode = context.getOperationCode(); - this.logger.fine("Invoked authorize operation for [" + opCode - + "] in region [" + regionName + "] for client: " + remoteDistributedMember); + final OperationCode opCode = context.getOperationCode(); + this.securityLogWriter.fine("Invoked authorize operation for [" + opCode + "] in region [" + regionName + "] for client: " + remoteMember); return this.allowedOps.contains(opCode); } + @Override public void close() { - this.allowedOps.clear(); } + private void addReaderOps() { + for (int index = 0; index < READER_OPS.length; index++) { + this.allowedOps.add(READER_OPS[index]); + } + } + + private void addWriterOps() { + for (int index = 0; index < WRITER_OPS.length; index++) { + this.allowedOps.add(WRITER_OPS[index]); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/FunctionSecurityPrmsHolder.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/FunctionSecurityPrmsHolder.java b/geode-core/src/test/java/templates/security/FunctionSecurityPrmsHolder.java index 5771fd4..e7280de 100755 --- a/geode-core/src/test/java/templates/security/FunctionSecurityPrmsHolder.java +++ b/geode-core/src/test/java/templates/security/FunctionSecurityPrmsHolder.java @@ -16,39 +16,35 @@ */ package templates.security; -import java.util.HashSet; +import java.util.Set; /** * This is a sample class for objects which hold information of the authorized - * function names and authorized value for the optimizeForWrite. + * function names and authorized value for the {@code optimizeForWrite}. * - * @author Aneesh Karayil * @since 6.0 */ public class FunctionSecurityPrmsHolder { - private final Boolean isOptimizeForWrite; + private final Boolean optimizeForWrite; + private final Set<String> functionIds; + private final Set<String> keySet; - private final HashSet<String> functionIds; - - private final HashSet<String> keySet; - - public FunctionSecurityPrmsHolder(Boolean isOptimizeForWrite, - HashSet<String> functionIds, HashSet<String> keySet) { - this.isOptimizeForWrite = isOptimizeForWrite; + public FunctionSecurityPrmsHolder(final Boolean optimizeForWrite, final Set<String> functionIds, final Set<String> keySet) { + this.optimizeForWrite = optimizeForWrite; this.functionIds = functionIds; this.keySet = keySet; } public Boolean isOptimizeForWrite() { - return isOptimizeForWrite; + return this.optimizeForWrite; } - public HashSet<String> getFunctionIds() { - return functionIds; + public Set<String> getFunctionIds() { + return this.functionIds; } - public HashSet<String> getKeySet() { - return keySet; + public Set<String> getKeySet() { + return this.keySet; } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/LdapUserAuthenticator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/LdapUserAuthenticator.java b/geode-core/src/test/java/templates/security/LdapUserAuthenticator.java index 49059c3..3bd4717 100755 --- a/geode-core/src/test/java/templates/security/LdapUserAuthenticator.java +++ b/geode-core/src/test/java/templates/security/LdapUserAuthenticator.java @@ -16,6 +16,12 @@ */ package templates.security; +import java.security.Principal; +import java.util.Properties; +import javax.naming.Context; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; + import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.distributed.DistributedMember; import com.gemstone.gemfire.internal.logging.LogService; @@ -23,96 +29,73 @@ import com.gemstone.gemfire.security.AuthenticationFailedException; import com.gemstone.gemfire.security.Authenticator; import org.apache.logging.log4j.Logger; -import java.security.Principal; -import java.util.Properties; -import javax.naming.Context; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; - /** - * @author Kumar Neeraj + * An implementation of {@link Authenticator} that uses LDAP. + * * @since 5.5 */ public class LdapUserAuthenticator implements Authenticator { - private static final Logger logger = LogService.getLogger(); - private String ldapServer = null; - - private String basedn = null; - - private String ldapUrlScheme = null; + private static final Logger logger = LogService.getLogger(); public static final String LDAP_SERVER_NAME = "security-ldap-server"; - - public static final String LDAP_BASEDN_NAME = "security-ldap-basedn"; - + public static final String LDAP_BASEDN_NAME = "security-ldap-baseDomainName"; public static final String LDAP_SSL_NAME = "security-ldap-usessl"; + private String ldapServer = null; + private String baseDomainName = null; + private String ldapUrlScheme = null; + public static Authenticator create() { return new LdapUserAuthenticator(); } - public LdapUserAuthenticator() { - } - - public void init(Properties securityProps, LogWriter systemLogger, - LogWriter securityLogger) throws AuthenticationFailedException { + public void init(final Properties securityProps, final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { this.ldapServer = securityProps.getProperty(LDAP_SERVER_NAME); if (this.ldapServer == null || this.ldapServer.length() == 0) { - throw new AuthenticationFailedException( - "LdapUserAuthenticator: LDAP server property [" + LDAP_SERVER_NAME - + "] not specified"); + throw new AuthenticationFailedException("LdapUserAuthenticator: LDAP server property [" + LDAP_SERVER_NAME + "] not specified"); } - this.basedn = securityProps.getProperty(LDAP_BASEDN_NAME); - if (this.basedn == null || this.basedn.length() == 0) { - throw new AuthenticationFailedException( - "LdapUserAuthenticator: LDAP base DN property [" + LDAP_BASEDN_NAME - + "] not specified"); + + this.baseDomainName = securityProps.getProperty(LDAP_BASEDN_NAME); + if (this.baseDomainName == null || this.baseDomainName.length() == 0) { + throw new AuthenticationFailedException("LdapUserAuthenticator: LDAP base DN property [" + LDAP_BASEDN_NAME + "] not specified"); } - String sslStr = securityProps.getProperty(LDAP_SSL_NAME); - if (sslStr != null && sslStr.toLowerCase().equals("true")) { + + final String sslName = securityProps.getProperty(LDAP_SSL_NAME); + if (sslName != null && sslName.toLowerCase().equals("true")) { this.ldapUrlScheme = "ldaps://"; - } - else { + } else { this.ldapUrlScheme = "ldap://"; } } - public Principal authenticate(Properties props, DistributedMember member) { - - String userName = props.getProperty(UserPasswordAuthInit.USER_NAME); + public Principal authenticate(final Properties credentials, final DistributedMember member) { + final String userName = credentials.getProperty(UserPasswordAuthInit.USER_NAME); if (userName == null) { - throw new AuthenticationFailedException( - "LdapUserAuthenticator: user name property [" - + UserPasswordAuthInit.USER_NAME + "] not provided"); + throw new AuthenticationFailedException("LdapUserAuthenticator: user name property [" + UserPasswordAuthInit.USER_NAME + "] not provided"); } - String passwd = props.getProperty(UserPasswordAuthInit.PASSWORD); - if (passwd == null) { - passwd = ""; + + String password = credentials.getProperty(UserPasswordAuthInit.PASSWORD); + if (password == null) { + password = ""; } - Properties env = new Properties(); - env - .put(Context.INITIAL_CONTEXT_FACTORY, - com.sun.jndi.ldap.LdapCtxFactory.class.getName()); - env.put(Context.PROVIDER_URL, this.ldapUrlScheme + this.ldapServer + '/' - + this.basedn); - String fullentry = "uid=" + userName + "," + this.basedn; - env.put(Context.SECURITY_PRINCIPAL, fullentry); - env.put(Context.SECURITY_CREDENTIALS, passwd); + final Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, com.sun.jndi.ldap.LdapCtxFactory.class.getName()); + env.put(Context.PROVIDER_URL, this.ldapUrlScheme + this.ldapServer + '/' + this.baseDomainName); + env.put(Context.SECURITY_PRINCIPAL, "uid=" + userName + "," + this.baseDomainName); + env.put(Context.SECURITY_CREDENTIALS, password); + try { - DirContext ctx = new InitialDirContext(env); + final DirContext ctx = new InitialDirContext(env); ctx.close(); + } catch (Exception e) { + throw new AuthenticationFailedException("LdapUserAuthenticator: Failure with provided username, password combination for user name: " + userName, e); } - catch (Exception e) { - throw new AuthenticationFailedException( - "LdapUserAuthenticator: Failure with provided username, password " - + "combination for user name: " + userName, e); - } + return new UsernamePrincipal(userName); } public void close() { } - } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/PKCSAuthInit.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/PKCSAuthInit.java b/geode-core/src/test/java/templates/security/PKCSAuthInit.java index f4004f3..8709cc4 100755 --- a/geode-core/src/test/java/templates/security/PKCSAuthInit.java +++ b/geode-core/src/test/java/templates/security/PKCSAuthInit.java @@ -16,14 +16,6 @@ */ package templates.security; -import com.gemstone.gemfire.LogWriter; -import com.gemstone.gemfire.distributed.DistributedMember; -import com.gemstone.gemfire.internal.logging.LogService; -import com.gemstone.gemfire.security.AuthInitialize; -import com.gemstone.gemfire.security.AuthenticationFailedException; -import com.gemstone.gemfire.security.GemFireSecurityException; -import org.apache.logging.log4j.Logger; - import java.io.FileInputStream; import java.security.Key; import java.security.KeyStore; @@ -32,101 +24,95 @@ import java.security.Signature; import java.security.cert.X509Certificate; import java.util.Properties; +import com.gemstone.gemfire.LogWriter; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.security.AuthInitialize; +import com.gemstone.gemfire.security.AuthenticationFailedException; +import org.apache.logging.log4j.Logger; + /** * An {@link AuthInitialize} implementation that obtains the digital signature * for use with PKCS scheme on server from the given set of properties. * - * To use this class the <c>security-client-auth-init</c> property should be - * set to the fully qualified name the static <code>create</code> function - * viz. <code>templates.security.PKCSAuthInit.create</code> + * To use this class the {@code security-client-auth-init} property should be + * set to the fully qualified name the static {@code create} function + * viz. <{@code templates.security.PKCSAuthInit.create} * - * @author Kumar Neeraj * @since 5.5 */ public class PKCSAuthInit implements AuthInitialize { + private static final Logger logger = LogService.getLogger(); public static final String KEYSTORE_FILE_PATH = "security-keystorepath"; - public static final String KEYSTORE_ALIAS = "security-alias"; - public static final String KEYSTORE_PASSWORD = "security-keystorepass"; - public static final String SIGNATURE_DATA = "security-signature"; - protected LogWriter securitylog; - - protected LogWriter systemlog; - - public void close() { - } + protected LogWriter systemLogWriter; + protected LogWriter securityLogWriter; public static AuthInitialize create() { return new PKCSAuthInit(); } - public PKCSAuthInit() { + public void init(final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { + this.systemLogWriter = systemLogWriter; + this.securityLogWriter = securityLogWriter; } - public void init(LogWriter systemLogger, LogWriter securityLogger) - throws AuthenticationFailedException { - this.systemlog = systemLogger; - this.securitylog = securityLogger; - } - - public Properties getCredentials(Properties props, DistributedMember server, - boolean isPeer) throws AuthenticationFailedException { - String keyStorePath = props.getProperty(KEYSTORE_FILE_PATH); + @Override + public Properties getCredentials(final Properties securityProperties, final DistributedMember server, final boolean isPeer) throws AuthenticationFailedException { + final String keyStorePath = securityProperties.getProperty(KEYSTORE_FILE_PATH); if (keyStorePath == null) { - throw new AuthenticationFailedException( - "PKCSAuthInit: key-store file path property [" + KEYSTORE_FILE_PATH - + "] not set."); + throw new AuthenticationFailedException("PKCSAuthInit: key-store file path property [" + KEYSTORE_FILE_PATH + "] not set."); } - String alias = props.getProperty(KEYSTORE_ALIAS); + + final String alias = securityProperties.getProperty(KEYSTORE_ALIAS); if (alias == null) { - throw new AuthenticationFailedException( - "PKCSAuthInit: key alias name property [" + KEYSTORE_ALIAS - + "] not set."); + throw new AuthenticationFailedException("PKCSAuthInit: key alias name property [" + KEYSTORE_ALIAS + "] not set."); } - String keyStorePass = props.getProperty(KEYSTORE_PASSWORD); + + final String keyStorePass = securityProperties.getProperty(KEYSTORE_PASSWORD); try { - KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] passPhrase = (keyStorePass != null ? keyStorePass.toCharArray() - : null); - FileInputStream certificatefile = new FileInputStream(keyStorePath); + final KeyStore ks = KeyStore.getInstance("PKCS12"); + final char[] passPhrase = (keyStorePass != null ? keyStorePass.toCharArray() : null); + final FileInputStream certificatefile = new FileInputStream(keyStorePath); + try { ks.load(certificatefile, passPhrase); - } - finally { + } finally { certificatefile.close(); } - Key key = ks.getKey(alias, passPhrase); + final Key key = ks.getKey(alias, passPhrase); if (key instanceof PrivateKey) { - - PrivateKey privKey = (PrivateKey)key; - X509Certificate cert = (X509Certificate)ks.getCertificate(alias); - Signature sig = Signature.getInstance(cert.getSigAlgName()); + final PrivateKey privKey = (PrivateKey)key; + final X509Certificate cert = (X509Certificate)ks.getCertificate(alias); + final Signature sig = Signature.getInstance(cert.getSigAlgName()); sig.initSign(privKey); sig.update(alias.getBytes("UTF-8")); - byte[] signatureBytes = sig.sign(); + final byte[] signatureBytes = sig.sign(); - Properties newprops = new Properties(); + final Properties newprops = new Properties(); newprops.put(KEYSTORE_ALIAS, alias); newprops.put(SIGNATURE_DATA, signatureBytes); return newprops; + + } else { + throw new AuthenticationFailedException("PKCSAuthInit: " + "Failed to load private key from the given file: " + keyStorePath); } - else { - throw new AuthenticationFailedException("PKCSAuthInit: " - + "Failed to load private key from the given file: " + keyStorePath); - } - } - catch (Exception ex) { - throw new AuthenticationFailedException( - "PKCSAuthInit: Exception while getting credentials: " + ex, ex); + + } catch (Exception ex) { + throw new AuthenticationFailedException("PKCSAuthInit: Exception while getting credentials: " + ex, ex); } } + + @Override + public void close() { + } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/PKCSAuthenticator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/PKCSAuthenticator.java b/geode-core/src/test/java/templates/security/PKCSAuthenticator.java index 7af7312..c136447 100755 --- a/geode-core/src/test/java/templates/security/PKCSAuthenticator.java +++ b/geode-core/src/test/java/templates/security/PKCSAuthenticator.java @@ -16,14 +16,6 @@ */ package templates.security; -import com.gemstone.gemfire.LogWriter; -import com.gemstone.gemfire.distributed.DistributedMember; -import com.gemstone.gemfire.internal.logging.LogService; -import com.gemstone.gemfire.security.AuthenticationFailedException; -import com.gemstone.gemfire.security.Authenticator; -import com.gemstone.gemfire.security.GemFireSecurityException; -import org.apache.logging.log4j.Logger; - import java.io.FileInputStream; import java.security.KeyStore; import java.security.NoSuchAlgorithmException; @@ -37,130 +29,129 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; +import com.gemstone.gemfire.LogWriter; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.security.AuthenticationFailedException; +import com.gemstone.gemfire.security.Authenticator; +import org.apache.logging.log4j.Logger; + /** - * @author kneeraj - * + * An implementation of {@link Authenticator} that uses PKCS. */ public class PKCSAuthenticator implements Authenticator { + private static final Logger logger = LogService.getLogger(); public static final String PUBLIC_KEY_FILE = "security-publickey-filepath"; - public static final String PUBLIC_KEYSTORE_PASSWORD = "security-publickey-pass"; private String pubKeyFilePath; - private String pubKeyPass; - private Map aliasCertificateMap; - protected LogWriter systemlog; - - protected LogWriter securitylog; + private LogWriter systemLogWriter; + private LogWriter securityLogWriter; public static Authenticator create() { return new PKCSAuthenticator(); } - public PKCSAuthenticator() { - } + @Override + public void init(final Properties securityProperties, final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { + this.systemLogWriter = systemLogWriter; + this.securityLogWriter = securityLogWriter; - private void populateMap() { - try { - KeyStore ks = KeyStore.getInstance("JKS"); - char[] passPhrase = (pubKeyPass != null ? pubKeyPass.toCharArray() : null); - FileInputStream keystorefile = new FileInputStream(this.pubKeyFilePath); - try { - ks.load(keystorefile, passPhrase); - } - finally { - keystorefile.close(); - } - Enumeration e = ks.aliases(); - while (e.hasMoreElements()) { - Object alias = e.nextElement(); - Certificate cert = ks.getCertificate((String)alias); - if (cert instanceof X509Certificate) { - this.aliasCertificateMap.put(alias, cert); - } - } - } - catch (Exception e) { - throw new AuthenticationFailedException( - "Exception while getting public keys: " + e.getMessage(), e); - } - } - - public void init(Properties systemProps, LogWriter systemLogger, - LogWriter securityLogger) throws AuthenticationFailedException { - this.systemlog = systemLogger; - this.securitylog = securityLogger; - this.pubKeyFilePath = systemProps.getProperty(PUBLIC_KEY_FILE); + this.pubKeyFilePath = securityProperties.getProperty(PUBLIC_KEY_FILE); if (this.pubKeyFilePath == null) { - throw new AuthenticationFailedException("PKCSAuthenticator: property " - + PUBLIC_KEY_FILE + " not specified as the public key file."); - } - this.pubKeyPass = systemProps.getProperty(PUBLIC_KEYSTORE_PASSWORD); - this.aliasCertificateMap = new HashMap(); - populateMap(); - } - - private AuthenticationFailedException getException(String exStr, - Exception cause) { - - String exMsg = "PKCSAuthenticator: Authentication of client failed due to: " - + exStr; - if (cause != null) { - return new AuthenticationFailedException(exMsg, cause); - } - else { - return new AuthenticationFailedException(exMsg); + throw new AuthenticationFailedException("PKCSAuthenticator: property " + PUBLIC_KEY_FILE + " not specified as the public key file."); } - } - private AuthenticationFailedException getException(String exStr) { - return getException(exStr, null); - } + this.pubKeyPass = securityProperties.getProperty(PUBLIC_KEYSTORE_PASSWORD); + this.aliasCertificateMap = new HashMap(); - private X509Certificate getCertificate(String alias) - throws NoSuchAlgorithmException, InvalidKeySpecException { - if (this.aliasCertificateMap.containsKey(alias)) { - return (X509Certificate)this.aliasCertificateMap.get(alias); - } - return null; + populateMap(); } - public Principal authenticate(Properties props, DistributedMember member) - throws AuthenticationFailedException { - String alias = (String)props.get(PKCSAuthInit.KEYSTORE_ALIAS); + @Override + public Principal authenticate(final Properties credentials, final DistributedMember member) throws AuthenticationFailedException { + final String alias = (String)credentials.get(PKCSAuthInit.KEYSTORE_ALIAS); if (alias == null || alias.length() <= 0) { throw new AuthenticationFailedException("No alias received"); } + try { - X509Certificate cert = getCertificate(alias); + final X509Certificate cert = getCertificate(alias); if (cert == null) { - throw getException("No certificate found for alias:" + alias); + throw newException("No certificate found for alias:" + alias); } - byte[] signatureBytes = (byte[])props.get(PKCSAuthInit.SIGNATURE_DATA); + + final byte[] signatureBytes = (byte[])credentials.get(PKCSAuthInit.SIGNATURE_DATA); if (signatureBytes == null) { - throw getException("signature data property [" - + PKCSAuthInit.SIGNATURE_DATA + "] not provided"); + throw newException("signature data property [" + PKCSAuthInit.SIGNATURE_DATA + "] not provided"); } - Signature sig = Signature.getInstance(cert.getSigAlgName()); + + final Signature sig = Signature.getInstance(cert.getSigAlgName()); sig.initVerify(cert); sig.update(alias.getBytes("UTF-8")); if (!sig.verify(signatureBytes)) { - throw getException("verification of client signature failed"); + throw newException("verification of client signature failed"); } + return new PKCSPrincipal(alias); - } - catch (Exception ex) { - throw getException(ex.toString(), ex); + + } catch (Exception ex) { + throw newException(ex.toString(), ex); } } + @Override public void close() { } + private void populateMap() { + try { + final KeyStore keyStore = KeyStore.getInstance("JKS"); + final char[] passPhrase = this.pubKeyPass != null ? this.pubKeyPass.toCharArray() : null; + final FileInputStream keyStoreFile = new FileInputStream(this.pubKeyFilePath); + + try { + keyStore.load(keyStoreFile, passPhrase); + } finally { + keyStoreFile.close(); + } + + for (Enumeration e = keyStore.aliases(); e.hasMoreElements();) { + final Object alias = e.nextElement(); + final Certificate cert = keyStore.getCertificate((String)alias); + if (cert instanceof X509Certificate) { + this.aliasCertificateMap.put(alias, cert); + } + } + + } catch (Exception e) { + throw new AuthenticationFailedException("Exception while getting public keys: " + e.getMessage(), e); + } + } + + private AuthenticationFailedException newException(final String message, final Exception cause) { + final String fullMessage = "PKCSAuthenticator: Authentication of client failed due to: " + message; + if (cause != null) { + return new AuthenticationFailedException(fullMessage, cause); + } else { + return new AuthenticationFailedException(fullMessage); + } + } + + private AuthenticationFailedException newException(final String message) { + return newException(message, null); + } + + private X509Certificate getCertificate(final String alias) throws NoSuchAlgorithmException, InvalidKeySpecException { + if (this.aliasCertificateMap.containsKey(alias)) { + return (X509Certificate) this.aliasCertificateMap.get(alias); + } + return null; + } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/PKCSPrincipal.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/PKCSPrincipal.java b/geode-core/src/test/java/templates/security/PKCSPrincipal.java index bc3049f..5d878bf 100755 --- a/geode-core/src/test/java/templates/security/PKCSPrincipal.java +++ b/geode-core/src/test/java/templates/security/PKCSPrincipal.java @@ -20,18 +20,15 @@ package templates.security; import java.io.Serializable; import java.security.Principal; -/** - * @author kneeraj - * - */ public class PKCSPrincipal implements Principal, Serializable { - private String alias; + private final String alias; - public PKCSPrincipal(String alias) { + public PKCSPrincipal(final String alias) { this.alias = alias; } + @Override public String getName() { return this.alias; } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/PKCSPrincipalTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/PKCSPrincipalTest.java b/geode-core/src/test/java/templates/security/PKCSPrincipalTest.java index fc8454c..6ce216f 100644 --- a/geode-core/src/test/java/templates/security/PKCSPrincipalTest.java +++ b/geode-core/src/test/java/templates/security/PKCSPrincipalTest.java @@ -16,15 +16,15 @@ */ package templates.security; +import static org.assertj.core.api.Assertions.*; + +import java.io.Serializable; + import com.gemstone.gemfire.test.junit.categories.UnitTest; import org.apache.commons.lang.SerializationUtils; import org.junit.Test; import org.junit.experimental.categories.Category; -import java.io.Serializable; - -import static org.assertj.core.api.Assertions.assertThat; - /** * Unit tests for {@link PKCSPrincipal} */ http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/UserPasswordAuthInit.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/UserPasswordAuthInit.java b/geode-core/src/test/java/templates/security/UserPasswordAuthInit.java index 1c48773..58f356e 100755 --- a/geode-core/src/test/java/templates/security/UserPasswordAuthInit.java +++ b/geode-core/src/test/java/templates/security/UserPasswordAuthInit.java @@ -16,68 +16,60 @@ */ package templates.security; +import java.util.Properties; + import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.distributed.DistributedMember; import com.gemstone.gemfire.security.AuthInitialize; import com.gemstone.gemfire.security.AuthenticationFailedException; -import java.util.Properties; - /** * An {@link AuthInitialize} implementation that obtains the user name and * password as the credentials from the given set of properties. * - * To use this class the <c>security-client-auth-init</c> property should be - * set to the fully qualified name the static <code>create</code> function - * viz. <code>templates.security.UserPasswordAuthInit.create</code> + * To use this class the {@code security-client-auth-init} property should be + * set to the fully qualified name the static {@code create} function + * viz. {@code templates.security.UserPasswordAuthInit.create} * - * @author Sumedh Wale * @since 5.5 */ public class UserPasswordAuthInit implements AuthInitialize { public static final String USER_NAME = "security-username"; - public static final String PASSWORD = "security-password"; - protected LogWriter securitylog; - - protected LogWriter systemlog; + protected LogWriter systemLogWriter; + protected LogWriter securityLogWriter; public static AuthInitialize create() { return new UserPasswordAuthInit(); } - public void init(LogWriter systemLogger, LogWriter securityLogger) - throws AuthenticationFailedException { - this.systemlog = systemLogger; - this.securitylog = securityLogger; + @Override + public void init(final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { + this.systemLogWriter = systemLogWriter; + this.securityLogWriter = securityLogWriter; } - public UserPasswordAuthInit() { - } - - public Properties getCredentials(Properties props, DistributedMember server, - boolean isPeer) throws AuthenticationFailedException { - - Properties newProps = new Properties(); - String userName = props.getProperty(USER_NAME); + @Override + public Properties getCredentials(final Properties securityProperties, final DistributedMember server, final boolean isPeer) throws AuthenticationFailedException { + String userName = securityProperties.getProperty(USER_NAME); if (userName == null) { - throw new AuthenticationFailedException( - "UserPasswordAuthInit: user name property [" + USER_NAME - + "] not set."); + throw new AuthenticationFailedException("UserPasswordAuthInit: user name property [" + USER_NAME + "] not set."); } - newProps.setProperty(USER_NAME, userName); - String passwd = props.getProperty(PASSWORD); - // If password is not provided then use empty string as the password. - if (passwd == null) { - passwd = ""; + + String password = securityProperties.getProperty(PASSWORD); + if (password == null) { + password = ""; } - newProps.setProperty(PASSWORD, passwd); - return newProps; + + Properties securityPropertiesCopy = new Properties(); + securityPropertiesCopy.setProperty(USER_NAME, userName); + securityPropertiesCopy.setProperty(PASSWORD, password); + return securityPropertiesCopy; } + @Override public void close() { } - } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/UsernamePrincipal.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/UsernamePrincipal.java b/geode-core/src/test/java/templates/security/UsernamePrincipal.java index 781dd5a..b6d94ae 100755 --- a/geode-core/src/test/java/templates/security/UsernamePrincipal.java +++ b/geode-core/src/test/java/templates/security/UsernamePrincipal.java @@ -22,17 +22,17 @@ import java.security.Principal; /** * An implementation of {@link Principal} class for a simple user name. * - * @author Kumar Neeraj * @since 5.5 */ public class UsernamePrincipal implements Principal, Serializable { private final String userName; - public UsernamePrincipal(String userName) { + public UsernamePrincipal(final String userName) { this.userName = userName; } + @Override public String getName() { return this.userName; } @@ -41,5 +41,4 @@ public class UsernamePrincipal implements Principal, Serializable { public String toString() { return this.userName; } - } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/UsernamePrincipalTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/UsernamePrincipalTest.java b/geode-core/src/test/java/templates/security/UsernamePrincipalTest.java index 023c214..e88fd18 100644 --- a/geode-core/src/test/java/templates/security/UsernamePrincipalTest.java +++ b/geode-core/src/test/java/templates/security/UsernamePrincipalTest.java @@ -16,15 +16,15 @@ */ package templates.security; +import static org.assertj.core.api.Assertions.*; + +import java.io.Serializable; + import com.gemstone.gemfire.test.junit.categories.UnitTest; import org.apache.commons.lang.SerializationUtils; import org.junit.Test; import org.junit.experimental.categories.Category; -import java.io.Serializable; - -import static org.assertj.core.api.Assertions.assertThat; - /** * Unit tests for {@link UsernamePrincipal} */ http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/XmlAuthorization.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/XmlAuthorization.java b/geode-core/src/test/java/templates/security/XmlAuthorization.java index 29d94de..3f18b62 100755 --- a/geode-core/src/test/java/templates/security/XmlAuthorization.java +++ b/geode-core/src/test/java/templates/security/XmlAuthorization.java @@ -16,6 +16,19 @@ */ package templates.security; +import java.io.IOException; +import java.io.InputStream; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.operations.ExecuteFunctionOperationContext; @@ -35,28 +48,15 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; -import java.io.IOException; -import java.io.InputStream; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - /** - * An implementation of the <code>{@link AccessControl}</code> interface that - * allows authorization using the permissions as specified in the given XML + * An implementation of the {@link AccessControl} interface that allows + * authorization using the permissions as specified in the given XML * file. * * The format of the XML file is specified in <a href="authz5_5.dtd"/>. It * implements a role-based authorization at the operation level for each region. * Each principal name may be associated with a set of roles. The name of the - * principal is obtained using the {@link Principal#getName} method and no other + * principal is obtained using the {@link Principal#getName()} method and no other * information of the principal is utilized. Each role can be provided * permissions to execute operations for each region. * @@ -83,99 +83,106 @@ import javax.xml.parsers.DocumentBuilderFactory; * (e.g. {@link OperationCode#REGION_DESTROY}) specified for a particular region * is ignored i.e. the cache-level operations are only applicable when no region * name is specified. A {@link OperationCode#QUERY} operation is permitted when - * either the <code>QUERY</code> permission is provided at the cache-level for - * the user or when <code>QUERY</code> permission is provided for all the + * either the {@code QUERY} permission is provided at the cache-level for + * the user or when {@code QUERY} permission is provided for all the * regions that are part of the query string. * * Any roles specified in the "user" tag that do not have a specified permission * set using the "permission" tags are ignored. When no {@link Principal} is * associated with the current connection, then empty user name is used to * search for the roles so an empty user name can be used to specify roles of - * unauthenticated clients (i.e. <code>Everyone</code>). + * unauthenticated clients (i.e. {@code Everyone}). * * This sample implementation is useful only for pre-operation checks and should * not be used for post-operation authorization since it does nothing useful for * post-operation case. * - * @author Sumedh Wale * @since 5.5 */ public class XmlAuthorization implements AccessControl { public static final String DOC_URI_PROP_NAME = "security-authz-xml-uri"; - private static final String TAG_ROLE = "role"; + private static final Object sync = new Object(); + private static final String EMPTY_VALUE = ""; + private static final String TAG_ROLE = "role"; private static final String TAG_USER = "user"; - private static final String TAG_PERMS = "permission"; - private static final String TAG_OP = "operation"; private static final String ATTR_ROLENAME = "name"; - private static final String ATTR_ROLE = "role"; - private static final String ATTR_REGIONS = "regions"; - private static final String ATTR_FUNCTION_IDS = "functionIds"; - - private static final String ATTR_FUNCTION_OPTIMIZE_FOR_WRITE = - "optimizeForWrite"; - + private static final String ATTR_FUNCTION_OPTIMIZE_FOR_WRITE = "optimizeForWrite"; private static final String ATTR_FUNCTION_KEY_SET = "keySet"; private static String currentDocUri = null; - private static Map<String, HashSet<String>> userRoles = null; - - private static Map<String, Map<String, - Map<OperationCode, FunctionSecurityPrmsHolder>>> rolePermissions = null; - + private static Map<String, Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>>> rolePermissions = null; private static NotAuthorizedException xmlLoadFailure = null; - private static final Object sync = new Object(); - - private static final String EMPTY_VALUE = ""; - - private final Map<String, Map<OperationCode, - FunctionSecurityPrmsHolder>> allowedOps; + private final Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>> allowedOps; - protected LogWriter logger; + protected LogWriter systemLogWriter; + protected LogWriter securityLogWriter; - protected LogWriter securityLogger; - - private XmlAuthorization() { + /** + * Public static factory method to create an instance of + * {@code XmlAuthorization}. The fully qualified name of the class + * ({@code templates.security.XmlAuthorization.create}) + * should be mentioned as the {@code security-client-accessor} system + * property to enable pre-operation authorization checks as implemented in + * this class. + * + * @return an object of {@code XmlAuthorization} class + */ + public static AccessControl create() { + return new XmlAuthorization(); + } - this.allowedOps = new HashMap<String, Map<OperationCode, - FunctionSecurityPrmsHolder>>(); - this.logger = null; - this.securityLogger = null; + /** + * Clear all the statically cached information. + */ + public static void clear() { + XmlAuthorization.currentDocUri = null; + if (XmlAuthorization.userRoles != null) { + XmlAuthorization.userRoles.clear(); + XmlAuthorization.userRoles = null; + } + if (XmlAuthorization.rolePermissions != null) { + XmlAuthorization.rolePermissions.clear(); + XmlAuthorization.rolePermissions = null; + } + XmlAuthorization.xmlLoadFailure = null; } /** * Change the region name to a standard format having single '/' as separator * and starting with a '/' as in standard POSIX paths */ - public static String normalizeRegionName(String regionName) { - + public static String normalizeRegionName(final String regionName) { if (regionName == null || regionName.length() == 0) { return EMPTY_VALUE; } + char[] resultName = new char[regionName.length() + 1]; boolean changed = false; boolean isPrevCharSlash = false; int startIndex; + if (regionName.charAt(0) != '/') { changed = true; startIndex = 0; - } - else { + } else { isPrevCharSlash = true; startIndex = 1; } + resultName[0] = '/'; int resultLength = 1; + // Replace all more than one '/'s with a single '/' for (int index = startIndex; index < regionName.length(); ++index) { char currChar = regionName.charAt(index); @@ -185,294 +192,82 @@ public class XmlAuthorization implements AccessControl { continue; } isPrevCharSlash = true; - } - else { + } else { isPrevCharSlash = false; } resultName[resultLength++] = currChar; } + // Remove any trailing slash if (resultName[resultLength - 1] == '/') { --resultLength; changed = true; } + if (changed) { return new String(resultName, 0, resultLength); - } - else { + } else { return regionName; } } - /** Get the attribute value for a given attribute name of a node. */ - private static String getAttributeValue(Node node, String attrName) { - - NamedNodeMap attrMap = node.getAttributes(); - Node attrNode; - if (attrMap != null && (attrNode = attrMap.getNamedItem(attrName)) != null) { - return ((Attr)attrNode).getValue(); - } - return EMPTY_VALUE; - } - - /** Get the string contained in the first text child of the node. */ - private static String getNodeValue(Node node) { - - NodeList childNodes = node.getChildNodes(); - for (int index = 0; index < childNodes.getLength(); index++) { - Node childNode = childNodes.item(index); - if (childNode.getNodeType() == Node.TEXT_NODE) { - return childNode.getNodeValue(); - } - } - return EMPTY_VALUE; - } - - /** - * Public static factory method to create an instance of - * <code>XmlAuthorization</code>. The fully qualified name of the class - * (<code>templates.security.XmlAuthorization.create</code>) - * should be mentioned as the <code>security-client-accessor</code> system - * property to enable pre-operation authorization checks as implemented in - * this class. - * - * @return an object of <code>XmlAuthorization</code> class - */ - public static AccessControl create() { - - return new XmlAuthorization(); - } - - /** - * Cache authorization information for all users statically. This method is - * not thread-safe and is should either be invoked only once, or the caller - * should take the appropriate locks. - * - * @param cache - * reference to the cache object for the distributed system - */ - private static void init(Cache cache) throws NotAuthorizedException { - - LogWriter logger = cache.getLogger(); - String xmlDocumentUri = (String)cache.getDistributedSystem() - .getSecurityProperties().get(DOC_URI_PROP_NAME); - try { - if (xmlDocumentUri == null) { - throw new NotAuthorizedException("No ACL file defined using tag [" - + DOC_URI_PROP_NAME + "] in system properties"); - } - if (xmlDocumentUri.equals(XmlAuthorization.currentDocUri)) { - if (XmlAuthorization.xmlLoadFailure != null) { - throw XmlAuthorization.xmlLoadFailure; - } - return; - } - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setValidating(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - XmlErrorHandler errorHandler = new XmlErrorHandler(logger, xmlDocumentUri); - builder.setErrorHandler(errorHandler); - builder.setEntityResolver(new AuthzDtdResolver()); - Document xmlDocument = builder.parse(xmlDocumentUri); - - XmlAuthorization.userRoles = new HashMap<String, HashSet<String>>(); - XmlAuthorization.rolePermissions = new HashMap<String, Map<String, - Map<OperationCode, FunctionSecurityPrmsHolder>>>(); - NodeList roleUserNodes = xmlDocument.getElementsByTagName(TAG_ROLE); - for (int roleIndex = 0; roleIndex < roleUserNodes.getLength(); - roleIndex++) { - Node roleUserNode = roleUserNodes.item(roleIndex); - String roleName = getAttributeValue(roleUserNode, ATTR_ROLENAME); - NodeList userNodes = roleUserNode.getChildNodes(); - for (int userIndex = 0; userIndex < userNodes.getLength(); - userIndex++) { - Node userNode = userNodes.item(userIndex); - if (userNode.getNodeName() == TAG_USER) { - String userName = getNodeValue(userNode); - HashSet<String> userRoleSet = XmlAuthorization.userRoles - .get(userName); - if (userRoleSet == null) { - userRoleSet = new HashSet<String>(); - XmlAuthorization.userRoles.put(userName, userRoleSet); - } - userRoleSet.add(roleName); - } - else { - throw new SAXParseException("Unknown tag [" - + userNode.getNodeName() + "] as child of tag [" + TAG_ROLE - + ']', null); - } - } - } - NodeList rolePermissionNodes = xmlDocument - .getElementsByTagName(TAG_PERMS); - for (int permIndex = 0; permIndex < rolePermissionNodes.getLength(); - permIndex++) { - Node rolePermissionNode = rolePermissionNodes.item(permIndex); - String roleName = getAttributeValue(rolePermissionNode, ATTR_ROLE); - Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>> - regionOperationMap = XmlAuthorization.rolePermissions.get(roleName); - if (regionOperationMap == null) { - regionOperationMap = new HashMap<String, - Map<OperationCode, FunctionSecurityPrmsHolder>>(); - XmlAuthorization.rolePermissions.put(roleName, regionOperationMap); - } - NodeList operationNodes = rolePermissionNode.getChildNodes(); - HashMap<OperationCode, FunctionSecurityPrmsHolder> operationMap = - new HashMap<OperationCode, FunctionSecurityPrmsHolder>(); - for (int opIndex = 0; opIndex < operationNodes.getLength(); opIndex++) { - Node operationNode = operationNodes.item(opIndex); - if (operationNode.getNodeName() == TAG_OP) { - String operationName = getNodeValue(operationNode); - OperationCode code = OperationCode.parse(operationName); - if (code == null) { - throw new SAXParseException("Unknown operation [" + operationName - + ']', null); - } - if (code != OperationCode.EXECUTE_FUNCTION) { - operationMap.put(code, null); - } - else { - String optimizeForWrite = getAttributeValue(operationNode, - ATTR_FUNCTION_OPTIMIZE_FOR_WRITE); - String functionAttr = getAttributeValue(operationNode, - ATTR_FUNCTION_IDS); - String keysAttr = getAttributeValue(operationNode, - ATTR_FUNCTION_KEY_SET); - - Boolean isOptimizeForWrite; - HashSet<String> functionIds; - HashSet<String> keySet; - - if (optimizeForWrite == null || optimizeForWrite.length() == 0) { - isOptimizeForWrite = null; - } - else { - isOptimizeForWrite = Boolean.parseBoolean(optimizeForWrite); - } - - if (functionAttr == null || functionAttr.length() == 0) { - functionIds = null; - } - else { - String[] functionArray = functionAttr.split(","); - functionIds = new HashSet<String>(); - for (int strIndex = 0; strIndex < functionArray.length; - ++strIndex) { - functionIds.add((functionArray[strIndex])); - } - } - - if (keysAttr == null || keysAttr.length() == 0) { - keySet = null; - } - else { - String[] keySetArray = keysAttr.split(","); - keySet = new HashSet<String>(); - for (int strIndex = 0; strIndex < keySetArray.length; - ++strIndex) { - keySet.add((keySetArray[strIndex])); - } - } - FunctionSecurityPrmsHolder functionContext = - new FunctionSecurityPrmsHolder(isOptimizeForWrite, - functionIds, keySet); - operationMap.put(code, functionContext); - } - } - else { - throw new SAXParseException("Unknown tag [" - + operationNode.getNodeName() + "] as child of tag [" - + TAG_PERMS + ']', null); - } - } - String regionNames = getAttributeValue(rolePermissionNode, ATTR_REGIONS); - if (regionNames == null || regionNames.length() == 0) { - regionOperationMap.put(EMPTY_VALUE, operationMap); - } - else { - String[] regionNamesSplit = regionNames.split(","); - for (int strIndex = 0; strIndex < regionNamesSplit.length; - ++strIndex) { - regionOperationMap.put( - normalizeRegionName(regionNamesSplit[strIndex]), operationMap); - } - } - } - XmlAuthorization.currentDocUri = xmlDocumentUri; - } - catch (Exception ex) { - String exStr; - if (ex instanceof NotAuthorizedException) { - exStr = ex.getMessage(); - } - else { - exStr = ex.getClass().getName() + ": " + ex.getMessage(); - } - logger.warning("XmlAuthorization.init: " + exStr); - XmlAuthorization.xmlLoadFailure = new NotAuthorizedException(exStr, ex); - throw XmlAuthorization.xmlLoadFailure; - } + private XmlAuthorization() { + this.allowedOps = new HashMap<String, Map<OperationCode, FunctionSecurityPrmsHolder>>(); + this.systemLogWriter = null; + this.securityLogWriter = null; } /** - * Initialize the <code>XmlAuthorization</code> callback for a client having + * Initialize the {@code XmlAuthorization} callback for a client having * the given principal. * * This method caches the full XML authorization file the first time it is * invoked and caches all the permissions for the provided - * <code>principal</code> to speed up lookup the - * <code>authorizeOperation</code> calls. The permissions for the principal + * {@code principal} to speed up lookup the + * {@code authorizeOperation} calls. The permissions for the principal * are maintained as a {@link Map} of region name to the {@link HashSet} of * operations allowed for that region. A global entry with region name as * empty string is also made for permissions provided for all the regions. * - * @param principal - * the principal associated with the authenticated client - * @param cache - * reference to the cache object - * @param remoteMember - * the {@link DistributedMember} object for the remote - * authenticated client + * @param principal + * the principal associated with the authenticated client + * @param cache + * reference to the cache object + * @param remoteMember + * the {@link DistributedMember} object for the remote authenticated + * client * * @throws NotAuthorizedException - * if some exception condition happens during the - * initialization while reading the XML; in such a case all - * subsequent client operations will throw - * <code>NotAuthorizedException</code> + * if some exception condition happens during the initialization + * while reading the XML; in such a case all subsequent client + * operations will throw {@code NotAuthorizedException} */ - public void init(Principal principal, DistributedMember remoteMember, - Cache cache) throws NotAuthorizedException { - + @Override + public void init(final Principal principal, final DistributedMember remoteMember, final Cache cache) throws NotAuthorizedException { synchronized (sync) { XmlAuthorization.init(cache); } - this.logger = cache.getLogger(); - this.securityLogger = cache.getSecurityLogger(); + + this.systemLogWriter = cache.getLogger(); + this.securityLogWriter = cache.getSecurityLogger(); String name; if (principal != null) { name = principal.getName(); - } - else { + } else { name = EMPTY_VALUE; } + HashSet<String> roles = XmlAuthorization.userRoles.get(name); if (roles != null) { for (String roleName : roles) { - Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>> - regionOperationMap = XmlAuthorization.rolePermissions.get(roleName); + Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>> regionOperationMap = XmlAuthorization.rolePermissions.get(roleName); if (regionOperationMap != null) { - for (Map.Entry<String, Map<OperationCode, FunctionSecurityPrmsHolder>> - regionEntry : regionOperationMap.entrySet()) { + for (Map.Entry<String, Map<OperationCode, FunctionSecurityPrmsHolder>> regionEntry : regionOperationMap.entrySet()) { String regionName = regionEntry.getKey(); - Map<OperationCode, FunctionSecurityPrmsHolder> regionOperations = - this.allowedOps.get(regionName); + Map<OperationCode, FunctionSecurityPrmsHolder> regionOperations = this.allowedOps.get(regionName); if (regionOperations == null) { - regionOperations = - new HashMap<OperationCode, FunctionSecurityPrmsHolder>(); + regionOperations = new HashMap<OperationCode, FunctionSecurityPrmsHolder>(); this.allowedOps.put(regionName, regionOperations); } regionOperations.putAll(regionEntry.getValue()); @@ -490,19 +285,18 @@ public class XmlAuthorization implements AccessControl { * empty region name are looked up. The operation is allowed if it is found * this permission list. * - * @param regionName - * When null then it indicates a cache-level operation, else - * the name of the region for the operation. - * @param context - * the data required by the operation + * @param regionName + * When null then it indicates a cache-level operation, else the + * name of the region for the operation. + * @param context + * the data required by the operation * * @return true if the operation is authorized and false otherwise - * */ - public boolean authorizeOperation(String regionName, - final OperationContext context) { - + @Override + public boolean authorizeOperation(String regionName, final OperationContext context) { Map<OperationCode, FunctionSecurityPrmsHolder> operationMap; + // Check GET permissions for updates from server to client if (context.isClientUpdate()) { operationMap = this.allowedOps.get(regionName); @@ -516,17 +310,15 @@ public class XmlAuthorization implements AccessControl { } OperationCode opCode = context.getOperationCode(); - if (opCode.isQuery() || opCode.isExecuteCQ() || opCode.isCloseCQ() - || opCode.isStopCQ()) { + if (opCode.isQuery() || opCode.isExecuteCQ() || opCode.isCloseCQ() || opCode.isStopCQ()) { // First check if cache-level permission has been provided operationMap = this.allowedOps.get(EMPTY_VALUE); - boolean globalPermission = (operationMap != null && operationMap - .containsKey(opCode)); - Set<String> regionNames = ((QueryOperationContext)context) - .getRegionNames(); + boolean globalPermission = (operationMap != null && operationMap .containsKey(opCode)); + Set<String> regionNames = ((QueryOperationContext)context) .getRegionNames(); if (regionNames == null || regionNames.size() == 0) { return globalPermission; } + for (String r : regionNames) { regionName = normalizeRegionName(r); operationMap = this.allowedOps.get(regionName); @@ -534,8 +326,7 @@ public class XmlAuthorization implements AccessControl { if (!globalPermission) { return false; } - } - else if (!operationMap.containsKey(opCode)) { + } else if (!operationMap.containsKey(opCode)) { return false; } } @@ -550,67 +341,52 @@ public class XmlAuthorization implements AccessControl { if (operationMap != null) { if (context.getOperationCode() != OperationCode.EXECUTE_FUNCTION) { return operationMap.containsKey(context.getOperationCode()); - }else { + + } else { if (!operationMap.containsKey(context.getOperationCode())) { return false; - } - else { + + } else { if (!context.isPostOperation()) { - FunctionSecurityPrmsHolder functionParameter = - operationMap.get( - context.getOperationCode()); - ExecuteFunctionOperationContext functionContext = - (ExecuteFunctionOperationContext)context; + FunctionSecurityPrmsHolder functionParameter = operationMap.get(context.getOperationCode()); + ExecuteFunctionOperationContext functionContext = (ExecuteFunctionOperationContext) context; // OnRegion execution if (functionContext.getRegionName() != null) { - if (functionParameter.isOptimizeForWrite() != null - && functionParameter.isOptimizeForWrite().booleanValue() - != functionContext.isOptimizeForWrite()) { + if (functionParameter.isOptimizeForWrite() != null && functionParameter.isOptimizeForWrite().booleanValue() != functionContext.isOptimizeForWrite()) { return false; } - if (functionParameter.getFunctionIds() != null - && !functionParameter.getFunctionIds().contains( - functionContext.getFunctionId())) { + if (functionParameter.getFunctionIds() != null && !functionParameter.getFunctionIds().contains( functionContext.getFunctionId())) { return false; } - if (functionParameter.getKeySet() != null - && functionContext.getKeySet() != null) { - if (functionContext.getKeySet().containsAll( - functionParameter.getKeySet())) { + if (functionParameter.getKeySet() != null && functionContext.getKeySet() != null) { + if (functionContext.getKeySet().containsAll( functionParameter.getKeySet())) { return false; } } return true; - } - else {// On Server execution - if (functionParameter.getFunctionIds() != null - && !functionParameter.getFunctionIds().contains( - functionContext.getFunctionId())) { + + } else {// On Server execution + if (functionParameter.getFunctionIds() != null && !functionParameter.getFunctionIds().contains(functionContext.getFunctionId())) { return false; } return true; } - } - else { - ExecuteFunctionOperationContext functionContext = - (ExecuteFunctionOperationContext)context; - FunctionSecurityPrmsHolder functionParameter = operationMap.get( - context.getOperationCode()); + + } else { + ExecuteFunctionOperationContext functionContext = (ExecuteFunctionOperationContext)context; + FunctionSecurityPrmsHolder functionParameter = operationMap.get(context.getOperationCode()); if (functionContext.getRegionName() != null) { - if (functionContext.getResult() instanceof ArrayList - && functionParameter.getKeySet() != null) { - ArrayList<String> resultList = (ArrayList)functionContext - .getResult(); - HashSet<String> nonAllowedKeys = functionParameter.getKeySet(); + if (functionContext.getResult() instanceof ArrayList && functionParameter.getKeySet() != null) { + ArrayList<String> resultList = (ArrayList)functionContext.getResult(); + Set<String> nonAllowedKeys = functionParameter.getKeySet(); if (resultList.containsAll(nonAllowedKeys)) { return false; } } return true; - } - else { - ArrayList<String> resultList = (ArrayList)functionContext - .getResult(); + + } else { + ArrayList<String> resultList = (ArrayList)functionContext.getResult(); final String inSecureItem = "Insecure item"; if (resultList.contains(inSecureItem)) { return false; @@ -627,41 +403,207 @@ public class XmlAuthorization implements AccessControl { /** * Clears the cached information for this principal. */ + @Override public void close() { - this.allowedOps.clear(); } + /** Get the attribute value for a given attribute name of a node. */ + private static String getAttributeValue(final Node node, final String attrName) { + NamedNodeMap attrMap = node.getAttributes(); + Node attrNode; + if (attrMap != null && (attrNode = attrMap.getNamedItem(attrName)) != null) { + return ((Attr)attrNode).getValue(); + } + return EMPTY_VALUE; + } + + /** Get the string contained in the first text child of the node. */ + private static String getNodeValue(final Node node) { + NodeList childNodes = node.getChildNodes(); + for (int index = 0; index < childNodes.getLength(); index++) { + Node childNode = childNodes.item(index); + if (childNode.getNodeType() == Node.TEXT_NODE) { + return childNode.getNodeValue(); + } + } + return EMPTY_VALUE; + } + /** - * Clear all the statically cached information. + * Cache authorization information for all users statically. This method is + * not thread-safe and is should either be invoked only once, or the caller + * should take the appropriate locks. + * + * @param cache reference to the cache object for the distributed system */ - public static void clear() { + private static void init(final Cache cache) throws NotAuthorizedException { + final LogWriter systemLogWriter = cache.getLogger(); + final String xmlDocumentUri = (String)cache.getDistributedSystem().getSecurityProperties().get(DOC_URI_PROP_NAME); - XmlAuthorization.currentDocUri = null; - if (XmlAuthorization.userRoles != null) { - XmlAuthorization.userRoles.clear(); - XmlAuthorization.userRoles = null; - } - if (XmlAuthorization.rolePermissions != null) { - XmlAuthorization.rolePermissions.clear(); - XmlAuthorization.rolePermissions = null; + try { + if (xmlDocumentUri == null) { + throw new NotAuthorizedException("No ACL file defined using tag [" + DOC_URI_PROP_NAME + "] in system properties"); + } + if (xmlDocumentUri.equals(XmlAuthorization.currentDocUri)) { + if (XmlAuthorization.xmlLoadFailure != null) { + throw XmlAuthorization.xmlLoadFailure; + } + return; + } + + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setValidating(true); + + final DocumentBuilder builder = factory.newDocumentBuilder(); + final XmlErrorHandler errorHandler = new XmlErrorHandler(systemLogWriter, xmlDocumentUri); + builder.setErrorHandler(errorHandler); + builder.setEntityResolver(new AuthzDtdResolver()); + + final Document xmlDocument = builder.parse(xmlDocumentUri); + + XmlAuthorization.userRoles = new HashMap<String, HashSet<String>>(); + XmlAuthorization.rolePermissions = new HashMap<String, Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>>>(); + + final NodeList roleUserNodes = xmlDocument.getElementsByTagName(TAG_ROLE); + + for (int roleIndex = 0; roleIndex < roleUserNodes.getLength(); roleIndex++) { + final Node roleUserNode = roleUserNodes.item(roleIndex); + final String roleName = getAttributeValue(roleUserNode, ATTR_ROLENAME); + final NodeList userNodes = roleUserNode.getChildNodes(); + + for (int userIndex = 0; userIndex < userNodes.getLength(); userIndex++) { + final Node userNode = userNodes.item(userIndex); + + if (userNode.getNodeName() == TAG_USER) { + final String userName = getNodeValue(userNode); + HashSet<String> userRoleSet = XmlAuthorization.userRoles.get(userName); + if (userRoleSet == null) { + userRoleSet = new HashSet<String>(); + XmlAuthorization.userRoles.put(userName, userRoleSet); + } + userRoleSet.add(roleName); + + } else { + throw new SAXParseException("Unknown tag [" + userNode.getNodeName() + "] as child of tag [" + TAG_ROLE + ']', null); + } + } + } + + final NodeList rolePermissionNodes = xmlDocument.getElementsByTagName(TAG_PERMS); + + for (int permIndex = 0; permIndex < rolePermissionNodes.getLength(); permIndex++) { + final Node rolePermissionNode = rolePermissionNodes.item(permIndex); + final String roleName = getAttributeValue(rolePermissionNode, ATTR_ROLE); + Map<String, Map<OperationCode, FunctionSecurityPrmsHolder>> regionOperationMap = XmlAuthorization.rolePermissions.get(roleName); + + if (regionOperationMap == null) { + regionOperationMap = new HashMap<String, Map<OperationCode, FunctionSecurityPrmsHolder>>(); + XmlAuthorization.rolePermissions.put(roleName, regionOperationMap); + } + + final NodeList operationNodes = rolePermissionNode.getChildNodes(); + final HashMap<OperationCode, FunctionSecurityPrmsHolder> operationMap = new HashMap<OperationCode, FunctionSecurityPrmsHolder>(); + + for (int opIndex = 0; opIndex < operationNodes.getLength(); opIndex++) { + final Node operationNode = operationNodes.item(opIndex); + + if (operationNode.getNodeName() == TAG_OP) { + final String operationName = getNodeValue(operationNode); + final OperationCode code = OperationCode.parse(operationName); + + if (code == null) { + throw new SAXParseException("Unknown operation [" + operationName + ']', null); + } + + if (code != OperationCode.EXECUTE_FUNCTION) { + operationMap.put(code, null); + + } else { + final String optimizeForWrite = getAttributeValue(operationNode, ATTR_FUNCTION_OPTIMIZE_FOR_WRITE); + final String functionAttr = getAttributeValue(operationNode, ATTR_FUNCTION_IDS); + final String keysAttr = getAttributeValue(operationNode, ATTR_FUNCTION_KEY_SET); + + Boolean isOptimizeForWrite; + HashSet<String> functionIds; + HashSet<String> keySet; + + if (optimizeForWrite == null || optimizeForWrite.length() == 0) { + isOptimizeForWrite = null; + } else { + isOptimizeForWrite = Boolean.parseBoolean(optimizeForWrite); + } + + if (functionAttr == null || functionAttr.length() == 0) { + functionIds = null; + } else { + final String[] functionArray = functionAttr.split(","); + functionIds = new HashSet<String>(); + for (int strIndex = 0; strIndex < functionArray.length; ++strIndex) { + functionIds.add((functionArray[strIndex])); + } + } + + if (keysAttr == null || keysAttr.length() == 0) { + keySet = null; + } else { + final String[] keySetArray = keysAttr.split(","); + keySet = new HashSet<String>(); + for (int strIndex = 0; strIndex < keySetArray.length; ++strIndex) { + keySet.add((keySetArray[strIndex])); + } + } + + final FunctionSecurityPrmsHolder functionContext = new FunctionSecurityPrmsHolder(isOptimizeForWrite, functionIds, keySet); + operationMap.put(code, functionContext); + } + + } else { + throw new SAXParseException("Unknown tag [" + operationNode.getNodeName() + "] as child of tag [" + TAG_PERMS + ']', null); + } + } + + final String regionNames = getAttributeValue(rolePermissionNode, ATTR_REGIONS); + if (regionNames == null || regionNames.length() == 0) { + regionOperationMap.put(EMPTY_VALUE, operationMap); + } else { + final String[] regionNamesSplit = regionNames.split(","); + for (int strIndex = 0; strIndex < regionNamesSplit.length; ++strIndex) { + regionOperationMap.put(normalizeRegionName(regionNamesSplit[strIndex]), operationMap); + } + } + } + XmlAuthorization.currentDocUri = xmlDocumentUri; + + } catch (Exception ex) { + String message; + if (ex instanceof NotAuthorizedException) { + message = ex.getMessage(); + } + else { + message = ex.getClass().getName() + ": " + ex.getMessage(); + } + systemLogWriter.warning("XmlAuthorization.init: " + message); + XmlAuthorization.xmlLoadFailure = new NotAuthorizedException(message, ex); + throw XmlAuthorization.xmlLoadFailure; } - XmlAuthorization.xmlLoadFailure = null; } - + private static class AuthzDtdResolver implements EntityResolver { - Pattern authzPattern = Pattern.compile("authz.*\\.dtd"); + final Pattern authzPattern = Pattern.compile("authz.*\\.dtd"); @Override - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException, IOException { + public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException { try { - Matcher matcher = authzPattern.matcher(systemId); - if(matcher.find()) { - String dtdName = matcher.group(0); - InputStream stream = XmlAuthorization.class.getResourceAsStream(dtdName); + final Matcher matcher = authzPattern.matcher(systemId); + if (matcher.find()) { + final String dtdName = matcher.group(0); + final InputStream stream = XmlAuthorization.class.getResourceAsStream(dtdName); return new InputSource(stream); } + } catch(Exception e) { //do nothing, use the default resolver } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a6388000/geode-core/src/test/java/templates/security/XmlErrorHandler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/templates/security/XmlErrorHandler.java b/geode-core/src/test/java/templates/security/XmlErrorHandler.java index 1326548..8e30f46 100755 --- a/geode-core/src/test/java/templates/security/XmlErrorHandler.java +++ b/geode-core/src/test/java/templates/security/XmlErrorHandler.java @@ -27,23 +27,21 @@ import org.xml.sax.SAXParseException; * Implementation of {@link ErrorHandler} interface to handle validation errors * while XML parsing. * - * This throws back exceptions raised for <code>error</code> and - * <code>fatalError</code> cases while a {@link LogWriter#warning(String)} level - * logging is done for the <code>warning</code> case. + * This throws back exceptions raised for {@code error} and {@code fatalError} + * cases while a {@link LogWriter#warning(String)} level logging is done for + * the {@code warning} case. * - * @author Sumedh Wale * @since 5.5 */ public class XmlErrorHandler implements ErrorHandler { - private static final Logger logger = LogService.getLogger(); - - private LogWriter logWriter; - private String xmlFileName; + private static final Logger logger = LogService.getLogger(); - public XmlErrorHandler(LogWriter logWriter, String xmlFileName) { + private final LogWriter systemLogWriter; + private final String xmlFileName; - this.logWriter = logWriter; + public XmlErrorHandler(final LogWriter systemLogWriter, final String xmlFileName) { + this.systemLogWriter = systemLogWriter; this.xmlFileName = xmlFileName; } @@ -51,31 +49,23 @@ public class XmlErrorHandler implements ErrorHandler { * Throws back the exception with the name of the XML file and the position * where the exception occurred. */ - public void error(SAXParseException exception) throws SAXException { - throw new SAXParseException("Error while parsing XML at line " - + exception.getLineNumber() + " column " + exception.getColumnNumber() - + ": " + exception.getMessage(), null, exception); + public void error(final SAXParseException exception) throws SAXException { + throw new SAXParseException("Error while parsing XML at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), null, exception); } /** * Throws back the exception with the name of the XML file and the position * where the exception occurred. */ - public void fatalError(SAXParseException exception) throws SAXException { - throw new SAXParseException("Fatal error while parsing XML at line " - + exception.getLineNumber() + " column " + exception.getColumnNumber() - + ": " + exception.getMessage(), null, exception); + public void fatalError(final SAXParseException exception) throws SAXException { + throw new SAXParseException("Fatal error while parsing XML at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), null, exception); } /** * Log the exception at {@link LogWriter#warning(String)} level with XML * filename and the position of exception in the file. */ - public void warning(SAXParseException exception) throws SAXException { - this.logWriter.warning("Warning while parsing XML [" + this.xmlFileName - + "] at line " + exception.getLineNumber() + " column " - + exception.getColumnNumber() + ": " + exception.getMessage(), exception); + public void warning(final SAXParseException exception) throws SAXException { + this.systemLogWriter.warning("Warning while parsing XML [" + this.xmlFileName + "] at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), exception); } - - }