using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using System.Web;

namespace MSSConnexion
{
    class Auth
    {
        private static string idNat = "00B1058656";
        private static string userId = "2400294781";
        private static string services = "Item";
        private static string method = "sendMessage";
        private static string postData = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ser=""http://services.msg.mss.asip.fr/"">
            <soapenv:Header/>
             <soapenv:Body>
              <ser:sendMessage>
                 <email>prenom.nom@mssante.fr</email>
                 <message>
                    <addresses>
                       <email>jean.dest@mssante.fr</email>
                       <type>TO</type>
                    </addresses>
                    <body>Ceci est le sujet du message</body>
                    <replyType>FORWARDED</replyType>
                    <messageId>351</messageId>
                    <messageTransferedId>351</messageTransferedId>
                    <subject>Ceci est le contenu du message</subject>
                 </message>
              </ser:sendMessage>
           </soapenv:Body>
        </soapenv:Envelope>";

        // Paramètres de configuration
		// Renseigner les champs serverSp, portSp, serverIdp, portIdp avec les informations relatives à l'environnement utilisé
        // Service provider
        private static string serverSp = "URL du serveur";
        private static string portSp = "port";
        private static string endpointSp = "/mss-msg-services/services/";
        
        // Idp
        private static string serverIdp = "URL du serveur";
        private static string portIdp = "port";
        private static string endpointIdp = "/openam/SSOSoap/metaAlias/asip/idp";

        /*
         * Call Service
         */
        public static string callSp(CookieContainer myCookie)
        {
            CookieContainer cookieJar = new CookieContainer();
            string url = serverSp + ":" + portSp + endpointSp + services + "/soap/v1/" + method;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.CookieContainer = myCookie;
            request.Method = "POST";
            request.Headers.Add("PAOS", "ver='urn:liberty:paos:2003-08';'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'");
            request.Accept = "application/vnd.paos+xml:application/json";
            request.Headers.Add("CPSIDNAT", userId);

            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = byteArray.Length;
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            string responseFromServer = reader.ReadToEnd();
            return responseFromServer;
        }

        /*
         * Find Certificate
         */
        private static X509Certificate2 FindCertificateBySubject(string subject)
        {
            X509Certificate2 cert = null;
            // Certificate
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            try
            {
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certs = store.Certificates
                    .Find(X509FindType.FindBySubjectName, subject, false)
                    .Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false);
                if (certs.Count >= 1)
                {
                    cert = certs[0];
                }
                return cert;
            }
            finally
            {
                if (store != null)
                {
                    store.Close();
                }
            }
        }

        static void Main(string[] args)
        {
            CookieContainer cookieJar = new CookieContainer();

            /*
             * Begin - First request
             */
            ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
            string responseFromServer = callSp(cookieJar);

            /*
            * Begin - Read the cert from cps and get it
            */
            X509Certificate2 certificatCPS = FindCertificateBySubject(idNat);

            if (certificatCPS == null)
            {
                Environment.Exit(0);
            }

            /*
             * Begin - Send Authrequest to IDP
             */
            ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack; 
            
            string UrlIdp = serverIdp + ":" + portIdp + endpointIdp;
            HttpWebRequest request2 = (HttpWebRequest)WebRequest.Create(UrlIdp);
            request2.CookieContainer = new CookieContainer();
            request2.ClientCertificates.Add(certificatCPS);
            request2.Method = "POST";
            request2.Headers.Add("PAOS", "ver='urn:liberty:paos:2003-08';'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'");
            request2.Headers.Add("CPSIDNAT", userId);
            request2.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            string postData2 = responseFromServer;
            byte[] byteArray2 = Encoding.UTF8.GetBytes(postData2);
            request2.ContentType = "text/xml;charset=UTF-8";
            request2.ContentLength = byteArray2.Length;
            Stream dataStream2 = request2.GetRequestStream();
            dataStream2.Write(byteArray2, 0, byteArray2.Length);
            HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse();
            dataStream2 = response2.GetResponseStream();
            StreamReader reader2 = new StreamReader(dataStream2);
            string responseFromServer2 = reader2.ReadToEnd();

            /*
             * Beging - Call assertion URL
             */
            ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack; 
            string UrlAssertion = serverSp + ":" + portSp + "/mss-msg-services/saml/SSO/alias/defaultAlias";
            HttpWebRequest request3 = (HttpWebRequest)WebRequest.Create(UrlAssertion);
            request3.CookieContainer = new CookieContainer();
            request3.CookieContainer = cookieJar;
            request3.Method = "POST";
            request3.Headers.Add("PAOS", "ver='urn:liberty:paos:2003-08';'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'");
            request3.Accept = "application/vnd.paos+xml";
            request3.ContentType = "application/vnd.paos+xml";
            request3.Headers.Add("IDNAT", userId);
            request3.Headers.Add("numHomologation", "APPMOBILE");
            request3.AllowAutoRedirect = false;
            System.Text.RegularExpressions.Regex myRegex = new Regex("<soap-env:Header>.*</soap-env:Header>");
            responseFromServer2 = myRegex.Replace(responseFromServer2, "<soap-env:Header></soap-env:Header>");
            string postData3 = responseFromServer2;
            byte[] byteArray3 = Encoding.UTF8.GetBytes(postData3);
            request3.ContentLength = byteArray3.Length;
            Stream dataStream3 = request3.GetRequestStream();
            dataStream3.Write(byteArray3, 0, byteArray3.Length);
            HttpWebResponse response3 = (HttpWebResponse)request3.GetResponse();
            dataStream3 = response3.GetResponseStream();
            StreamReader reader3 = new StreamReader(dataStream3);
            string responseFromServer3 = reader3.ReadToEnd();

            /*
             * Call Service after we get authentified
             */
            ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack; 
            string responseFromServer4 = callSp(cookieJar);
        }

        /*
         * Permits to validate all certificates
         */
        private static bool CertificateValidationCallBack(
         object sender,
         System.Security.Cryptography.X509Certificates.X509Certificate certificate,
         System.Security.Cryptography.X509Certificates.X509Chain chain,
         System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
    }
}
