/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }