Ejemplo n.º 1
0
        /// <summary>
        /// Apply this authenticator to the given authentication parameters.
        /// </summary>
        /// <param name="parameters">The complex object containing authentication specific information.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>
        /// An instance of <see cref="AuthenticationResult" /> that represents the access token generated as result of a successful authenication.
        /// </returns>
        public override async Task <AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, CancellationToken cancellationToken = default)
        {
            JsonWebToken token;
            string       value = parameters.Account.GetProperty(MgmtAccountPropertyType.AccessToken);

            token = new JsonWebToken(value);

            ServiceClientTracing.Information($"[AccessTokenAuthenticator] The specified access token expires at {token.ValidTo}");

            if (DateTimeOffset.UtcNow > token.ValidTo)
            {
                throw new MgmtPowerShellException("The access token has expired. Generate a new one and try again.", MgmtPowerShellErrorCategory.TokenExpired);
            }

            await Task.CompletedTask.ConfigureAwait(false);

            ServiceClientTracing.Information("[AccessTokenAuthenticator] Constructing the authentication result based on the specified access token");

            return(new AuthenticationResult(
                       value,
                       false,
                       null,
                       token.ValidTo,
                       token.ValidTo,
                       token.GetClaim("tid").Value,
                       GetAccount(token),
                       null,
                       parameters.Scopes,
                       Guid.Empty));
        }
Ejemplo n.º 2
0
 private static void LogMessages(string message)
 {
     if (ServiceClientTracing.IsEnabled)
     {
         ServiceClientTracing.Information(message);
     }
 }
Ejemplo n.º 3
0
 internal static void LogInfo(string message, params object[] parameters)
 {
     if (shouldTrace)
     {
         ServiceClientTracing.Information(message, parameters);
     }
 }
