Beispiel #1
0
        /// <summary>
        /// Authenticates with the currently set environment parameters.
        /// </summary>
        /// <param name="promptBehavior">The ADAL prompt behavior (default is "Auto")</param>
        /// <returns>The authentication result.</returns>
        /// <exception cref="AdalException">If authentication fails</exception>
        internal static SdkAuthResult Auth(PromptBehavior promptBehavior = PromptBehavior.Auto)
        {
            // If there have been no successful logins with the module and the PromptBehavior is anything other than "Never", force an interactive window
            if (LatestAdalAuthResult == null && promptBehavior != PromptBehavior.Never)
            {
                promptBehavior = PromptBehavior.SelectAccount;
            }

            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            // Get the AuthenticationResult from AAD
            AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(
                environmentParameters.ResourceId,
                environmentParameters.AppId,
                new Uri(environmentParameters.RedirectLink),
                new PlatformParameters(promptBehavior))
                                                        .GetAwaiter().GetResult();

            // Convert the auth result into our own type
            SdkAuthResult authResult = authenticationResult.ToSdkAuthResult();

            // Save the auth result
            AuthUtils.LatestAdalAuthResult = authResult;

            return(authResult);
        }
        /// <summary>
        /// Authenticates using the device code flow. See here for more information:
        /// https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-deviceprofile/.
        /// </summary>
        /// <param name="displayDeviceCodeMessageToUser">
        /// The action which displays the message from ADAL (containing the retrieved device code) to the user.
        /// The message will instruct the user to enter the device code by navigating to http://aka.ms/devicelogin/.
        /// </param>
        /// <param name="useAdminConsentFlow">
        /// Whether or not to trigger the admin consent flow for this app ID.
        /// </param>
        /// <returns>The HTTP header to use when making calls.</returns>
        internal static SdkAuthResult AuthWithDeviceCode(
            Action <string> displayDeviceCodeMessageToUser,
            bool useAdminConsentFlow = false)
        {
            if (displayDeviceCodeMessageToUser == null)
            {
                throw new ArgumentNullException(nameof(displayDeviceCodeMessageToUser));
            }

            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            if (useAdminConsentFlow)
            {
                // Remove this user's token from the token cache so they have to log in again (we must use the "Auto" Prompt behavior to add query parameters)
                SdkAuthResult currentLogin = AuthUtils.LatestAdalAuthResult;
                if (currentLogin != null)
                {
                    // Find all the items in the cache with the logged in user ID, client ID and resource ID
                    IEnumerable <TokenCacheItem> toRemove = authContext.TokenCache.ReadItems()
                                                            .Where(
                        tokenCacheItem => tokenCacheItem.UniqueId == currentLogin.UserUniqueId &&
                        tokenCacheItem.ClientId == environmentParameters.AppId &&
                        tokenCacheItem.Resource == environmentParameters.ResourceId);

                    // Remove the items
                    foreach (TokenCacheItem tokenCacheItem in toRemove)
                    {
                        authContext.TokenCache.DeleteItem(tokenCacheItem);
                    }
                }
            }

            // Get the device code
            DeviceCodeResult deviceCodeResult = authContext.AcquireDeviceCodeAsync(
                environmentParameters.ResourceId,
                environmentParameters.AppId,
                useAdminConsentFlow ? AuthUtils.AdminConsentQueryParameter : null)
                                                .GetAwaiter().GetResult();

            // Display the device code
            displayDeviceCodeMessageToUser(deviceCodeResult.Message);

            // Get the auth token
            //TODO: Figure out why this call hangs and crashes the PowerShell session if the first login was cancelled and the second login times out
            AuthenticationResult authenticationResult = authContext.AcquireTokenByDeviceCodeAsync(deviceCodeResult)
                                                        .GetAwaiter().GetResult();

            // Convert the auth result into our own type
            SdkAuthResult authResult = authenticationResult.ToSdkAuthResult();

            // Save the auth result
            AuthUtils.LatestAdalAuthResult = authResult;

            return(authResult);
        }
