示例#1
0
        private async Task <MsalTokenResponse> AcquireBasicTokenSilentAsync(
            WebAccount webAccount,
            string clientId)
        {
            // we checked that it exists previously
            _wamProxy.TryGetAccountProperty(webAccount, "Authority", out string accountAuthority);
            var provider = await _webAccountProviderFactory.GetAccountProviderAsync(accountAuthority).ConfigureAwait(false);

            // We are not requesting any additional scopes beyond "profile" and "openid" (which are added by default)
            // since we do not want to require any additional claims (and thus be unable to renew the refresh token).
            var request = await CreateWebTokenRequestAsync(provider, clientId, "profile openid").ConfigureAwait(false);

            // Note that this is never a guest flow, we are always acquiring a token for the home realm,
            // since we only need the client info.


            var wamResult = await _wamProxy.GetTokenSilentlyAsync(webAccount, request).ConfigureAwait(false);

            if (!wamResult.ResponseStatus.IsSuccessStatus())
            {
                _logger.Warning($"[WAM AAD Provider] GetIdFromWebResponseAsync failed {wamResult.ResponseStatus} - {wamResult.ResponseError}");
                return(null);
            }

            return(ParseSuccessfullWamResponse(wamResult.ResponseData[0], out _));
        }
示例#2
0
        private async Task <string> FetchMsaPassthroughTransferTokenAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            WebAccountProvider accountProvider)
        {
            try
            {
                // step 1 - get a response from the MSA provider, just to have a WebAccount
                _logger.Info("WAM MSA-PT: Making initial call to MSA provider");
                WebAccount msaPtWebAccount = await TryFetchWebAccountFromMsaAsync(
                    authenticationRequestParameters,
                    accountProvider).ConfigureAwait(false);

                if (msaPtWebAccount != null)
                {
                    // step 2 - get a trasnfer token
                    _logger.Info("WAM MSA-PT: Getting transfer token");
                    string transferToken = await FetchTransferTokenAsync(
                        accountProvider,
                        msaPtWebAccount,
                        authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(true);

                    return(transferToken);
                }

                return(null);
            }
            catch (Exception ex)
            {
                _logger.Warning("WAM MSA-PT: Getting a transfer token failed " + ex);
                return(null);
            }
        }
        public async Task <IEnumerable <IAccount> > GetAccountsAsync(string clientID, string redirectUri)
        {
            using (_logger.LogMethodDuration())
            {
                if (!IsBrokerInstalledAndInvokable())
                {
                    _logger.Warning("Android broker is either not installed or is not reachable so no accounts will be returned. ");
                    return(new List <IAccount>());
                }

                BrokerRequest brokerRequest = new BrokerRequest()
                {
                    ClientId = clientID, RedirectUri = new Uri(redirectUri)
                };

                try
                {
                    await _brokerHelper.InitiateBrokerHandshakeAsync(_parentActivity).ConfigureAwait(false);

                    return(_brokerHelper.GetBrokerAccountsInAccountManager(brokerRequest));
                }
                catch (Exception ex)
                {
                    _logger.Error("Failed to get Android broker accounts from the broker. ");
                    HandleBrokerOperationError(ex);
                    throw;
                }
            }
        }
示例#4
0
        public async Task <WebTokenRequest> CreateWebTokenRequestAsync(
            WebAccountProvider provider,
            AuthenticationRequestParameters authenticationRequestParameters,
            bool isForceLoginPrompt,
            bool isInteractive,
            bool isAccountInWam)
        {
            bool setLoginHint  = false;
            bool addNewAccount = false;

            string loginHint = authenticationRequestParameters.LoginHint ?? authenticationRequestParameters.Account?.Username;

            if (isInteractive && !isAccountInWam)
            {
                if (!string.IsNullOrEmpty(loginHint))
                {
                    setLoginHint = true;
                }
                else
                {
                    addNewAccount = !(await _webAccountProviderFactory.IsDefaultAccountMsaAsync().ConfigureAwait(false));
                }
            }

            var promptType = (setLoginHint || addNewAccount || (isForceLoginPrompt && isInteractive)) ?
                             WebTokenRequestPromptType.ForceAuthentication :
                             WebTokenRequestPromptType.Default;

            string          scopes  = ScopeHelper.GetMsalScopes(authenticationRequestParameters.Scope).AsSingleString();
            WebTokenRequest request = new WebTokenRequest(
                provider,
                scopes,
                authenticationRequestParameters.ClientId,
                promptType);

            if (addNewAccount || setLoginHint)
            {
                request.Properties.Add("Client_uiflow", "new_account"); // launch add account flow

                if (setLoginHint)
                {
                    request.Properties.Add("LoginHint", loginHint); // prefill username
                }
            }

            request.Properties.Add("api-version", "2.0"); // request V2 tokens over V1
            request.Properties.Add("oauth2_batch", "1");  // request tokens as OAuth style name/value pairs
            request.Properties.Add("x-client-info", "1"); // request client_info

            if (ApiInformation.IsPropertyPresent("Windows.Security.Authentication.Web.Core.WebTokenRequest", "CorrelationId"))
            {
                request.CorrelationId = authenticationRequestParameters.CorrelationId.ToString();
            }
            else
            {
                _logger.Warning("[WAM MSA Plugin] Could not add the correlation ID to the request.");
            }

            return(request);
        }
        public async Task <Uri> ListenToSingleRequestAndRespondAsync(
            int port,
            Func <Uri, MessageAndHttpCode> responseProducer,
            CancellationToken cancellationToken)
        {
            TestBeforeTopLevelCall?.Invoke();
            cancellationToken.ThrowIfCancellationRequested();

            HttpListener httpListener = null;

            try
            {
                string urlToListenTo = "http://localhost:" + port + "/";

                httpListener = new HttpListener();
                httpListener.Prefixes.Add(urlToListenTo);

                TestBeforeStart?.Invoke();

                httpListener.Start();
                _logger.Info("Listening for authorization code on " + urlToListenTo);

                using (cancellationToken.Register(() =>
                {
                    _logger.Warning("HttpListener stopped because cancellation was requested.");
                    TryStopListening(httpListener);
                }))
                {
                    TestBeforeGetContext?.Invoke();
                    HttpListenerContext context = await httpListener.GetContextAsync()
                                                  .ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    Respond(responseProducer, context);
                    _logger.Verbose("HttpListner received a message on " + urlToListenTo);

                    // the request URL should now contain the auth code and pkce
                    return(context.Request.Url);
                }
            }
            catch (ObjectDisposedException)
            {
                // If cancellation is requested before GetContextAsync is called
                // then an ObjectDisposedException is fired by GetContextAsync.
                // This is still just cancellation
                _logger.Warning("ObjectDisposedException - cancellation requested? " + cancellationToken.IsCancellationRequested);
                cancellationToken.ThrowIfCancellationRequested();

                throw;
            }
            finally
            {
                TryStopListening(httpListener);
            }
        }
        public async Task <string> GetBrokerAuthTokenSilentlyAsync(BrokerRequest brokerRequest, Activity callerActivity)
        {
            CheckForBrokerAccountInfoInAccountManager(brokerRequest, callerActivity);
            Bundle silentOperationBundle = CreateSilentBrokerBundle(brokerRequest);

            silentOperationBundle.PutString(BrokerConstants.BrokerAccountManagerOperationKey, BrokerConstants.AcquireTokenSilent);

            IAccountManagerFuture result = _androidAccountManager.AddAccount(BrokerConstants.BrokerAccountType,
                                                                             BrokerConstants.AuthtokenType,
                                                                             null,
                                                                             silentOperationBundle,
                                                                             null,
                                                                             null,
                                                                             GetPreferredLooper(callerActivity));

            if (result != null)
            {
                Bundle bundleResult = null;

                try
                {
                    bundleResult = (Bundle)await result.GetResultAsync(
                        AccountManagerTimeoutSeconds,
                        TimeUnit.Seconds)
                                   .ConfigureAwait(false);
                }
                catch (OperationCanceledException ex)
                {
                    _logger.Error("An error occurred when trying to communicate with the account manager: " + ex.Message);
                }
                catch (Exception ex)
                {
                    throw new MsalClientException(MsalError.BrokerApplicationRequired, MsalErrorMessage.AndroidBrokerCannotBeInvoked, ex);
                }

                string responseJson = bundleResult.GetString(BrokerConstants.BrokerResultV2);

                bool success = bundleResult.GetBoolean(BrokerConstants.BrokerRequestV2Success);
                _logger.Info($"Android Broker Silent call result - success? {success}. ");

                if (!success)
                {
                    _logger.Warning($"Android Broker Silent call failed. " +
                                    $"This usually means that the RT cannot be refreshed and interaction is required. " +
                                    $"BundleResult: {bundleResult} Result string: {responseJson}");
                }

                // upstream logic knows how to extract potential errors from this result
                return(responseJson);
            }

            _logger.Info("Android Broker didn't return any results. ");
            return(null);
        }
        private async Task <RegionInfo> DiscoverAsync(ICoreLogger logger, CancellationToken requestCancellationToken)
        {
            string region = Environment.GetEnvironmentVariable("REGION_NAME");

            if (ValidateRegion(region, "REGION_NAME env variable", logger)) // this is just to validate the region string
            {
                logger.Info($"[Region discovery] Region found in environment variable: {region}.");
                return(new RegionInfo(region, RegionAutodetectionSource.EnvVariable));
            }

            try
            {
                var headers = new Dictionary <string, string>
                {
                    { "Metadata", "true" }
                };

                Uri imdsUri = BuildImdsUri(DefaultApiVersion);

                HttpResponse response = await _httpManager.SendGetAsync(imdsUri, headers, logger, retry : false, GetCancellationToken(requestCancellationToken))
                                        .ConfigureAwait(false);

                // A bad request occurs when the version in the IMDS call is no longer supported.
                if (response.StatusCode == HttpStatusCode.BadRequest)
                {
                    string apiVersion = await GetImdsUriApiVersionAsync(logger, headers, requestCancellationToken).ConfigureAwait(false); // Get the latest version

                    imdsUri  = BuildImdsUri(apiVersion);
                    response = await _httpManager.SendGetAsync(BuildImdsUri(apiVersion), headers, logger, retry : false, GetCancellationToken(requestCancellationToken))
                               .ConfigureAwait(false); // Call again with updated version
                }

                if (response.StatusCode == HttpStatusCode.OK && !response.Body.IsNullOrEmpty())
                {
                    region = response.Body;

                    if (ValidateRegion(region, $"IMDS call to {imdsUri.AbsoluteUri}", logger))
                    {
                        logger.Info($"[Region discovery] Call to local IMDS succeeded. Region: {region}.");
                        return(new RegionInfo(region, RegionAutodetectionSource.Imds));
                    }
                }
                else
                {
                    logger.Warning($"[Region discovery] Call to local IMDS failed with status code {response.StatusCode} or an empty response.");
                }
            }
            catch (Exception e)
            {
                if (e is MsalServiceException msalEx && MsalError.RequestTimeout.Equals(msalEx?.ErrorCode))
                {
                    logger.Warning($"[Region discovery] Call to local IMDS timed out after {_imdsCallTimeoutMs}.");
                }
示例#8
0
        public async Task <IReadOnlyList <IAccount> > GetAccountsAsync(
            string clientId,
            string redirectUri,
            AuthorityInfo authorityInfo,
            ICacheSessionManager cacheSessionManager,
            IInstanceDiscoveryManager instanceDiscoveryManager)
        {
            using (_logger.LogMethodDuration())
            {
                if (!IsBrokerInstalledAndInvokable())
                {
                    _logger.Warning("[Android broker] Broker is either not installed or is not reachable so no accounts will be returned. ");
                    return(null);
                }

                return(await GetAccountsInternalAsync(clientId, redirectUri).ConfigureAwait(false));
            }
        }
        public bool IsBrokerInstalledAndInvokable(AuthorityType authorityType)
        {
            if (!DesktopOsHelper.IsWin10OrServerEquivalent())
            {
                _logger.Warning("[WAM Broker] Not a supported operating system. WAM broker is not available. ");
                return(false);
            }

            // WAM does not work on pure ADFS environments
            if (authorityType == AuthorityType.Adfs)
            {
                _logger.Warning("[WAM Broker] WAM does not work in pure ADFS environments. Falling back to browser for an ADFS authority. ");
                return(false);
            }

            _logger.Verbose("[WAM Broker] IsBrokerInstalledAndInvokable true");
            return(true);
        }
示例#10
0
        public string GetSilentResultFromBundle(Bundle bundleResult)
        {
            string responseJson = bundleResult.GetString(BrokerConstants.BrokerResultV2);

            bool success = bundleResult.GetBoolean(BrokerConstants.BrokerRequestV2Success);

            _logger.Info($"[Android broker] Silent call result - success? {success}. ");

            if (!success)
            {
                _logger.Warning($"[Android broker] Silent call failed. " +
                                $"This usually means that the RT cannot be refreshed and interaction is required. " +
                                $"BundleResult: {bundleResult} Result string: {responseJson}");
            }

            // upstream logic knows how to extract potential errors from this result
            return(responseJson);
        }
示例#11
0
        public void WriteValueToTag(string tagname, object value)
        {
            var currentTag = Collection.GetReadTagWithName(tagname);

            if (currentTag == null)
            {
                logger.Warning(null, $"{Name}({Ip}) device write error. Tag not found : {tagname}");
                return;
            }
            logger.Trace($"{Name}({Ip}) device write.  Tag name : {currentTag?.Name} Tag Value : {value}");
            if (isdeviceConnected)
            {
                WriteTagHelper(currentTag, value);
            }
            else
            {
                logger.Warning(null, $"{Name}({Ip}) device not connected. Tag not written : {tagname} ");
            }
        }
        internal XmsCliTelemInfo ParseXMsTelemHeader(string headerValue, ICoreLogger logger)
        {
            if (string.IsNullOrEmpty(headerValue))
            {
                return(null);
            }

            string[] headerSegments = headerValue.Split(',');
            if (headerSegments.Length == 0)
            {
                logger.Warning(
                    FormatLogMessage(TelemetryError.XmsCliTelemMalformed, headerValue));
                return(null);
            }

            string          headerVersion    = headerSegments[0];
            XmsCliTelemInfo xMsTelemetryInfo = new XmsCliTelemInfo
            {
                Version = headerVersion
            };

            if (!string.Equals(headerVersion, ExpectedCliTelemHeaderVersion))
            {
                logger.Warning(
                    FormatLogMessage(TelemetryError.XmsUnrecognizedHeaderVersion, headerVersion));
                return(xMsTelemetryInfo);
            }

            MatchCollection formatMatcher = MatchHeaderToExpectedFormat(headerValue);

            if (formatMatcher.Count < 1)
            {
                logger.Warning(
                    FormatLogMessage(TelemetryError.XmsCliTelemMalformed, headerValue));
                return(xMsTelemetryInfo);
            }

            xMsTelemetryInfo.ServerErrorCode    = headerSegments[ErrorCodeIndex];
            xMsTelemetryInfo.ServerSubErrorCode = headerSegments[SubErrorCodeIndex];
            xMsTelemetryInfo.TokenAge           = headerSegments[TokenAgeIndex];
            xMsTelemetryInfo.SpeInfo            = headerSegments[SpeInfoIndex];
            return(xMsTelemetryInfo);
        }
示例#13
0
 private bool Connect()
 {
     if (master != null)
     {
         master.Dispose();
     }
     if (tcpClient != null)
     {
         tcpClient.Close();
     }
     if (CheckInternet())
     {
         try
         {
             tcpClient = new TcpClient();
             IAsyncResult asyncResult = tcpClient.BeginConnect(IpAddress, ModbusPort, null, null);
             asyncResult.AsyncWaitHandle.WaitOne(3000, true); //wait for 3 sec
             if (!asyncResult.IsCompleted)
             {
                 tcpClient.Close();
                 logger.Warning(null, $"Not connecting to server - {IpAddress}");
                 return(false);
             }
             // create Modbus TCP Master by the tcpclient
             master = ModbusIpMaster.CreateIp(tcpClient);
             master.Transport.Retries = 0; //don't have to do retries
             //master.Transport.ReadTimeout = 1500;
             logger.Info($"Connected to server - {IpAddress}");
             isreading = false;
             return(tcpClient.Connected);
         }
         catch (Exception ex)
         {
             logger.Warning(ex, "Connection error");
             return(false);
         }
     }
     return(false);
 }
示例#14
0
 new internal void Add(string devicename, Device device)
 {
     if (ContainsKey(devicename))
     {
         logger.Warning(null, $"Device already added - {devicename}");
         return;
     }
     base.Add(devicename, device);
     device.ConnectionStatusChanged     += Device_ConnectionStatusChanged;
     device.Collection.TagStatusChanged += delegate(Tag sender, object value, bool quality)
     {
         TagStatusChanged?.Invoke(sender, value, quality);
     };
 }
示例#15
0
        private async Task <WebAccount> FindWamAccountForMsalAccountAsync(
            WebAccountProvider provider,
            IWamPlugin wamPlugin,
            IAccount msalAccount,
            string loginHint,
            string clientId)
        {
            if (msalAccount == null && string.IsNullOrEmpty(loginHint))
            {
                return(null);
            }

            Account accountInternal = (msalAccount as Account);

            if (accountInternal?.WamAccountIds != null &&
                accountInternal.WamAccountIds.TryGetValue(clientId, out string wamAccountId))
            {
                _logger.Info("WAM will try to find an account based on the WAM account id from the cache");
                WebAccount result = await _wamProxy.FindAccountAsync(provider, wamAccountId).ConfigureAwait(false);

                if (result != null)
                {
                    return(result);
                }

                _logger.Warning("WAM account was not found for given WAM account id.");
            }

            var wamAccounts = await _wamProxy.FindAllWebAccountsAsync(provider, clientId).ConfigureAwait(false);

            return(MatchWamAccountToMsalAccount(
                       wamPlugin,
                       msalAccount,
                       loginHint,
                       wamAccounts));
        }
        public async Task <IReadOnlyList <IAccount> > GetAccountsAsync(
            string clientId,
            string redirectUri,
            AuthorityInfo authorityInfo,
            ICacheSessionManager cacheSessionManager,
            IInstanceDiscoveryManager instanceDiscoveryManager)
        {
            using (_logger.LogMethodDuration())
            {
                if (!IsBrokerInstalledAndInvokable())
                {
                    _logger.Warning("[Android broker] Broker is either not installed or is not reachable so no accounts will be returned. ");
                    return(new List <IAccount>());
                }

                BrokerRequest brokerRequest = new BrokerRequest()
                {
                    ClientId = clientId, RedirectUri = new Uri(redirectUri)
                };

                try
                {
                    await InitiateBrokerHandshakeAsync().ConfigureAwait(false);

                    var accounts = GetBrokerAccounts(brokerRequest);

                    return(_brokerHelper.ExtractBrokerAccountsFromAccountData(accounts));
                }
                catch (Exception ex)
                {
                    _logger.Error("[Android broker] Failed to get Android broker accounts from the broker. ");
                    _brokerHelper.HandleBrokerOperationError(ex);
                    throw;
                }
            }
        }
示例#17
0
        public static IDictionary <AdalTokenCacheKey, AdalResultWrapper> Deserialize(ICoreLogger logger, byte[] state)
        {
            IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary =
                new Dictionary <AdalTokenCacheKey, AdalResultWrapper>();

            if (state == null || state.Length == 0)
            {
                return(dictionary);
            }

            using (Stream stream = new MemoryStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(state);
                writer.Flush();
                stream.Position = 0;

                BinaryReader reader            = new BinaryReader(stream);
                int          blobSchemaVersion = reader.ReadInt32();
                if (blobSchemaVersion != SchemaVersion)
                {
                    logger.Warning("The version of the persistent state of the cache does not match the current schema, so skipping deserialization.");
                    return(dictionary);
                }

                int count = reader.ReadInt32();
                for (int n = 0; n < count; n++)
                {
                    string keyString = reader.ReadString();

                    string[]          kvpElements = keyString.Split(new[] { Delimiter }, StringSplitOptions.None);
                    AdalResultWrapper resultEx    = AdalResultWrapper.Deserialize(reader.ReadString());
                    AdalTokenCacheKey key         = new AdalTokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2],
                                                                          (TokenSubjectType)int.Parse(kvpElements[3], CultureInfo.CurrentCulture),
                                                                          resultEx.Result.UserInfo);

                    dictionary.Add(key, resultEx);
                }

                logger.Info(string.Format(CultureInfo.CurrentCulture, "Deserialized {0} items to token cache.", count));
            }

            return(dictionary);
        }
 new internal void Add(string devicename, Device device)
 {
     if (ContainsKey(devicename))
     {
         logger.Warning(null, $"Device already added - {devicename}");
         return;
     }
     base.Add(devicename, device);
     device.ConnectionStatusChanged     += Device_ConnectionStatusChanged;
     device.Collection.TagStatusChanged += (sender, e) =>
     {
         if (sender is Tag tag)
         {
             TagStatusChanged?.Invoke(this, new TagChangedEventArgs {
                 Name = tag.Name, Value = tag.Value, Quality = tag.Quality
             });
         }
     };
 }
        public static long GetDurationFromWindowsTimestamp(string windowsTimestampInFuture, ICoreLogger logger)
        {
            if (string.IsNullOrEmpty(windowsTimestampInFuture))
            {
                return(0);
            }

            if (!ulong.TryParse(windowsTimestampInFuture, out ulong winTimestamp) ||
                winTimestamp <= 11644473600 ||
                winTimestamp == ulong.MaxValue)
            {
                logger.Warning("Invalid Universal time " + windowsTimestampInFuture);
                return(0);
            }

            ulong unixTimestamp = winTimestamp - 11644473600;

            return((long)unixTimestamp - CurrDateTimeInUnixTimestamp());
        }
示例#20
0
        public async Task <AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken)
        {
            if (!Broker.IsBrokerInstalledAndInvokable(_authenticationRequestParameters.AuthorityInfo.AuthorityType))
            {
                _logger.Warning("Broker is not installed. Cannot respond to silent request.");
                return(null);
            }

            MsalTokenResponse response = await SendTokenRequestToBrokerAsync().ConfigureAwait(false);

            if (response != null)
            {
                ValidateResponseFromBroker(response);
                Metrics.IncrementTotalAccessTokensFromBroker();
                return(await _silentRequest.CacheTokenResponseAndCreateAuthenticationResultAsync(response).ConfigureAwait(false));
            }

            return(null);
        }
        /// <summary>
        /// Parse Native Interop AuthResult Response to MSAL Token Response
        /// </summary>
        /// <param name="authResult"></param>
        /// <param name="authenticationRequestParameters"></param>
        /// <param name="logger"></param>
        /// <exception cref="MsalServiceException"></exception>
        public static MsalTokenResponse ParseRuntimeResponse(
            NativeInterop.AuthResult authResult,
            AuthenticationRequestParameters authenticationRequestParameters,
            ICoreLogger logger)
        {
            try
            {
                string expiresOn     = authResult.ExpiresOn.ToString();
                string correlationId = authenticationRequestParameters.CorrelationId.ToString("D");

                if (string.IsNullOrWhiteSpace(correlationId))
                {
                    logger.Warning("No correlation ID in response");
                    correlationId = null;
                }

                //parsing Pop token from auth header if pop was performed. Otherwise use access token field.
                var token = authResult.IsPopAuthorization ? authResult.AuthorizationHeader.Split(' ')[1] : authResult.AccessToken;

                MsalTokenResponse msalTokenResponse = new MsalTokenResponse()
                {
                    AccessToken   = token,
                    IdToken       = authResult.RawIdToken,
                    CorrelationId = correlationId,
                    Scope         = authResult.GrantedScopes,
                    ExpiresIn     = DateTimeHelpers.GetDurationFromWindowsTimestamp(expiresOn, logger),
                    ClientInfo    = authResult.Account.ClientInfo.ToString(),
                    TokenType     = authResult.IsPopAuthorization ? Constants.PoPAuthHeaderPrefix : BrokerResponseConst.Bearer,
                    WamAccountId  = authResult.Account.Id,
                    TokenSource   = TokenSource.Broker
                };

                logger.Info("WAM response status success");

                return(msalTokenResponse);
            }
            catch (NativeInterop.MsalRuntimeException ex)
            {
                throw new MsalServiceException("wam_failed", $"Could not acquire token using WAM. {ex.Message}");
            }
        }
        private bool VerifyAuthenticator()
        {
            // there may be multiple authenticators from same package
            // , but there is only one entry for an authenticator type in
            // AccountManager.
            // If another app tries to install same authenticator type, it will
            // queue up and will be active after first one is uninstalled.
            AuthenticatorDescription[] authenticators = _androidAccountManager.GetAuthenticatorTypes();
            foreach (AuthenticatorDescription authenticator in authenticators)
            {
                if (authenticator.Type.Equals(BrokerConstants.BrokerAccountType, StringComparison.OrdinalIgnoreCase) &&
                    VerifySignature(authenticator.PackageName))
                {
                    _logger.Verbose("Found the Authenticator on the device");
                    return(true);
                }
            }

            _logger.Warning("No Authenticator found on the device.");
            return(false);
        }
示例#23
0
        public static long GetDurationFromWindowsTimestamp(string windowsTimestampInFuture, ICoreLogger logger)
        {
            if (string.IsNullOrEmpty(windowsTimestampInFuture))
            {
                return(0);
            }

            // Windows uses in most functions the FILETIME structure, which represents the actual time as the number of 100-nanosecond intervals since January 1, 1601 (UTC).
            // To convert to unix timestamp (Jan 1, 1970), you have to substract 11644473600 seconds.

            if (!ulong.TryParse(windowsTimestampInFuture, out ulong winTimestamp) ||
                winTimestamp <= 11644473600 ||
                winTimestamp == ulong.MaxValue)
            {
                logger.Warning("Invalid Universal time " + windowsTimestampInFuture);
                return(0);
            }

            ulong unixTimestamp = winTimestamp - 11644473600;

            return((long)unixTimestamp - CurrDateTimeInUnixTimestamp());
        }
        internal /* internal for testing only */ MessageAndHttpCode GetResponseMessage(Uri authCodeUri)
        {
            // Parse the uri to understand if an error was returned. This is done just to show the user a nice error message in the browser.
            var authorizationResult = AuthorizationResult.FromUri(authCodeUri.OriginalString);

            if (!string.IsNullOrEmpty(authorizationResult.Error))
            {
                _logger.Warning($"Default OS Browser intercepted an Uri with an error: " +
                                $"{authorizationResult.Error} {authorizationResult.ErrorDescription}");

                string errorMessage = string.Format(
                    CultureInfo.InvariantCulture,
                    _webViewOptions?.HtmlMessageError ?? DefaultFailureHtml,
                    authorizationResult.Error,
                    authorizationResult.ErrorDescription);

                return(GetMessage(_webViewOptions?.BrowserRedirectError, errorMessage));
            }

            return(GetMessage(
                       _webViewOptions?.BrowserRedirectSuccess,
                       _webViewOptions?.HtmlMessageSuccess ?? DefaultSuccessHtml));
        }
示例#25
0
        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);
        }
        public MsalTokenResponse ParseSuccesfullWamResponse(WebTokenResponse webTokenResponse)
        {
            if (!webTokenResponse.Properties.TryGetValue("TokenExpiresOn", out string expiresOn))
            {
                _logger.Warning("Result from WAM does not have expiration. Marking access token as expired.");
                expiresOn = null;
            }

            if (!webTokenResponse.Properties.TryGetValue("ExtendedLifetimeToken", out string extendedExpiresOn))
            {
                extendedExpiresOn = null;
            }

            if (!webTokenResponse.Properties.TryGetValue("Authority", out string authority))
            {
                _logger.Error("Result from WAM does not have authority.");
                return(new MsalTokenResponse()
                {
                    Error = "no_authority_in_wam_response",
                    ErrorDescription = "No authority in WAM response"
                });
            }

            if (!webTokenResponse.Properties.TryGetValue("correlationId", out string correlationId))
            {
                _logger.Warning("No correlation ID in response");
                correlationId = null;
            }

            bool hasIdToken = webTokenResponse.Properties.TryGetValue("wamcompat_id_token", out string idToken);

            _logger.Info("Result from WAM has id token? " + hasIdToken);

            bool hasClientInfo = webTokenResponse.Properties.TryGetValue("wamcompat_client_info", out string clientInfo);

            _logger.Info("Result from WAM has client info? " + hasClientInfo);

            bool hasScopes = webTokenResponse.Properties.TryGetValue("wamcompat_scopes", out string scopes);

            _logger.InfoPii("Result from WAM scopes: " + scopes,
                            "Result from WAM has scopes? " + hasScopes);

            //foreach (var kvp in webTokenResponse.Properties)
            //{
            //    Debug.WriteLine($"Other params {kvp.Key}: {kvp.Value}");
            //}

            MsalTokenResponse msalTokenResponse = new MsalTokenResponse()
            {
                AccessToken       = webTokenResponse.Token,
                IdToken           = idToken,
                CorrelationId     = correlationId,
                Scope             = scopes,
                ExpiresIn         = CoreHelpers.GetDurationFromWindowsTimestamp(expiresOn, _logger),
                ExtendedExpiresIn = CoreHelpers.GetDurationFromWindowsTimestamp(extendedExpiresOn, _logger),
                ClientInfo        = clientInfo,
                TokenType         = "Bearer",
                WamAccountId      = webTokenResponse.WebAccount.Id,
                TokenSource       = TokenSource.Broker
            };

            return(msalTokenResponse);
        }
        public async Task<Uri> ListenToSingleRequestAndRespondAsync(
            int port,
            string path,
            Func<Uri, MessageAndHttpCode> responseProducer,
            CancellationToken cancellationToken)
        {
            TestBeforeTopLevelCall?.Invoke();
            cancellationToken.ThrowIfCancellationRequested();

            HttpListener httpListener = null;
            try
            {
                if(string.IsNullOrEmpty(path))
                {
                    path = "/";
                }
                else
                {
                    path = (path.StartsWith("/") ? path : "/" + path);
                }

                string urlToListenTo = "http://localhost:" + port + path;

                if (!urlToListenTo.EndsWith("/"))
                {
                    urlToListenTo += "/";
                }

                httpListener = new HttpListener();
                httpListener.Prefixes.Add(urlToListenTo);

                TestBeforeStart?.Invoke(urlToListenTo);

                httpListener.Start();
                _logger.Info("Listening for authorization code on " + urlToListenTo);

                using (cancellationToken.Register(() =>
                {
                    _logger.Warning("HttpListener stopped because cancellation was requested.");
                    TryStopListening(httpListener);
                }))
                {
                    TestBeforeGetContext?.Invoke();
                    HttpListenerContext context = await httpListener.GetContextAsync()
                        .ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    Respond(responseProducer, context);
                    _logger.Verbose("HttpListner received a message on " + urlToListenTo);

                    // the request URL should now contain the auth code and pkce
                    return context.Request.Url;
                }
            }
            // If cancellation is requested before GetContextAsync is called, then either 
            // an ObjectDisposedException or an HttpListenerException is thrown.
            // But this is just cancellation...
            catch (Exception ex) when (ex is HttpListenerException || ex is ObjectDisposedException)
            {
                _logger.Info("HttpListenerException - cancellation requested? " + cancellationToken.IsCancellationRequested);
                cancellationToken.ThrowIfCancellationRequested();

                // if cancellation was not requested, propagate original ex
                throw;
            }
            finally
            {
                TryStopListening(httpListener);
            }
        }
        private async Task <HttpResponse> ExecuteWithRetryAsync(
            Uri endpoint,
            IDictionary <string, string> headers,
            HttpContent body,
            HttpMethod method,
            ICoreLogger logger,
            bool doNotThrow = false,
            bool retry      = true,
            CancellationToken cancellationToken = default)
        {
            Exception    timeoutException = null;
            bool         isRetryable      = false;
            bool         is5xxError       = false;
            HttpResponse response         = null;

            try
            {
                HttpContent clonedBody = body;
                if (body != null)
                {
                    // Since HttpContent would be disposed by underlying client.SendAsync(),
                    // we duplicate it so that we will have a copy in case we would need to retry
                    clonedBody = await CloneHttpContentAsync(body).ConfigureAwait(false);
                }

                response = await ExecuteAsync(endpoint, headers, clonedBody, method, cancellationToken).ConfigureAwait(false);

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    return(response);
                }

                logger.Info(string.Format(CultureInfo.InvariantCulture,
                                          MsalErrorMessage.HttpRequestUnsuccessful,
                                          (int)response.StatusCode, response.StatusCode));


                is5xxError  = (int)response.StatusCode >= 500 && (int)response.StatusCode < 600;
                isRetryable = is5xxError && !HasRetryAfterHeader(response);
            }
            catch (TaskCanceledException exception)
            {
                logger.Error("The HTTP request failed or it was canceled. " + exception.Message);
                isRetryable = true;

                if (cancellationToken.IsCancellationRequested)
                {
                    isRetryable = false;
                }

                timeoutException = exception;
            }

            if (isRetryable && retry)
            {
                logger.Info("Retrying one more time..");
                await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);

                return(await ExecuteWithRetryAsync(
                           endpoint,
                           headers,
                           body,
                           method,
                           logger,
                           doNotThrow,
                           retry : false).ConfigureAwait(false));
            }

            logger.Warning("Request retry failed.");
            if (timeoutException != null)
            {
                throw new MsalServiceException(
                          MsalError.RequestTimeout,
                          "Request to the endpoint timed out.",
                          timeoutException);
            }

            if (doNotThrow)
            {
                return(response);
            }

            if (is5xxError)
            {
                throw MsalServiceExceptionFactory.FromHttpResponse(
                          MsalError.ServiceNotAvailable,
                          "Service is unavailable to process the request",
                          response);
            }

            return(response);
        }