Ejemplo n.º 4
0
        private static void Respond(Func <Uri, MessageAndHttpCode> responseProducer, HttpListenerContext context)
        {
            MessageAndHttpCode messageAndCode = responseProducer(context.Request.Url);

            ServiceClientTracing.Information($"[HttpListenerInterceptor] Processing a response message to the browser. HttpStatus: {messageAndCode.HttpCode}");

            switch (messageAndCode.HttpCode)
            {
            case HttpStatusCode.Found:
                context.Response.StatusCode       = (int)HttpStatusCode.Found;
                context.Response.RedirectLocation = messageAndCode.Message;
                break;

            case HttpStatusCode.OK:
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(messageAndCode.Message);
                context.Response.ContentLength64 = buffer.Length;
                context.Response.OutputStream.Write(buffer, 0, buffer.Length);
                break;

            default:
                throw new NotImplementedException("HttpCode not supported" + messageAndCode.HttpCode);
            }

            context.Response.OutputStream.Close();
        }
        /// <summary>
        /// Creates a public client used for generating tokens.
        /// </summary>
        /// <param name="cloudInstance">The cloud instance used for authentication.</param>
        /// <param name="clientId">Identifier of the client requesting the token.</param>
        /// <param name="redirectUri">The redirect URI for the client.</param>
        /// <param name="tenantId">Identifier of the tenant requesting the token.</param>
        /// <returns>An aptly configured public client.</returns>
        private static IPublicClientApplication CreatePublicClient(
            AzureCloudInstance cloudInstance,
            string clientId    = null,
            string redirectUri = null,
            string tenantId    = null)
        {
            PublicClientApplicationBuilder builder = PublicClientApplicationBuilder.Create(clientId);

            builder = builder.WithAuthority(cloudInstance, tenantId);

            if (!string.IsNullOrEmpty(redirectUri))
            {
                builder = builder.WithRedirectUri(redirectUri);
            }

            if (!string.IsNullOrEmpty(tenantId))
            {
                builder = builder.WithTenantId(tenantId);
            }

            IPublicClientApplication client = builder.WithLogging((level, message, pii) =>
            {
                MgmtSession.Instance.DebugMessages.Enqueue($"[MSAL] {level} {message}");
            }).Build();

            if (MgmtSession.Instance.TryGetComponent(ComponentKey.TokenCache, out IMgmtTokenCache tokenCache))
            {
                ServiceClientTracing.Information($"[MSAL] Registering the token cache for client {clientId}");
                tokenCache.RegisterCache(client);
            }

            return(client);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Apply this authenticator to the given authentication parameters.
        /// </summary>
        /// <param name="parameters">The complex object containing authentication specific information.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>
        /// An instance of <see cref="AuthenticationResult" /> that represents the access token generated as result of a successful authenication.
        /// </returns>
        public override async Task <AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, CancellationToken cancellationToken = default)
        {
            AuthenticationResult   authResult;
            IClientApplicationBase app;
            InteractiveParameters  interactiveParameters = parameters as InteractiveParameters;
            TcpListener            listener = null;
            string redirectUri = null;
            int    port        = 8399;

            while (++port < 9000)
            {
                try
                {
                    listener = new TcpListener(IPAddress.Loopback, port);
                    listener.Start();
                    redirectUri = $"http://localhost:{port}/";
                    listener.Stop();
                    break;
                }
                catch (Exception ex)
                {
                    WriteWarning($"Port {port} is taken with exception '{ex.Message}'; trying to connect to the next port.");
                    listener?.Stop();
                }
            }

            app = GetClient(parameters.Account, parameters.Environment, redirectUri);

            if (app is IConfidentialClientApplication)
            {
                ICustomWebUi customWebUi = new DefaultOsBrowserWebUi(interactiveParameters.Message);

                ServiceClientTracing.Information($"[InteractiveUserAuthenticator] Calling AcquireAuthorizationCodeAsync - Scopes: '{string.Join(",", parameters.Scopes)}'");

                Uri authCodeUrl = await customWebUi.AcquireAuthorizationCodeAsync(
                    await app.AsConfidentialClient().GetAuthorizationRequestUrl(parameters.Scopes).ExecuteAsync(cancellationToken).ConfigureAwait(false),
                    new Uri(redirectUri),
                    cancellationToken).ConfigureAwait(false);

                NameValueCollection queryStringParameters = HttpUtility.ParseQueryString(authCodeUrl.Query);

                ServiceClientTracing.Information($"[InteractiveUserAuthenticator] Calling AcquireTokenByAuthorizationCode - Scopes: '{string.Join(",", parameters.Scopes)}'");

                authResult = await app.AsConfidentialClient().AcquireTokenByAuthorizationCode(
                    parameters.Scopes,
                    queryStringParameters["code"]).ExecuteAsync(cancellationToken).ConfigureAwait(false);
            }
            else
            {
                ServiceClientTracing.Information(string.Format(CultureInfo.InvariantCulture, "[InteractiveUserAuthenticator] Calling AcquireTokenInteractive - Scopes: '{0}'", string.Join(",", parameters.Scopes)));

                authResult = await app.AsPublicClient().AcquireTokenInteractive(parameters.Scopes)
                             .WithCustomWebUi(new DefaultOsBrowserWebUi(interactiveParameters.Message))
                             .WithPrompt(Prompt.ForceLogin)
                             .ExecuteAsync(cancellationToken).ConfigureAwait(false);
            }

            return(authResult);
        }
        /// <summary>
        /// Apply this authenticator to the given authentication parameters.
        /// </summary>
        /// <param name="parameters">The complex object containing authentication specific information.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>
        /// An instance of <see cref="AuthenticationToken" /> that represents the access token generated as result of a successful authenication.
        /// </returns>
        public override async Task <AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, CancellationToken cancellationToken = default)
        {
            IPublicClientApplication app = GetClient(parameters.Account, parameters.Environment).AsPublicClient();

            ServiceClientTracing.Information($"[DeviceCodeAuthenticator] Calling AcquireTokenWithDeviceCode - Scopes: '{string.Join(", ", parameters.Scopes)}'");
            return(await app.AcquireTokenWithDeviceCode(parameters.Scopes, deviceCodeResult =>
            {
                WriteWarning(deviceCodeResult.Message);
                return Task.CompletedTask;
            }).ExecuteAsync(cancellationToken).ConfigureAwait(false));
        }
        /// <summary>
        /// Apply this authenticator to the given authentication parameters.
        /// </summary>
        /// <param name="parameters">The complex object containing authentication specific information.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>
        /// An instance of <see cref="AuthenticationResult" /> that represents the access token generated as result of a successful authenication.
        /// </returns>
        public override async Task <AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, CancellationToken cancellationToken = default)
        {
            IClientApplicationBase app = GetClient(parameters.Account, parameters.Environment);

            ServiceClientTracing.Information("[SilentAuthenticator] Calling GetAccountsAsync");
            IEnumerable <IAccount> accounts = await app.AsPublicClient().GetAccountsAsync().ConfigureAwait(false);

            ServiceClientTracing.Information($"[SilentAuthenticator] Calling AcquireTokenSilent - Scopes: '{string.Join(",", parameters.Scopes)}', UserId: '{((SilentParameters)parameters).UserId}', Number of accounts: '{accounts.Count()}'");
            AuthenticationResult authResult = await app.AsPublicClient().AcquireTokenSilent(
                parameters.Scopes,
                accounts.FirstOrDefault(a => a.HomeAccountId.ObjectId.Equals(((SilentParameters)parameters).UserId, StringComparison.InvariantCultureIgnoreCase)))
                                              .ExecuteAsync(cancellationToken).ConfigureAwait(false);

            return(authResult);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Apply this authenticator to the given authentication parameters.
        /// </summary>
        /// <param name="parameters">The complex object containing authentication specific information.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>
        /// An instance of <see cref="AuthenticationResult" /> that represents the access token generated as result of a successful authenication.
        /// </returns>
        public override async Task <AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, CancellationToken cancellationToken = default)
        {
            IClientApplicationBase app = GetClient(parameters.Account, parameters.Environment);

            ServiceClientTracing.Information("[RefreshTokenAuthenticator] Calling GetAccountsAysnc");
            IAccount account = await app.GetAccountAsync(parameters.Account.Identifier).ConfigureAwait(false);

            if (account != null)
            {
                ServiceClientTracing.Information($"[RefreshTokenAuthenticator] Calling AcquireTokenSilent - Scopes: '{string.Join(", ", parameters.Scopes)}'");
                return(await app.AcquireTokenSilent(parameters.Scopes, account).ExecuteAsync(cancellationToken).ConfigureAwait(false));
            }

            ServiceClientTracing.Information($"[RefreshTokenAuthenticator] Calling AcquireTokenByRefreshToken - Scopes: '{string.Join(", ", parameters.Scopes)}'");
            return(await app.AsRefreshTokenClient().AcquireTokenByRefreshToken(
                       parameters.Scopes,
                       parameters.Account.GetProperty(PartnerAccountPropertyType.RefreshToken)).ExecuteAsync(cancellationToken).ConfigureAwait(false));
        }
        /// <summary>
        /// Listens for a single request and responds.
        /// </summary>
        /// <param name="port">The port where to listen for requests.</param>
        /// <param name="responseProducer">The function responsible for responding.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns></returns>
        public async Task<Uri> ListenToSingleRequestAndRespondAsync(int port, Func<Uri, MessageAndHttpCode> responseProducer, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            HttpListener httpListener = null;

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

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

                httpListener.Start();
                ServiceClientTracing.Information($"[HttpListenerInterceptor] Listening for authorization code on {urlToListenTo}");

                using (cancellationToken.Register(() =>
                {
                    TryStopListening(httpListener);
                }))
                {
                    HttpListenerContext context = await httpListener.GetContextAsync().ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    Respond(responseProducer, context);
                    ServiceClientTracing.Information($"[HttpListenerInterceptor] Received a message on {urlToListenTo}");

                    // the request URL should now contain the auth code and pkce
                    return context.Request.Url;
                }
            }
            catch (ObjectDisposedException)
            {
                cancellationToken.ThrowIfCancellationRequested();

                throw;
            }
            finally
            {
                TryStopListening(httpListener);
            }
        }
