Example #1
0
        protected override async ValueTask <IConfidentialClientApplication> CreateClientAsync(bool async, CancellationToken cancellationToken)
        {
            ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(ClientId)
                                                                     .WithAuthority(Pipeline.AuthorityHost.AbsoluteUri, TenantId)
                                                                     .WithHttpClientFactory(new HttpPipelineClientFactory(Pipeline.HttpPipeline))
                                                                     .WithLogging(AzureIdentityEventSource.Singleton.LogMsal, enablePiiLogging: LogPII);

            if (_clientSecret != null)
            {
                confClientBuilder.WithClientSecret(_clientSecret);
            }

            if (_certificateProvider != null)
            {
                X509Certificate2 clientCertificate = await _certificateProvider.GetCertificateAsync(async, cancellationToken).ConfigureAwait(false);

                confClientBuilder.WithCertificate(clientCertificate);
            }

            if (RegionalAuthority.HasValue)
            {
                confClientBuilder.WithAzureRegion(RegionalAuthority.Value.ToString());
            }

            return(confClientBuilder.Build());
        }
        private async Task InitializeAsync()
        {
            ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(_options.ClientId).WithAuthority(_options.AuthorityHost.AbsoluteUri, _options.TenantId).WithHttpClientFactory(new HttpPipelineClientFactory(_options.Pipeline.HttpPipeline));

            if (_options.Secret != null)
            {
                confClientBuilder.WithClientSecret(_options.Secret);
            }

            if (_options.CertificateProvider != null)
            {
                X509Certificate2 clientCertificate = await _options.CertificateProvider.GetCertificateAsync(true, default).ConfigureAwait(false);

                confClientBuilder.WithCertificate(clientCertificate);
            }

            _client = confClientBuilder.Build();

            if (_options.AttachSharedCache)
            {
                StorageCreationProperties storageProperties = new StorageCreationPropertiesBuilder(Constants.DefaultMsalTokenCacheName, Constants.DefaultMsalTokenCacheDirectory, _options.ClientId)
                                                              .WithMacKeyChain(Constants.DefaultMsalTokenCacheKeychainService, Constants.DefaultMsalTokenCacheKeychainAccount)
                                                              .WithLinuxKeyring(Constants.DefaultMsalTokenCacheKeyringSchema, Constants.DefaultMsalTokenCacheKeyringCollection, Constants.DefaultMsalTokenCacheKeyringLabel, Constants.DefaultMsaltokenCacheKeyringAttribute1, Constants.DefaultMsaltokenCacheKeyringAttribute2)
                                                              .Build();

                MsalCacheHelper cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false);

                cacheHelper.RegisterCache(_client.UserTokenCache);
            }
        }