示例#29
0
        public async Task <Uri> ListenToSingleRequestAndRespondAsync(
            int port,
            string path,
            Func <Uri, MessageAndHttpCode> responseProducer,
            CancellationToken cancellationToken)
        {
            TestBeforeTopLevelCall?.Invoke();
            cancellationToken.ThrowIfCancellationRequested();

            HttpListener httpListener  = null;
            string       urlToListenTo = string.Empty;

            try
            {
                if (string.IsNullOrEmpty(path))
                {
                    path = "/";
                }
                else
                {
                    path = (path.StartsWith("/") ? path : "/" + path);
                }

                urlToListenTo = "http://localhost:" + port + path;

                if (!urlToListenTo.EndsWith("/"))
                {
                    urlToListenTo += "/";
                }

                httpListener = new HttpListener();
                httpListener.Prefixes.Add(urlToListenTo);

                TestBeforeStart?.Invoke(urlToListenTo);

                httpListener.Start();
                _logger.Info("Listening for authorization code on " + urlToListenTo);

                using (cancellationToken.Register(() =>
                {
                    _logger.Warning("HttpListener stopped because cancellation was requested.");
                    TryStopListening(httpListener);
                }))
                {
                    TestBeforeGetContext?.Invoke();
                    HttpListenerContext context = await httpListener.GetContextAsync()
                                                  .ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    Respond(responseProducer, context);
                    _logger.Verbose("HttpListner received a message on " + urlToListenTo);

                    // the request URL should now contain the auth code and pkce
                    return(context.Request.Url);
                }
            }
            // If cancellation is requested before GetContextAsync is called, then either
            // an ObjectDisposedException or an HttpListenerException is thrown.
            // But this is just cancellation...
            catch (Exception ex) when(ex is HttpListenerException || ex is ObjectDisposedException)
            {
                _logger.Info("HttpListenerException - cancellation requested? " + cancellationToken.IsCancellationRequested);
                cancellationToken.ThrowIfCancellationRequested();

                if (ex is HttpListenerException)
                {
                    throw new MsalClientException(MsalError.HttpListenerError,
                                                  $"An HttpListenerException occurred while listening on {urlToListenTo} for the system browser to complete the login. " +
                                                  "Possible cause and mitigation: the app is unable to listen on the specified URL; " +
                                                  "run 'netsh http add iplisten 127.0.0.1' from the Admin command prompt.",
                                                  ex);
                }

                // if cancellation was not requested, propagate original ex
                throw;
            }
            finally
            {
                TryStopListening(httpListener);
            }
        }
