blob: 406ad50bcc228e1683c6342f74a8008bca9366e5 [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 System.Collections.Generic;
using System.Threading;
namespace Apache.Geode.Client.UnitTests
{
using NUnit.Framework;
using Apache.Geode.DUnitFramework;
using Apache.Geode.Client.Tests;
using Apache.Geode.Client;
//using Region = Apache.Geode.Client.IRegion<Object, Object>;
using AssertionException = Apache.Geode.Client.AssertionException;
public abstract class ThinClientSecurityAuthzTestBase : ThinClientRegionSteps
{
#region Protected members
protected const string SubregionName = "AuthSubregion";
protected const string CacheXml1 = "cacheserver_notify_subscription.xml";
protected const string CacheXml2 = "cacheserver_notify_subscription2.xml";
#endregion
#region Private methods
private static string IndicesToString(int[] indices)
{
string str = string.Empty;
if (indices != null && indices.Length > 0)
{
str += indices[0];
for (int index = 1; index < indices.Length; ++index)
{
str += ',';
str += indices[index];
}
}
return str;
}
private IRegion<TKey, TValue> CreateSubregion<TKey, TValue>(IRegion<TKey, TValue> region)
{
Util.Log("CreateSubregion " + SubregionName);
IRegion<TKey, TValue> subregion = region.GetSubRegion(SubregionName);
if (subregion == null)
{
//subregion = region.CreateSubRegion(SubregionName, region.Attributes);
subregion = CacheHelper.GetRegion<TKey, TValue>(region.FullPath).CreateSubRegion(SubregionName, region.Attributes);
}
return subregion;
}
private bool CheckFlags(OpFlags flags, OpFlags checkFlag)
{
return ((flags & checkFlag) == checkFlag);
}
protected void DoOp(OperationCode op, int[] indices,
OpFlags flags, ExpectedResult expectedResult)
{
DoOp(op, indices, flags, expectedResult, null, false);
}
protected void DoOp(OperationCode op, int[] indices,
OpFlags flags, ExpectedResult expectedResult, Properties<string, string> creds, bool isMultiuser)
{
IRegion<object, object> region;
if(isMultiuser)
region = CacheHelper.GetRegion<object, object>(RegionName, creds);
else
region = CacheHelper.GetRegion<object, object>(RegionName);
if (CheckFlags(flags, OpFlags.UseSubRegion))
{
IRegion<object, object> subregion = null;
if (CheckFlags(flags, OpFlags.NoCreateSubRegion))
{
subregion = region.GetSubRegion(SubregionName);
if (CheckFlags(flags, OpFlags.CheckNoRegion))
{
Assert.IsNull(subregion);
return;
}
else
{
Assert.IsNotNull(subregion);
}
}
else
{
subregion = CreateSubregion(region);
if (isMultiuser)
subregion = region.GetSubRegion(SubregionName);
}
Assert.IsNotNull(subregion);
region = subregion;
}
else if (CheckFlags(flags, OpFlags.CheckNoRegion))
{
Assert.IsNull(region);
return;
}
else
{
Assert.IsNotNull(region);
}
string valPrefix;
if (CheckFlags(flags, OpFlags.UseNewVal))
{
valPrefix = NValuePrefix;
}
else
{
valPrefix = ValuePrefix;
}
int numOps = indices.Length;
Util.Log("Got DoOp for op: " + op + ", numOps: " + numOps
+ ", indices: " + IndicesToString(indices));
bool exceptionOccured = false;
bool breakLoop = false;
for (int indexIndex = 0; indexIndex < indices.Length; ++indexIndex)
{
if (breakLoop)
{
break;
}
int index = indices[indexIndex];
string key = KeyPrefix + index;
string expectedValue = (valPrefix + index);
try
{
switch (op)
{
case OperationCode.Get:
Object value = null;
if (CheckFlags(flags, OpFlags.LocalOp))
{
int sleepMillis = 100;
int numTries = 30;
bool success = false;
while (!success && numTries-- > 0)
{
if (!isMultiuser && region.ContainsValueForKey(key))
{
value = region[key];
success = expectedValue.Equals(value.ToString());
if (CheckFlags(flags, OpFlags.CheckFail))
{
success = !success;
}
}
else
{
value = null;
success = CheckFlags(flags, OpFlags.CheckFail);
}
if (!success)
{
Thread.Sleep(sleepMillis);
}
}
}
else
{
if (!isMultiuser)
{
if (CheckFlags(flags, OpFlags.CheckNoKey))
{
Assert.IsFalse(region.GetLocalView().ContainsKey(key));
}
else
{
Assert.IsTrue(region.GetLocalView().ContainsKey(key));
region.GetLocalView().Invalidate(key);
}
}
try
{
value = region[key];
}
catch (Client.KeyNotFoundException )
{
Util.Log("KeyNotFoundException while getting key. should be ok as we are just testing auth");
}
}
if (!isMultiuser && value != null)
{
if (CheckFlags(flags, OpFlags.CheckFail))
{
Assert.AreNotEqual(expectedValue, value.ToString());
}
else
{
Assert.AreEqual(expectedValue, value.ToString());
}
}
break;
case OperationCode.Put:
region[key] = expectedValue;
break;
case OperationCode.Destroy:
if (!isMultiuser && !region.GetLocalView().ContainsKey(key))
{
// Since DESTROY will fail unless the value is present
// in the local cache, this is a workaround for two cases:
// 1. When the operation is supposed to succeed then in
// the current AuthzCredentialGenerators the clients having
// DESTROY permission also has CREATE/UPDATE permission
// so that calling region.Put() will work for that case.
// 2. When the operation is supposed to fail with
// NotAuthorizedException then in the current
// AuthzCredentialGenerators the clients not
// having DESTROY permission are those with reader role that have
// GET permission.
//
// If either of these assumptions fails, then this has to be
// adjusted or reworked accordingly.
if (CheckFlags(flags, OpFlags.CheckNotAuthz))
{
value = region[key];
Assert.AreEqual(expectedValue, value.ToString());
}
else
{
region[key] = expectedValue;
}
}
if ( !isMultiuser && CheckFlags(flags, OpFlags.LocalOp))
{
region.GetLocalView().Remove(key); //Destroyed replaced by Remove() API
}
else
{
region.Remove(key); //Destroyed replaced by Remove API
}
break;
//TODO: Need to fix Stack overflow exception..
case OperationCode.RegisterInterest:
if (CheckFlags(flags, OpFlags.UseList))
{
breakLoop = true;
// Register interest list in this case
List<CacheableKey> keyList = new List<CacheableKey>(numOps);
for (int keyNumIndex = 0; keyNumIndex < numOps; ++keyNumIndex)
{
int keyNum = indices[keyNumIndex];
keyList.Add(KeyPrefix + keyNum);
}
region.GetSubscriptionService().RegisterKeys(keyList.ToArray());
}
else if (CheckFlags(flags, OpFlags.UseRegex))
{
breakLoop = true;
region.GetSubscriptionService().RegisterRegex(KeyPrefix + "[0-" + (numOps - 1) + ']');
}
else if (CheckFlags(flags, OpFlags.UseAllKeys))
{
breakLoop = true;
region.GetSubscriptionService().RegisterAllKeys();
}
break;
//TODO: Need to fix Stack overflow exception..
case OperationCode.UnregisterInterest:
if (CheckFlags(flags, OpFlags.UseList))
{
breakLoop = true;
// Register interest list in this case
List<CacheableKey> keyList = new List<CacheableKey>(numOps);
for (int keyNumIndex = 0; keyNumIndex < numOps; ++keyNumIndex)
{
int keyNum = indices[keyNumIndex];
keyList.Add(KeyPrefix + keyNum);
}
region.GetSubscriptionService().UnregisterKeys(keyList.ToArray());
}
else if (CheckFlags(flags, OpFlags.UseRegex))
{
breakLoop = true;
region.GetSubscriptionService().UnregisterRegex(KeyPrefix + "[0-" + (numOps - 1) + ']');
}
else if (CheckFlags(flags, OpFlags.UseAllKeys))
{
breakLoop = true;
region.GetSubscriptionService().UnregisterAllKeys();
}
break;
case OperationCode.Query:
breakLoop = true;
ISelectResults<object> queryResults;
if (!isMultiuser)
{
queryResults = (ResultSet<object>)region.Query<object>(
"SELECT DISTINCT * FROM " + region.FullPath);
}
else
{
queryResults = CacheHelper.getMultiuserCache(creds).GetQueryService().NewQuery<object>("SELECT DISTINCT * FROM " + region.FullPath).Execute();
}
Assert.IsNotNull(queryResults);
if (!CheckFlags(flags, OpFlags.CheckFail))
{
Assert.AreEqual(numOps, queryResults.Size);
}
var querySet = new List<string>((int) queryResults.Size);
ResultSet<object> rs = queryResults as ResultSet<object>;
foreach ( object result in rs)
{
querySet.Add(result.ToString());
}
for (int keyNumIndex = 0; keyNumIndex < numOps; ++keyNumIndex)
{
int keyNum = indices[keyNumIndex];
string expectedVal = valPrefix + keyNumIndex;
if (CheckFlags(flags, OpFlags.CheckFail))
{
Assert.IsFalse(querySet.Contains(expectedVal));
}
else
{
Assert.IsTrue(querySet.Contains(expectedVal));
}
}
break;
case OperationCode.RegionDestroy:
breakLoop = true;
if ( !isMultiuser && CheckFlags(flags, OpFlags.LocalOp))
{
region.GetLocalView().DestroyRegion();
}
else
{
region.DestroyRegion();
}
break;
case OperationCode.GetServerKeys:
breakLoop = true;
ICollection<object> serverKeys = region.Keys;
break;
//TODO: Need to fix System.ArgumentOutOfRangeException: Index was out of range. Know issue with GetAll()
case OperationCode.GetAll:
//ICacheableKey[] keymap = new ICacheableKey[5];
List<object> keymap = new List<object>();
for (int i = 0; i < 5; i++)
{
keymap.Add(i);
//CacheableInt32 item = CacheableInt32.Create(i);
//Int32 item = i;
// NOTE: GetAll should operate right after PutAll
//keymap[i] = item;
}
Dictionary<Object, Object> entrymap = new Dictionary<Object, Object>();
//CacheableHashMap entrymap = CacheableHashMap.Create();
region.GetAll(keymap, entrymap, null, false);
if (entrymap.Count < 5)
{
Assert.Fail("DoOp: Got fewer entries for op " + op);
}
break;
case OperationCode.PutAll:
// NOTE: PutAll should operate right before GetAll
//CacheableHashMap entrymap2 = CacheableHashMap.Create();
Dictionary<Object, Object> entrymap2 = new Dictionary<object, object>();
for (int i = 0; i < 5; i++)
{
//CacheableInt32 item = CacheableInt32.Create(i);
Int32 item = i;
entrymap2.Add(item, item);
}
region.PutAll(entrymap2);
break;
case OperationCode.RemoveAll:
Dictionary<Object, Object> entrymap3 = new Dictionary<object, object>();
for (int i = 0; i < 5; i++)
{
//CacheableInt32 item = CacheableInt32.Create(i);
Int32 item = i;
entrymap3.Add(item, item);
}
region.PutAll(entrymap3);
ICollection<object> keys = new LinkedList<object>();
for (int i = 0; i < 5; i++)
{
Int32 item = i;
keys.Add(item);
}
region.RemoveAll(keys);
break;
case OperationCode.ExecuteCQ:
Pool/*<object, object>*/ pool = CacheHelper.DCache.GetPoolManager().Find("__TESTPOOL1_");
QueryService qs;
if (pool != null)
{
qs = pool.GetQueryService();
}
else
{
//qs = CacheHelper.DCache.GetQueryService();
qs = null;
}
CqAttributesFactory<object, object> cqattrsfact = new CqAttributesFactory<object, object>();
CqAttributes<object, object> cqattrs = cqattrsfact.Create();
CqQuery<object, object> cq = qs.NewCq("cq_security", "SELECT * FROM /" + region.Name, cqattrs, false);
qs.ExecuteCqs();
qs.StopCqs();
qs.CloseCqs();
break;
case OperationCode.ExecuteFunction:
if (!isMultiuser)
{
Pool/*<object, object>*/ pool2 = CacheHelper.DCache.GetPoolManager().Find("__TESTPOOL1_");
if (pool2 != null)
{
Client.FunctionService<object>.OnServer(pool2).Execute("securityTest");
Client.FunctionService<object>.OnRegion<object, object>(region).Execute("FireNForget");
}
else
{
expectedResult = ExpectedResult.Success;
}
}
else
{
//FunctionService fs = CacheHelper.getMultiuserCache(creds).GetFunctionService();
//Execution exe = fs.OnServer();
IRegionService userCache = CacheHelper.getMultiuserCache(creds);
Apache.Geode.Client.Execution<object> exe = Client.FunctionService<object>.OnServer(userCache);
exe.Execute("securityTest");
exe = Client.FunctionService<object>.OnServers(userCache);
Client.FunctionService<object>.OnRegion<object, object>(region);
Client.FunctionService<object>.OnRegion<object, object>(userCache.GetRegion<object, object>(region.Name)).Execute("FireNForget");
}
break;
default:
Assert.Fail("DoOp: Unhandled operation " + op);
break;
}
if (expectedResult != ExpectedResult.Success)
{
Assert.Fail("Expected an exception while performing operation");
}
}
catch (AssertionException ex)
{
Util.Log("DoOp: failed assertion: {0}", ex);
throw;
}
catch (NotAuthorizedException ex)
{
exceptionOccured = true;
if (expectedResult == ExpectedResult.NotAuthorizedException)
{
Util.Log(
"DoOp: Got expected NotAuthorizedException when doing operation ["
+ op + "] with flags [" + flags + "]: " + ex.Message);
continue;
}
else
{
Assert.Fail("DoOp: Got unexpected NotAuthorizedException when " +
"doing operation: " + ex.Message);
}
}
catch (Exception ex)
{
exceptionOccured = true;
if (expectedResult == ExpectedResult.OtherException)
{
Util.Log("DoOp: Got expected exception when doing operation: " +
ex.GetType() + "::" + ex.Message);
continue;
}
else
{
Assert.Fail("DoOp: Got unexpected exception when doing operation: " + ex);
}
}
}
if (!exceptionOccured
&& expectedResult != ExpectedResult.Success)
{
Assert.Fail("Expected an exception while performing operation");
}
Util.Log(" doop done");
}
protected void ExecuteOpBlock(List<OperationWithAction> opBlock,
string authInit, Properties<string, string> extraAuthProps, Properties<string, string> extraAuthzProps,
TestCredentialGenerator gen, Random rnd, bool isMultiuser, bool ssl,bool withPassword)
{
foreach (OperationWithAction currentOp in opBlock)
{
// Start client with valid credentials as specified in
// OperationWithAction
OperationCode opCode = currentOp.OpCode;
OpFlags opFlags = currentOp.Flags;
int clientNum = currentOp.ClientNum;
if (clientNum > m_clients.Length)
{
Assert.Fail("ExecuteOpBlock: Unknown client number " + clientNum);
}
ClientBase client = m_clients[clientNum - 1];
Util.Log("ExecuteOpBlock: performing operation number [" +
currentOp.OpNum + "]: " + currentOp);
Properties<string, string> clientProps = null;
if (!CheckFlags(opFlags, OpFlags.UseOldConn))
{
Properties<string, string> opCredentials;
int newRnd = rnd.Next(100) + 1;
string currentRegionName = '/' + RegionName;
if (CheckFlags(opFlags, OpFlags.UseSubRegion))
{
currentRegionName += ('/' + SubregionName);
}
string credentialsTypeStr;
OperationCode authOpCode = currentOp.AuthzOperationCode;
int[] indices = currentOp.Indices;
CredentialGenerator cGen = gen.GetCredentialGenerator();
Properties<string, string> javaProps = null;
if (CheckFlags(opFlags, OpFlags.CheckNotAuthz) ||
CheckFlags(opFlags, OpFlags.UseNotAuthz))
{
opCredentials = gen.GetDisallowedCredentials(
new OperationCode[] { authOpCode },
new string[] { currentRegionName }, indices, newRnd);
credentialsTypeStr = " unauthorized " + authOpCode;
}
else
{
opCredentials = gen.GetAllowedCredentials(new OperationCode[] {
opCode, authOpCode }, new string[] { currentRegionName },
indices, newRnd);
credentialsTypeStr = " authorized " + authOpCode;
}
if (cGen != null)
{
javaProps = cGen.JavaProperties;
}
clientProps = SecurityTestUtil.ConcatProperties(
opCredentials, extraAuthProps, extraAuthzProps);
// Start the client with valid credentials but allowed or disallowed to
// perform an operation
Util.Log("ExecuteOpBlock: For client" + clientNum +
credentialsTypeStr + " credentials: " + opCredentials);
if(!isMultiuser)
client.Call(SecurityTestUtil.CreateClientSSL, RegionName,
CacheHelper.Locators, authInit, clientProps, ssl, withPassword);
else
client.Call(SecurityTestUtil.CreateClientMU, RegionName,
CacheHelper.Locators, authInit, (Properties<string, string>)null, true);
}
ExpectedResult expectedResult;
if (CheckFlags(opFlags, OpFlags.CheckNotAuthz))
{
expectedResult = ExpectedResult.NotAuthorizedException;
}
else if (CheckFlags(opFlags, OpFlags.CheckException))
{
expectedResult = ExpectedResult.OtherException;
}
else
{
expectedResult = ExpectedResult.Success;
}
// Perform the operation from selected client
if (!isMultiuser)
client.Call(DoOp, opCode, currentOp.Indices, opFlags, expectedResult);
else
client.Call(DoOp, opCode, currentOp.Indices, opFlags, expectedResult, clientProps, true);
}
}
protected List<AuthzCredentialGenerator> GetAllGeneratorCombos(bool isMultiUser)
{
List<AuthzCredentialGenerator> generators =
new List<AuthzCredentialGenerator>();
foreach (AuthzCredentialGenerator.ClassCode authzClassCode in
Enum.GetValues(typeof(AuthzCredentialGenerator.ClassCode)))
{
List<CredentialGenerator> cGenerators =
SecurityTestUtil.getAllGenerators(isMultiUser);
foreach (CredentialGenerator cGen in cGenerators)
{
AuthzCredentialGenerator authzGen = AuthzCredentialGenerator
.Create(authzClassCode);
if (authzGen != null)
{
if (authzGen.Init(cGen))
{
generators.Add(authzGen);
}
}
}
}
return generators;
}
protected void RunOpsWithFailoverSSL(OperationWithAction[] opCodes,
string testName, bool withPassword)
{
RunOpsWithFailover(opCodes, testName, false, true,withPassword);
}
protected void RunOpsWithFailover(OperationWithAction[] opCodes,
string testName)
{
RunOpsWithFailover(opCodes, testName, false);
}
protected void RunOpsWithFailover(OperationWithAction[] opCodes,
string testName, bool isMultiUser)
{
RunOpsWithFailover(opCodes, testName, isMultiUser, false, false);
}
protected void RunOpsWithFailover(OperationWithAction[] opCodes,
string testName, bool isMultiUser, bool ssl, bool withPassword)
{
CacheHelper.SetupJavaServers(true, CacheXml1, CacheXml2);
CacheHelper.StartJavaLocator(1, "GFELOC", null, ssl);
Util.Log("Locator started");
foreach (AuthzCredentialGenerator authzGen in GetAllGeneratorCombos(isMultiUser))
{
CredentialGenerator cGen = authzGen.GetCredentialGenerator();
Properties<string, string> extraAuthProps = cGen.SystemProperties;
Properties<string, string> javaProps = cGen.JavaProperties;
Properties<string, string> extraAuthzProps = authzGen.SystemProperties;
string authenticator = cGen.Authenticator;
string authInit = cGen.AuthInit;
string accessor = authzGen.AccessControl;
TestAuthzCredentialGenerator tgen = new TestAuthzCredentialGenerator(authzGen);
Util.Log(testName + ": Using authinit: " + authInit);
Util.Log(testName + ": Using authenticator: " + authenticator);
Util.Log(testName + ": Using accessor: " + accessor);
// Start servers with all required properties
string serverArgs = SecurityTestUtil.GetServerArgs(authenticator,
accessor, null, SecurityTestUtil.ConcatProperties(extraAuthProps,
extraAuthzProps), javaProps);
// Perform all the ops on the clients
List<OperationWithAction> opBlock = new List<OperationWithAction>();
Random rnd = new Random();
for (int opNum = 0; opNum < opCodes.Length; ++opNum)
{
// Start client with valid credentials as specified in
// OperationWithAction
OperationWithAction currentOp = opCodes[opNum];
if (currentOp == OperationWithAction.OpBlockEnd ||
currentOp == OperationWithAction.OpBlockNoFailover)
{
// End of current operation block; execute all the operations
// on the servers with/without failover
if (opBlock.Count > 0)
{
// Start the first server and execute the operation block
CacheHelper.StartJavaServerWithLocators(1, "GFECS1", 1, serverArgs, ssl);
Util.Log("Cacheserver 1 started.");
CacheHelper.StopJavaServer(2, false);
ExecuteOpBlock(opBlock, authInit, extraAuthProps,
extraAuthzProps, tgen, rnd, isMultiUser, ssl, withPassword);
if (currentOp == OperationWithAction.OpBlockNoFailover)
{
CacheHelper.StopJavaServer(1);
}
else
{
// Failover to the second server and run the block again
CacheHelper.StartJavaServerWithLocators(2, "GFECS2", 1, serverArgs, ssl);
Util.Log("Cacheserver 2 started.");
CacheHelper.StopJavaServer(1);
ExecuteOpBlock(opBlock, authInit, extraAuthProps,
extraAuthzProps, tgen, rnd, isMultiUser, ssl, withPassword);
}
opBlock.Clear();
}
}
else
{
currentOp.OpNum = opNum;
opBlock.Add(currentOp);
}
}
// Close all clients here since we run multiple iterations for pool and non pool configs
foreach (ClientBase client in m_clients)
{
client.Call(Close);
}
}
CacheHelper.StopJavaLocator(1, true, ssl);
CacheHelper.ClearEndpoints();
CacheHelper.ClearLocators();
}
#endregion
/// <summary>
/// This class specifies flags that can be used to alter the behaviour of
/// operations being performed by the <see cref="DoOp"/> method.
/// </summary>
[Flags]
public enum OpFlags
{
/// <summary>
/// Default behaviour.
/// </summary>
None = 0x0,
/// <summary>
/// Check that the operation should fail.
/// </summary>
CheckFail = 0x1,
/// <summary>
/// Check that the operation should throw <c>NotAuthorizedException</c>.
/// </summary>
CheckNotAuthz = 0x2,
/// <summary>
/// Do the connection with unauthorized credentials but do not check that the
/// operation throws <c>NotAuthorizedException</c>.
/// </summary>
UseNotAuthz = 0x4,
/// <summary>
/// Check that the region should not be available.
/// </summary>
CheckNoRegion = 0x8,
/// <summary>
/// Check that the operation should throw an exception other than the
/// <c>NotAuthorizedException</c>.
/// </summary>
CheckException = 0x10,
/// <summary>
/// Check for values starting with <c>NValuePrefix</c> instead of
/// <c>ValuePrefix</c>.
/// </summary>
UseNewVal = 0x20,
/// <summary>
/// Register a regular expression.
/// </summary>
UseRegex = 0x40,
/// <summary>
/// Register a list of keys.
/// </summary>
UseList = 0x80,
/// <summary>
/// Register all keys.
/// </summary>
UseAllKeys = 0x100,
/// <summary>
/// Perform the local version of the operation (if applicable).
/// </summary>
LocalOp = 0x200,
/// <summary>
/// Check that the key for the operation should not be present.
/// </summary>
CheckNoKey = 0x400,
/// <summary>
/// Use the sub-region for performing the operation.
/// </summary>
UseSubRegion = 0x800,
/// <summary>
/// Do not try to create the sub-region.
/// </summary>
NoCreateSubRegion = 0x1000,
/// <summary>
/// Do not re-connect using new credentials rather use the previous
/// connection.
/// </summary>
UseOldConn = 0x2000,
}
/// <summary>
/// This class encapsulates an <see cref="OperationCode"/> with associated flags, the
/// client to perform the operation, and the number of operations to perform.
/// </summary>
public class OperationWithAction
{
/// <summary>
/// The operation to be performed.
/// </summary>
private OperationCode m_opCode;
/// <summary>
/// The operation for which authorized or unauthorized credentials have to be
/// generated. This is the same as {@link #opCode} when not specified.
/// </summary>
private OperationCode m_authzOpCode;
/// <summary>
/// The client number on which the operation has to be performed.
/// </summary>
private int m_clientNum;
/// <summary>
/// Bitwise or'd <see cref="OpFlags"/> to change/specify the behaviour of
/// the operations.
/// </summary>
private OpFlags m_flags;
/// <summary>
/// Indices of the keys array to be used for operations. The keys used
/// will be concatenation of <c>KeyPrefix</c> and <c>index</c> integer.
/// </summary>
private int[] m_indices;
/// <summary>
/// An index for the operation used for logging.
/// </summary>
private int m_opNum;
/// <summary>
/// Indicates end of an operation block which can be used for testing with
/// failover.
/// </summary>
public static readonly OperationWithAction OpBlockEnd = new OperationWithAction(
OperationCode.Get, 4);
/// <summary>
/// Indicates end of an operation block which should not be used for testing
/// with failover.
/// </summary>
public static readonly OperationWithAction OpBlockNoFailover =
new OperationWithAction(OperationCode.Get, 5);
private void SetIndices(int numOps)
{
this.m_indices = new int[numOps];
for (int index = 0; index < numOps; ++index)
{
this.m_indices[index] = index;
}
}
public OperationWithAction(OperationCode opCode)
{
this.m_opCode = opCode;
this.m_authzOpCode = opCode;
this.m_clientNum = 1;
this.m_flags = OpFlags.None;
SetIndices(4);
this.m_opNum = 0;
}
public OperationWithAction(OperationCode opCode, int clientNum)
{
this.m_opCode = opCode;
this.m_authzOpCode = opCode;
this.m_clientNum = clientNum;
this.m_flags = OpFlags.None;
SetIndices(4);
this.m_opNum = 0;
}
public OperationWithAction(OperationCode opCode, int clientNum, OpFlags flags,
int numOps)
{
this.m_opCode = opCode;
this.m_authzOpCode = opCode;
this.m_clientNum = clientNum;
this.m_flags = flags;
SetIndices(numOps);
this.m_opNum = 0;
}
public OperationWithAction(OperationCode opCode,
OperationCode deniedOpCode, int clientNum, OpFlags flags, int numOps)
{
this.m_opCode = opCode;
this.m_authzOpCode = deniedOpCode;
this.m_clientNum = clientNum;
this.m_flags = flags;
SetIndices(numOps);
this.m_opNum = 0;
}
public OperationWithAction(OperationCode opCode, int clientNum,
OpFlags flags, int[] indices)
{
this.m_opCode = opCode;
this.m_authzOpCode = opCode;
this.m_clientNum = clientNum;
this.m_flags = flags;
this.m_indices = indices;
this.m_opNum = 0;
}
public OperationWithAction(OperationCode opCode, OperationCode authzOpCode,
int clientNum, OpFlags flags, int[] indices)
{
this.m_opCode = opCode;
this.m_authzOpCode = authzOpCode;
this.m_clientNum = clientNum;
this.m_flags = flags;
this.m_indices = indices;
this.m_opNum = 0;
}
public OperationCode OpCode
{
get
{
return this.m_opCode;
}
}
public OperationCode AuthzOperationCode
{
get
{
return this.m_authzOpCode;
}
}
public int ClientNum
{
get
{
return this.m_clientNum;
}
}
public OpFlags Flags
{
get
{
return this.m_flags;
}
}
public int[] Indices
{
get
{
return this.m_indices;
}
}
public int OpNum
{
get
{
return this.m_opNum;
}
set
{
this.m_opNum = value;
}
}
public override string ToString()
{
return "opCode:" + this.m_opCode + ",authOpCode:" + this.m_authzOpCode
+ ",clientNum:" + this.m_clientNum + ",flags:" + this.m_flags
+ ",numOps:" + this.m_indices.Length + ",indices:"
+ IndicesToString(this.m_indices);
}
}
/// <summary>
/// Simple interface to generate credentials with authorization based on key
/// indices also. This is utilized by the post-operation authorization tests
/// <c>ThinClientAuthzObjectModTests</c> where authorization depends on
/// the actual keys being used for the operation.
/// </summary>
public interface TestCredentialGenerator
{
/// <summary>
/// Get allowed credentials for the given set of operations in the given
/// regions and indices of keys.
/// </summary>
Properties<string, string> GetAllowedCredentials(OperationCode[] opCodes,
string[] regionNames, int[] keyIndices, int num);
/// <summary>
/// Get disallowed credentials for the given set of operations in the given
/// regions and indices of keys.
/// </summary>
Properties<string, string> GetDisallowedCredentials(OperationCode[] opCodes,
string[] regionNames, int[] keyIndices, int num);
/// <summary>
/// Get the <see cref="CredentialGenerator"/> if any.
/// </summary>
/// <returns></returns>
CredentialGenerator GetCredentialGenerator();
}
/// <summary>
/// Contains a <c>AuthzCredentialGenerator</c> and implements the
/// <c>TestCredentialGenerator</c> interface.
/// </summary>
protected class TestAuthzCredentialGenerator : TestCredentialGenerator
{
private AuthzCredentialGenerator authzGen;
public TestAuthzCredentialGenerator(AuthzCredentialGenerator authzGen)
{
this.authzGen = authzGen;
}
public Properties<string, string> GetAllowedCredentials(OperationCode[] opCodes,
string[] regionNames, int[] keyIndices, int num)
{
return this.authzGen.GetAllowedCredentials(opCodes, regionNames, num);
}
public Properties<string, string> GetDisallowedCredentials(OperationCode[] opCodes,
string[] regionNames, int[] keyIndices, int num)
{
return this.authzGen.GetDisallowedCredentials(opCodes, regionNames, num);
}
public CredentialGenerator GetCredentialGenerator()
{
return authzGen.GetCredentialGenerator();
}
}
}
}