Ejemplo n.º 11
0
        private IAccount GetAccount(JsonWebToken token)
        {
            token.AssertNotNull(nameof(token));

            token.TryGetClaim("upn", out Claim claim);

            if (claim != null)
            {
                ServiceClientTracing.Information($"[AccessTokenAuthenticator] The UPN claim value is {claim.Value}");
                ServiceClientTracing.Information($"[AccessTokenAuthenticator] Constructing the resource account value based on specified access token");

                return(new ResourceAccount(
                           "login.microsoftonline.com",
                           $"{token.GetClaim("oid").Value}.{token.GetClaim("tid")}",
                           token.GetClaim("oid").Value,
                           token.GetClaim("tid").Value,
                           claim.Value));
            }

            ServiceClientTracing.Information("[AccessTokenAuthenticator] The UPN claim is not present in the access token.");
            return(null);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Apply this authenticator to the given authentication parameters.
        /// </summary>
        /// <param name="parameters">The complex object containing authentication specific information.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>
        /// An instance of <see cref="AuthenticationResult" /> that represents the access token generated as result of a successful authenication.
        /// </returns>
        public override async Task <AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, CancellationToken cancellationToken = default)
        {
            JsonWebToken token;
            string       value;

            if (parameters.Scopes.Contains($"{parameters.Environment.PartnerCenterEndpoint}/user_impersonation"))
            {
                value = parameters.Account.GetProperty(PartnerAccountPropertyType.AccessToken);
            }
            else
            {
                throw new PSInvalidOperationException("This operation is not supported when you connect using an access token. Please connect interactively or using a refresh token.");
            }

            token = new JsonWebToken(value);

            ServiceClientTracing.Information($"[AccessTokenAuthenticator] The specified access token expires at {token.ValidTo}");

            if (DateTimeOffset.UtcNow > token.ValidTo)
            {
                throw new PartnerException("The access token has expired. Generate a new one and try again.");
            }

            await Task.CompletedTask;

            ServiceClientTracing.Information("[AccessTokenAuthenticator] Constructing the authentication result based on the specified access token");

            return(new AuthenticationResult(
                       value,
                       false,
                       null,
                       token.ValidTo,
                       token.ValidTo,
                       token.GetClaim("tid").Value,
                       GetAccount(token),
                       null,
                       parameters.Scopes,
                       Guid.Empty));
        }
