private MsalTokenResponse CreateMsalTokenResponse( IWebTokenRequestResultWrapper wamResponse, IWamPlugin wamPlugin, bool isInteractive) { string internalErrorCode = null; string errorMessage; string errorCode; switch (wamResponse.ResponseStatus) { case WebTokenRequestStatus.Success: _logger.Info("WAM response status success"); return(wamPlugin.ParseSuccesfullWamResponse(wamResponse.ResponseData[0])); // Account Switch occurs when a login hint is passed to WAM but the user chooses a different account for login. // MSAL treats this as a success scenario case WebTokenRequestStatus.AccountSwitch: _logger.Info("WAM response status account switch. Treating as success"); return(wamPlugin.ParseSuccesfullWamResponse(wamResponse.ResponseData[0])); case WebTokenRequestStatus.UserInteractionRequired: errorCode = wamPlugin.MapTokenRequestError(wamResponse.ResponseStatus, wamResponse.ResponseError?.ErrorCode ?? 0, isInteractive); internalErrorCode = (wamResponse.ResponseError?.ErrorCode ?? 0).ToString(CultureInfo.InvariantCulture); errorMessage = WamErrorPrefix + $"Wam plugin {wamPlugin.GetType()}" + $" error code: {internalErrorCode}" + $" error: " + wamResponse.ResponseError?.ErrorMessage; break; case WebTokenRequestStatus.UserCancel: errorCode = MsalError.AuthenticationCanceledError; errorMessage = MsalErrorMessage.AuthenticationCanceled; break; case WebTokenRequestStatus.ProviderError: errorCode = wamPlugin.MapTokenRequestError(wamResponse.ResponseStatus, wamResponse.ResponseError?.ErrorCode ?? 0, isInteractive); errorMessage = WamErrorPrefix + wamPlugin.GetType() + wamResponse.ResponseError?.ErrorMessage; internalErrorCode = (wamResponse.ResponseError?.ErrorCode ?? 0).ToString(CultureInfo.InvariantCulture); break; default: errorCode = MsalError.UnknownBrokerError; internalErrorCode = wamResponse.ResponseError.ErrorCode.ToString(CultureInfo.InvariantCulture); errorMessage = $"Unknown WebTokenRequestStatus {wamResponse.ResponseStatus} (internal error code {internalErrorCode})"; break; } return(new MsalTokenResponse() { Error = errorCode, ErrorCodes = internalErrorCode != null ? new[] { internalErrorCode } : null, ErrorDescription = errorMessage }); }
public async Task GetAccounts_WamAccount_NoCacheAccountMatch_WebRequest_Async() { // Arrange using (MockHttpAndServiceBundle harness = CreateTestHarness()) { const string User1Upn = "*****@*****.**"; var wamAccountProvider = new WebAccountProvider("id", User1Upn, null); _webAccountProviderFactory.GetAccountProviderAsync("organizations").Returns(wamAccountProvider); var wamAccount = new WebAccount(wamAccountProvider, "*****@*****.**", WebAccountState.Connected); _wamProxy.FindAllWebAccountsAsync(wamAccountProvider, TestConstants.ClientId).Returns(new[] { wamAccount }); _wamProxy.TryGetAccountProperty(wamAccount, "Authority", out string _).Returns(x => { x[2] = TestConstants.AuthorityCommonTenant; return(true); }); var rq = new Client.Internal.RequestContext(harness.ServiceBundle, Guid.NewGuid(), default); _cacheSessionManager.RequestContext.Returns(rq); _cacheSessionManager.GetAccountsAsync().Returns(new[] { new Account(TestConstants.HomeAccountId, "some_other_user", null, null) }); _instanceDiscoveryManager.GetMetadataEntryTryAvoidNetworkAsync( Arg.Any <AuthorityInfo>(), Arg.Any <IEnumerable <string> >(), rq) .Returns(CreateEntryForSingleAuthority(new Uri(TestConstants.AuthorityCommonTenant))); // user set this authority in config // Setup for the silent token request we're going to do via WAM _webAccountProviderFactory.GetAccountProviderAsync(TestConstants.AuthorityCommonTenant).Returns(wamAccountProvider); IWebTokenRequestResultWrapper webTokenResponseWrapper = CreateSuccessResponse(wamAccount); var newlyAddedAccountToCache = new Account("Id_From_ESTS", "upn", null); _wamProxy.GetTokenSilentlyAsync(wamAccount, Arg.Any <WebTokenRequest>()).Returns(webTokenResponseWrapper); _cacheSessionManager.SaveTokenResponseAsync(Arg.Any <MsalTokenResponse>()).Returns(Task.FromResult( new Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account>(null, null, newlyAddedAccountToCache))); // Act var accounts = await _aadPlugin.GetAccountsAsync( TestConstants.ClientId, AuthorityInfo.FromAuthorityUri(TestConstants.AuthorityCommonTenant, true), _cacheSessionManager, _instanceDiscoveryManager).ConfigureAwait(false); // Assert Assert.AreEqual(1, accounts.Count()); Assert.AreEqual("Id_From_ESTS", accounts.Single().HomeAccountId.Identifier); } }
private (Client.Internal.Requests.AuthenticationRequestParameters requestParams, IWebTokenRequestResultWrapper webTokenResponseWrapper) SetupSilentCall(MockHttpAndServiceBundle harness) { var wamAccountProvider = new WebAccountProvider("id", "*****@*****.**", null); var requestParams = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityHomeTenant); requestParams.Account = new Account( $"{TestConstants.Uid}.{TestConstants.Utid}", TestConstants.DisplayableId, null, new Dictionary <string, string>() { { TestConstants.ClientId, "wam_id_1" } }); // account has wam_id! var webAccount = new WebAccount(wamAccountProvider, "*****@*****.**", WebAccountState.Connected); var webTokenRequest = new WebTokenRequest(wamAccountProvider); IWebTokenRequestResultWrapper webTokenResponseWrapper = Substitute.For <IWebTokenRequestResultWrapper>(); _webAccountProviderFactory.GetAccountProviderAsync(null).ReturnsForAnyArgs(Task.FromResult(wamAccountProvider)); _wamProxy.FindAccountAsync(Arg.Any <WebAccountProvider>(), "wam_id_1").Returns(Task.FromResult(webAccount)); _aadPlugin.CreateWebTokenRequestAsync( wamAccountProvider, requestParams, isForceLoginPrompt: false, isAccountInWam: true, isInteractive: false) .Returns(Task.FromResult(webTokenRequest)); _wamProxy.GetTokenSilentlyAsync(webAccount, webTokenRequest). Returns(Task.FromResult(webTokenResponseWrapper)); return(requestParams, webTokenResponseWrapper); }
private string ExtractTransferToken( string clientId, IWebTokenRequestResultWrapper transferResponse, bool isInteractive) { if (!transferResponse.ResponseStatus.IsSuccessStatus()) { try { _ = WamAdapters.CreateMsalResponseFromWamResponse( transferResponse, _msaPlugin, clientId, _logger, isInteractive: isInteractive); } catch (MsalServiceException exception) { _logger.Warning( "WAM MSA-PT: could not get a transfer token, ussually this is because the " + "1st party app is configured for MSA-PT but not configured to login MSA users (signinaudience =2). " + "Error was: " + exception.ErrorCode + " " + exception.Message); } return(null); } _ = _msaPlugin.ParseSuccessfullWamResponse(transferResponse.ResponseData[0], out var properties); properties.TryGetValue("code", out string code); // Important: cannot use this WebAccount with the AAD provider WebAccount msaPtWebAccount = transferResponse.ResponseData[0].WebAccount; _logger.InfoPii($"Obtained a transfer token for {msaPtWebAccount.UserName} ? {code != null}", $"Obtained a transfer token? {code != null}"); return(code); }
internal static MsalTokenResponse CreateMsalResponseFromWamResponse( IWebTokenRequestResultWrapper wamResponse, IWamPlugin wamPlugin, string clientId, ICoreLogger logger, bool isInteractive) { string internalErrorCode = null; string errorMessage; string errorCode; switch (wamResponse.ResponseStatus) { case WebTokenRequestStatus.Success: logger.Info("WAM response status success"); return(wamPlugin.ParseSuccessfullWamResponse(wamResponse.ResponseData[0], out _)); // Account Switch occurs when a login hint is passed to WAM but the user chooses a different account for login. // MSAL treats this as a success scenario case WebTokenRequestStatus.AccountSwitch: logger.Info("WAM response status account switch. Treating as success"); return(wamPlugin.ParseSuccessfullWamResponse(wamResponse.ResponseData[0], out _)); case WebTokenRequestStatus.UserInteractionRequired: errorCode = wamPlugin.MapTokenRequestError(wamResponse.ResponseStatus, wamResponse.ResponseError?.ErrorCode ?? 0, isInteractive); internalErrorCode = (wamResponse.ResponseError?.ErrorCode ?? 0).ToString(CultureInfo.InvariantCulture); errorMessage = WamErrorPrefix + $"Wam plugin {wamPlugin.GetType()}" + $" Error code: {internalErrorCode}" + $" Error Message: " + wamResponse.ResponseError?.ErrorMessage; break; case WebTokenRequestStatus.UserCancel: errorCode = MsalError.AuthenticationCanceledError; errorMessage = MsalErrorMessage.AuthenticationCanceled; break; case WebTokenRequestStatus.ProviderError: errorCode = wamPlugin.MapTokenRequestError(wamResponse.ResponseStatus, wamResponse.ResponseError?.ErrorCode ?? 0, isInteractive); errorMessage = $"{WamErrorPrefix} {wamPlugin.GetType()} \n" + $" Error Code: {errorCode} \n" + $" Error Message: {wamResponse.ResponseError?.ErrorMessage} \n" + $" Possible causes: \n " + $"- Invalid redirect uri - ensure you have configured the following url in the AAD portal App Registration: {GetExpectedRedirectUri(clientId)} \n" + $"- No Internet connection \n" + $"Please see https://aka.ms/msal-net-wam for details about Windows Broker integration"; internalErrorCode = (wamResponse.ResponseError?.ErrorCode ?? 0).ToString(CultureInfo.InvariantCulture); break; default: errorCode = MsalError.UnknownBrokerError; internalErrorCode = wamResponse.ResponseError.ErrorCode.ToString(CultureInfo.InvariantCulture); errorMessage = $"Unknown WebTokenRequestStatus {wamResponse.ResponseStatus} (internal error code {internalErrorCode})"; break; } return(new MsalTokenResponse() { Error = errorCode, ErrorCodes = internalErrorCode != null ? new[] { internalErrorCode } : null, ErrorDescription = errorMessage }); }