Functions.cs

A collection of exportable example functions which uses the NiP.Client class. For example CreateTask, Search etc.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;

namespace SecMaker.NiP.Client
{
    public partial class Client
    {

        public string GetVersion(bool verbose = false)
        {
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <GetVersion xmlns=""http://www.secmaker.com/NiP"">
    </GetVersion>
  </soap:Body>
</soap:Envelope>";
            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            string sResponse = InvokeMessage(verbose);

            //VerifySuccess will throw an exception if the user does not have an image. I choose to return an empty string then. You choose what you want.
            try
            {
                Utility.VerifySuccess(sResponse);
            }
            catch (Exception e)
            {
                return "";
            }
            string version = Utility.NaiveParseXmlTag(sResponse, "Version", false);
            return version;
        }
        public string FillInActions(string taskXml, Tuple<string, string>[] inputList)
        {
            XmlDocument task = new XmlDocument();
            task.LoadXml(taskXml);


            var activeAction = task.SelectSingleNode(".//ActionList/ActionObj[State/Id/. = '1']");

            if (activeAction == null)
            {
                activeAction = task.SelectSingleNode(".//ActionList[State/Id/. = '1']");
            }


            foreach (Tuple<string, string> inputValue in inputList)
            {
                string valueName = inputValue.Item1;
                string valueText = inputValue.Item2;

                XmlNode valueObj = null;

                var inputField = activeAction.SelectSingleNode(".//InputFieldObj[Id/. ='" + valueName + "']");
                if (inputField == null)
                {
                    inputField = activeAction.SelectSingleNode(".//InputFieldList[Id/. ='" + valueName + "']");
                }

                //No inputfield found
                if (inputField == null)
                {
                    throw new ArgumentException("Action does not contain inputfieldobject with ID " + valueName);
                }
                //inputfield is selectmultiple
                else if (inputField.SelectSingleNode(".//Type").InnerText.ToLower() == "selectmultiple")
                {

                    var value = "";
                    var options = valueText.Split('|');
                    bool first = true;
                    //Get all options
                    foreach (string option in options)
                    {
                        string trimmedOption = option.Trim();
                        valueObj = inputField.SelectSingleNode(".//ValueObj[Name/. = '" + trimmedOption + "']");
                        if (valueObj == null)
                        {
                            valueObj = inputField.SelectSingleNode(".//ValueList[Name/. = '" + trimmedOption + "']");
                        }
                        if (valueObj == null)
                        {
                            valueObj = inputField.SelectSingleNode(".//ValueObj[Id/. = '" + trimmedOption + "']");
                        }
                        if (valueObj == null)
                        {
                            valueObj = inputField.SelectSingleNode(".//ValueList[Id/. = '" + trimmedOption + "']");
                        }
                        if (valueObj == null && trimmedOption.Length > 0)
                        {
                            throw new ArgumentException("Inputfield with ID " + valueName + "  does not contain Select Option with Name or ID " + valueText);
                        }
                        else
                        {
                            if (!first)
                            {
                                value += ",";
                            }
                            else
                            {
                                first = false;
                            }
                            value = value + valueObj.SelectSingleNode(".//Id/.").InnerText;

                        }
                    }
                    inputField.SelectSingleNode(".//Value/.").InnerText = value;
                }
                else //Inputfield is not selectmultiple
                {
                    if (valueText.Length > 0)
                    {
                        try
                        {
                            valueObj = inputField.SelectSingleNode(".//ValueObj[Name/. = '" + valueText + "']");
                            if (valueObj == null && inputField.SelectSingleNode(".//ValueObj") == null)
                            {
                                valueObj = inputField.SelectSingleNode(".//ValueList[Name/. = '" + valueText + "']");
                            }
                            if (valueObj == null)
                            {
                                valueObj = inputField.SelectSingleNode(".//ValueObj[Id/. = '" + valueText + "']");
                            }
                            if (valueObj == null)
                            {
                                valueObj = inputField.SelectSingleNode(".//ValueList[Id/. = '" + valueText + "']");
                            }
                        }
                        catch (Exception e)
                        {
                            //TODO, perhaps make this configurable instead of throwing and catching exception like a noob
                            valueObj = null;
                        }

                    }
                    //If no valueObj with our name but valueobj exists throw exception
                    if (valueObj == null && inputField.SelectSingleNode(".//ValueObj") != null)
                    {
                        throw new ArgumentException("Inputfield with ID " + valueName + "  does not contain Select Option with Name " + valueText);
                    }
                    //If we have found a valueobject then select it
                    else if (valueObj != null)
                    {
                        inputField.SelectSingleNode(".//Value/.").InnerText = valueObj.SelectSingleNode(".//Id/.").InnerText;
                    }
                    //No multiple choice, just fill in the value
                    else
                    {
                        inputField.SelectSingleNode(".//Value/.").InnerText = valueText;
                    }
                }
            }
            return task.OuterXml;
        }