Example #3
0
        public static IConfidentialClientApplication CreateConfidentialClient(
            string authority             = null,
            string clientId              = null,
            string clientSecret          = null,
            X509Certificate2 certificate = null,
            string redirectUri           = null,
            string tenantId              = null)
        {
            ConfidentialClientApplicationBuilder builder = ConfidentialClientApplicationBuilder.Create(clientId);

            if (!string.IsNullOrEmpty(authority))
            {
                builder = builder.WithAuthority(authority);
            }

            if (!string.IsNullOrEmpty(clientSecret))
            {
                builder = builder.WithClientSecret(clientSecret);
            }

            if (certificate != null)
            {
                builder = builder.WithCertificate(certificate);
            }

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

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

            IConfidentialClientApplication client = builder.WithLogging(
                DebugLoggingMethod,
                LogLevel.Info,
                enablePiiLogging: false,
                enableDefaultPlatformLogging: true).Build();

            MsalCacheHelper cacheHelper = InitializeCacheHelper(clientId);

            cacheHelper.RegisterCache(client.UserTokenCache);

            return(client);
        }
        /// <summary>
        /// Creates a confidential 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="certificate">Certificate used by the client requesting the token.</param>
        /// <param name="clientSecret">Secret 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 confidential client.</returns>
        private static IConfidentialClientApplication CreateConfidentialClient(
            AzureCloudInstance cloudInstance,
            string clientId              = null,
            string clientSecret          = null,
            X509Certificate2 certificate = null,
            string redirectUri           = null,
            string tenantId              = null)
        {
            ConfidentialClientApplicationBuilder builder = ConfidentialClientApplicationBuilder.Create(clientId);

            builder = builder.WithAuthority(cloudInstance, tenantId);

            if (!string.IsNullOrEmpty(clientSecret))
            {
                builder = builder.WithClientSecret(clientSecret);
            }

            if (certificate != null)
            {
                builder = builder.WithCertificate(certificate);
            }

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

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

            IConfidentialClientApplication 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);
        }
        protected override async ValueTask <IConfidentialClientApplication> CreateClientAsync(bool async, CancellationToken cancellationToken)
        {
            ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(ClientId).WithAuthority(Pipeline.AuthorityHost.AbsoluteUri, TenantId).WithHttpClientFactory(new HttpPipelineClientFactory(Pipeline.HttpPipeline));

            if (_clientSecret != null)
            {
                confClientBuilder.WithClientSecret(_clientSecret);
            }

            if (_certificateProvider != null)
            {
                X509Certificate2 clientCertificate = await _certificateProvider.GetCertificateAsync(async, cancellationToken).ConfigureAwait(false);

                confClientBuilder.WithCertificate(clientCertificate);
            }

            return(confClientBuilder.Build());
        }
        protected override async ValueTask <IConfidentialClientApplication> CreateClientAsync(bool async, CancellationToken cancellationToken)
        {
            ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(ClientId)
                                                                     .WithAuthority(Pipeline.AuthorityHost.AbsoluteUri, TenantId)
                                                                     .WithHttpClientFactory(new HttpPipelineClientFactory(Pipeline.HttpPipeline))
                                                                     .WithLogging(LogMsal, enablePiiLogging: IsPiiLoggingEnabled);

            if (_clientSecret != null)
            {
                confClientBuilder.WithClientSecret(_clientSecret);
            }

            if (_assertionCallback != null)
            {
                confClientBuilder.WithClientAssertion(_assertionCallback);
            }

            if (_asyncAssertionCallback != null)
            {
                confClientBuilder.WithClientAssertion(_asyncAssertionCallback);
            }

            if (_certificateProvider != null)
            {
                X509Certificate2 clientCertificate = await _certificateProvider.GetCertificateAsync(async, cancellationToken).ConfigureAwait(false);

                confClientBuilder.WithCertificate(clientCertificate);
            }

            if (RegionalAuthority.HasValue)
            {
                confClientBuilder.WithAzureRegion(RegionalAuthority.Value.ToString());
            }

            if (!string.IsNullOrEmpty(RedirectUrl))
            {
                confClientBuilder.WithRedirectUri(RedirectUrl);
            }

            return(confClientBuilder.Build());
        }
        /// <summary>
        /// Creates a confidential 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="certificate">Certificate used by the client requesting the token.</param>
        /// <param name="clientSecret">Secret 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 confidential client.</returns>
        private static IConfidentialClientApplication CreateConfidentialClient(
            AzureCloudInstance cloudInstance,
            string clientId              = null,
            string clientSecret          = null,
            X509Certificate2 certificate = null,
            string redirectUri           = null,
            string tenantId              = null)
        {
            ConfidentialClientApplicationBuilder builder = ConfidentialClientApplicationBuilder.Create(clientId);

            builder = builder.WithAuthority(cloudInstance, tenantId);

            if (!string.IsNullOrEmpty(clientSecret))
            {
                builder = builder.WithClientSecret(clientSecret);
            }

            if (certificate != null)
            {
                builder = builder.WithCertificate(certificate);
            }

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

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

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

            return(client);
        }
        /// <summary>
        /// Executes Authentication against a service
        /// </summary>
        /// <param name="serviceUrl"></param>
        /// <param name="clientCredentials"></param>
        /// <param name="user"></param>
        /// <param name="clientId"></param>
        /// <param name="redirectUri"></param>
        /// <param name="promptBehavior"></param>
        /// <param name="isOnPrem"></param>
        /// <param name="authority"></param>
        /// <param name="userCert">Certificate of provided to login with</param>
        /// <param name="logSink">(optional) Initialized CdsTraceLogger Object</param>
        /// <param name="useDefaultCreds">(optional) if set, tries to login as the current user.</param>
        /// <param name="msalAuthClient">Object of either confidential or public client</param>
        /// <param name="clientSecret"></param>
        /// <param name="addVersionInfoToUri">indicates if the serviceURI should be updated to include the /web?sdk version</param>
        /// <returns>AuthenticationResult containing a JWT Token for the requested Resource and user/app</returns>
        internal async static Task <ExecuteAuthenticationResults> ExecuteAuthenticateServiceProcessAsync(
            Uri serviceUrl,
            ClientCredentials clientCredentials,
            X509Certificate2 userCert,
            string clientId,
            Uri redirectUri,
            PromptBehavior promptBehavior,
            bool isOnPrem,
            string authority,
            object msalAuthClient,
            CdsTraceLogger logSink    = null,
            bool useDefaultCreds      = false,
            SecureString clientSecret = null,
            bool addVersionInfoToUri  = true,
            IAccount user             = null
            )
        {
            ExecuteAuthenticationResults processResult = new ExecuteAuthenticationResults();
            bool createdLogSource = false;

            AuthenticationResult authenticationResult = null;

            try
            {
                if (logSink == null)
                {
                    // when set, the log source is locally created.
                    createdLogSource = true;
                    logSink          = new CdsTraceLogger();
                }

                string Authority = string.Empty;
                string Resource  = string.Empty;

                bool clientCredentialsCheck = clientCredentials != null && clientCredentials.UserName != null && !string.IsNullOrEmpty(clientCredentials.UserName.UserName) && !string.IsNullOrEmpty(clientCredentials.UserName.Password);
                Resource = serviceUrl.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped);
                if (!Resource.EndsWith("/"))
                {
                    Resource += "/";
                }

                if (addVersionInfoToUri)
                {
                    processResult.TargetServiceUrl = GetUriBuilderWithVersion(serviceUrl).Uri;
                }
                else
                {
                    processResult.TargetServiceUrl = serviceUrl;
                }

                if (!string.IsNullOrWhiteSpace(authority))
                {
                    //Overriding the tenant specific authority if clientCredentials are null
                    Authority = authority;
                }
                else
                {
                    var rslt = GetAuthorityFromTargetServiceAsync(ClientServiceProviders.Instance.GetService <IHttpClientFactory>(), processResult.TargetServiceUrl, logSink).ConfigureAwait(false).GetAwaiter().GetResult();
                    if (!string.IsNullOrEmpty(rslt.Authority))
                    {
                        Authority = rslt.Authority;
                        Resource  = rslt.Resource;
                    }
                    else
                    {
                        throw new ArgumentNullException("Authority", "Need a non-empty authority");
                    }
                }
                //	clientCredentialsCheck = false;  // Forcing system to provide a UX popup vs UID/PW

                // Assign outbound properties.
                processResult.Resource  = Resource;
                processResult.Authority = Authority;

                logSink.Log("AuthenticateService - found authority with name " + (string.IsNullOrEmpty(Authority) ? "<Not Provided>" : Authority));
                logSink.Log("AuthenticateService - found resource with name " + (string.IsNullOrEmpty(Resource) ? "<Not Provided>" : Resource));

                Uri ResourceUri = new Uri(Resource);
                // Add Scope,
                List <string> Scopes = Utilities.AddScope($"{Resource}/user_impersonation");

                AuthenticationResult _authenticationResult = null;
                if (userCert != null || clientSecret != null)
                {
                    // Add Scope,
                    Scopes.Clear();
                    Scopes = Utilities.AddScope($"{Resource}.default", Scopes);

                    IConfidentialClientApplication       cApp        = null;
                    ConfidentialClientApplicationBuilder cAppBuilder = null;

                    if (msalAuthClient is IConfidentialClientApplication)
                    {
                        cApp = (IConfidentialClientApplication)msalAuthClient;
                    }
                    else
                    {
                        cAppBuilder = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(
                            new ConfidentialClientApplicationOptions()
                        {
                            ClientId         = clientId,
                            EnablePiiLogging = true,
                            LogLevel         = LogLevel.Verbose,
                        })
                                      .WithAuthority(Authority)
                                      .WithLogging(Microsoft.PowerPlatform.Cds.Client.Utils.ADALLoggerCallBack.Log);
                    }

                    if (userCert != null)
                    {
                        logSink.Log("Initial ObtainAccessToken - CERT", TraceEventType.Verbose);
                        cApp = cAppBuilder.WithCertificate(userCert).Build();
                        _authenticationResult = await ObtainAccessTokenAsync(cApp, Scopes, logSink);
                    }
                    else
                    {
                        if (clientSecret != null)
                        {
                            logSink.Log("Initial ObtainAccessToken - Client Secret", TraceEventType.Verbose);
                            cApp = cAppBuilder.WithClientSecret(clientSecret.ToUnsecureString()).Build();
                            _authenticationResult = await ObtainAccessTokenAsync(cApp, Scopes, logSink);
                        }
                        else
                        {
                            throw new Exception("Invalid Cert or Client Secret Auth flow");
                        }
                    }

                    // Update the MSAL Client handed back.
                    processResult.MsalAuthClient = cApp;
                }
                else
                {
                    PublicClientApplicationBuilder cApp = null;
                    IPublicClientApplication       pApp = null;
                    if (msalAuthClient is IPublicClientApplication)
                    {
                        pApp = (IPublicClientApplication)msalAuthClient;
                    }
                    else
                    {
                        cApp = PublicClientApplicationBuilder.CreateWithApplicationOptions(
                            new PublicClientApplicationOptions()
                        {
                            ClientId         = clientId,
                            EnablePiiLogging = true,
                            RedirectUri      = redirectUri.ToString(),
                            LogLevel         = LogLevel.Verbose,
                        })
                               .WithAuthority(Authority)
                               .WithLogging(Microsoft.PowerPlatform.Cds.Client.Utils.ADALLoggerCallBack.Log);

                        pApp = cApp.Build();
                    }

                    //Run user Auth flow.
                    _authenticationResult = await ObtainAccessTokenAsync(pApp, Scopes, user, promptBehavior, clientCredentials, useDefaultCreds, logSink);

                    // Assign the application back out
                    processResult.MsalAuthClient = pApp;

                    //Assigning the authority to ref object to pass back to ConnMgr to store the latest Authority in Credential Manager.
                    authority = Authority;
                }

                if (_authenticationResult != null && _authenticationResult.Account != null)
                {
                    //To use same userId while connecting to OrgService (ConnectAndInitCrmOrgService)
                    //_userId = _authenticationResult.Account;
                    processResult.UserIdent = _authenticationResult.Account;
                }

                if (null == _authenticationResult)
                {
                    throw new ArgumentNullException("AuthenticationResult");
                }
                authenticationResult         = _authenticationResult;
                processResult.MsalAuthResult = authenticationResult;
            }
            catch (AggregateException ex)
            {
                if (ex.InnerException is Microsoft.Identity.Client.MsalException)
                {
                    var errorHandledResult = await ProcessAdalExecptionAsync(serviceUrl, clientCredentials, userCert, clientId, redirectUri, promptBehavior, isOnPrem, authority, msalAuthClient, logSink, useDefaultCreds, (Microsoft.Identity.Client.MsalException) ex.InnerException);

                    if (errorHandledResult != null)
                    {
                        processResult = errorHandledResult;
                    }
                }
                else
                {
                    logSink.Log("ERROR REQUESTING Token FROM THE Authentication context - General ADAL Error", TraceEventType.Error, ex);
                    logSink.Log(ex);
                    throw;
                }
            }
            catch (Microsoft.Identity.Client.MsalException ex)
            {
                var errorHandledResult = await ProcessAdalExecptionAsync(serviceUrl, clientCredentials, userCert, clientId, redirectUri, promptBehavior, isOnPrem, authority, msalAuthClient, logSink, useDefaultCreds, ex);

                if (errorHandledResult != null)
                {
                    processResult = errorHandledResult;
                }
            }
            catch (System.Exception ex)
            {
                logSink.Log("ERROR REQUESTING Token FROM THE Authentication context", TraceEventType.Error);
                logSink.Log(ex);
                throw;
            }
            finally
            {
                if (createdLogSource)                 // Only dispose it if it was created locally.
                {
                    logSink.Dispose();
                }
            }
            return(processResult);
        }
