blob: e826be6333cfa92285407525ff7d6d2d57e3b323 [file] [log] [blame]
/*
* 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.
*/
using System;
using Apache.Geode.DUnitFramework;
namespace Apache.Geode.Client.Tests
{
using Apache.Geode.Client;
/// <summary>
/// Enumeration for the various client server operations.
/// </summary>
public enum OperationCode
{
Get,
Put,
GetAll,
PutAll,
RemoveAll,
Destroy,
Invalidate,
GetServerKeys,
RegisterInterest,
UnregisterInterest,
Query,
ExecuteCQ,
ExecuteFunction,
RegionDestroy
}
/// <summary>
/// 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.
/// </summary>
public abstract class AuthzCredentialGenerator
{
/// <summary>
/// Enumeration for various <c>AuthzCredentialGenerator</c> implementations.
/// </summary>
/// <remarks>
/// The following schemes are supported as of now:
/// <list type="number">
/// <item><description>
/// <c>DummyAuthorization</c> with <c>DummyAuthenticator</c>
/// </description></item>
/// <item><description>
/// <c>XMLAuthorization</c> with <c>DummyAuthenticator</c></li>
/// </description></item>
/// <item><description>
/// <c>XMLAuthorization</c> with <c>LDAPAuthenticator</c>
/// </description></item>
/// <item><description>
/// <c>XMLAuthorization</c> with <c>PKCSAuthenticator</c>
/// </description></item>
/// <item><description>
/// <c>XMLAuthorization</c> when using SSL sockets
/// </description></item>
/// </list>
///
/// To add a new authorization scheme the following needs to be done:
/// <list type="number">
/// <item><description>
/// Add implementation for <c>AccessControl</c> on the java server.
/// </description></item>
/// <item><description>
/// Choose the authentication schemes that it shall work with, from
/// <see cref="CredentialGenerator.ClassCode"/>
/// </description></item>
/// <item><description>
/// Add a new enumeration value for the scheme in this enum.
/// </description></item>
/// <item><description>
/// Add an implementation for <c>AuthzCredentialGenerator</c>. Note the
/// <see cref="AuthzCredentialGenerator.init"/> method where different
/// authentication schemes can be passed and initialize differently for
/// the authentication schemes that shall be handled by this authorization
/// callback.
/// </description></item>
/// <item><description>
/// Modify the <see cref="AuthzCredentialGenerator.create"/> method to add
/// creation of an instance of the new implementation for the
/// <c>ClassCode</c> enumeration value.
/// </description></item>
/// </list>
/// All dunit tests will automagically start testing the new
/// implementation after this.
/// </remarks>
public enum ClassCode
{
Dummy,
XML
}
/// <summary>
/// The <see cref="CredentialGenerator"/> being used.
/// </summary>
protected CredentialGenerator m_cGen;
/// <summary>
/// A set of system properties that should be added to the java server
/// system properties before using the authorization module.
/// </summary>
private Properties<string, string> m_sysProps;
/// <summary>
/// A factory method to create a new instance of an
/// <c>AuthzCredentialGenerator</c>
/// for the given <c>ClassCode</c>. Caller
/// is supposed to invoke
/// <see cref="AuthzCredentialGenerator.init"/> immediately
/// after obtaining the instance.
/// </summary>
/// <param name="classCode">
/// the <c>ClassCode</c> of the <c>AuthzCredentialGenerator</c>
/// implementation
/// </param>
/// <returns>
/// an instance of <c>AuthzCredentialGenerator</c> for
/// the given class code
/// </returns>
public static AuthzCredentialGenerator Create(ClassCode classCode)
{
switch (classCode)
{
case ClassCode.Dummy:
//return new DummyAuthzCredentialGenerator();
return null;
case ClassCode.XML:
return new XmlAuthzCredentialGenerator();
}
return null;
}
/// <summary>
/// Initialize the authorized credential generator.
/// </summary>
/// <param name="cGen">
/// an instance of <see cref="CredentialGenerator"/> of the credential
/// implementation for which to obtain authorized/unauthorized credentials.
/// </param>
/// <returns>
/// false when the given <c>CredentialGenerator</c> is incompatible with
/// this authorization module.
/// </returns>
public bool Init(CredentialGenerator cGen)
{
this.m_cGen = cGen;
try
{
this.m_sysProps = Init();
}
catch (Exception)
{
return false;
}
return true;
}
/// <summary>
/// A set of extra properties that should be added to java server system
/// properties when not null.
/// </summary>
public Properties<string, string> SystemProperties
{
get
{
return this.m_sysProps;
}
}
/// <summary>
/// Get the <c>CredentialGenerator</c> being used by this instance.
/// </summary>
public CredentialGenerator GetCredentialGenerator()
{
return this.m_cGen;
}
/// <summary>
/// The <see cref="ClassCode"/> of the particular implementation.
/// </summary>
/// <returns>the <c>ClassCode</c></returns>
public abstract ClassCode GetClassCode();
/// <summary>
/// The name of the <c>AccessControl</c> factory function that should be
/// used as the authorization module on the java server side.
/// </summary>
/// <returns>name of the <c>AccessControl</c> factory function</returns>
public abstract string AccessControl
{
get;
}
/// <summary>
/// Get a set of credentials generated using the given index allowed to
/// perform the given <see cref="OperationCode"/>s for the given regions.
/// </summary>
/// <param name="opCodes">
/// the list of <see cref="OperationCode"/>s of the operations requiring
/// authorization; should not be null
/// </param>
/// <param name="regionNames">
/// list of the region names requiring authorization; a value of null
/// indicates all regions
/// </param>
/// <param name="index">
/// used to generate multiple such credentials by passing different
/// values for this
/// </param>
/// <returns>
/// the set of credentials authorized to perform the given operation in
/// the given regions
/// </returns>
public Properties<string, string> GetAllowedCredentials(OperationCode[] opCodes,
string[] regionNames, int index)
{
int numTries = GetNumPrincipalTries(opCodes, regionNames);
if (numTries <= 0)
{
numTries = 1;
}
for (int tries = 0; tries < numTries; ++tries)
{
Properties<string, string> principal = GetAllowedPrincipal(opCodes, regionNames,
(index + tries) % numTries);
try
{
return this.m_cGen.GetValidCredentials(principal);
}
catch (IllegalArgumentException)
{
}
}
return null;
}
/// <summary>
/// Get a set of credentials generated using the given index not allowed to
/// perform the given <see cref="OperationCode"/>s for the given regions.
/// The credentials are required to be valid for authentication.
/// </summary>
/// <param name="opCodes">
/// the <see cref="OperationCode"/>s of the operations requiring
/// authorization failure; should not be null
/// </param>
/// <param name="regionNames">
/// list of the region names requiring authorization failure;
/// a value of null indicates all regions
/// </param>
/// <param name="index">
/// used to generate multiple such credentials by passing different
/// values for this
/// </param>
/// <returns>
/// the set of credentials that are not authorized to perform the given
/// operation in the given region
/// </returns>
public Properties<string, string> GetDisallowedCredentials(OperationCode[] opCodes,
string[] regionNames, 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++)
{
Properties<string, string> principal = GetDisallowedPrincipal(opCodes, regionNames,
(index + tries) % numTries);
try
{
return this.m_cGen.GetValidCredentials(principal);
}
catch (IllegalArgumentException)
{
}
}
return null;
}
/// <summary>
/// Initialize the authorized credential generator.
/// </summary>
/// <returns>
/// A set of extra properties that should be added to java server
/// system properties when not null.
/// </returns>
/// <exception cref="IllegalArgumentException">
/// when the <see cref="CredentialGenerator"/> is incompatible with
/// this authorization module.
/// </exception>
protected abstract Properties<string, string> Init();
/// <summary>
/// Get the number of tries to be done for obtaining valid credentials for
/// the given operations in the given region. It is required that
/// <c>getAllowedPrincipal</c> method returns valid principals for values
/// of <c>index</c> from 0 through (n-1) where <c>n</c> is the value
/// returned by this method. It is recommended that the principals so
/// returned be unique for efficiency.
/// </summary>
/// <param name="opCodes">
/// the <see cref="OperationCode"/>s of the operations requiring
/// authorization
/// </param>
/// <param name="regionNames">
/// list of the region names requiring authorization; a value of null
/// indicates all regions
/// </param>
/// <returns>
/// the number of principals allowed to perform the given operation in
/// the given region
/// </returns>
protected abstract int GetNumPrincipalTries(OperationCode[] opCodes,
string[] regionNames);
/// <summary>
/// Get a <c>Principal</c> generated using the given index allowed to
/// perform the given <see cref="OperationCode"/>s for the given region.
/// </summary>
/// <param name="opCodes">
/// the list of <see cref="OperationCode"/>s of the operations requiring
/// authorization; should not be null
/// </param>
/// <param name="regionNames">
/// list of the region names requiring authorization; a value of null
/// indicates all regions
/// </param>
/// <param name="index">
/// used to generate multiple such credentials by passing different
/// values for this
/// </param>
/// <returns>
/// the <c>Principal</c> authorized to perform the given operation in
/// the given region
/// </returns>
protected abstract Properties<string, string> GetAllowedPrincipal(OperationCode[] opCodes,
string[] regionNames, int index);
/// <summary>
/// Required to be implemented by concrete classes that implement this
/// abstract class.
/// </summary>
/// <param name="opCodes">
/// the <see cref="OperationCode"/>s of the operations requiring
/// authorization failure; should not be null
/// </param>
/// <param name="regionNames">
/// list of the region names requiring authorization failure;
/// a value of null indicates all regions
/// </param>
/// <param name="index">
/// used to generate multiple such credentials by passing different
/// values for this
/// </param>
/// <returns>
/// a <c>Principal</c> not authorized to perform the given operation
/// in the given region
/// </returns>
protected abstract Properties<string, string> GetDisallowedPrincipal(OperationCode[] opCodes,
string[] regionNames, int index);
}
/// <summary>
/// Utility class for security generators.
/// </summary>
public static class Utility
{
/// <summary>
/// Build the string to be passed to the cacheserver command for the given
/// security authenticator/accessor properties.
/// </summary>
public static string GetServerArgs(string authenticator,
string accessor, string accessorPP, Properties<string, string> extraProps,
Properties<string, string> javaProps)
{
string args = string.Empty;
if (authenticator != null && authenticator.Length > 0)
{
args += (" --J=-Dgemfire.security-client-authenticator=" + authenticator);
}
if (accessor != null && accessor.Length > 0)
{
args += (" --J=-Dgemfire.security-client-accessor=" + accessor);
}
if (accessorPP != null && accessorPP.Length > 0)
{
args += (" --J=-Dgemfire.security-client-accessor-pp=" + accessorPP);
}
if (extraProps != null)
{
PropertyVisitorGeneric<string, string> visitor =
delegate(string key, string value)
{
args += (" --J=-D" + key.ToString() + '=' + value);
};
extraProps.ForEach(visitor);
}
if (javaProps != null)
{
PropertyVisitorGeneric<string, string> visitor =
delegate(string key, string value)
{
args += (" --J=-D" + key.ToString() + '=' + value);
};
javaProps.ForEach(visitor);
}
args = args.Trim();
return args;
}
/// <summary>
/// Get the client system properties.
/// </summary>
public static void GetClientProperties(string authInit,
Properties<string, string> credentials, ref Properties<string, string> props)
{
if (authInit != null && authInit.Length > 0)
{
if (props == null)
{
props = new Properties<string, string>();
}
string library;
string factory;
const string cppIndicator = "::";
int libIndex = authInit.IndexOf(cppIndicator);
if (libIndex > 0)
{
library = authInit.Substring(0, libIndex);
factory = authInit.Substring(libIndex + cppIndicator.Length);
}
else
{
library = "Apache.Geode.Templates.Cache.Security";
factory = authInit;
}
props.Insert("security-client-auth-library", library);
props.Insert("security-client-auth-factory", factory);
if (credentials != null)
{
props.AddAll(credentials);
}
}
}
}
}