示例#30
0
        public static MsalRefreshTokenCacheItem GetRefreshToken(
            ICoreLogger logger,
            ILegacyCachePersistence legacyCachePersistence,
            IEnumerable <string> environmentAliases,
            string clientId,
            IAccount account)
        {
            try
            {
                IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary =
                    AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache());

                IEnumerable <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > listToProcess =
                    dictionary.Where(p =>
                                     p.Key.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase) &&
                                     environmentAliases.Contains(new Uri(p.Key.Authority).Host));

                bool filtered = false;

                if (!string.IsNullOrEmpty(account?.Username))
                {
                    listToProcess =
                        listToProcess.Where(p => account.Username.Equals(
                                                p.Key.DisplayableId, StringComparison.OrdinalIgnoreCase));

                    filtered = true;
                }

                if (!string.IsNullOrEmpty(account?.HomeAccountId?.ObjectId))
                {
                    listToProcess =
                        listToProcess.Where(p => account.HomeAccountId.ObjectId.Equals(
                                                p.Key.UniqueId, StringComparison.OrdinalIgnoreCase)).ToList();

                    filtered = true;
                }

                // We should filter at leasts by one criteria to ensure we retrun adequate RT
                if (!filtered)
                {
                    logger.Warning("Could not filter ADAL entries by either UPN or unique ID, skipping.");
                    return(null);
                }

                return(listToProcess.Select(adalEntry => new MsalRefreshTokenCacheItem(
                                                new Uri(adalEntry.Key.Authority).Host,
                                                adalEntry.Key.ClientId,
                                                adalEntry.Value.RefreshToken,
                                                adalEntry.Value.RawClientInfo,
                                                familyId: null,
                                                homeAccountId: GetHomeAccountId(adalEntry.Value)))
                       .FirstOrDefault());
            }
            catch (Exception ex)
            {
                logger.WarningPiiWithPrefix(ex, "An error occurred while searching for refresh tokens in ADAL format in the cache for MSAL. " +
                                            "For details please see https://aka.ms/net-cache-persistence-errors. ");

                return(null);
            }
        }