none
active directory authentication - daemon or windows service to SharePoint Online

    Question

  • Hi,

    I want to authenticate to Active Directory(Azure AD) where my Windows service should pass the Client ID and Certificate details and get authenticated and then uploads the document to SPO. This is not working if it runs as a service. 

    If I create a console application project and run the same code, it gets authenticated correctly.

    CODE:

    string authString = "https://login.microsoftonline.com/common";
    AuthenticationContext authContext = new AuthenticationContext(authString, false);

    ClientAssertionCertificate certCred = new ClientAssertionCertificate(clientId, certificate);

    /***** I'm getting the error at below line: *****/

    authenticationResult = authContext.AcquireToken(audienceUrl, certCred);

    Error Message:

    A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 11.111.111.11:443

    I'm trying the same code as that of the following link:
    https://github.com/Azure-Samples/active-directory-dotnet-daemon-certificate-credential
    https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-scenarios#daemon-or-server-application-to-web-api
    I have created the self signed certificate and I have saved the details of the certificate in the Aure AD manifest file.
    I am trying to get the access token and it works fine if it runs as a console application but fails if runs as a windows service.
    Code Snippet:
    private static string GetAccessToken()
            {
                
                string result = null;
                X509Certificate2 cert = new X509Certificate2();
                X509Certificate2 x509 = new X509Certificate2();
                X509Store store = new X509Store();
                try
                {
                    
                    var rawData = ReadData(CertificatePath);        
                    x509.Import(rawData);                
                    store.Open(OpenFlags.MaxAllowed);
                    store.Add(x509);                
                    if (x509.NotAfter.Subtract(DateTime.Now).Days < 180)
                    {
                        LogMessage(string.Format("#################### Certificate will expire on {0} ####################", x509.NotAfter));
                    }                
                    
                    rawData = ReadData(@"PfxFilePath"); 
                    var rawData1 = ReadData(PfxFilePath);               
                    x509.Import(rawData1, "***Privatekey***", X509KeyStorageFlags.PersistKeySet);                
                    store.Open(OpenFlags.MaxAllowed);              
                    store.Add(x509);
                    
                    var certCollection = store.Certificates;
                    var currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);                                
                    string certThumbPrint = Regex.Replace(CertThumbPrint, @"[^\da-zA-z]", string.Empty).ToUpper();                
                    X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindByThumbprint, certThumbPrint, false);                
                    if (signingCert.Count == 0)
                    {
                        // No matching certificate found.
                        LogMessage("***************** No matching certificates found on the machine *******************");
                    }               
                    cert = signingCert[0];                
                }
                catch (Exception ex)
                {
                    if (isDebugMode)
                        LogMessage("Error in Adding certificate: " + ex.Message);
                }

                finally
                {
                    store.Close();
                }
                string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
                AuthenticationContext authContext = new AuthenticationContext(authority);
                ClientAssertionCertificate certCred = new ClientAssertionCertificate(clientId, cert);
                
                var retryCount = 0;
                bool retry;
                do
                {
                    retry = false;
                    try
                    {
                        if (authContext.TokenCache != null) authContext.TokenCache.Clear();
                        
                        GetAuthenticationResult(authContext, audienceUrl, certCred).Wait();
                        
                        result = authenticationResult.AccessToken;
                        
                    }
                    catch (AdalException ex)
                    {
                        if (isDebugMode)
                        LogError(ex);
                        if (ex.ErrorCode == "temporarily_unavailable")
                        {                        
                            retry = true;
                            retryCount++;
                            Thread.Sleep(3000);
                        }                      
                    }
                    catch(Exception e)
                    {
                        LogError(e);
                    }
                } while (retry && (retryCount < 3));


                return result;
            }

    private static async Task GetAuthenticationResult(AuthenticationContext authContext, string mfdServiceResourceId,
                ClientAssertionCertificate certCred)
            {
                
               
                //return Task.Run(async () =>
                //{
                //    authenticationResult = (await authContext.AcquireTokenAsync(mfdServiceResourceId, certCred));
                //});
                try
                {
                    // ADAL includes an in memory cache, so this call will only send a message to the server if the cached token is expired.
                    authenticationResult = await authContext.AcquireTokenAsync(mfdServiceResourceId, certCred);
                }
                catch (AdalException ex)
                {              
                    using (StreamWriter writer = new StreamWriter(LogfilePath, true))
                    {
                        writer.WriteLine(ex.Message);
                        writer.Close();
                    }
                    LogError(ex);
                }
                catch(Exception e)
                {
                    LogError(e);
                }
            }

    Wednesday, May 3, 2017 7:05 AM

All replies

  • Error Message:

    A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 11.111.111.11:443

    When https network communication works while signed in as a user, and not when running from a Windows Service, it is often due to a proxy setting. You may have a proxy configuration set for your user account which is not set for the service account (e.g. LocalSystem). 

    At first glance, I don't see anything in the code that wouldn't work when running as a service.

    The simplest (yet insecure) way of testing whether it is a proxy configuration problem is to make your service login with your credentials (that requires you to give your user account the "Log on as a service" permission in Windows).

    There are other ways to configure proxy settings for LocalSystem: https://serverfault.com/questions/34940/how-do-i-configure-proxy-settings-for-local-system 


    • Edited by rasmusw Wednesday, May 3, 2017 8:57 AM make link out of URL
    Wednesday, May 3, 2017 8:57 AM