Example #9
0
        public async Task <bool> GetAccessToken(bool throwExceptionIfFail)
        {
            bool      success = true;
            Stopwatch timer   = new Stopwatch();

            timer.Start();
            int timeout = this.Timeout;

            try
            {
                ConfidentialClientApplicationBuilder appBuilder = ConfidentialClientApplicationBuilder.Create(ClientId).WithAuthority(this.CloudInstance, this.Tenant);
                IConfidentialClientApplication       app        = null;
                if (!String.IsNullOrWhiteSpace(ClientSecret))
                {
                    // Get bearer token using a client secret
                    ClaimsProviderLogging.Log($"[{ClaimsProviderName}] Getting new access token for tenant '{Tenant}' on cloud instance '{CloudInstance}' using client ID {ClientId} and a client secret.", TraceSeverity.Verbose, EventSeverity.Information, TraceCategory.Core);
                    app = appBuilder.WithClientSecret(ClientSecret).Build();
                }
                else
                {
                    // Get bearer token using a client certificate
                    ClaimsProviderLogging.Log($"[{ClaimsProviderName}] Getting new access token for tenant '{Tenant}' on cloud instance '{CloudInstance}' using client ID {ClientId} and a client certificate with thumbprint {ClientCertificate.Thumbprint}.", TraceSeverity.Verbose, EventSeverity.Information, TraceCategory.Core);
                    app = appBuilder.WithCertificate(ClientCertificate).Build();
                }
                // Acquire bearer token
                Task <AuthenticationResult> acquireTokenTask = app.AcquireTokenForClient(this.Scopes).ExecuteAsync();
                AuthNResult = await TaskHelper.TimeoutAfter <AuthenticationResult>(acquireTokenTask, new TimeSpan(0, 0, 0, 0, timeout)).ConfigureAwait(false);

                TimeSpan duration = new TimeSpan(AuthNResult.ExpiresOn.UtcTicks - DateTime.Now.ToUniversalTime().Ticks);
                ClaimsProviderLogging.Log($"[{ClaimsProviderName}] Got new access token for tenant '{Tenant}' on cloud instance '{CloudInstance}', valid for {Math.Round((duration.TotalHours), 1)} hour(s) and retrieved in {timer.ElapsedMilliseconds.ToString()} ms", TraceSeverity.High, EventSeverity.Information, TraceCategory.Core);
            }
            catch (MsalServiceException ex)
            {
                ClaimsProviderLogging.Log($"[{ClaimsProviderName}] Unable to get access token for tenant '{Tenant}' on cloud instance '{CloudInstance}': {ex.Message}", TraceSeverity.Unexpected, EventSeverity.Error, TraceCategory.Core);
                success = false;
                if (throwExceptionIfFail)
                {
                    throw;
                }
            }
            catch (TimeoutException)
            {
                ClaimsProviderLogging.Log($"[{ClaimsProviderName}] Could not get access token before timeout of {timeout.ToString()} ms for tenant '{Tenant}' on cloud instance '{CloudInstance}'", TraceSeverity.Unexpected, EventSeverity.Error, TraceCategory.Core);
                success = false;
                if (throwExceptionIfFail)
                {
                    throw;
                }
            }
            catch (Exception ex)
            {
                ClaimsProviderLogging.LogException(ClaimsProviderName, $"while getting access token for tenant '{Tenant}' on cloud instance '{CloudInstance}'", TraceCategory.Lookup, ex);
                success = false;
                if (throwExceptionIfFail)
                {
                    throw;
                }
            }
            finally
            {
                timer.Stop();
            }
            return(success);
        }