        public string GetLoginStatus(bool verbose = false)
        {
            SetCounter(_counter + 1);
            // SOAP-message request for 'GetLoginStatus'. You may want to use this to check that the login was succesful or not and act accordingly. In this example the result is just written out.
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <GetLoginStatus xmlns=""http://www.secmaker.com/NiP""><Info><SessionId>" + _sSessionId + "</SessionId><Count>" +
                          _counter +
                          "</Count></Info></GetLoginStatus></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);
            if (verbose)
            {
                Console.WriteLine(sResponse);
            }
            return sResponse;
        }
        public string GetApplicationInfo(bool verbose = false)
        {
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <GetObject xmlns=""http://www.secmaker.com/NiP""><Info>
<Type>APPLICATIONINFO</Type>
</Info>
</GetObject></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);

            return sResponse;
        }

        public bool LoginWithOTP(string otp, string username, bool verbose = false)
        {
            string applicationInfo = GetApplicationInfo(verbose);
            //Parses out the SecurityMode to an array
            var SecurityMode = Utility.ParseXmlElem(applicationInfo, "<SecurityMode>").Split('|');

            //Get the symmetrical algorithm, currently the SDK only supports AES encryption.
            var SymmetricalAlgorithm = SecurityMode[0];
            if (!String.Equals(SymmetricalAlgorithm, "AES",
                StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("Symmetrical algorithm " + SymmetricalAlgorithm + " not implemented in this example.");
            }

            //Parse out and set the symmetrical key size.
            int SymmetricalKeySize = Int32.Parse(SecurityMode[1]);
            SetSymmetricalKeySize(SymmetricalKeySize);

            //We always use ENCRYPTION in production, therefore the SDK does not allow for changing encryption to none. 
            //If you wish to trace on client side and turn off encryption then pass the flag "encryptionDisabled"

            //Get the HMAC algorithm from the security mode
            var hashAlgorithm = SecurityMode[3];
            String hashAlgorithmOID = null;
            switch (hashAlgorithm)
            {
                case "SHA1-HMAC":
                    {
                        hashAlgorithmOID = "1.3.14.3.2.26";
                        break;
                    }
                case "SHA256-HMAC":
                    {
                        hashAlgorithmOID = "2.16.840.1.101.3.4.2.1";
                        break;
                    }
                case "SHA384-HMAC":
                    {
                        hashAlgorithmOID = "2.16.840.1.101.3.4.2.2";
                        break;
                    }

                case "SHA512HMAC":
                    {
                        hashAlgorithmOID = "2.16.840.1.101.3.4.2.3";
                        break;
                    }
                default:
                    {
                        hashAlgorithmOID = "1.3.14.3.2.26";//Default SHA1-HMAC;
                        break;
                    }
            }
            //Sets the clients HMAC algorithm
            SetHashAlgorithm(hashAlgorithmOID);

            //If compression is not implemented (NiP version < 5.3) this will be empty.
            if (SecurityMode.Length > 4 && SecurityMode[4] != "")
            {
                var compressionMode = SecurityMode[4];
                SetCompressionMode(compressionMode);
            }
            else
            {
                SetCompressionMode("NONE");
            }
            //If the choice of format for the encrypted blob is not implemented (NiP version < 5.4) this will be empty, then default is json
            if (SecurityMode.Length > 5 && SecurityMode[5] != "")
            {
                SetBlobFormat(SecurityMode[5]);
            }
            else
            {
                SetBlobFormat("JSON");
            }

            //We can now log in:
            Console.WriteLine("Starting login process...");
            // Session ID generated by the server after successfully login.
            _sSessionId = InvokeLoginOTP(otp, username, verbose);
            Console.WriteLine("Login process complete, checking login status...");
            Console.WriteLine();

            // Invoke the SOAP-message request and get the SOAP-response.
            var loginStatus = GetLoginStatus(verbose);
            if (Utility.VerifySuccess(loginStatus))
            {
                Console.WriteLine("Successfully logged in");
            }
            return Utility.VerifySuccess(loginStatus);

        }
        public bool Login(bool verbose = false)
        {
            SetCounter(0);
            string applicationInfo = GetApplicationInfo(verbose);
            //Parses out the SecurityMode to an array
            var SecurityMode = Utility.ParseXmlElem(applicationInfo, "<SecurityMode>").Split('|');

            //Get the symmetrical algorithm, currently the SDK only supports AES encryption.
            var SymmetricalAlgorithm = SecurityMode[0];
            if (!String.Equals(SymmetricalAlgorithm, "AES",
                StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("Symmetrical algorithm " + SymmetricalAlgorithm + " not implemented in this example.");
            }

            //Parse out and set the symmetrical key size.
            int SymmetricalKeySize = Int32.Parse(SecurityMode[1]);
            SetSymmetricalKeySize(SymmetricalKeySize);

            //We always use ENCRYPTION in production, therefore the SDK does not allow for changing encryption to none. 
            //If you wish to trace on client side and turn off encryption then change the SDK accordingly. By changing the "UseEncryption" function

            //Get the HMAC algorithm from the security mode
            var hashAlgorithm = SecurityMode[3];
            String hashAlgorithmOID = null;
            switch (hashAlgorithm)
            {
                case "SHA1-HMAC":
                    {
                        hashAlgorithmOID = "1.3.14.3.2.26";
                        break;
                    }
                case "SHA256-HMAC":
                    {
                        hashAlgorithmOID = "2.16.840.1.101.3.4.2.1";
                        break;
                    }
                case "SHA384-HMAC":
                    {
                        hashAlgorithmOID = "2.16.840.1.101.3.4.2.2";
                        break;
                    }

                case "SHA512HMAC":
                    {
                        hashAlgorithmOID = "2.16.840.1.101.3.4.2.3";
                        break;
                    }
                default:
                    {
                        hashAlgorithmOID = "1.3.14.3.2.26";//Default SHA1-HMAC;
                        break;
                    }
            }
            //Sets the clients HMAC algorithm
            SetHashAlgorithm(hashAlgorithmOID);

            //If compression is not implemented (NiP version < 5.3) this will be empty.
            if (SecurityMode.Length > 4 && SecurityMode[4] != "")
            {
                var compressionMode = SecurityMode[4];
                SetCompressionMode(compressionMode);
            }
            else
            {
                SetCompressionMode("NONE");
            }
            //If the choice of format for the encrypted blob is not implemented (NiP version < 5.4) this will be empty, then default is json
            if (SecurityMode.Length > 5 && SecurityMode[5] != "")
            {
                SetBlobFormat(SecurityMode[5]);
            }
            else
            {
                SetBlobFormat("JSON");
            }

            //We can now log in:
            Console.WriteLine("Starting login process...");
            // Session ID generated by the server after successfully login.
            _sSessionId = InvokeLogin(verbose);
            Console.WriteLine("Login process complete, checking login status...");
            Console.WriteLine();

            // Invoke the SOAP-message request and get the SOAP-response.
            var loginStatus = GetLoginStatus(verbose);
            if (Utility.VerifySuccess(loginStatus))
            {
                Console.WriteLine("Successfully logged in");
            }
            return Utility.VerifySuccess(loginStatus);

        }
        public string CreateTask(string TaskTypeId, string ObjectId, bool verbose = false)
        {
            Console.WriteLine("Creating task with ID: " + TaskTypeId + " and objectId: " + ObjectId + "....");
            // Prepare next call by increasing the counter with 1.
            SetCounter(_counter + 1);

            // SOAP-message request for 'CreateTask'
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <CreateTask xmlns=""http://www.secmaker.com/NiP"">
      <Info>
        <SessionId>" + GetSessionId() + "</SessionId>" +
         "<Count>" + _counter + "</Count>" +
         "<TypeId>" + TaskTypeId + "</TypeId>" +
         "<ObjectId>" + ObjectId + "</ObjectId>" +
       "</Info></CreateTask></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);


            var task = Utility.ParseTaskElem(sResponse);
            Console.WriteLine("Created Task.");
            return task;
        }
        /// <summary>
        /// Returns if the id should be added or not
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        bool AddValueToDataToBeSigned(string id)
        {
            // Only all password values that should be skipped (Password/UnlockPassword/etc)
            return (id.IndexOf("Password") == -1);
        }
        /// <summary>
        /// Creates Data from a task to be signed.
        /// </summary>
        /// <param name=""></param>
        /// <param name=""></param>
        /// <returns></returns>
        string AddSignatureToTask(string taskXML)
        {

            XmlDocument task = new XmlDocument();
            task.LoadXml(taskXML);

            var actions = task.SelectNodes(".//ActionList/ActionObj");
            XmlNode activeAction = null;

            //Since XML -> JSON -> XML is lossy be prepared that <*List><*obj><*obj/><*list/> tags get turned into <*List></*List>
            if (actions == null || actions.Count == 0)
            {
                actions = task.SelectNodes(".//ActionList");
            }
            int index = 0;
            string actionIndex = "";
            foreach (XmlElement act in actions)
            {
                if (act.SelectSingleNode(".//State/Id/.").InnerText == "1")
                {
                    actionIndex = index.ToString();
                    activeAction = act;
                    break;
                }
                index++;
            }
            if(activeAction.SelectSingleNode(".//RequireSignature/.") != null &&
                activeAction.SelectSingleNode(".//RequireSignature/.").InnerText.ToLower() != "true")
            {
                return taskXML;
            }
            var inputFields = activeAction.SelectNodes(".//InputFieldObj");
            //Same here, XML -> JSON -> XML is lossy 
            if (inputFields == null || inputFields.Count > 0)
            {
                inputFields = activeAction.SelectNodes(".//InputFieldList");
            }

            var parameterFields = activeAction.SelectNodes(".//ParameterObj");
            //Same here, XML -> JSON -> XML is lossy 
            if (parameterFields == null ||parameterFields.Count > 0)
            {
                parameterFields = activeAction.SelectNodes(".//ParameterList");
            }



            string userId = activeAction.SelectSingleNode("./UserId/.").InnerText;
            string taskId = task.SelectSingleNode("./Task/Id/.").InnerText;
            string actionTypeName = activeAction.SelectSingleNode("./Type/Name/.").InnerText;
            string data = "";
            data += "user=" + userId;
            data += "|task=" + taskId;
            data += "|index=" + actionIndex;
            data += "|action=" + actionTypeName;
            foreach (XmlElement inputField in inputFields)
            {
                string value = inputField.SelectSingleNode(".//Value/.").InnerText;
                string id = inputField.SelectSingleNode(".//Id/.").InnerText;
                if (AddValueToDataToBeSigned(id))
                {
                    data += "|value:" + id + "=" + value;
                }
            }
            foreach (XmlElement parameterField in parameterFields)
            {
                var value = parameterField.SelectSingleNode(".//Value/.").InnerText;
                string id = parameterField.SelectSingleNode(".//Id/.").InnerText;
                if (AddValueToDataToBeSigned(id))
                {
                    data += "|hidden:" + id + "=" + value;
                }
            }
            XmlNode confirmation = activeAction.SelectSingleNode(".//Info/confirmation");
            if ((confirmation != null) &&
                (confirmation.SelectSingleNode(".//id/.") != null) &&
                (confirmation.SelectSingleNode(".//value/.") != null)
            )
            {
                data += "|confirm:" + confirmation.SelectSingleNode(".//id/.").InnerText
                    + "=" + confirmation.SelectSingleNode(".//value/.").InnerText;
            }
            data = Utility.ToBase64String(Encoding.UTF8.GetBytes(data));
            //Create signature
            var pkcs7 = new Pkcs7();
            var x509CltCert =
                 CertificateStore.GetCertificate(_sCertHash);
            string signature =
                Utility.ToBase64String(
                    pkcs7.SignData(
                        Utility.ToBytes(data),
                        x509CltCert,
                        false));
            activeAction.SelectSingleNode(".//Signature/.").InnerText = signature;
            return task.OuterXml;
        }


        /// <summary>
        /// Execute a given task. This will send the task to the server, completed the active action. The task is then returned by the server with the next step prepared.
        /// </summary>
        /// <param name="task">A task obj, you can get this from either the return value to CreateTask or by calling a GetTask</param>
        /// <returns></returns>
        public string ExecuteTask(string task, bool verbose = false)
        {
            Console.WriteLine("Executing task:");
            var counter = GetCounter();
            task = AddSignatureToTask(task);
            // Prepare next call by increasing the counter 
            SetCounter(counter = counter + 1);
            // SOAP-message request for 'ExecuteTask'.
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <ExecuteTask xmlns=""http://www.secmaker.com/NiP""><Info><SessionId>" + GetSessionId() +
                       "</SessionId><Count>" + counter + "</Count>" +
                        task + //task variable contains <Task> tag
                       "</Info></ExecuteTask></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);
            //If all has gone well task should be a success
            Utility.VerifySuccess(sResponse);
            Console.WriteLine("Executed task:");
            return Utility.ParseTaskElem(sResponse); 
        }
        /// <summary>
        /// Cancel a task with a given taskID. Note that your user must have permission to do this (which you get from being the user which created the task)
        /// </summary>
        /// <param name="taskId"></param>
        /// <returns></returns>
        public string CancelTask(string taskId, bool verbose = false)
        {
            Console.WriteLine("Canceling task: " + taskId);

            var counter = GetCounter();

            SetCounter(counter = counter + 1);
            // SOAP-message request for 'CancelTask'.
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <CancelTask xmlns=""http://www.secmaker.com/NiP""><Info><SessionId>" + GetSessionId() +
                       "</SessionId><Count>" + counter + "</Count><Id>" +
                        taskId + //taskId for the task to cancel
                       "</Id></Info></CancelTask></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.

            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);
            // Writes the SOAP-response into the console.


            Console.WriteLine("Cancelled task: " + taskId);
            return sResponse;
        }

        public string Search(string type, string directive, string limit, string offset, bool verbose = false)
        {
            SetCounter(_counter + 1);
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <Search xmlns=""http://www.secmaker.com/NiP"">
      <Info>
        <SessionId>" + _sSessionId + @"</SessionId><Count>" + _counter + @"</Count><Type>" + type + @"</Type><Directive>"
+ directive + @"</Directive><Offset>" + offset +
@"</Offset><Limit>" + limit + @"</Limit></Info>
    </Search>
  </soap:Body>
</soap:Envelope>";

            string sResponse = InvokeMessage(verbose);

            //VerifySuccess will throw an exception if the user does not have an image. I choose to return an empty string then. You choose what you want.

            Utility.VerifySuccess(sResponse);

            string sResultCounter = Utility.NaiveParseXmlTag(sResponse, "ResultCounter", false);
            Console.WriteLine("Found " + sResultCounter + " results");
            return "<ResultCounter>" + sResultCounter + "</ResultCounter>" + Utility.NaiveParseXmlTag(sResponse, type + "List", true);
        }

        public string GetData(string type, string id, bool verbose = false)
        {
            SetCounter(_counter + 1);
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <GetData xmlns=""http://www.secmaker.com/NiP"">
      <Info>
        <Count>" + _counter + @"</Count>
        <SessionId>" + _sSessionId + @"</SessionId>
        <Type>" + type + @"</Type>
        <Id>" + id + @"</Id>
      </Info>
    </GetData>
  </soap:Body>
</soap:Envelope>";
            string sResponse = InvokeMessage(verbose);

            //VerifySuccess will throw an exception if the user does not have an image. I choose to return an empty string then. You choose what you want.
            try
            {
                Utility.VerifySuccess(sResponse);
            }
            catch (Exception e)
            {
                return "";
            }
            string data = Utility.NaiveParseXmlTag(sResponse, "Value", false);
            return data;
        }
        public string GetList(string listType, bool verbose = false)
        {
            Console.WriteLine("Getting list of type: " + listType + "....");

            // Prepare next call by increasing the counter with 1.
            SetCounter(_counter + 1);

            // SOAP-message request for 'GetList'
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
            <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
              <soap:Body>
                <GetList xmlns=""http://www.secmaker.com/NiP"">
                  <Info>
                    <Count>" + _counter + @"</Count>
                    <SessionId>" + _sSessionId + @"</SessionId>
                    <Type>" + listType + @"</Type>
                  </Info>
                </GetList>
              </soap:Body>
            </soap:Envelope>";


            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);
            Utility.VerifySuccess(sResponse);
            return Utility.NaiveParseXmlTag(sResponse, listType, true);

        }

