/// <summary> /// Call AcquireTokenAsync - to acquire a token requiring user to sign-in /// </summary> internal async static Task <bool> MSALWork(AADAction action) { OOFSponder.Logger.Info(OOFSponderInsights.CurrentMethod()); bool _result = false; //lock this so we don't get multiple auth prompts OOFSponder.Logger.Info("Attempting to enter critical section for auth code"); await semaphoreSlim.WaitAsync(); OOFSponder.Logger.Info("Inside critical section for auth code"); OOFSponder.Logger.Info("Attempting to build PublicClientApp with multitenant endpoint"); lock (pcaInitLock) { PublicClientApp = PublicClientApplicationBuilder.Create(ClientId) .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") .WithAuthority(logonUrl) .Build(); MSALTokenCacheHelper.EnableSerialization(PublicClientApp.UserTokenCache); } //grab the logged in user UPN so we can decide whether or not to force the prompt try { Task <IEnumerable <IAccount> > accountTask = PublicClientApp.GetAccountsAsync(); accountTask.Wait(10000); // give UserTokenCache a go IAccount account = null; try { account = accountTask.Result.FirstOrDefault(p => p.Username.ToLower() == DefaultUserUPN.ToLower()); } catch (Exception) { } if (account != null && account.Username.ToLower() == DefaultUserUPN.ToLower()) { try { Task <AuthenticationResult> authUITask = PublicClientApp.AcquireTokenSilent(_scopes, account) .ExecuteAsync(); authUITask.Wait(10000); authResult = authUITask.Result; if (authResult != null) { OOFSponder.Logger.Info("AcquireTokenSilent -> OK"); } _result = true; } catch (Exception x) { OOFSponder.Logger.Error("AcquireTokenSilent -> " + x.GetType().ToString()); } } try { Task <AuthenticationResult> authUITask = PublicClientApp.AcquireTokenInteractive(_scopes) .WithLoginHint(DefaultUserUPN) .WithPrompt(Prompt.NoPrompt) .ExecuteAsync(); authUITask.Wait(10000); authResult = authUITask.Result; _result = true; } catch (Exception ex) { if (ex is MsalUiRequiredException || ex.InnerException is MsalUiRequiredException || ex is MsalClientException || ex.InnerException is MsalClientException || ex is MsalServiceException || ex.InnerException is MsalServiceException) // MSAL service or client exception here is most likely down to need for UI // even if it is not MsalUiRequiredException { //try //{ // if (!UPN.ToLower().EndsWith("@microsoft.com")) // throw new Exception("Skip IWA for outsourcer logon"); // Task<AuthenticationResult> authIWATask = PublicClientApp.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync(); // authIWATask.Wait(10000); // authResult = authIWATask.Result; //} //catch (Exception ex1) //{ try { Task <AuthenticationResult> authUITask = PublicClientApp.AcquireTokenInteractive(_scopes) .WithPrompt(Prompt.NoPrompt) .WithLoginHint(DefaultUserUPN).ExecuteAsync(); authUITask.Wait(10000); authResult = authUITask.Result; _result = true; } catch (Exception ex2) { string _error2 = "GetTokenFromAAD: Failed to get interactive auth token: " + ExceptionChain(ex2); OOFSponder.Logger.Error(new Exception(_error2, ex2)); } //} } else { string _error = "GetTokenFromAAD: UI might be required for MSAL logon: " + ExceptionChain(ex); OOFSponder.Logger.Error(new Exception(_error)); } } //} } catch (Exception ex) { OOFSponder.Logger.Error(new Exception("Generalized auth failure: ** ", ex)); } finally { //store the UPN for future use if (authResult != null) { DefaultUserUPN = authResult.Account.Username; } //release the critical section we are using to prevent multiple auth prompts OOFSponder.Logger.Info("Leaving critical section for auth code"); semaphoreSlim.Release(); OOFSponder.Logger.Info("Left critical section for auth code"); } return(_result); }
/// <summary> /// Call AcquireTokenAsync - to acquire a token requiring user to sign-in /// </summary> internal async static Task <bool> MSALWork(AADAction action) { OOFSponder.Logger.Info(OOFSponderInsights.CurrentMethod()); //lock this so we don't get multiple auth prompts OOFSponder.Logger.Info("Attempting to enter critical section for auth code"); await semaphoreSlim.WaitAsync(); OOFSponder.Logger.Info("Inside critical section for auth code"); bool _result = false; var accounts = await PublicClientApp.GetAccountsAsync(); var firstAccount = accounts.FirstOrDefault(); try { if (action == AADAction.SignIn | action == AADAction.ForceSignIn) { try { //MSAL 1.0 style - deprecated //authResult = await PublicClientApp.AcquireTokenSilentAsync(_scopes, PublicClientApp.Users.FirstOrDefault()); //MSAL 3.0 style authResult = await PublicClientApp.AcquireTokenSilent(_scopes, firstAccount).ExecuteAsync(); } catch (MsalUiRequiredException ex) { // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token //Don't track this one since it can basically be considered expected. OOFSponder.Logger.Warning(new Exception($"Unable to acquire token silently: ", ex)); try { //MSAL 1.0 style //authResult = await PublicClientApp.AcquireTokenAsync(_scopes); //MSAL 3.0 style authResult = await PublicClientApp.AcquireTokenInteractive(_scopes).ExecuteAsync(); } catch (MsalException msalex) { OOFSponder.Logger.Error(new Exception($"Error acquiring token interactively: ", msalex)); } } catch (Exception ex) { OOFSponder.Logger.Error(new Exception($"Error acquiring token: ", ex)); return(false); } //MSAL 1.0 style //if (PublicClientApp.Users.Count() > 0) //MSAL 3.0 style if (authResult != null) { _result = true; //also, update the Application Insights info with the authenticated user //MSAL 1.0 style //OOFSponderInsights.AIClient.Context.User.Id = authResult.User.DisplayableId.Split('@')[0]; //MSAL 3.0 style OOFSponderInsights.AIClient.Context.User.Id = authResult.Account.Username; } else { _result = false; } } else { //MSAL 1.0 //if (PublicClientApp.Users.Any()) //MSAL 3.0 if (firstAccount != null) { try { //MSAL 1.0 //PublicClientApp.Remove(PublicClientApp.Users.FirstOrDefault()); //MSAL 3.0 await PublicClientApp.RemoveAsync(firstAccount); _result = true; } catch (MsalException ex) { OOFSponder.Logger.Error(new Exception("Error signing out user: "******"MSAL code failed miserably for user: "******"Leaving critical section for auth code"); semaphoreSlim.Release(); OOFSponder.Logger.Info("Left critical section for auth code"); } return(_result); }
/// <summary> /// Call AcquireTokenAsync - to acquire a token requiring user to sign-in /// </summary> internal async static Task <bool> MSALWork(AADAction action) { OOFSponderInsights.TrackInfo(OOFSponderInsights.CurrentMethod()); bool _result = false; if (action == AADAction.SignIn | action == AADAction.ForceSignIn) { try { authResult = await PublicClientApp.AcquireTokenSilentAsync(_scopes, PublicClientApp.Users.FirstOrDefault()); } catch (MsalUiRequiredException ex) { // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token //Don't track this one since it can basically be considered expected. //OOFSponderInsights.TrackException($"MsalUiRequiredException: {ex.Message}", ex); try { authResult = await PublicClientApp.AcquireTokenAsync(_scopes); } catch (MsalException msalex) { OOFSponderInsights.TrackException("MsalException", new Exception($"Error Acquiring Token:{System.Environment.NewLine}", msalex)); } } catch (Exception ex) { OOFSponderInsights.TrackException("Error Acquiring Token Silently", ex); return(false); } if (PublicClientApp.Users.Count() > 0) { //BuddyOptions.authResult = BuddyOptions.authResult; _result = true; //also, update the Application Insights info with the authenticated user OOFSponderInsights.AIClient.Context.User.Id = authResult.User.DisplayableId.Split('@')[0]; } else { _result = false; } } else { if (PublicClientApp.Users.Any()) { try { PublicClientApp.Remove(PublicClientApp.Users.FirstOrDefault()); _result = true; } catch (MsalException ex) { OOFSponder.Logger.Error($"Error signing-out user: {ex.Message}"); OOFSponderInsights.TrackException($"Error signing-out user: {ex.Message}", ex); } } } return(_result); }