///#################################################################
/// PROJECT : CASA - Common Authentication Services Adapter
/// FILE : StoreDataInterface.cs
/// DESCRIPTION : Implementation of Store Data Interface for CASA.
/// Abstracts the back-end and acts as an interface
/// to the GUI.
/// AUTHORS : Manohar, CSL.Manojna
/// UPDATED ON : 24 Sept, 2005
///#################################################################
namespace Novell.CASA.GUI {
using System;
using System.IO;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using GLib;
using Gtk;
using Novell.CASA.DataEngines;
public class StoreDataInterface
{
private static XmlDocument ccfDoc;
private static AD ad;
private static string CCFXML_ELEMENT_MICASA_KEYCHAIN = "Keychain",
CCFXML_ELEMENT_GKEYRING_KEYRING = "Keyring",
CCFXML_ELEMENT_KWALLET_WALLET = "Wallet",
CCFXML_ELEMENT_SECRET = "Secret",
CCFXML_ELEMENT_FOLDER = "Folder",
CCFXML_ATTRIBUTE_FOLDERNAME = "Name",
CCFXML_ELEMENT_TYPE = "Type",
CCFXML_ELEMENT_KEY = "Key",
CCFXML_ELEMENT_VALUE = "Value",
CCFXML_ELEMENT_TIME = "Time",
CCFXML_ELEMENT_TIME_ZONE = "Zone",
CCFXML_ELEMENT_TIME_CREATION = "Creation",
CCFXML_ELEMENT_TIME_MODIFIED = "Modified",
CCFXML_ELEMENT_TIME_ACCESSED = "Accessed",
CCFXML_ATTRIBUTE_ID = "ID",
CCFXML_ATTRIBUTE_MICASA_SYNCH = "Synch",
CCFXML_ATTRIBUTE_GKEYRING_TYPE = "Type";
///#######################################################################
/// INIT
///
/// Initializes the CCF from miCASA-D
///
public static int Init()
{
Logger.DbgLog("GUI:StoreDataInterface.StoreDataInterface() - BEGIN");
try
{
ccfDoc = new XmlDocument();
ad = new AD();
}
catch(Exception exp)
{
Logger.DbgLog("GUI:StoreDataInterface.Init() - EXCEPTION" + exp.ToString());
//Common.ShowErrorDialog( exp );
return( Common.STATUS_STORE_ADINITFAILED );
}
Logger.DbgLog("GUI:StoreDataInterface.StoreDataInterface() - END");
return( Common.STATUS_SUCCESS );
}
///#######################################################################
/// AGGREGATE A SPECIFIC STORE
///
/// Initializes the CCF from miCASA-D
///
public static int AggregateStore(int storeIDentifier)
{
Logger.DbgLog("GUI:StoreDataInterface.AggregateStore()");
try
{
return( ad.AggregateStore(ccfDoc, storeIDentifier) );
}
catch(Exception exp)
{
Logger.DbgLog("GUI:StoreDataInterface.AggregateStore() - EXCEPTION" + exp.ToString());
//Common.ShowErrorDialog(exp);
return( Common.STATUS_STORE_AGGREGATEFAILED );
}
}
///#######################################################################
/// REFRESH ALL STORES
///
/// Initializes the CCF from miCASA-D
///
public static int RefreshAllStores()
{
Logger.DbgLog("GUI:StoreDataInterface.RefreshAllStores() - BEGIN");
try
{
ccfDoc = ad.Aggregate();
}
catch(Exception exp)
{
Logger.DbgLog("GUI:StoreDataInterface.RefreshAllStores() - EXCEPTION" + exp.ToString());
//Common.ShowErrorDialog(exp);
return( Common.STATUS_STORE_AGGREGATEFAILED );
}
Logger.DbgLog("GUI:StoreDataInterface.RefreshAllStores() - END");
return( Common.STATUS_SUCCESS );
}
///#######################################################################
/// READ STORE
///
/// Gets the GUI Data store
///
public static int ReadStore(int storeIDentifier,ref Gtk.TreeStore ls)
{
Logger.DbgLog("GUI:StoreDataInterface.ReadStore()");
//Common Keys
string storeChainKey = CCFXML_ELEMENT_MICASA_KEYCHAIN;
//TreeStore structure
string secretID = null;
string[] strKeyArray = null;
string[] strValueArray = null;
string storeID = null;
string[] strNativeKeyArray = new string[Common.MAX_NATIVE_ELEMENTS];
string[] strNativeValueArray = new string[Common.MAX_NATIVE_ELEMENTS];
//Vars for ccf data
string folderName = null;
string typeID = null;
string modifiedTime = null;
string synch = null;
string synchType = null;
//Flags & Variables
bool bKey = false;
bool bEndOfSecret = false;
//bool bEndOfTime=false;
string ccfPath = null;
//Counters
int noOfSecretsFound = 0;
int noOfKeys = 0;
int noOfKeysFound = 0;
//Init Native Information TypeNames
strNativeKeyArray[Common.INDEX_NATIVEINFO_FOLDERNAME] = Common.NATIVEINFO_FOLDERNAME;
strNativeKeyArray[Common.INDEX_NATIVEINFO_TYPEID] = Common.NATIVEINFO_TYPEID;
strNativeKeyArray[Common.INDEX_NATIVEINFO_SYNC] = Common.NATIVEINFO_SYNC;
strNativeKeyArray[Common.INDEX_NATIVEINFO_SYNCTYPE] = Common.NATIVEINFO_SYNCTYPE;
strNativeKeyArray[Common.INDEX_NATIVEINFO_MODIFIEDTIME] = Common.NATIVEINFO_MODIFIEDTIME;
//Form the XPATH Query definitions
if( storeIDentifier == Common.STORE_MICASA )
{
ccfPath = "//CCF/miCASA";
storeChainKey = CCFXML_ELEMENT_MICASA_KEYCHAIN;
}
else if( storeIDentifier == Common.STORE_GNOMEKEYRING )
{
ccfPath = "//CCF/GK";
storeChainKey = CCFXML_ELEMENT_GKEYRING_KEYRING;
}
else if( storeIDentifier == Common.STORE_KDEWALLET )
{
ccfPath = "//CCF/KWallet";
storeChainKey = CCFXML_ELEMENT_KWALLET_WALLET;
}
else
return( Common.STATUS_STORE_INVALIDSTOREID );
try
{
XPathNavigator nav = ccfDoc.CreateNavigator();
XPathNodeIterator iter = null;
string ccfExtPath = null;
//Query on the CCF and point to the store
iter = nav.Select(ccfPath);
if( 0 == iter.Count )
return( Common.STATUS_STORE_DATANOTFOUNDINSTORE );
//Enumerate all store instances [storeID's-Keychain\Wallet\Profile\Keyring]
while( iter.MoveNext() )
{//Get Next Store instance. Ideally this should always be 1
//Get all descendants of this store. Ideally this should always be keychains
//So this should get all keychains of this store.
XPathNodeIterator iterSecret = iter.Current.SelectDescendants( XPathNodeType.Element,false );
while( iterSecret.MoveNext() )
{//Enumerate this Keychain\Wallet\Profile\Keyring
if( true == iterSecret.Current.HasAttributes )
{//Elements With attributes, get the attributes first before going to next sub element
if( iterSecret.Current.Name.Equals(storeChainKey) )
{//miCASA-KeyChain //GK-Keyring //KWallet-Wallet
iterSecret.Current.MoveToFirstAttribute();
do
{
//Keychain\Wallet\Profile\Keyring ID
if( iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_ID) )
{
storeID = iterSecret.Current.Value;
}
}while( iterSecret.Current.MoveToNextAttribute() );
iterSecret.Current.MoveToParent();
}
else if( iterSecret.Current.Name.Equals(CCFXML_ELEMENT_SECRET) )
{//miCASA-KeyChain-Secret:secretID
noOfSecretsFound++;
iterSecret.Current.MoveToFirstAttribute();
do
{
if( iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_ID) )
{
secretID = iterSecret.Current.Value;
}
else if( iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_MICASA_SYNCH) )
{
synch = iterSecret.Current.Value;
}
else if( iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_GKEYRING_TYPE) )
{
synchType = iterSecret.Current.Value;
}
}while( iterSecret.Current.MoveToNextAttribute() );
iterSecret.Current.MoveToParent();
//Now get more details about the secret
//End of secret is after read of all keys of the secret
{
XPathNodeIterator secIter;
ccfExtPath = "Key";
secIter = iterSecret.Current.Select(ccfExtPath);
noOfKeys = secIter.Count;
//Reinit arrays to the no of keys for this secret
strKeyArray = new string[noOfKeys];
strValueArray = new string[noOfKeys];
//Get Last Modified Time for the secret
ccfExtPath = CCFXML_ELEMENT_TIME + "/" + CCFXML_ELEMENT_TIME_MODIFIED;
secIter = iterSecret.Current.Select(ccfExtPath);
if( 0 != secIter.Count )
{
while( secIter.MoveNext() )
{//Enumerate the Time Nodes of this secret
if( secIter.Current.Name.Equals(CCFXML_ELEMENT_TIME_MODIFIED) )
{//miCASA-KeyChain-Secret-Key-Value-Time-modified
modifiedTime = secIter.Current.Value;
}
}
}
}
}
else if( iterSecret.Current.Name.Equals(CCFXML_ELEMENT_KEY) )
{//miCASA-KeyChain-Secret-Key:ID
iterSecret.Current.MoveToFirstAttribute();
do
{
if( (iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_ID)) && (noOfKeysFound<=noOfKeys) )
{
bKey = true;
strKeyArray[noOfKeysFound] = iterSecret.Current.Value; //KeyName
}
}while( iterSecret.Current.MoveToNextAttribute() );
iterSecret.Current.MoveToParent();
}
else if( iterSecret.Current.Name.Equals(CCFXML_ELEMENT_FOLDER) )
{//Folder:
iterSecret.Current.MoveToFirstAttribute();
do
{
if( iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_FOLDERNAME) )
{//Folder:Name
folderName = iterSecret.Current.Value;
}
}while( iterSecret.Current.MoveToNextAttribute() );
iterSecret.Current.MoveToParent();
}
else if( iterSecret.Current.Name.Equals(CCFXML_ELEMENT_TYPE) )
{//Type:
iterSecret.Current.MoveToFirstAttribute();
do
{
if( iterSecret.Current.LocalName.Equals(CCFXML_ATTRIBUTE_ID) )
{//Type:ID
typeID = iterSecret.Current.Value;
}
}while( iterSecret.Current.MoveToNextAttribute() );
iterSecret.Current.MoveToParent();
}
}//Elements Without attributes,Get element values and then go to next subelement
else if( iterSecret.Current.Name.Equals(CCFXML_ELEMENT_VALUE) )
{//miCASA-KeyChain-Secret-Key-Value:
if( true == bKey )
{
//Update Corresponding KeyValue
strValueArray[noOfKeysFound++] = iterSecret.Current.Value; //KeyValue
bKey = false;
//Are alll keys read? If so its the end of the secret
if( noOfKeysFound == noOfKeys )
bEndOfSecret = true;
}
}
//Update this Secret to the GUI Store
if( true == bEndOfSecret )
{
//Updating TreeStore Native Array structure
strNativeValueArray = new string[Common.MAX_NATIVE_ELEMENTS];
strNativeValueArray[Common.INDEX_NATIVEINFO_FOLDERNAME] = folderName;
strNativeValueArray[Common.INDEX_NATIVEINFO_TYPEID] = typeID;
strNativeValueArray[Common.INDEX_NATIVEINFO_SYNC] = synch;
strNativeValueArray[Common.INDEX_NATIVEINFO_SYNCTYPE] = synchType;
strNativeValueArray[Common.INDEX_NATIVEINFO_MODIFIEDTIME] = modifiedTime;
//Console.WriteLine("folderName="+folderName+"\n"+"typeID="+typeID+"\n"+"synch="+synch+"\n"+"synchType="+synchType+"\n"+"modifiedTime="+modifiedTime);
ls.AppendValues(secretID,strKeyArray,strValueArray,storeID,strNativeKeyArray,strNativeValueArray);
//Re-Initialize for next iteration
secretID = "";
noOfKeysFound = 0;
noOfKeys = 0;
bKey = false;
//bTime=false;- For Use Later
bEndOfSecret = false;
}
}
}
}
catch(Exception exp)
{
Logger.DbgLog("GUI:StoreDataInterface.ReadStore() - EXCEPTION" + exp.ToString());
//Common.ShowErrorDialog( exp );
return( Common.STATUS_STORE_READFAILED );
}
ShowDocOnConsole("READ STORE:");
return( Common.STATUS_SUCCESS );
}
///#######################################################################
/// UPDATE STORE: ADD NEW secret/keyvalue, MODIFY keyvalue, DELETE secret
///
/// Supported Update Functionalities - on miCASA Store only
///
public static int UpdateStore(int storeIDentifier,int operation,string keyID,string valueToBeModfied,ref TreeModel model,ref TreeIter iter)
{
Logger.DbgLog("GUI:StoreDataInterface.UpdateStore()");
//TreeStore row elements
string SecretID = null;
string keyChainID = null;
string[] strKeyArray = new string[Common.MAX_ARRAY_ELEMENTS];
string[] strValueArray = new string[Common.MAX_ARRAY_ELEMENTS];
//XPATH query strings
string ccfKeyChainPath = null;
string ccfSecretPath = null;
//Intialization of New Secret\Key elements
XmlElement newKeychainElement = ccfDoc.CreateElement(CCFXML_ELEMENT_MICASA_KEYCHAIN);
XmlElement newSecretElement = ccfDoc.CreateElement(CCFXML_ELEMENT_SECRET);
XmlElement newKeyElement = ccfDoc.CreateElement(CCFXML_ELEMENT_KEY);
//Reading and Initialzing from the passed iter object
SecretID = (string) model.GetValue (iter, 0);
strKeyArray = (string[]) model.GetValue (iter, 1);
strValueArray = (string[]) model.GetValue (iter, 2);
keyChainID = (string) model.GetValue (iter, 3);
try
{
//Form the query to reach to an element for modify\delete\add
if( Common.STORE_MICASA == storeIDentifier )
{
if( Common.OPERATION_MODIFY_KEY == operation || Common.OPERATION_DELETE_KEY == operation )
{
ccfSecretPath = "//CCF/miCASA/Keychain[@ID='" + keyChainID + "']/Secret[@ID='" + SecretID + "']/Key[@ID='" + keyID + "']";
}
else if( Common.OPERATION_DELETE_SECRET == operation )
{
//ccfSecretPath="//CCF/miCASA/Keychain[@ID='"+keyChainID+"']/Secret[@ID='"+SecretID+"']";
ccfKeyChainPath = "//CCF/miCASA/Keychain[@ID='" + keyChainID + "']";
ccfSecretPath = "Secret[@ID='" + SecretID + "']";
}
else if( Common.OPERATION_ADD_SECRET == operation )
{
ccfKeyChainPath = "//CCF/miCASA/Keychain[@ID='" + keyChainID + "']";
ccfSecretPath = "";
//Create the Secret element
newSecretElement = ccfDoc.CreateElement(CCFXML_ELEMENT_SECRET);
newSecretElement.SetAttribute(CCFXML_ATTRIBUTE_ID,SecretID);
newSecretElement.SetAttribute(CCFXML_ATTRIBUTE_MICASA_SYNCH,"NSL");
//Add all keys from strKeyArray to the new secret
for( int i=0; i< strKeyArray.Length; i++)
{
XmlElement newKey = ccfDoc.CreateElement(CCFXML_ELEMENT_KEY);
newKey.SetAttribute(CCFXML_ATTRIBUTE_ID,strKeyArray[i]);
XmlElement newValue = ccfDoc.CreateElement(CCFXML_ELEMENT_VALUE);
newValue.InnerText = strValueArray[i];
newKey.AppendChild(newValue);
newSecretElement.AppendChild(newKey);
}
//Time
XmlElement newTime = ccfDoc.CreateElement(CCFXML_ELEMENT_TIME);
XmlElement newZone = ccfDoc.CreateElement(CCFXML_ELEMENT_TIME_ZONE);
newZone.InnerText = "IST";
newTime.AppendChild(newZone);
XmlElement newCreateTime = ccfDoc.CreateElement(CCFXML_ELEMENT_TIME_CREATION);
newCreateTime.InnerText = "1234";
newTime.AppendChild(newCreateTime);
XmlElement newModifiedTime = ccfDoc.CreateElement(CCFXML_ELEMENT_TIME_MODIFIED);
newModifiedTime.InnerText = "5678";
newTime.AppendChild(newModifiedTime);
XmlElement newAccessedTime = ccfDoc.CreateElement(CCFXML_ELEMENT_TIME_ACCESSED);
newAccessedTime.InnerText = "9012";
newTime.AppendChild(newAccessedTime);
newSecretElement.AppendChild(newTime);
}
else if( Common.OPERATION_ADD_KEY == operation )
{
ccfKeyChainPath = "//CCF/miCASA/Keychain[@ID='" + keyChainID + "']/Secret[@ID='" + SecretID + "']";
ccfSecretPath = "";
//Create the Key element
//strKeyArray[0]-[n] -If Support needed for multiple keys at once
newKeyElement = ccfDoc.CreateElement(CCFXML_ELEMENT_KEY);
newKeyElement.SetAttribute(CCFXML_ATTRIBUTE_ID,keyID);
XmlElement newValue = ccfDoc.CreateElement(CCFXML_ELEMENT_VALUE);
newValue.InnerText = valueToBeModfied;
newKeyElement.AppendChild(newValue);
}
}
else
return( Common.STATUS_STORE_UNSUPPORTEDOPERATION );
//Execute the query for modify\delete\add
if( Common.OPERATION_MODIFY_KEY == operation )
{
//For Modify operation get to the Node in the tree which needs to be modified
XmlNode root = ccfDoc.DocumentElement;
XmlNodeList keylist = root.SelectNodes(ccfSecretPath);
foreach ( XmlNode key in keylist )
{
key.ChildNodes[0].InnerText=valueToBeModfied ;
ad.SetSecret(key.ParentNode,storeIDentifier);
}
}
else if( Common.OPERATION_DELETE_SECRET == operation )
{
//Delete the specific secret from the keychain
XmlNode root = ccfDoc.DocumentElement;
XmlNodeList keychainNodeList = root.SelectNodes(ccfKeyChainPath);
foreach( XmlNode keychain in keychainNodeList )
{
XmlNodeList secretNodelist = keychain.SelectNodes(ccfSecretPath);
foreach ( XmlNode secret in secretNodelist )
{
ad.Remove(secret,storeIDentifier);
}
}
}
else if( Common.OPERATION_DELETE_KEY == operation )
{
//For Modify operation get to the Node in the tree which needs to be modified
XmlNode root = ccfDoc.DocumentElement;
XmlNodeList keylist = root.SelectNodes(ccfSecretPath);
foreach ( XmlNode key in keylist )
{
//key.ChildNodes[0].InnerText=valueToBeModfied ;
XmlNode keyParentNode = key.ParentNode;
key.ParentNode.RemoveChild(key);
ad.SetSecret(keyParentNode,storeIDentifier);
}
}
else if( Common.OPERATION_ADD_SECRET == operation )
{
//Add a new secret to the keychain
XmlNode root = ccfDoc.DocumentElement;
XmlNodeList keychainNodeList = root.SelectNodes(ccfKeyChainPath);
if( (null == keychainNodeList) || (0 == keychainNodeList.Count) )
{
newKeychainElement = ccfDoc.CreateElement(CCFXML_ELEMENT_MICASA_KEYCHAIN);
newKeychainElement.SetAttribute(CCFXML_ATTRIBUTE_ID,keyChainID);
ccfKeyChainPath = "//CCF/miCASA";
keychainNodeList = root.SelectNodes(ccfKeyChainPath);
XmlNode miCASANode = keychainNodeList.Item(0);
if( null != miCASANode )
{
miCASANode.AppendChild(newKeychainElement);
newKeychainElement.AppendChild(newSecretElement);
ccfSecretPath = "//CCF/miCASA/Keychain[@ID='" + keyChainID + "']/Secret[@ID='" + SecretID + "']";
keychainNodeList = root.SelectNodes(ccfSecretPath);
XmlNode SecretNode = keychainNodeList.Item(0);
ad.SetSecret(SecretNode,storeIDentifier);
}
}
else
{
XmlNode keychain = keychainNodeList.Item(0);
keychain.AppendChild(newSecretElement);
XmlNode lastChild = keychain.LastChild;
ad.SetSecret(lastChild,storeIDentifier);
}
}
else if( Common.OPERATION_ADD_KEY == operation )
{
//Add a new KN\KV to the keychain-Secret
XmlNode root = ccfDoc.DocumentElement;
XmlNodeList keyNodeList = root.SelectNodes(ccfKeyChainPath);
XmlNode keyNode=keyNodeList.Item(0);
XmlNode lastChild = keyNode.LastChild;
keyNode.InsertBefore(newKeyElement,lastChild);
ad.SetSecret(keyNode,storeIDentifier);
}
}
catch(Exception exp)
{
Logger.DbgLog("GUI:StoreDataInterface.UpdateStore() - EXCEPTION" + exp.ToString());
//Common.ShowErrorDialog( exp );
return( Common.STATUS_STORE_UPDATEFAILED );
}
ShowDocOnConsole("UPDATE STORE:");
return( Common.STATUS_SUCCESS );
}
///#######################################################################
/// DUMP THE XML CCF ON CONSOLE
///
/// Print Doc to the console for verification
///
public static void ShowDocOnConsole(string str)
{
#if DEBUG
Console.WriteLine("\n#######################################################");
Console.WriteLine(" "+str);
Console.WriteLine("\n#######################################################");
ccfDoc.Save(Console.Out);
Console.WriteLine("\n#######################################################");
#endif
}
}
}
///###########################################################################
/// END OF FILE
///###########################################################################