        public string GetObject(string type, string id, bool verbose = false)
        {
            SetCounter(_counter + 1);

            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <GetObject xmlns=""http://www.secmaker.com/NiP"">
<Info>
        <Count>" + _counter + @"</Count>
        <SessionId>" + _sSessionId + @"</SessionId>
<Type>" + type + @"</Type>
            <Id>" + id + @"</Id>
</Info>
</GetObject></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);

            // Writes the SOAP-response into the console.
            if (verbose)
            {
                Console.WriteLine(sResponse);
            }

            try
            {
                Utility.VerifySuccess(sResponse);
            }
            catch (Exception e)
            {
                return "";
            }
            string data = Utility.NaiveParseXmlTag(sResponse, type, true);
            return data;
        }
        public string GetTask(string taskId, bool verbose = false)
        {
            SetCounter(_counter + 1);
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <GetTask xmlns=""http://www.secmaker.com/NiP"">
      <Info>
        <Count>" + _counter + @"</Count>
        <SessionId>" + _sSessionId + @"</SessionId>
        <Id>" + taskId + @"</Id>
      </Info>
    </GetTask>
  </soap:Body>
</soap:Envelope>";
            string sResponse = InvokeMessage(verbose);

            //VerifySuccess will throw an exception if the user does not have an image. I choose to return an empty string then. You choose what you want.

            Utility.VerifySuccess(sResponse);
            return sResponse;
        }
        public void Logout(bool verbose = false)
        {
            SetCounter(_counter + 1);
            // SOAP-message request for 'Logout'.
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <Logout xmlns=""http://www.secmaker.com/NiP""><Info><SessionId>" + _sSessionId +
                        "</SessionId></Info></Logout></soap:Body></soap:Envelope>";

            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);

            // Writes the SOAP-response into the console.
            if (verbose)
            {
                Console.WriteLine(sResponse);
            }

            _sSessionId = null;
        }
        public bool SwitchOrganization(string orgId, bool verbose = false)
        {
            SetCounter(_counter + 1);

            // SOAP-message request for 'SwitchOrganization'
            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <SwitchOrganization xmlns=""http://www.secmaker.com/NiP"">
      <Info>
        <SessionId>" + _sSessionId + "</SessionId>" +
        "<Count>" + _counter + "</Count>" +
       "<Id>" + orgId + "</Id>" +
        "</Info></SwitchOrganization></soap:Body></soap:Envelope>";


            // Set the SOAP-message request.


            // Invoke the SOAP-message request and get the SOAP-response.
            var sResponse = InvokeMessage(verbose);
            if (!sResponse.Contains("NPR_SUCCESS"))
            {
                throw new System.ArgumentException("Failed to switch to org with ID " + orgId);
            }
            Console.WriteLine("Switched org to org with ID: " + orgId + "....");
            return true;
        }
        /// <summary>
        /// Takes in a listResponse from search, and returns a list of format [obj,obj,obj]
        /// As an example, to parse out serialnumber and firstname from a search user response.
        /// ParseSearchListResponse(listXML, "User", ["SerialNumber","FirstName"]
        /// </summary>
        /// <param name="listXML"></param>
        /// <returns></returns>
        public List<Dictionary<string, string>> ParseSearchListResponse(string listXML, string type)
        {
            List<Dictionary<string, string>> toReturn = new List<Dictionary<string, string>>();

            //To avoid invalid xml
            listXML = "<root>" + listXML + "</root>";

            if (Utility.NaiveParseXmlTag(listXML, "ResultCounter", false) != "" && Utility.NaiveParseXmlTag(listXML, "ResultCounter", false) == "0")
            {
                return toReturn;
            }
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(listXML);
            string xpath;
            if (listXML.IndexOf(type + "List") == -1)
            {
                throw new Exception("Missing tag " + type + "List");
            }

            if (listXML.IndexOf(type + "ListObj") == -1)
            {
                xpath = ".//" + type + "List";
            }
            else
            {
                xpath = ".//" + type + "List/" + type + "ListObj";
            }

            var nodes = xmlDoc.SelectNodes(xpath);
            foreach (XmlElement node in nodes)
            {
                Dictionary<string, string> obj = new Dictionary<string, string>();
                foreach (XmlElement child in node.ChildNodes)
                {
                    obj[child.Name] = child.InnerText;
                }
                toReturn.Add(obj);
            }

            return toReturn;
        }
        public List<Dictionary<string, string>> GetInputFieldsFromTask(string taskXML)
        {
            List<Dictionary<string, string>> toReturn = new List<Dictionary<string, string>>();


            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(taskXML);
            string xpath;
            if (taskXML.IndexOf("InputFieldList") == -1)
            {
                throw new Exception("Missing tag InputFieldList");
            }

            if (taskXML.IndexOf("InputFieldObj") == -1)
            {
                xpath = ".//InputFieldList";
            }
            else
            {
                xpath = ".//InputFieldObj";
            }

            var nodes = xmlDoc.SelectNodes(xpath);
            foreach (XmlElement node in nodes)
            {
                Dictionary<string, string> obj = new Dictionary<string, string>();
                foreach (XmlElement child in node.ChildNodes)
                {
                    obj[child.Name] = child.InnerText;
                }
                toReturn.Add(obj);
            }

            return toReturn;
        }

        public void CancelAllMyTasks()
        {
            int resultCounter;
            List<Dictionary<string, string>> tasks;
            List<string> taskIDs = new List<string>();
            List<string> taskTypes = new List<string> { "USER", "TOKEN", "SERVER", "ENDENTITY", "ADMIN" };

            foreach (string taskType in taskTypes)
            {
                resultCounter = Int32.Parse(Utility.NaiveParseXmlTag(Search("Task", taskType, "1", "0"), "ResultCounter", false));
                for (int offset = 0; offset < resultCounter; offset += 100)
                {
                    tasks = ParseSearchListResponse(Search("Task", taskType, "100", offset.ToString()), "Task");
                    Console.WriteLine("Adding users...");
                    foreach (Dictionary<string, string> task in tasks)
                    {
                        taskIDs.Add(task["Id"]);
                    }
                }
            }

            foreach (string taskId in taskIDs)
            {
                CancelTask(taskId);
            }

        }
        public void CancelAllTasksOnObjectWithId(string objectId, string objectType = "USER", bool verbose = false)
        {
            SetCounter(_counter + 1);

            //Step one: load user object to get list of tokens.
            string sRequest = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
  <soap:Body>
    <GetObject xmlns=""http://www.secmaker.com/NiP"">
      <Info>
        <SessionId>" + _sSessionId + @"</SessionId>
        <Type>" + objectType + @"</Type>
        <Id>" + objectId + @"</Id>
        <Count>" + _counter + @"</Count>
      </Info>
    </GetObject>
  </soap:Body>
</soap:Envelope>";
            // Set the SOAP-message request.
            SetMessage(sRequest);

            // Invoke the SOAP-message request and get the SOAP-response.
            string sResponse = InvokeMessage(verbose);
            Utility.VerifySuccess(sResponse);
            string sObjXml = Utility.NaiveParseXmlTag(sResponse, "GetObjectResult", true);
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(sObjXml);
            //Note that when encrypting a message it is stored as JSON by default. Since the conversion between JSON and XML can be lossy we sometimes lose the outer list tag
            //when we convert to XML. Hence <TaskList><TaskListObj>...</TaskListObj><TaskListObj>...</TaskListObj></TaskList> can come out as simply 
            //<TaskList>...</<TaskList><TaskList>...</<TaskList>
            //While there are more elegant ways to solve this I simply choose to naively check if there are xml tags named TaskListObj, if not I grab TokenList Instead.


            // Note here that I am selected all Tasks. On a User this will include tasks on the user itself (for example update user) AND token tasks on tokens belonging to the user

            XmlNodeList taskObjList = xDoc.SelectNodes(".//TaskListObj");
            if (taskObjList.Count == 0)
            {
                taskObjList = xDoc.SelectNodes(".//TaskList");
            }

            //Step two: from the list of tasks. Cancel all tasks.
            foreach (XmlNode node in taskObjList)
            {
                var taskIdNode = node.SelectSingleNode(".//Id");
                if (taskIdNode != null)
                {
                    Console.WriteLine("Irma banana");
                    Console.WriteLine(taskIdNode.InnerText);
                    CancelTask(taskIdNode.InnerText, verbose);
                }
            }
        }


    }

}