Beispiel #3
0
        /// <summary>
        /// Refreshes the access token using ADAL if required, otherwise returns the most recent still-valid refresh token.
        /// </summary>
        /// <returns>A valid access token.</returns>
        /// <exception cref="AdalException">If the silent login attempt fails</exception>
        internal static SdkAuthResult RefreshAdalAuth()
        {
            // Make sure there was at least 1 successful login
            if (AuthUtils.HasNeverLoggedIn)
            {
                throw new InvalidOperationException($"No successful login attempts were found. Check for this using the '{nameof(AuthUtils)}.{nameof(HasNeverLoggedIn)}' property before calling the '{nameof(RefreshAdalAuth)}()' method");
            }

            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            // Check if the existing token has expired
            SdkAuthResult authResult = AuthUtils.LatestAdalAuthResult;

            if (authResult.IsExpired)
            {
                // Try to get a new token for the same user/app
                AuthenticationResult adalResult;
                try
                {
                    if (string.IsNullOrEmpty(authResult.UserUniqueId))
                    {
                        // App-only auth
                        adalResult = authContext.AcquireTokenSilentAsync(
                            environmentParameters.ResourceId,
                            environmentParameters.AppId)
                                     .GetAwaiter().GetResult();
                    }
                    else
                    {
                        // User auth
                        adalResult = authContext.AcquireTokenSilentAsync(
                            environmentParameters.ResourceId,
                            environmentParameters.AppId,
                            new UserIdentifier(authResult.UserUniqueId, UserIdentifierType.UniqueId))
                                     .GetAwaiter().GetResult();
                    }
                }
                catch (AdalException ex)
                {
                    throw new AdalAuthException(ex.Message, ex);
                }

                // Convert the ADAL result into our own type
                authResult = adalResult.ToSdkAuthResult();

                // Save the auth result
                AuthUtils.LatestAdalAuthResult = authResult;
            }

            return(authResult);
        }
Beispiel #4
0
        /// <summary>
        /// Performs an admin consent interaction.
        /// </summary>
        internal static SdkAuthResult GrantAdminConsent()
        {
            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            // Remove this user's token from the token cache so they have to log in again (we must use the "Auto" Prompt behavior to add query parameters)
            SdkAuthResult currentLogin = AuthUtils.LatestAdalAuthResult;

            if (currentLogin != null)
            {
                // Find all the items in the cache with the logged in user ID, client ID and resource ID
                IEnumerable <TokenCacheItem> toRemove = authContext.TokenCache.ReadItems()
                                                        .Where(
                    tokenCacheItem => tokenCacheItem.UniqueId == currentLogin.UserUniqueId &&
                    tokenCacheItem.ClientId == environmentParameters.AppId &&
                    tokenCacheItem.Resource == environmentParameters.ResourceId);

                // Remove the items
                foreach (TokenCacheItem tokenCacheItem in toRemove)
                {
                    authContext.TokenCache.DeleteItem(tokenCacheItem);
                }
            }

            // Get the AuthenticationResult from AAD
            AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(
                environmentParameters.ResourceId,
                environmentParameters.AppId,
                new Uri(environmentParameters.RedirectLink),
                new PlatformParameters(PromptBehavior.Auto),
                UserIdentifier.AnyUser,
                AdminConsentQueryParameter)
                                                        .GetAwaiter().GetResult();

            // Convert the auth result into our own type
            SdkAuthResult authResult = authenticationResult.ToSdkAuthResult();

            // Save the auth result
            AuthUtils.LatestAdalAuthResult = authResult;

            return(authResult);
        }