Ejemplo n.º 13
0
            /// <summary>
            /// Get The value from the cache
            /// </summary>
            /// <param name="requestUri"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            protected virtual bool TryGetFromCache(string requestUri, out T value)
            {
                bool result = false;

                value = null;
                ICacheable cacheValue;

                ServiceClientTracing.Information(string.Format(Resources.CacheCheck, requestUri));
                if (_cache != null && _cache.TryGetValue(requestUri, out cacheValue))
                {
                    ServiceClientTracing.Information(Resources.CacheHit);
                    if (cacheValue.IsExpired())
                    {
                        _cache.TryRemove(requestUri, out cacheValue);
                    }
                    else
                    {
                        result = true;
                        value  = cacheValue as T;
                    }
                }

                return(result);
            }
Ejemplo n.º 14
0
 public IHttpOperations <T> WithHeader(string name, IEnumerable <string> value)
 {
     ServiceClientTracing.Information(Resources.HttpClientAddingHeader, name);
     _headers.TryAdd(name, value);
     return(this);
 }
Ejemplo n.º 15
0
        protected async override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (LogLevel == Level.None)
            {
                return(await base.SendAsync(request, cancellationToken));
            }

            ServiceClientTracing.Information("Request: {0} {1}", request.Method, request.RequestUri);
            if (LogLevel == Level.BodyAndHeaders || LogLevel == Level.Headers)
            {
                ServiceClientTracing.Information("  headers:");
                foreach (var header in request.Headers)
                {
                    ServiceClientTracing.Information("    {0} : {1}", header.Key, string.Join(" ", header.Value));
                }
            }

            if (LogLevel == Level.Body || LogLevel == Level.BodyAndHeaders)
            {
                if (request.Content != null)
                {
                    string content = await request.Content.ReadAsStringAsync();

                    ServiceClientTracing.Information("  body: " + content);
                }
                // TODO: Checking for binary request contents and omitting them
            }

            HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

            if (LogLevel == Level.BodyAndHeaders || LogLevel == Level.Headers)
            {
                ServiceClientTracing.Information("Response:");
                ServiceClientTracing.Information("  headers:");
                foreach (var header in response.Headers)
                {
                    ServiceClientTracing.Information("    {0} : {1}", header.Key, string.Join(" ", header.Value));
                }
            }


            if (LogLevel == Level.Body || LogLevel == Level.BodyAndHeaders)
            {
                bool isEncoded = IsHeaderPresent(response.Content.Headers, "Content-Encoding");
                if (!isEncoded && response.Content != null)
                {
                    string content = await response.Content.ReadAsStringAsync();

                    string contentType = GetHeader(response.Content.Headers, "Content-Type");
                    if (contentType != null && contentType.Contains("application/json"))
                    {
                        try
                        {
                            dynamic parsedJson = JsonConvert.DeserializeObject(content);
                            content = JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
                        }
                        catch (Exception) { /*ignore and print below as it is*/ }
                    }
                    ServiceClientTracing.Information(content);
                }

                // TODO: Checking for binary response content and omitting them
                if (isEncoded)
                {
                    ServiceClientTracing.Information("    body: <encoded body omitted>");
                }
            }
            return(response);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Registers the token cache with client application.
        /// </summary>
        /// <param name="client">The client application to be used when registering the token cache.</param>
        public override void RegisterCache(IClientApplicationBase client)
        {
            ServiceClientTracing.Information("Registering the persistent token cache.");

            base.RegisterCache(client);
        }