http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/AuthzCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/AuthzCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/AuthzCredentialGenerator.java new file mode 100755 index 0000000..1a99974 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/AuthzCredentialGenerator.java @@ -0,0 +1,447 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; + +import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode; +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.security.AccessControl; +import com.gemstone.gemfire.security.templates.DummyAuthorization; +import com.gemstone.gemfire.security.templates.XmlAuthorization; + +/** + * Encapsulates obtaining authorized and unauthorized credentials for a given + * operation in a region. Implementations will be for different kinds of + * authorization scheme and authentication scheme combos. + * + * @since GemFire 5.5 + */ +public abstract class AuthzCredentialGenerator { + + private static final Logger logger = LogService.getLogger(); + + /** + * The {@link CredentialGenerator} being used. + */ + protected CredentialGenerator generator; + + /** + * A set of system properties that should be added to the gemfire system + * properties before using the authorization module. + */ + private Properties systemProperties; + + /** + * A factory method to create a new instance of an + * {@link AuthzCredentialGenerator} for the given {@link ClassCode}. Caller + * is supposed to invoke {@link AuthzCredentialGenerator#init} immediately + * after obtaining the instance. + * + * @param classCode + * the {@code ClassCode} of the {@code AuthzCredentialGenerator} + * implementation + * + * @return an instance of {@code AuthzCredentialGenerator} for the given + * class code + */ + public static AuthzCredentialGenerator create(final ClassCode classCode) { + switch (classCode.classType) { + case ClassCode.ID_DUMMY: + return new DummyAuthzCredentialGenerator(); + case ClassCode.ID_XML: + return new XmlAuthzCredentialGenerator(); + default: + return null; + } + } + + /** + * Initialize the authorized credential generator. + * + * @param generator + * an instance of {@link CredentialGenerator} of the credential + * implementation for which to obtain authorized/unauthorized + * credentials. + * + * @return false when the given {@link CredentialGenerator} is incompatible + * with this authorization module. + */ + public boolean init(final CredentialGenerator generator) { + this.generator = generator; + try { + this.systemProperties = init(); + } catch (IllegalArgumentException ex) { + return false; + } + return true; + } + + /** + * + * @return A set of extra properties that should be added to Gemfire system + * properties when not null. + */ + public Properties getSystemProperties() { + return this.systemProperties; + } + + /** + * Get the {@link CredentialGenerator} being used by this instance. + */ + public CredentialGenerator getCredentialGenerator() { + return this.generator; + } + + /** + * Initialize the authorized credential generator. + * + * Required to be implemented by concrete classes that implement this abstract + * class. + * + * @return A set of extra properties that should be added to Gemfire system + * properties when not null. + * + * @throws IllegalArgumentException when the {@link CredentialGenerator} is + * incompatible with this authorization module. + */ + protected abstract Properties init() throws IllegalArgumentException; + + /** + * The {@link ClassCode} of the particular implementation. + * + * @return the {@code ClassCode} + */ + public abstract ClassCode classCode(); + + /** + * The name of the {@link AccessControl} factory function that should be used + * as the authorization module on the server side. + * + * @return name of the {@code AccessControl} factory function + */ + public abstract String getAuthorizationCallback(); + + /** + * Get a set of credentials generated using the given index allowed to perform + * the given {@link OperationCode}s for the given regions. + * + * @param opCodes + * the list of {@link OperationCode}s of the operations requiring + * authorization; should not be null + * @param regionNames + * list of the region names requiring authorization; a value of + * null indicates all regions + * @param index + * used to generate multiple such credentials by passing different + * values for this + * + * @return the set of credentials authorized to perform the given operation in + * the given regions + */ + public Properties getAllowedCredentials(final OperationCode[] opCodes, final String[] regionNames, final int index) { + int numTries = getNumPrincipalTries(opCodes, regionNames); + if (numTries <= 0) { + numTries = 1; + } + + for (int tries = 0; tries < numTries; tries++) { + final Principal principal = getAllowedPrincipal(opCodes, regionNames, (index + tries) % numTries); + try { + return this.generator.getValidCredentials(principal); + } catch (IllegalArgumentException ex) { + } + } + return null; + } + + /** + * Get a set of credentials generated using the given index not allowed to + * perform the given {@link OperationCode}s for the given regions. The + * credentials are required to be valid for authentication. + * + * @param opCodes + * the {@link OperationCode}s of the operations requiring + * authorization failure; should not be null + * @param regionNames + * list of the region names requiring authorization failure; a value + * of null indicates all regions + * @param index + * used to generate multiple such credentials by passing different + * values for this + * + * @return the set of credentials that are not authorized to perform the given + * operation in the given region + */ + public Properties getDisallowedCredentials(final OperationCode[] opCodes, final String[] regionNames, final int index) { + // This may not be very correct since we use the value of + // getNumPrincipalTries() but is used to avoid adding another method. + // Also something like getNumDisallowedPrincipals() will be normally always + // infinite, and the number here is just to perform some number of tries + // before giving up. + + int numTries = getNumPrincipalTries(opCodes, regionNames); + if (numTries <= 0) { + numTries = 1; + } + + for (int tries = 0; tries < numTries; tries++) { + final Principal principal = getDisallowedPrincipal(opCodes, regionNames, (index + tries) % numTries); + try { + return this.generator.getValidCredentials(principal); + } catch (IllegalArgumentException ex) { + } + } + return null; + } + + /** + * Get the number of tries to be done for obtaining valid credentials for the + * given operations in the given region. It is required that + * {@link #getAllowedPrincipal} method returns valid principals for values of + * {@code index} from 0 through (n-1) where {@code n} is the + * value returned by this method. It is recommended that the principals so + * returned be unique for efficiency. + * + * This will be used by {@link #getAllowedCredentials} to step through + * different principals and obtain a set of valid credentials. + * + * Required to be implemented by concrete classes that implement this abstract + * class. + * + * @param opCodes + * the {@link OperationCode}s of the operations requiring + * authorization + * @param regionNames + * list of the region names requiring authorization; a value of null + * indicates all regions + * + * @return the number of principals allowed to perform the given operation in + * the given region + */ + protected abstract int getNumPrincipalTries(final OperationCode[] opCodes, final String[] regionNames); + + /** + * Get a {@link Principal} generated using the given index allowed to perform + * the given {@link OperationCode}s for the given region. + * + * Required to be implemented by concrete classes that implement this abstract + * class. + * + * @param opCodes + * the {@link OperationCode}s of the operations requiring + * authorization + * @param regionNames + * list of the region names requiring authorization; a value of null + * indicates all regions + * @param index + * used to generate multiple such principals by passing different + * values for this + * + * @return the {@link Principal} authorized to perform the given operation in + * the given region + */ + protected abstract Principal getAllowedPrincipal(final OperationCode[] opCodes, final String[] regionNames, final int index); + + /** + * Get a {@link Principal} generated using the given index not allowed to + * perform the given {@link OperationCode}s for the given region. + * + * Required to be implemented by concrete classes that implement this abstract + * class. + * + * @param opCodes + * the {@link OperationCode}s of the operations requiring + * authorization failure + * @param regionNames + * list of the region names requiring authorization failure; a value + * of null indicates all regions + * @param index + * used to generate multiple such principals by passing different + * values for this + * + * @return a {@link Principal} not authorized to perform the given operation + * in the given region + */ + protected abstract Principal getDisallowedPrincipal(final OperationCode[] opCodes, final String[] regionNames, final int index); + + /** + * Enumeration for various {@link AuthzCredentialGenerator} implementations. + * + * <p>The following schemes are supported as of now: + * <ul> + * <li>{@code DummyAuthorization} with {@code DummyAuthenticator}</li> + * <li>{@code XMLAuthorization} with {@code DummyAuthenticator}</li> + * <li>{@code XMLAuthorization} with {@code LDAPAuthenticator}</li> + * <li>{@code XMLAuthorization} with {@code PKCSAuthenticator}</li> + * <li>{@code XMLAuthorization} when using SSL sockets</li> + * </ul> + * + * <p>To add a new authorization scheme the following needs to be done: + * <ul> + * <li>Add implementation for {@link AccessControl}.</li> + * <li>Choose the authentication schemes that it shall work with from + * {@link CredentialGenerator.ClassCode}</li> + * <li>Add a new enumeration value for the scheme in this class. Notice the + * size of {@code VALUES} array and increase that if it is getting + * overflowed. Note the methods and fields for existing schemes and add for + * the new one in a similar manner.</li> + * <li>Add an implementation for {@link AuthzCredentialGenerator}. Note the + * {@link AuthzCredentialGenerator#init} method where different authentication + * schemes can be passed and initialize differently for the authentication + * schemes that shall be handled.</li> + * <li>Modify the {@link AuthzCredentialGenerator#create} method to add + * creation of an instance of the new implementation for the + * {@code ClassCode} enumeration value.</li> + * </ul> + * + * <p>All dunit tests will automagically start testing the new implementation + * after this. + * + * @since GemFire 5.5 + */ + public static final class ClassCode { + + private static byte nextOrdinal = 0; + + private static final byte ID_DUMMY = 1; + private static final byte ID_XML = 2; + + private static final ClassCode[] VALUES = new ClassCode[10]; + private static final Map CODE_NAME_MAP = new HashMap(); + + public static final ClassCode DUMMY = new ClassCode(DummyAuthorization.class.getName() + ".create", ID_DUMMY); + public static final ClassCode XML = new ClassCode(XmlAuthorization.class.getName() + ".create", ID_XML); + + /** The name of this class. */ + private final String name; + + /** byte used as ordinal to represent this class */ + private final byte ordinal; + + /** + * One of the following: ID_DUMMY, ID_LDAP, ID_PKI + */ + private final byte classType; + + /** Creates a new instance of class code. */ + private ClassCode(final String name, final byte classType) { + this.name = name; + this.classType = classType; + this.ordinal = nextOrdinal++; + VALUES[this.ordinal] = this; + CODE_NAME_MAP.put(name, this); + } + + public boolean isDummy() { + return this.classType == ID_DUMMY; + } + + public boolean isXml() { + return this.classType == ID_XML; + } + + /** + * Returns the {@code ClassCode} represented by specified ordinal. + */ + public static ClassCode fromOrdinal(final byte ordinal) { + return VALUES[ordinal]; + } + + /** + * Returns the {@code ClassCode} represented by specified string. + */ + public static ClassCode parse(final String operationName) { + return (ClassCode) CODE_NAME_MAP.get(operationName); + } + + /** + * Returns all the possible values. + */ + public static List getAll() { + final List codes = new ArrayList(); + for (Iterator iter = CODE_NAME_MAP.values().iterator(); iter.hasNext();) { + codes.add(iter.next()); + } + return codes; + } + + /** + * Returns the ordinal for this class code. + * + * @return the ordinal of this class code. + */ + public byte toOrdinal() { + return this.ordinal; + } + + /** + * Returns a string representation for this class code. + * + * @return the name of this class code. + */ + @Override + public final String toString() { + return this.name; + } + + /** + * Indicates whether other object is same as this one. + * + * @return true if other object is same as this one. + */ + @Override + public final boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ClassCode)) { + return false; + } + final ClassCode other = (ClassCode)obj; + return other.ordinal == this.ordinal; + } + + /** + * Indicates whether other {@code ClassCode} is same as this one. + * + * @return true if other {@code ClassCode} is same as this one. + */ + public final boolean equals(final ClassCode opCode) { + return opCode != null && opCode.ordinal == this.ordinal; + } + + /** + * Returns a hash code value for this {@code ClassCode} which is the + * same as its ordinal. + * + * @return the ordinal of this {@code ClassCode}. + */ + @Override + public final int hashCode() { + return this.ordinal; + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/CredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/CredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/CredentialGenerator.java new file mode 100755 index 0000000..90584cd --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/CredentialGenerator.java @@ -0,0 +1,333 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; + +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.security.AuthInitialize; +import com.gemstone.gemfire.security.Authenticator; +import com.gemstone.gemfire.security.templates.DummyAuthenticator; +import com.gemstone.gemfire.security.templates.LdapUserAuthenticator; +import com.gemstone.gemfire.security.templates.PKCSAuthenticator; + +/** + * Encapsulates obtaining valid and invalid credentials. Implementations will be + * for different kinds of authentication schemes. + * + * @since GemFire 5.5 + */ +public abstract class CredentialGenerator { + + private static final Logger logger = LogService.getLogger(); + + /** + * A set of properties that should be added to the Gemfire system properties + * before using the authentication module. + */ + private Properties systemProperties = null; + + /** + * A set of properties that should be added to the java system properties + * before using the authentication module. + */ + protected Properties javaProperties = null; + + /** + * A factory method to create a new instance of an {@link CredentialGenerator} + * for the given {@link ClassCode}. Caller is supposed to invoke + * {@link CredentialGenerator#init} immediately after obtaining the instance. + * + * @param classCode + * the {@code ClassCode} of the {@code CredentialGenerator} + * implementation + * + * @return an instance of {@code CredentialGenerator} for the given class + * code + */ + public static CredentialGenerator create(final ClassCode classCode) { + switch (classCode.classType) { + // Removing dummy one to reduce test run times + // case ClassCode.ID_DUMMY: + // return new DummyCredentialGenerator(); + case ClassCode.ID_LDAP: + return new LdapUserCredentialGenerator(); + // case ClassCode.ID_SSL:ø + // return new SSLCredentialGenerator(); + case ClassCode.ID_PKCS: + return new PKCSCredentialGenerator(); + default: + return null; + } + } + + /** + * Initialize the credential generator. + * + * @throws IllegalArgumentException when there is a problem during + * initialization + */ + public void init() throws IllegalArgumentException { + this.systemProperties = initialize(); + logger.info("Generating CredentialGenerator with {}", this.systemProperties); + } + + /** + * @return A set of extra properties that should be added to Gemfire system + * properties when not null. + */ + public Properties getSystemProperties() { + return this.systemProperties; + } + + /** + * @return A set of extra properties that should be added to Gemfire system + * properties when not null. + */ + public Properties getJavaProperties() { + return this.javaProperties; + } + + /** + * The {@link ClassCode} of this particular implementation. + * + * @return the {@code ClassCode} + */ + public abstract ClassCode classCode(); + + /** + * The name of the {@link AuthInitialize} factory function that should be used + * in conjunction with the credentials generated by this generator. + * + * @return name of the {@code AuthInitialize} factory function + */ + public abstract String getAuthInit(); + + /** + * The name of the {@link Authenticator} factory function that should be used + * in conjunction with the credentials generated by this generator. + * + * @return name of the {@code Authenticator} factory function + */ + public abstract String getAuthenticator(); + + /** + * Get a set of valid credentials generated using the given index. + */ + public abstract Properties getValidCredentials(final int index); + + /** + * Get a set of valid credentials for the given {@link Principal}. + * + * @return credentials for the given {@code Principal} or null if none + * possible. + */ + public abstract Properties getValidCredentials(final Principal principal); + + /** + * Get a set of invalid credentials generated using the given index. + */ + public abstract Properties getInvalidCredentials(final int index); + + /** + * Initialize the credential generator. This is provided separately from the + * {@link #init()} method for convenience of implementations so that they do not + * need to store in {@link #systemProperties}. The latter is convenient for the users + * who do not need to store these properties rather can obtain it later by + * invoking {@link #getSystemProperties()} + * + * <p>Required to be implemented by concrete classes that implement this abstract + * class. + * + * @return A set of extra properties that should be added to Gemfire system + * properties when not null. + * + * @throws IllegalArgumentException when there is a problem during + * initialization + */ + protected abstract Properties initialize() throws IllegalArgumentException; + + /** + * Enumeration for various {@link CredentialGenerator} implementations. + * + * <p>The following schemes are supported as of now: + * {@code DummyAuthenticator}, {@code LdapUserAuthenticator}, + * {@code PKCSAuthenticator}. In addition SSL socket mode with mutual + * authentication is also supported. + * + * <p>To add a new authentication scheme the following needs to be done: + * <ul> + * <li>Add implementations for {@link AuthInitialize} and + * {@link Authenticator} classes for clients/peers.</li> + * <li>Add a new enumeration value for the scheme in this class. Notice the + * size of {@code VALUES} array and increase that if it is getting + * overflowed. Note the methods and fields for existing schemes and add for + * the new one in a similar manner.</li> + * <li>Add an implementation for {@link CredentialGenerator}.</li> + * <li>Modify the CredentialGenerator.Factory#create [no such Factory exists] method to add + * creation of an instance of the new implementation for the + * {@code ClassCode} enumeration value.</li> + * </ul> + * + * <p>All security dunit tests will automagically start testing the new + * implementation after this. + * + * @since GemFire 5.5 + */ + public static final class ClassCode { + + private static byte nextOrdinal = 0; + + private static final byte ID_DUMMY = 1; + private static final byte ID_LDAP = 2; + private static final byte ID_PKCS = 3; + private static final byte ID_SSL = 4; + + private static final ClassCode[] VALUES = new ClassCode[10]; + private static final Map CODE_NAME_MAP = new HashMap(); + + public static final ClassCode DUMMY = new ClassCode(DummyAuthenticator.class.getName() + ".create", ID_DUMMY); + public static final ClassCode LDAP = new ClassCode(LdapUserAuthenticator.class.getName() + ".create", ID_LDAP); + public static final ClassCode PKCS = new ClassCode(PKCSAuthenticator.class.getName() + ".create", ID_PKCS); + public static final ClassCode SSL = new ClassCode("SSL", ID_SSL); + + /** The name of this class. */ + private final String name; + + /** byte used as ordinal to represent this class */ + private final byte ordinal; + + /** + * One of the following: ID_DUMMY, ID_LDAP, ID_PKCS + */ + private final byte classType; + + /** Creates a new instance of class code. */ + private ClassCode(final String name, final byte classType) { + this.name = name; + this.classType = classType; + this.ordinal = nextOrdinal++; + VALUES[this.ordinal] = this; + CODE_NAME_MAP.put(name, this); + } + + public boolean isDummy() { + return this.classType == ID_DUMMY; + } + + public boolean isLDAP() { + return this.classType == ID_LDAP; + } + + public boolean isPKCS() { + return this.classType == ID_PKCS; + } + + public boolean isSSL() { + return this.classType == ID_SSL; + } + + /** + * Returns the {@code ClassCode} represented by specified ordinal. + */ + public static ClassCode fromOrdinal(final byte ordinal) { + return VALUES[ordinal]; + } + + /** + * Returns the {@code ClassCode} represented by specified string. + */ + public static ClassCode parse(final String operationName) { + return (ClassCode) CODE_NAME_MAP.get(operationName); + } + + /** + * Returns all the possible values. + */ + public static List getAll() { + final List codes = new ArrayList(); + for (Iterator iter = CODE_NAME_MAP.values().iterator(); iter.hasNext();) { + codes.add(iter.next()); + } + return codes; + } + + /** + * Returns the ordinal for this operation code. + * + * @return the ordinal of this operation. + */ + public byte toOrdinal() { + return this.ordinal; + } + + /** + * Returns a string representation for this operation. + * + * @return the name of this operation. + */ + @Override + public final String toString() { + return this.name; + } + + /** + * Indicates whether other object is same as this one. + * + * @return true if other object is same as this one. + */ + @Override + public final boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ClassCode)) { + return false; + } + final ClassCode other = (ClassCode)obj; + return other.ordinal == this.ordinal; + } + + /** + * Indicates whether other {@code ClassCode} is same as this one. + * + * @return true if other {@code ClassCode} is same as this one. + */ + public final boolean equals(final ClassCode opCode) { + return opCode != null && opCode.ordinal == this.ordinal; + } + + /** + * Returns a hash code value for this {@code ClassCode} which is the + * same as its ordinal. + * + * @return the ordinal of this operation. + */ + @Override + public final int hashCode() { + return this.ordinal; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/DummyAuthzCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/DummyAuthzCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/DummyAuthzCredentialGenerator.java new file mode 100755 index 0000000..64fb84a --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/DummyAuthzCredentialGenerator.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import java.security.Principal; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode; +import com.gemstone.gemfire.security.templates.DummyAuthorization; +import com.gemstone.gemfire.security.templates.UsernamePrincipal; + +public class DummyAuthzCredentialGenerator extends AuthzCredentialGenerator { + + public static final byte READER_ROLE = 1; + public static final byte WRITER_ROLE = 2; + public static final byte ADMIN_ROLE = 3; + + private static Set readerOpsSet; + private static Set writerOpsSet; + + static { + readerOpsSet = new HashSet(); + for (int index = 0; index < DummyAuthorization.READER_OPS.length; index++) { + readerOpsSet.add(DummyAuthorization.READER_OPS[index]); + } + + writerOpsSet = new HashSet(); + for (int index = 0; index < DummyAuthorization.WRITER_OPS.length; index++) { + writerOpsSet.add(DummyAuthorization.WRITER_OPS[index]); + } + } + + public static byte getRequiredRole(final OperationCode[] opCodes) { + byte roleType = ADMIN_ROLE; + boolean requiresReader = true; + boolean requiresWriter = true; + + for (int opNum = 0; opNum < opCodes.length; opNum++) { + if (requiresReader && !readerOpsSet.contains(opCodes[opNum])) { + requiresReader = false; + } + if (requiresWriter && !writerOpsSet.contains(opCodes[opNum])) { + requiresWriter = false; + } + } + if (requiresReader) { + roleType = READER_ROLE; + } + else if (requiresWriter) { + roleType = WRITER_ROLE; + } + return roleType; + } + + @Override + protected Properties init() throws IllegalArgumentException { + if (!this.generator.classCode().isDummy()) { + throw new IllegalArgumentException("DummyAuthorization module only works with DummyAuthenticator"); + } + return null; + } + + @Override + public ClassCode classCode() { + return ClassCode.DUMMY; + } + + @Override + public String getAuthorizationCallback() { + return DummyAuthorization.class.getName() + ".create"; + } + + @Override + protected Principal getAllowedPrincipal(final OperationCode[] opCodes, final String[] regionNames, final int index) { + final byte roleType = getRequiredRole(opCodes); + return getPrincipal(roleType, index); + } + + @Override + protected Principal getDisallowedPrincipal(final OperationCode[] opCodes, final String[] regionNames, final int index) { + byte roleType = getRequiredRole(opCodes); + byte disallowedRoleType; + switch (roleType) { + case READER_ROLE: + disallowedRoleType = WRITER_ROLE; + break; + case WRITER_ROLE: + disallowedRoleType = READER_ROLE; + break; + default: + disallowedRoleType = READER_ROLE; + break; + } + return getPrincipal(disallowedRoleType, index); + } + + @Override + protected int getNumPrincipalTries(final OperationCode[] opCodes, final String[] regionNames) { + return 5; + } + + private Principal getPrincipal(final byte roleType, final int index) { + String[] admins = new String[] { "root", "admin", "administrator" }; + switch (roleType) { + case READER_ROLE: + return new UsernamePrincipal("reader" + index); + case WRITER_ROLE: + return new UsernamePrincipal("writer" + index); + default: + return new UsernamePrincipal(admins[index % admins.length]); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/DummyCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/DummyCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/DummyCredentialGenerator.java new file mode 100755 index 0000000..77ffbd9 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/DummyCredentialGenerator.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import java.security.Principal; +import java.util.Properties; + +import com.gemstone.gemfire.security.templates.DummyAuthenticator; +import com.gemstone.gemfire.security.templates.UserPasswordAuthInit; + +public class DummyCredentialGenerator extends CredentialGenerator { + + @Override + protected Properties initialize() throws IllegalArgumentException { + return null; + } + + @Override + public ClassCode classCode() { + return ClassCode.DUMMY; + } + + @Override + public String getAuthInit() { + return UserPasswordAuthInit.class.getName() + ".create"; + } + + @Override + public String getAuthenticator() { + return DummyAuthenticator.class.getName() + ".create"; + } + + @Override + public Properties getValidCredentials(final int index) { + final String[] validGroups = new String[] { "admin", "user", "reader", "writer" }; + final String[] admins = new String[] { "root", "admin", "administrator" }; + + final Properties props = new Properties(); + final int groupNum = index % validGroups.length; + + String userName; + if (groupNum == 0) { + userName = admins[index % admins.length]; + } else { + userName = validGroups[groupNum] + (index / validGroups.length); + } + + props.setProperty(UserPasswordAuthInit.USER_NAME, userName); + props.setProperty(UserPasswordAuthInit.PASSWORD, userName); + return props; + } + + @Override + public Properties getValidCredentials(final Principal principal) { + final String userName = principal.getName(); + + if (DummyAuthenticator.checkValidName(userName)) { + Properties props = new Properties(); + props.setProperty(UserPasswordAuthInit.USER_NAME, userName); + props.setProperty(UserPasswordAuthInit.PASSWORD, userName); + return props; + + } else { + throw new IllegalArgumentException("Dummy: [" + userName + "] is not a valid user"); + } + } + + @Override + public Properties getInvalidCredentials(int index) { + Properties props = new Properties(); + props.setProperty(UserPasswordAuthInit.USER_NAME, "invalid" + index); + props.setProperty(UserPasswordAuthInit.PASSWORD, "none"); + return props; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/LdapUserCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/LdapUserCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/LdapUserCredentialGenerator.java new file mode 100755 index 0000000..7cde86d --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/LdapUserCredentialGenerator.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import com.gemstone.gemfire.distributed.internal.DistributionConfig; +import com.gemstone.gemfire.internal.cache.tier.sockets.HandShake; +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.security.templates.LdapUserAuthenticator; +import com.gemstone.gemfire.security.templates.UserPasswordAuthInit; +import com.gemstone.gemfire.test.dunit.Assert; +import com.gemstone.gemfire.util.test.TestUtil; +import org.apache.logging.log4j.Logger; + +import java.security.Principal; +import java.util.Properties; +import java.util.Random; + +import static com.gemstone.gemfire.distributed.ConfigurationProperties.*; + +public class LdapUserCredentialGenerator extends CredentialGenerator { + + private static final Logger logger = LogService.getLogger(); + + private static final String USER_PREFIX = "gemfire"; + private static final Random RANDOM = new Random(); + private static final String[] CIPHERS = new String[] { "", "DESede", "AES:128", "Blowfish:128" }; + + private static boolean enableServerAuthentication = false; + + private boolean serverAuthEnabled = false; + + public LdapUserCredentialGenerator() { + // Toggle server authentication enabled for each test + // This is done instead of running all the tests with both + // server auth enabled/disabled to reduce test run time. + enableServerAuthentication = !enableServerAuthentication; + this.serverAuthEnabled = enableServerAuthentication; + } + + @Override + protected Properties initialize() throws IllegalArgumentException { + final String ldapServer = System.getProperty("gf.ldap.server", "ldap"); + final String ldapBaseDN = System.getProperty("gf.ldap.basedn", "ou=ldapTesting,dc=pune,dc=gemstone,dc=com"); + final String ldapUseSSL = System.getProperty("gf.ldap.usessl"); + + final Properties extraProps = new Properties(); + extraProps.setProperty(LdapUserAuthenticator.LDAP_SERVER_NAME, ldapServer); + extraProps.setProperty(LdapUserAuthenticator.LDAP_BASEDN_NAME, ldapBaseDN); + + if (ldapUseSSL != null && ldapUseSSL.length() > 0) { + extraProps.setProperty(LdapUserAuthenticator.LDAP_SSL_NAME, ldapUseSSL); + } + + if (serverAuthEnabled) { + String keyStoreFile = TestUtil.getResourcePath(LdapUserCredentialGenerator.class, PKCSCredentialGenerator.keyStoreDir + "/gemfire1.keystore"); + extraProps.setProperty(HandShake.PRIVATE_KEY_FILE_PROP, keyStoreFile); + extraProps.setProperty(HandShake.PRIVATE_KEY_ALIAS_PROP, DistributionConfig.GEMFIRE_PREFIX); + extraProps.setProperty(HandShake.PRIVATE_KEY_PASSWD_PROP, "gemfire"); + } + + Assert.assertNotNull(extraProps.getProperty(LdapUserAuthenticator.LDAP_BASEDN_NAME)); + + logger.info("Generating LdapUserCredentialGenerator with {}", extraProps); + + return extraProps; + } + + @Override + public ClassCode classCode() { + return ClassCode.LDAP; + } + + @Override + public String getAuthInit() { + return UserPasswordAuthInit.class.getName() + ".create"; + } + + @Override + public String getAuthenticator() { + return LdapUserAuthenticator.class.getName() + ".create"; + } + + @Override + public Properties getValidCredentials(final int index) { + final Properties props = new Properties(); + props.setProperty(UserPasswordAuthInit.USER_NAME, USER_PREFIX + ((index % 10) + 1)); + props.setProperty(UserPasswordAuthInit.PASSWORD, USER_PREFIX + ((index % 10) + 1)); + props.setProperty(SECURITY_CLIENT_DHALGO, CIPHERS[RANDOM.nextInt(CIPHERS.length)]); + + if (serverAuthEnabled) { + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, PKCSCredentialGenerator.keyStoreDir + "/publickeyfile"); + props.setProperty(HandShake.PUBLIC_KEY_FILE_PROP, keyStoreFile); + props.setProperty(HandShake.PUBLIC_KEY_PASSWD_PROP, "gemfire"); + } + + return props; + } + + @Override + public Properties getValidCredentials(final Principal principal) { + Properties props = null; + final String userName = principal.getName(); + + if (userName != null && userName.startsWith(USER_PREFIX)) { + boolean isValid; + + try { + final int suffix = Integer.parseInt(userName.substring(USER_PREFIX.length())); + isValid = (suffix >= 1 && suffix <= 10); + } catch (Exception ex) { + isValid = false; + } + + if (isValid) { + props = new Properties(); + props.setProperty(UserPasswordAuthInit.USER_NAME, userName); + props.setProperty(UserPasswordAuthInit.PASSWORD, userName); + } + } + + if (props == null) { + throw new IllegalArgumentException("LDAP: [" + userName + "] not a valid user"); + } + + props.setProperty(SECURITY_CLIENT_DHALGO, CIPHERS[RANDOM.nextInt(CIPHERS.length)]); + + if (serverAuthEnabled) { + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, PKCSCredentialGenerator.keyStoreDir + "/publickeyfile"); + props.setProperty(HandShake.PUBLIC_KEY_FILE_PROP, keyStoreFile); + props.setProperty(HandShake.PUBLIC_KEY_PASSWD_PROP, "gemfire"); + } + + return props; + } + + @Override + public Properties getInvalidCredentials(final int index) { + final Properties props = new Properties(); + props.setProperty(UserPasswordAuthInit.USER_NAME, "invalid" + index); + props.setProperty(UserPasswordAuthInit.PASSWORD, "none"); + props.setProperty(SECURITY_CLIENT_DHALGO, CIPHERS[RANDOM.nextInt(CIPHERS.length)]); + + if (serverAuthEnabled) { + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, PKCSCredentialGenerator.keyStoreDir + "/publickeyfile"); + props.setProperty(HandShake.PUBLIC_KEY_FILE_PROP, keyStoreFile); + props.setProperty(HandShake.PUBLIC_KEY_PASSWD_PROP, "gemfire"); + } + + return props; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/PKCSCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/PKCSCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/PKCSCredentialGenerator.java new file mode 100755 index 0000000..09381b8 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/PKCSCredentialGenerator.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import java.security.Principal; +import java.security.Provider; +import java.security.Security; +import java.util.Properties; + +import com.gemstone.gemfire.security.templates.PKCSAuthInit; +import com.gemstone.gemfire.security.templates.PKCSAuthenticator; +import com.gemstone.gemfire.util.test.TestUtil; + +public class PKCSCredentialGenerator extends CredentialGenerator { + + public static String keyStoreDir = getKeyStoreDir(); + public static boolean usesIBMJSSE; + + // Checks if the current JVM uses only IBM JSSE providers. + private static boolean usesIBMProviders() { + final Provider[] providers = Security.getProviders(); + for (int index = 0; index < providers.length; ++index) { + if (!providers[index].getName().toLowerCase().startsWith("ibm")) { + return false; + } + } + return true; + } + + private static String getKeyStoreDir() { + usesIBMJSSE = usesIBMProviders(); + if (usesIBMJSSE) { + return "/com/gemstone/gemfire/security/generator/keys/ibm"; + } else { + return "/com/gemstone/gemfire/security/generator/keys"; + } + } + + @Override + protected Properties initialize() throws IllegalArgumentException { + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, keyStoreDir + "/publickeyfile"); + + final Properties props = new Properties(); + props.setProperty(PKCSAuthenticator.PUBLIC_KEY_FILE, keyStoreFile); + props.setProperty(PKCSAuthenticator.PUBLIC_KEYSTORE_PASSWORD, "gemfire"); + + return props; + } + + @Override + public ClassCode classCode() { + return ClassCode.PKCS; + } + + @Override + public String getAuthInit() { + return PKCSAuthInit.class.getName() + ".create"; + } + + @Override + public String getAuthenticator() { + return PKCSAuthenticator.class.getName() + ".create"; + } + + @Override + public Properties getInvalidCredentials(int index) { + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, keyStoreDir + "/gemfire11.keystore"); + + final Properties props = new Properties(); + props.setProperty(PKCSAuthInit.KEYSTORE_FILE_PATH, keyStoreFile); + props.setProperty(PKCSAuthInit.KEYSTORE_ALIAS, "gemfire11"); + props.setProperty(PKCSAuthInit.KEYSTORE_PASSWORD, "gemfire"); + + return props; + } + + @Override + public Properties getValidCredentials(int index) { + final int aliasnum = (index % 10) + 1; + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, keyStoreDir + "/gemfire" + aliasnum + ".keystore"); + + final Properties props = new Properties(); + props.setProperty(PKCSAuthInit.KEYSTORE_FILE_PATH, keyStoreFile); + props.setProperty(PKCSAuthInit.KEYSTORE_ALIAS, "gemfire" + aliasnum); + props.setProperty(PKCSAuthInit.KEYSTORE_PASSWORD, "gemfire"); + + return props; + } + + @Override + public Properties getValidCredentials(Principal principal) { + final String keyStoreFile = TestUtil.getResourcePath(PKCSCredentialGenerator.class, keyStoreDir + principal.getName() + ".keystore"); + + final Properties props = new Properties(); + props.setProperty(PKCSAuthInit.KEYSTORE_FILE_PATH, keyStoreFile); + props.setProperty(PKCSAuthInit.KEYSTORE_ALIAS, principal.getName()); + props.setProperty(PKCSAuthInit.KEYSTORE_PASSWORD, "gemfire"); + + return props; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/SSLCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/SSLCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/SSLCredentialGenerator.java new file mode 100755 index 0000000..6b6e3de --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/SSLCredentialGenerator.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.security.AuthenticationFailedException; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.security.Principal; +import java.util.Properties; + +import static com.gemstone.gemfire.distributed.ConfigurationProperties.*; + +public class SSLCredentialGenerator extends CredentialGenerator { + + private static final Logger logger = LogService.getLogger(); + + @Override + protected Properties initialize() throws IllegalArgumentException { + this.javaProperties = getValidJavaSSLProperties(); + return getSSLProperties(); + } + + @Override + public ClassCode classCode() { + return ClassCode.SSL; + } + + @Override + public String getAuthInit() { + return null; + } + + @Override + public String getAuthenticator() { + return null; + } + + @Override + public Properties getValidCredentials(int index) { + this.javaProperties = getValidJavaSSLProperties(); + return getSSLProperties(); + } + + @Override + public Properties getValidCredentials(final Principal principal) { + this.javaProperties = getValidJavaSSLProperties(); + return getSSLProperties(); + } + + @Override + public Properties getInvalidCredentials(final int index) { + this.javaProperties = getInvalidJavaSSLProperties(); + return getSSLProperties(); + } + + private File findTrustedJKS() { + final File ssldir = new File(System.getProperty("JTESTS") + "/ssl"); + return new File(ssldir, "trusted.keystore"); + } + + private File findUntrustedJKS() { + final File ssldir = new File(System.getProperty("JTESTS") + "/ssl"); + return new File(ssldir, "untrusted.keystore"); + } + + private Properties getValidJavaSSLProperties() { + final File jks = findTrustedJKS(); + + try { + final Properties props = new Properties(); + props.setProperty("javax.net.ssl.trustStore", jks.getCanonicalPath()); + props.setProperty("javax.net.ssl.trustStorePassword", "password"); + props.setProperty("javax.net.ssl.keyStore", jks.getCanonicalPath()); + props.setProperty("javax.net.ssl.keyStorePassword", "password"); + return props; + + } catch (IOException ex) { + throw new AuthenticationFailedException("SSL: Exception while opening the key store: " + ex.getMessage(), ex); + } + } + + private Properties getInvalidJavaSSLProperties() { + final File jks = findUntrustedJKS(); + + try { + final Properties props = new Properties(); + props.setProperty("javax.net.ssl.trustStore", jks.getCanonicalPath()); + props.setProperty("javax.net.ssl.trustStorePassword", "password"); + props.setProperty("javax.net.ssl.keyStore", jks.getCanonicalPath()); + props.setProperty("javax.net.ssl.keyStorePassword", "password"); + return props; + + } catch (IOException ex) { + throw new AuthenticationFailedException("SSL: Exception while opening the key store: " + ex.getMessage(), ex); + } + } + + private Properties getSSLProperties() { + Properties props = new Properties(); + props.setProperty(CLUSTER_SSL_CIPHERS, "true"); + props.setProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION, "true"); + props.setProperty(CLUSTER_SSL_CIPHERS, "SSL_RSA_WITH_3DES_EDE_CBC_SHA"); + props.setProperty(CLUSTER_SSL_PROTOCOLS, "TLSv1"); + return props; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/UserPasswordWithExtraPropsAuthInit.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/UserPasswordWithExtraPropsAuthInit.java b/geode-core/src/test/java/org/apache/geode/security/generator/UserPasswordWithExtraPropsAuthInit.java new file mode 100755 index 0000000..1240533 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/UserPasswordWithExtraPropsAuthInit.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.distributed.internal.DistributionConfig; +import com.gemstone.gemfire.security.AuthInitialize; +import com.gemstone.gemfire.security.AuthenticationFailedException; +import com.gemstone.gemfire.security.templates.UserPasswordAuthInit; + +import java.util.Iterator; +import java.util.Properties; + +/** + * An {@link AuthInitialize} implementation that obtains the user name and + * password as the credentials from the given set of properties. If + * keep-extra-props property exits, it will copy rest of the + * properties provided in getCredential props argument will also be + * copied as new credentials. + * + * @since GemFire 5.5 + */ +public class UserPasswordWithExtraPropsAuthInit extends UserPasswordAuthInit { + + public static final String SECURITY_PREFIX = DistributionConfig.SECURITY_PREFIX_NAME; + public static final String EXTRA_PROPS = "security-keep-extra-props"; + + public static AuthInitialize create() { + return new UserPasswordWithExtraPropsAuthInit(); + } + + public UserPasswordWithExtraPropsAuthInit() { + super(); + } + + @Override + public Properties getCredentials(final Properties securityProperties, final DistributedMember server, final boolean isPeer) throws AuthenticationFailedException { + final Properties securityPropertiesCopy = super.getCredentials(securityProperties, server, isPeer); + final String extraProps = securityProperties.getProperty(EXTRA_PROPS); + + if (extraProps != null) { + for (Iterator it = securityProperties.keySet().iterator(); it.hasNext();) { + final String key = (String) it.next(); + if (key.startsWith(SECURITY_PREFIX) && + key.equalsIgnoreCase(USER_NAME) == false && + key.equalsIgnoreCase(PASSWORD) == false && + key.equalsIgnoreCase(EXTRA_PROPS) == false) { + securityPropertiesCopy.setProperty(key, securityProperties.getProperty(key)); + } + } + this.securityLogWriter.fine("got everything and now have: " + securityPropertiesCopy.keySet().toString()); + } + + return securityPropertiesCopy; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/generator/XmlAuthzCredentialGenerator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/generator/XmlAuthzCredentialGenerator.java b/geode-core/src/test/java/org/apache/geode/security/generator/XmlAuthzCredentialGenerator.java new file mode 100755 index 0000000..7dcf5ae --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/generator/XmlAuthzCredentialGenerator.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.generator; + +import java.security.Principal; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode; +import com.gemstone.gemfire.security.templates.UsernamePrincipal; +import com.gemstone.gemfire.security.templates.XmlAuthorization; +import com.gemstone.gemfire.util.test.TestUtil; + +public class XmlAuthzCredentialGenerator extends AuthzCredentialGenerator { + + private static final String dummyXml = "authz-dummy.xml"; + private static final String ldapXml = "authz-ldap.xml"; + private static final String pkcsXml = "authz-pkcs.xml"; + private static final String sslXml = "authz-ssl.xml"; + + private static final String[] QUERY_REGIONS = { "/Portfolios", "/Positions", "/AuthRegion" }; + + public static OperationCode[] READER_OPS = { + OperationCode.GET, + OperationCode.REGISTER_INTEREST, + OperationCode.UNREGISTER_INTEREST, + OperationCode.KEY_SET, + OperationCode.CONTAINS_KEY, + OperationCode.EXECUTE_FUNCTION }; + + public static OperationCode[] WRITER_OPS = { + OperationCode.PUT, + OperationCode.DESTROY, + OperationCode.INVALIDATE, + OperationCode.REGION_CLEAR }; + + public static OperationCode[] QUERY_OPS = { + OperationCode.QUERY, + OperationCode.EXECUTE_CQ, + OperationCode.STOP_CQ, + OperationCode.CLOSE_CQ }; + + private static final byte READER_ROLE = 1; + private static final byte WRITER_ROLE = 2; + private static final byte QUERY_ROLE = 3; + private static final byte ADMIN_ROLE = 4; + + private static Set readerOpsSet; + private static Set writerOpsSet; + private static Set queryOpsSet; + private static Set queryRegionSet; + + static { + readerOpsSet = new HashSet(); + for (int index = 0; index < READER_OPS.length; index++) { + readerOpsSet.add(READER_OPS[index]); + } + + writerOpsSet = new HashSet(); + for (int index = 0; index < WRITER_OPS.length; index++) { + writerOpsSet.add(WRITER_OPS[index]); + } + + queryOpsSet = new HashSet(); + for (int index = 0; index < QUERY_OPS.length; index++) { + queryOpsSet.add(QUERY_OPS[index]); + } + + queryRegionSet = new HashSet(); + for (int index = 0; index < QUERY_REGIONS.length; index++) { + queryRegionSet.add(QUERY_REGIONS[index]); + } + } + + @Override + protected Properties init() throws IllegalArgumentException { + final Properties sysProps = new Properties(); + final String dirName = "/com/gemstone/gemfire/security/generator/"; + + if (this.generator.classCode().isDummy()) { + final String xmlFilename = TestUtil.getResourcePath(XmlAuthzCredentialGenerator.class, dirName + dummyXml); + sysProps.setProperty(XmlAuthorization.DOC_URI_PROP_NAME, xmlFilename); + + } else if (this.generator.classCode().isLDAP()) { + final String xmlFilename = TestUtil.getResourcePath(XmlAuthzCredentialGenerator.class, dirName + ldapXml); + sysProps.setProperty(XmlAuthorization.DOC_URI_PROP_NAME, xmlFilename); + + // } else if (this.generator.classCode().isPKCS()) { + // sysProps.setProperty(XmlAuthorization.DOC_URI_PROP_NAME, dirName + pkcsXml); + // } + // } else if (this.generator.classCode().isSSL()) { + // sysProps.setProperty(XmlAuthorization.DOC_URI_PROP_NAME, dirName + sslXml); + // } + + } else { + throw new IllegalArgumentException("No XML defined for XmlAuthorization module to work with " + this.generator.getAuthenticator()); + } + return sysProps; + } + + @Override + public ClassCode classCode() { + return ClassCode.XML; + } + + @Override + public String getAuthorizationCallback() { + return XmlAuthorization.class.getName() + ".create"; + } + + private Principal getDummyPrincipal(final byte roleType, final int index) { + final String[] admins = new String[] { "root", "admin", "administrator" }; + final int numReaders = 3; + final int numWriters = 3; + + switch (roleType) { + case READER_ROLE: + return new UsernamePrincipal("reader" + (index % numReaders)); + case WRITER_ROLE: + return new UsernamePrincipal("writer" + (index % numWriters)); + case QUERY_ROLE: + return new UsernamePrincipal("reader" + ((index % 2) + 3)); + default: + return new UsernamePrincipal(admins[index % admins.length]); + } + } + + @Override + protected Principal getAllowedPrincipal(final OperationCode[] opCodes, final String[] regionNames, final int index) { + if (this.generator.classCode().isDummy()) { + final byte roleType = getRequiredRole(opCodes, regionNames); + return getDummyPrincipal(roleType, index); + + } else if (this.generator.classCode().isLDAP()) { + final byte roleType = getRequiredRole(opCodes, regionNames); + return getLdapPrincipal(roleType, index); + } + + return null; + } + + @Override + protected Principal getDisallowedPrincipal(final OperationCode[] opCodes, final String[] regionNames, final int index) { + final byte roleType = getRequiredRole(opCodes, regionNames); + + byte disallowedRoleType = READER_ROLE; + switch (roleType) { + case READER_ROLE: + disallowedRoleType = WRITER_ROLE; + break; + case WRITER_ROLE: + disallowedRoleType = READER_ROLE; + break; + case QUERY_ROLE: + disallowedRoleType = READER_ROLE; + break; + case ADMIN_ROLE: + disallowedRoleType = READER_ROLE; + break; + } + + if (this.generator.classCode().isDummy()) { + return getDummyPrincipal(disallowedRoleType, index); + + } else if (this.generator.classCode().isLDAP()) { + return getLdapPrincipal(disallowedRoleType, index); + } + + return null; + } + + @Override + protected int getNumPrincipalTries(final OperationCode[] opCodes, final String[] regionNames) { + return 5; + } + + private Principal getLdapPrincipal(final byte roleType, final int index) { + final String userPrefix = "gemfire"; + final int[] readerIndices = { 3, 4, 5 }; + final int[] writerIndices = { 6, 7, 8 }; + final int[] queryIndices = { 9, 10 }; + final int[] adminIndices = { 1, 2 }; + + switch (roleType) { + case READER_ROLE: + int readerIndex = readerIndices[index % readerIndices.length]; + return new UsernamePrincipal(userPrefix + readerIndex); + case WRITER_ROLE: + int writerIndex = writerIndices[index % writerIndices.length]; + return new UsernamePrincipal(userPrefix + writerIndex); + case QUERY_ROLE: + int queryIndex = queryIndices[index % queryIndices.length]; + return new UsernamePrincipal(userPrefix + queryIndex); + default: + int adminIndex = adminIndices[index % adminIndices.length]; + return new UsernamePrincipal(userPrefix + adminIndex); + } + } + + private byte getRequiredRole(final OperationCode[] opCodes, final String[] regionNames) { + byte roleType = ADMIN_ROLE; + boolean requiresReader = true; + boolean requiresWriter = true; + boolean requiresQuery = true; + + for (int opNum = 0; opNum < opCodes.length; opNum++) { + final OperationCode opCode = opCodes[opNum]; + if (requiresReader && !readerOpsSet.contains(opCode)) { + requiresReader = false; + } + if (requiresWriter && !writerOpsSet.contains(opCode)) { + requiresWriter = false; + } + if (requiresQuery && !queryOpsSet.contains(opCode)) { + requiresQuery = false; + } + } + + if (requiresReader) { + roleType = READER_ROLE; + + } else if (requiresWriter) { + roleType = WRITER_ROLE; + + } else if (requiresQuery) { + if (regionNames != null && regionNames.length > 0) { + for (int index = 0; index < regionNames.length; index++) { + final String regionName = XmlAuthorization.normalizeRegionName(regionNames[index]); + if (requiresQuery && !queryRegionSet.contains(regionName)) { + requiresQuery = false; + break; + } + } + if (requiresQuery) { + roleType = QUERY_ROLE; + } + } + } + + return roleType; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthenticator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthenticator.java b/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthenticator.java new file mode 100755 index 0000000..f086b67 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthenticator.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.templates; + +import java.security.Principal; +import java.util.Properties; + +import com.gemstone.gemfire.LogWriter; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.security.AuthenticationFailedException; +import com.gemstone.gemfire.security.Authenticator; + +/** + * A dummy implementation of the {@link Authenticator} interface that expects a + * user name and password allowing authentication depending on the format of the + * user name. + * + * @since GemFire 5.5 + */ +public class DummyAuthenticator implements Authenticator { + + public static Authenticator create() { + return new DummyAuthenticator(); + } + + public static boolean checkValidName(final String userName) { + return userName.startsWith("user") || + userName.startsWith("reader") || + userName.startsWith("writer") || + userName.equals("admin") || + userName.equals("root") || + userName.equals("administrator"); + } + + @Override + public void init(final Properties securityProperties, final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { + } + + @Override + public Principal authenticate(final Properties credentials, final DistributedMember member) throws AuthenticationFailedException { + final String userName = credentials.getProperty(UserPasswordAuthInit.USER_NAME); + if (userName == null) { + throw new AuthenticationFailedException("DummyAuthenticator: user name property [" + UserPasswordAuthInit.USER_NAME + "] not provided"); + } + + final String password = credentials.getProperty(UserPasswordAuthInit.PASSWORD); + if (password == null) { + throw new AuthenticationFailedException( "DummyAuthenticator: password property [" + UserPasswordAuthInit.PASSWORD + "] not provided"); + } + + if (userName.equals(password) && checkValidName(userName)) { + return new UsernamePrincipal(userName); + } else { + throw new AuthenticationFailedException("DummyAuthenticator: Invalid user name [" + userName + "], password supplied."); + } + } + + @Override + public void close() { + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthorization.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthorization.java b/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthorization.java new file mode 100755 index 0000000..df08676 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/templates/DummyAuthorization.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.templates; + +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; +import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.security.AccessControl; +import com.gemstone.gemfire.security.NotAuthorizedException; + +/** + * A dummy implementation of the {@code AccessControl} interface that + * allows authorization depending on the format of the {@code Principal} + * string. + * + * @since GemFire 5.5 + */ +public class DummyAuthorization implements AccessControl { + + private Set allowedOps; + 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(); + } + + public DummyAuthorization() { + this.allowedOps = new HashSet(20); + } + + @Override + public void init(final Principal principal, final DistributedMember remoteMember, final Cache cache) throws NotAuthorizedException { + if (principal != null) { + + final String name = principal.getName().toLowerCase(); + + if (name != null) { + + 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")) { + addWriterOps(); + + } else if (name.startsWith("reader")) { + addReaderOps(); + } + + } + } + + this.remoteMember = remoteMember; + this.securityLogWriter = cache.getSecurityLogger(); + } + + @Override + public boolean authorizeOperation(String regionName, OperationContext context) { + 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/9d7a6960/geode-core/src/test/java/org/apache/geode/security/templates/FunctionSecurityPrmsHolder.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/templates/FunctionSecurityPrmsHolder.java b/geode-core/src/test/java/org/apache/geode/security/templates/FunctionSecurityPrmsHolder.java new file mode 100755 index 0000000..275a4ad --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/templates/FunctionSecurityPrmsHolder.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.templates; + +import java.util.Set; + +/** + * This is a sample class for objects which hold information of the authorized + * function names and authorized value for the {@code optimizeForWrite}. + * + * @since GemFire 6.0 + */ +public class FunctionSecurityPrmsHolder { + + private final Boolean optimizeForWrite; + private final Set<String> functionIds; + private final Set<String> keySet; + + 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 this.optimizeForWrite; + } + + public Set<String> getFunctionIds() { + return this.functionIds; + } + + public Set<String> getKeySet() { + return this.keySet; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/templates/LdapUserAuthenticator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/templates/LdapUserAuthenticator.java b/geode-core/src/test/java/org/apache/geode/security/templates/LdapUserAuthenticator.java new file mode 100755 index 0000000..a9e875e --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/templates/LdapUserAuthenticator.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.templates; + +import java.security.Principal; +import java.util.Properties; +import javax.naming.Context; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; + +import org.apache.logging.log4j.Logger; + +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; + +/** + * An implementation of {@link Authenticator} that uses LDAP. + * + * @since GemFire 5.5 + */ +public class LdapUserAuthenticator implements Authenticator { + + 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_SSL_NAME = "security-ldap-usessl"; + + private String ldapServer = null; + private String baseDomainName = null; + private String ldapUrlScheme = null; + + public static Authenticator create() { + return new LdapUserAuthenticator(); + } + + @Override + public void init(final Properties securityProps, final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { + logger.info("Initializing LdapUserAuthenticator with {}", securityProps); + + 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"); + } + + 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"); + } + + final String sslName = securityProps.getProperty(LDAP_SSL_NAME); + if (sslName != null && sslName.toLowerCase().equals("true")) { + this.ldapUrlScheme = "ldaps://"; + } else { + this.ldapUrlScheme = "ldap://"; + } + } + + @Override + 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"); + } + + String password = credentials.getProperty(UserPasswordAuthInit.PASSWORD); + if (password == null) { + password = ""; + } + + 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 { + 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); + } + + return new UsernamePrincipal(userName); + } + + @Override + public void close() { + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9d7a6960/geode-core/src/test/java/org/apache/geode/security/templates/PKCSAuthInit.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/security/templates/PKCSAuthInit.java b/geode-core/src/test/java/org/apache/geode/security/templates/PKCSAuthInit.java new file mode 100755 index 0000000..f58d305 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/security/templates/PKCSAuthInit.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.security.templates; + +import java.io.FileInputStream; +import java.security.Key; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; + +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; + +/** + * 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 {@code security-client-auth-init} property should be + * set to the fully qualified name the static {@code create} function + * viz. {@code com.gemstone.gemfire.security.templates.PKCSAuthInit.create} + * + * @since GemFire 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 systemLogWriter; + protected LogWriter securityLogWriter; + + public static AuthInitialize create() { + return new PKCSAuthInit(); + } + + @Override + public void init(final LogWriter systemLogWriter, final LogWriter securityLogWriter) throws AuthenticationFailedException { + this.systemLogWriter = systemLogWriter; + this.securityLogWriter = securityLogWriter; + } + + @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."); + } + + final String alias = securityProperties.getProperty(KEYSTORE_ALIAS); + if (alias == null) { + throw new AuthenticationFailedException("PKCSAuthInit: key alias name property [" + KEYSTORE_ALIAS + "] not set."); + } + + final String keyStorePass = securityProperties.getProperty(KEYSTORE_PASSWORD); + + try { + 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 { + certificatefile.close(); + } + + final Key key = ks.getKey(alias, passPhrase); + + if (key instanceof PrivateKey) { + 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")); + final byte[] signatureBytes = sig.sign(); + + 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); + } + + } catch (Exception ex) { + throw new AuthenticationFailedException("PKCSAuthInit: Exception while getting credentials: " + ex, ex); + } + } + + @Override + public void close() { + } +}