Beispiel #5
0
        /// <summary>
        /// Authenticates with the currently set environment parameters and the provided client certificate identified by thumbprint.
        /// </summary>
        /// <param name="certificateThumbprint">The client secret</param>
        /// <returns>The authentication result.</returns>
        internal static SdkAuthResult AuthWithCertificateThumbprint(string certificateThumbprint)
        {
            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            // Get certificate with specified Thumbprint from "My" store
            X509Certificate2 xCertificate = null;

            using (X509Store xStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
            {
                xStore.Open(OpenFlags.ReadOnly);
                // Get unexpired certificates with the specified name.
                X509Certificate2Collection unexpiredCerts = xStore.Certificates
                                                            .Find(X509FindType.FindByTimeValid, DateTime.Now, false)
                                                            .Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
                if (unexpiredCerts == null)
                {
                    throw new Exception($"{certificateThumbprint} certificate was not found or has expired.");
                }
                // Only return current cert.
                xCertificate = unexpiredCerts
                               .OfType <X509Certificate2>()
                               .OrderByDescending(c => c.NotBefore)
                               .FirstOrDefault();
            }

            // Build clientAssertionCertificate for the request
            ClientAssertionCertificate clientAssertionCertificate = new ClientAssertionCertificate(CurrentEnvironmentParameters.AppId, xCertificate);

            // Acquire token for Microsoft Graph via certificate credentials from AAD
            AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(CurrentEnvironmentParameters.GraphBaseAddress, clientAssertionCertificate).GetAwaiter().GetResult();

            // Convert the auth result into our own type
            SdkAuthResult authResult = authenticationResult.ToSdkAuthResult();

            // Save the auth result
            AuthUtils.LatestAdalAuthResult = authResult;

            return(authResult);
        }
Beispiel #6
0
        /// <summary>
        /// Authenticates with the currently set environment parameters and the provided client secret.
        /// </summary>
        /// <param name="clientSecret">The client secret</param>
        /// <returns>The authentication result.</returns>
        internal static SdkAuthResult AuthWithClientCredentials(string clientSecret)
        {
            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            // Get the AuthenticationResult from AAD
            AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(
                environmentParameters.ResourceId,
                new ClientCredential(environmentParameters.AppId, clientSecret))
                                                        .GetAwaiter().GetResult();

            // Convert the auth result into our own type
            SdkAuthResult authResult = authenticationResult.ToSdkAuthResult();

            // Save the auth result
            AuthUtils.LatestAdalAuthResult = authResult;

            return(authResult);
        }
Beispiel #7
0
        /// <summary>
        /// Refreshes the access token using MSI auth if required, otherwise returns the most recent still-valid refresh token.
        /// </summary>
        /// <returns>A valid access token.</returns>
        /// <exception cref="MsiAuthException">If the login attempt fails</exception>
        internal static SdkAuthResult RefreshMsiAuth()
        {
            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            SdkAuthResult authResult = AuthUtils.LatestMsiAuthResult;

            if (authResult == null || authResult.IsExpired)
            {
                // Create the HTTP client
                using (HttpClient client = new HttpClient())
                {
                    // Add the "Metadata:true" header
                    client.DefaultRequestHeaders.Add("Metadata", "true");

                    // Make the request for the desired resource
                    HttpResponseMessage response = client
                                                   .GetAsync($"{AuthUtils.ManagedServiceIdentityEndpoint}?resource={environmentParameters.ResourceId}")
                                                   .GetAwaiter().GetResult();

                    // Make sure we successfully retrieved the result
                    if (!response.IsSuccessStatusCode)
                    {
                        // Extract the error code and error message from the failure response
                        string errorCode;
                        string errorMessage;
                        try
                        {
                            // Get the content of the failure response
                            string errorJsonString = response.Content.ReadAsStringAsync()
                                                     .GetAwaiter().GetResult();
                            JToken errorJson = JToken.Parse(errorJsonString)["error"]?.Value <JToken>();

                            // Extract error code and error message
                            errorCode    = errorJson["code"].Value <string>() ?? string.Empty;
                            errorMessage = errorJson["message"].Value <string>() ?? string.Empty;
                        }
                        catch (Exception ex)
                        {
                            throw new MsiAuthException("Unable to authenticate using MSI", ex);
                        }

                        // Build the exception message
                        string exceptionMessage;
                        if (!string.IsNullOrWhiteSpace(errorMessage))
                        {
                            exceptionMessage = errorMessage;
                        }
                        else
                        {
                            exceptionMessage = "Unknown MSI authentication error";
                        }

                        if (!string.IsNullOrWhiteSpace(errorCode))
                        {
                            exceptionMessage = $"{errorCode}: {exceptionMessage}";
                        }

                        // Throw the exception
                        throw new MsiAuthException(exceptionMessage);
                    }

                    // Convert the response from JSON into an object
                    MsiAuthResult msiResult = JsonConvert.DeserializeObject <MsiAuthResult>(response.Content.ReadAsStringAsync()
                                                                                            .GetAwaiter().GetResult());

                    // Convert the MSI auth result to our own type
                    authResult = msiResult.ToSdkAuthResult();
                }
            }

            return(authResult);
        }