示例#1
0
        public async Task AuthenticateWithDeviceCodeMockAsync2()
        {
            var expectedCode = Guid.NewGuid().ToString();

            var expectedToken = Guid.NewGuid().ToString();

            var mockTransport = new MockTransport(request => ProcessMockRequest(request, expectedCode, expectedToken));

            var options = new TokenCredentialOptions()
            {
                Transport = mockTransport
            };

            var cred = InstrumentClient(new DeviceCodeCredential((code, cancelToken) => VerifyDeviceCode(code, expectedCode), ClientId, options: options));

            AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" }));

            Assert.AreEqual(token.Token, expectedToken);
        }
示例#2
0
        public async Task AuthenticateWithAuthCodeHonorsTenantId([Values(null, TenantIdHint)] string tenantId, [Values(true)] bool allowMultiTenantAuthentication)
        {
            options = new TokenCredentialOptions {
                AllowMultiTenantAuthentication = allowMultiTenantAuthentication
            };
            var context = new TokenRequestContext(new[] { Scope }, tenantId: tenantId);

            expectedTenantId = TenantIdResolver.Resolve(TenantId, context, options.AllowMultiTenantAuthentication);

            AuthorizationCodeCredential cred = InstrumentClient(new AuthorizationCodeCredential(TenantId, ClientId, clientSecret, authCode, options, mockMsalClient));

            AccessToken token = await cred.GetTokenAsync(context);

            Assert.AreEqual(token.Token, expectedToken, "Should be the expected token value");

            AccessToken token2 = await cred.GetTokenAsync(context);

            Assert.AreEqual(token2.Token, expectedToken, "Should be the expected token value");
        }
        public override TokenCredential GetTokenCredential(TokenCredentialOptions options)
        {
            using var env = new TestEnvVar(new Dictionary <string, string> { { "TENANT_ID", TenantId } });
            var environment = new IdentityTestEnvironment();
            var vscOptions  = new VisualStudioCodeCredentialOptions
            {
                Diagnostics = { IsAccountIdentifierLoggingEnabled = options.Diagnostics.IsAccountIdentifierLoggingEnabled },
                TenantId    = environment.TenantId,
                Transport   = new MockTransport()
            };

            return(InstrumentClient(
                       new VisualStudioCodeCredential(
                           vscOptions,
                           null,
                           mockPublicMsalClient,
                           CredentialTestHelpers.CreateFileSystemForVisualStudioCode(environment),
                           new TestVscAdapter("VS Code Azure", "AzureCloud", expectedToken))));
        }
示例#4
0
        public async Task AuthenticateWithDeviceCodeMockAsync([Values(null, TenantIdHint)] string tenantId, [Values(true)] bool allowMultiTenantAuthentication)
        {
            options = new TokenCredentialOptions {
                AllowMultiTenantAuthentication = allowMultiTenantAuthentication
            };
            var context = new TokenRequestContext(new[] { Scope }, tenantId: tenantId);

            expectedTenantId = TenantIdResolver.Resolve(TenantId, context, options.AllowMultiTenantAuthentication);
            var cred = InstrumentClient(
                new DeviceCodeCredential((code, _) => VerifyDeviceCode(code, expectedCode), TenantId, ClientId, options, null, mockMsalClient));

            AccessToken token = await cred.GetTokenAsync(context);

            Assert.AreEqual(token.Token, expectedToken);

            token = await cred.GetTokenAsync(context);

            Assert.AreEqual(token.Token, expectedToken);
        }
        public async Task AuthenticateWithDeviceCodeMockVerifyMsalCancellationAsync()
        {
            var cancelSource = new CancellationTokenSource();
            var options      = new TokenCredentialOptions();

            var cred = InstrumentClient(
                new DeviceCodeCredential(
                    (code, cancelToken) => VerifyDeviceCodeAndCancel(code, expectedCode, cancelSource),
                    null,
                    ClientId,
                    options,
                    null,
                    mockPublicMsalClient));

            var ex = Assert.CatchAsync <OperationCanceledException>(
                async() => await cred.GetTokenAsync(new TokenRequestContext(new[] { Scope }), cancelSource.Token));

            await Task.CompletedTask;
        }
示例#6
0
        public void AuthenticateWithDeviceCodeCallbackThrowsAsync()
        {
            var expectedCode = Guid.NewGuid().ToString();

            var expectedToken = Guid.NewGuid().ToString();

            var cancelSource = new CancellationTokenSource();

            var mockTransport = new MockTransport(request => ProcessMockRequest(request, expectedCode, expectedToken));

            var options = new TokenCredentialOptions()
            {
                Transport = mockTransport
            };

            var cred = InstrumentClient(new DeviceCodeCredential(ThrowingDeviceCodeCallback, ClientId, options: options));

            Assert.ThrowsAsync <MockException>(async() => await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" }), cancelSource.Token));
        }
示例#7
0
        public async Task VerifyImdsRequestMockAsync()
        {
            using (new TestEnvVar("MSI_ENDPOINT", null))
                using (new TestEnvVar("MSI_SECRET", null))
                {
                    var response = new MockResponse(200);

                    var expectedToken = "mock-msi-access-token";

                    response.SetContent($"{{ \"access_token\": \"{expectedToken}\", \"expires_on\": \"3600\" }}");

                    var mockTransport = new MockTransport(response);

                    var options = new TokenCredentialOptions()
                    {
                        Transport = mockTransport
                    };

                    var pipeline = CredentialPipeline.GetInstance(options);

                    ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential(pipeline, new MockManagedIdentityClient(pipeline, "mock-client-id")
                    {
                        ImdsAvailableFunc = _ => true
                    }));

                    AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default));

                    Assert.AreEqual(expectedToken, actualToken.Token);

                    MockRequest request = mockTransport.Requests[0];

                    string query = request.Uri.Query;

                    Assert.IsTrue(query.Contains("api-version=2018-02-01"));

                    Assert.IsTrue(query.Contains($"resource={Uri.EscapeDataString(ScopeUtilities.ScopesToResource(MockScopes.Default))}"));

                    Assert.IsTrue(request.Headers.TryGetValue("Metadata", out string metadataValue));

                    Assert.AreEqual("true", metadataValue);
                }
        }
        public async Task VerifyClientSecretRequestFailedAsync()
        {
            var response = new MockResponse(400);

            response.SetContent($"{{ \"error_code\": \"InvalidSecret\", \"message\": \"The specified client_secret is incorrect\" }}");
            var mockTransport = new MockTransport(response);
            var options       = new TokenCredentialOptions()
            {
                Transport = mockTransport
            };
            var expectedTenantId     = Guid.NewGuid().ToString();
            var expectedClientId     = Guid.NewGuid().ToString();
            var expectedClientSecret = "secret";

            ClientSecretCredential client = InstrumentClient(new ClientSecretCredential(expectedTenantId, expectedClientId, expectedClientSecret, options));

            Assert.ThrowsAsync <AuthenticationFailedException>(async() => await client.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));

            await Task.CompletedTask;
        }
示例#9
0
        public async Task VerifyAppServiceMsiRequestWithClientIdMockAsync()
        {
            using (new TestEnvVar("MSI_ENDPOINT", "https://mock.msi.endpoint/"))
                using (new TestEnvVar("MSI_SECRET", "mock-msi-secret"))
                {
                    var response = new MockResponse(200);

                    var expectedToken = "mock-msi-access-token";

                    response.SetContent($"{{ \"access_token\": \"{expectedToken}\", \"expires_on\": \"{DateTimeOffset.UtcNow.ToString()}\" }}");

                    var mockTransport = new MockTransport(response);

                    var options = new TokenCredentialOptions()
                    {
                        Transport = mockTransport
                    };

                    ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential("mock-client-id", options));

                    AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default));

                    Assert.AreEqual(expectedToken, actualToken.Token);

                    MockRequest request = mockTransport.SingleRequest;

                    Assert.IsTrue(request.Uri.ToString().StartsWith("https://mock.msi.endpoint/"));

                    string query = request.Uri.Query;

                    Assert.IsTrue(query.Contains("api-version=2017-09-01"));

                    Assert.IsTrue(query.Contains($"resource={Uri.EscapeDataString(ScopeUtilities.ScopesToResource(MockScopes.Default))}"));

                    Assert.IsTrue(query.Contains($"clientid=mock-client-id"));

                    Assert.IsTrue(request.Headers.TryGetValue("secret", out string actSecretValue));

                    Assert.AreEqual("mock-msi-secret", actSecretValue);
                }
        }
示例#10
0
        public void VerifyImdsAvailableUserCanceledMockAsync()
        {
            using (new TestEnvVar("MSI_ENDPOINT", null))
                using (new TestEnvVar("MSI_SECRET", null))
                {
                    var mockTransport = new MockTransport(request => throw new OperationCanceledException("mock user canceled exception"));

                    var options = new TokenCredentialOptions()
                    {
                        Transport = mockTransport
                    };

                    ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential("mock-client-id", options));

                    CancellationTokenSource cancellationSource = new CancellationTokenSource();

                    cancellationSource.Cancel();

                    Assert.CatchAsync <OperationCanceledException>(async() => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default), cancellationSource.Token));
                }
        }
        public async Task AuthenticateWithDeviceCodeMockVerifyMsalCancellationAsync()
        {
            var expectedCode = Guid.NewGuid().ToString();

            var expectedToken = Guid.NewGuid().ToString();

            var cancelSource = new CancellationTokenSource();

            var mockTransport = new MockTransport(request => ProcessMockRequest(request, expectedCode, expectedToken));

            var options = new TokenCredentialOptions()
            {
                Transport = mockTransport
            };

            var cred = InstrumentClient(new DeviceCodeCredential((code, cancelToken) => VerifyDeviceCodeAndCancel(code, expectedCode, cancelSource), null, ClientId, options: options));

            var ex = Assert.CatchAsync <OperationCanceledException>(async() => await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" }), cancelSource.Token));

            await Task.CompletedTask;
        }
示例#12
0
        public async Task VerifyImdsRequestWithClientIdMockAsync()
        {
            using (new TestEnvVar("MSI_ENDPOINT", null))
                using (new TestEnvVar("MSI_SECRET", null))
                {
                    var response = new MockResponse(200);

                    var expectedToken = "mock-msi-access-token";

                    response.SetContent($"{{ \"access_token\": \"{expectedToken}\", \"expires_on\": \"3600\" }}");

                    var mockTransport = new MockTransport(response, response);

                    var options = new TokenCredentialOptions()
                    {
                        Transport = mockTransport
                    };

                    ManagedIdentityClient client = InstrumentClient(new ManagedIdentityClient(options));

                    AccessToken actualToken = await client.AuthenticateAsync(MockScopes.Default, clientId : "mock-client-id");

                    Assert.AreEqual(expectedToken, actualToken.Token);

                    MockRequest request = mockTransport.Requests[mockTransport.Requests.Count - 1];

                    string query = request.Uri.Query;

                    Assert.IsTrue(query.Contains("api-version=2018-02-01"));

                    Assert.IsTrue(query.Contains($"resource={Uri.EscapeDataString(ScopeUtilities.ScopesToResource(MockScopes.Default))}"));

                    Assert.IsTrue(query.Contains($"client_id=mock-client-id"));

                    Assert.IsTrue(request.Headers.TryGetValue("Metadata", out string metadataValue));

                    Assert.AreEqual("true", metadataValue);
                }
        }
        public void AuthenticateWithDeviceCodeCallbackThrowsAsync()
        {
            IdentityTestEnvironment testEnvironment = new IdentityTestEnvironment();
            var expectedCode = Guid.NewGuid().ToString();

            var expectedToken = Guid.NewGuid().ToString();

            var cancelSource = new CancellationTokenSource();

            var mockTransport = new MockTransport(request => ProcessMockRequest(request, expectedCode, expectedToken));

            var options = new TokenCredentialOptions()
            {
                Transport = mockTransport
            };

            var cred = InstrumentClient(new DeviceCodeCredential(ThrowingDeviceCodeCallback, ClientId, options: options));

            var ex = Assert.ThrowsAsync <AuthenticationFailedException>(async() => await cred.GetTokenAsync(new TokenRequestContext(new string[] { testEnvironment.KeyvaultScope }), cancelSource.Token));

            Assert.IsInstanceOf(typeof(MockException), ex.InnerException);
        }
示例#14
0
 public abstract TokenCredential GetTokenCredential(TokenCredentialOptions options);
示例#15
0
        public async Task <string> GetData(string configuration, string name)
        {
            var configurationObj = JsonSerializerHelper.Deserialize <Configuration>(configuration);

            var credentialOption = new TokenCredentialOptions();

            credentialOption.AuthorityHost = new Uri(configurationObj.AzureLoginUri);

            TokenCredential credential;

            switch (configurationObj.Type)
            {
            case 1:
                //ClientSecret
                credential = new ClientSecretCredential(configurationObj.TenantId, configurationObj.ClientId, configurationObj.ClientSecret, credentialOption);
                break;

            case 2:
                //UsernamePassword
                credential = new UsernamePasswordCredential(configurationObj.UserName, configurationObj.Password, configurationObj.TenantId, configurationObj.ClientId, credentialOption);
                break;

            case 3:
                //ManagedIdentity
                string clientID = null;
                if (!string.IsNullOrEmpty(configurationObj.ClientId))
                {
                    clientID = configurationObj.ClientId;
                }
                credential = new ManagedIdentityCredential(clientID);
                break;

            default:
                var fragment = new TextFragment()
                {
                    Code = TextCodes.NotSupportAzureVaultAuthType,
                    DefaultFormatting = "不支持方式为{0}的AzureVault验证方式,发生位置为{1}",
                    ReplaceParameters = new List <object>()
                    {
                        configurationObj.Type.ToString(), $"{this.GetType().FullName}.GetData"
                    }
                };
                throw new UtilityException((int)Errors.NotSupportAzureVaultAuthType, fragment);
            }

            SecretClientOptions options = new SecretClientOptions()
            {
                Retry =
                {
                    Delay      = TimeSpan.FromSeconds(2),
                    MaxDelay   = TimeSpan.FromSeconds(16),
                    MaxRetries =                        5,
                    Mode       = RetryMode.Exponential
                }
            };

            var client = new SecretClient(new Uri($"https://{configurationObj.VaultName}{configurationObj.VaultUriSuffix}"), credential, options);

            var result = await client.GetSecretAsync(name);

            return(result.Value.Value);
        }
示例#16
0
 /// <summary>
 /// Creates an instance of the ClientSecretCredential with the details needed to authenticate against Azure Active Directory with a client secret.
 /// </summary>
 /// <param name="tenantId">The Azure Active Directory tenant (directory) Id of the service principal.</param>
 /// <param name="clientId">The client (application) ID of the service principal</param>
 /// <param name="clientSecret">A client secret that was generated for the App Registration used to authenticate the client.</param>
 /// <param name="options">Options that allow to configure the management of the requests sent to the Azure Active Directory service.</param>
 public ClientAssertionCredential(string tenantId, string clientId, string clientSecret, TokenCredentialOptions options)
     : this(tenantId, clientId, clientSecret, options, null, null)
 {
 }
示例#17
0
        internal static TokenCredential CreateCredential(IConfiguration configuration, TokenCredentialOptions identityClientOptions = null)
        {
            var credentialType           = configuration["credential"];
            var clientId                 = configuration["clientId"];
            var tenantId                 = configuration["tenantId"];
            var clientSecret             = configuration["clientSecret"];
            var certificate              = configuration["clientCertificate"];
            var certificateStoreName     = configuration["clientCertificateStoreName"];
            var certificateStoreLocation = configuration["clientCertificateStoreLocation"];

            if (string.Equals(credentialType, "managedidentity", StringComparison.OrdinalIgnoreCase))
            {
                return(new ManagedIdentityCredential(clientId));
            }

            if (!string.IsNullOrWhiteSpace(tenantId) &&
                !string.IsNullOrWhiteSpace(clientId) &&
                !string.IsNullOrWhiteSpace(clientSecret))
            {
                return(new ClientSecretCredential(tenantId, clientId, clientSecret, identityClientOptions));
            }

            if (!string.IsNullOrWhiteSpace(tenantId) &&
                !string.IsNullOrWhiteSpace(clientId) &&
                !string.IsNullOrWhiteSpace(certificate))
            {
                StoreLocation storeLocation = StoreLocation.CurrentUser;

                if (!string.IsNullOrWhiteSpace(certificateStoreLocation))
                {
                    storeLocation = (StoreLocation)Enum.Parse(typeof(StoreLocation), certificateStoreLocation, true);
                }

                if (string.IsNullOrWhiteSpace(certificateStoreName))
                {
                    certificateStoreName = "MY"; // MY is the default used in X509Store
                }

                using var store = new X509Store(certificateStoreName, storeLocation);
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByThumbprint, certificate, false);

                if (certs.Count == 0)
                {
                    throw new InvalidOperationException($"Unable to find a certificate with thumbprint '{certificate}'");
                }

                var credential = new ClientCertificateCredential(tenantId, clientId, certs[0], identityClientOptions);
                store.Close();

                return(credential);
            }

            // TODO: More logging
            return(null);
        }
示例#18
0
        private ManagedIdentityCredential CreateManagedIdentityCredential(string clientId = null, TokenCredentialOptions options = null)
        {
            options = Recording.InstrumentClientOptions(options ?? new TokenCredentialOptions());

            var pipeline = CredentialPipeline.GetInstance(options);

            // if we're in playback mode we need to mock the ImdsAvailable call since we won't be able to open a connection
            var client = (Mode == RecordedTestMode.Playback) ? new MockManagedIdentityClient(pipeline, clientId)
            {
                ImdsAvailableFunc = _ => true
            } : new ManagedIdentityClient(pipeline, clientId);

            var cred = new ManagedIdentityCredential(pipeline, client);

            return(cred);
        }
 public MockMsalClient(CredentialPipeline pipeline, string tenantId, string clientId, TokenCredentialOptions options)
     : base(pipeline, tenantId, clientId, options)
 {
 }
示例#20
0
        internal ClientAssertionCredential(string tenantId, string clientId, string clientSecret, TokenCredentialOptions options, CredentialPipeline pipeline, MsalConfidentialClient client)
        {
            TenantId = Validations.ValidateTenantId(tenantId, nameof(tenantId));

            ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));

            ClientSecret = clientSecret ?? throw new ArgumentNullException(nameof(clientSecret));

            _pipeline = pipeline ?? CredentialPipeline.GetInstance(options);

            _client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, clientSecret, options as ITokenCacheOptions);
        }
示例#21
0
        public void SetAuthorityHostToNonHttpsEndpointThrows()
        {
            TokenCredentialOptions options = new TokenCredentialOptions();

            Assert.Throws <ArgumentException>(() => options.AuthorityHost = new Uri("http://unprotected.login.com"));
        }
示例#22
0
        protected async Task Initialize()
        {
            Location     = AzureLocation.CanadaCentral;
            Client       = GetArmClient();
            Subscription = await Client.GetDefaultSubscriptionAsync();

            DeletedVaultCollection = Subscription.GetDeletedVaults();

            if (Mode == RecordedTestMode.Playback)
            {
                this.ObjectId = Recording.GetVariable(ObjectIdKey, string.Empty);
            }
            else if (Mode == RecordedTestMode.Record)
            {
                // Get ObjectId of Service Principal
                // [warning] Microsoft.Graph required corresponding api permission, Please make sure the service has these two api permissions as follows.
                // 1. ServicePrincipalEndpoint.Read.All(TYPE-Application) 2.ServicePrincipalEndpoint.ReadWrite.All(TYPE-Application)
                var scopes  = new[] { "https://graph.microsoft.com/.default" };
                var options = new TokenCredentialOptions
                {
                    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
                };
                var clientSecretCredential = new ClientSecretCredential(TestEnvironment.TenantId, TestEnvironment.ClientId, TestEnvironment.ClientSecret, options);
                var graphClient            = new GraphServiceClient(clientSecretCredential, scopes);
                var response = await graphClient.ServicePrincipals.Request().GetAsync();

                var result = response.CurrentPage.Where(i => i.AppId == TestEnvironment.ClientId).FirstOrDefault();
                this.ObjectId = result.Id;
                Recording.GetVariable(ObjectIdKey, this.ObjectId);
            }

            ResGroupName = Recording.GenerateAssetName("sdktestrg-kv-");
            ArmOperation <ResourceGroupResource> rgResponse = await Subscription.GetResourceGroups().CreateOrUpdateAsync(WaitUntil.Completed, ResGroupName, new ResourceGroupData(Location)).ConfigureAwait(false);

            ResourceGroupResource = rgResponse.Value;

            VaultCollection = ResourceGroupResource.GetVaults();
            VaultName       = Recording.GenerateAssetName("sdktest-vault-");
            MHSMName        = Recording.GenerateAssetName("sdktest-mhsm-");
            TenantIdGuid    = new Guid(TestEnvironment.TenantId);
            Tags            = new Dictionary <string, string> {
                { "tag1", "value1" }, { "tag2", "value2" }, { "tag3", "value3" }
            };

            IdentityAccessPermissions permissions = new IdentityAccessPermissions
            {
                Keys         = { new KeyPermission("all") },
                Secrets      = { new SecretPermission("all") },
                Certificates = { new CertificatePermission("all") },
                Storage      = { new StoragePermission("all") },
            };

            AccessPolicy = new VaultAccessPolicy(TenantIdGuid, ObjectId, permissions);

            VaultProperties = new VaultProperties(TenantIdGuid, new KeyVaultSku(KeyVaultSkuFamily.A, KeyVaultSkuName.Standard));

            VaultProperties.EnabledForDeployment         = true;
            VaultProperties.EnabledForDiskEncryption     = true;
            VaultProperties.EnabledForTemplateDeployment = true;
            VaultProperties.EnableSoftDelete             = true;
            VaultProperties.SoftDeleteRetentionInDays    = DefSoftDeleteRetentionInDays;
            VaultProperties.VaultUri       = new Uri("http://vaulturi.com");
            VaultProperties.NetworkRuleSet = new VaultNetworkRuleSet()
            {
                Bypass        = "******",
                DefaultAction = "Allow",
                IPRules       =
                {
                    new VaultIPRule("1.2.3.4/32"),
                    new VaultIPRule("1.0.0.0/25")
                }
            };
            VaultProperties.AccessPolicies.Add(AccessPolicy);

            ManagedHsmCollection = ResourceGroupResource.GetManagedHsms();
            ManagedHsmProperties = new ManagedHsmProperties();
            ManagedHsmProperties.InitialAdminObjectIds.Add(ObjectId);
            ManagedHsmProperties.CreateMode                = ManagedHsmCreateMode.Default;
            ManagedHsmProperties.EnableSoftDelete          = true;
            ManagedHsmProperties.SoftDeleteRetentionInDays = DefSoftDeleteRetentionInDays;
            ManagedHsmProperties.EnablePurgeProtection     = false;
            ManagedHsmProperties.NetworkRuleSet            = new ManagedHsmNetworkRuleSet()
            {
                Bypass        = "******",
                DefaultAction = "Deny" //Property properties.networkAcls.ipRules is not supported currently and must be set to null.
            };
            ManagedHsmProperties.PublicNetworkAccess = PublicNetworkAccess.Disabled;
            ManagedHsmProperties.TenantId            = TenantIdGuid;
        }
示例#23
0
        /// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
        public override async Task <SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters)
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // Use Connection timeout value to cancel token acquire request after certain period of time.
            cts.CancelAfter(parameters.ConnectionTimeout * 1000); // Convert to milliseconds

            string scope = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;

            string[] scopes = new string[] { scope };

            int    seperatorIndex = parameters.Authority.LastIndexOf('/');
            string tenantId       = parameters.Authority.Substring(seperatorIndex + 1);
            string authority      = parameters.Authority.Remove(seperatorIndex + 1);

            TokenRequestContext tokenRequestContext = new TokenRequestContext(scopes);
            string clientId = string.IsNullOrWhiteSpace(parameters.UserId) ? null : parameters.UserId;

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDefault)
            {
                DefaultAzureCredentialOptions defaultAzureCredentialOptions = new DefaultAzureCredentialOptions()
                {
                    AuthorityHost                       = new Uri(authority),
                    ManagedIdentityClientId             = clientId,
                    InteractiveBrowserTenantId          = tenantId,
                    SharedTokenCacheTenantId            = tenantId,
                    SharedTokenCacheUsername            = clientId,
                    VisualStudioCodeTenantId            = tenantId,
                    VisualStudioTenantId                = tenantId,
                    ExcludeInteractiveBrowserCredential = true // Force disabled, even though it's disabled by default to respect driver specifications.
                };
                AccessToken accessToken = await new DefaultAzureCredential(defaultAzureCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token);
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Default auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
                return(new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn));
            }

            TokenCredentialOptions tokenCredentialOptions = new TokenCredentialOptions()
            {
                AuthorityHost = new Uri(authority)
            };

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity || parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryMSI)
            {
                AccessToken accessToken = await new ManagedIdentityCredential(clientId, tokenCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token);
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Managed Identity auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
                return(new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn));
            }

            AuthenticationResult result;

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal)
            {
                AccessToken accessToken = await new ClientSecretCredential(tenantId, parameters.UserId, parameters.Password, tokenCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token);
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Service Principal auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
                return(new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn));
            }

            /*
             * Today, MSAL.NET uses another redirect URI by default in desktop applications that run on Windows
             * (urn:ietf:wg:oauth:2.0:oob). In the future, we'll want to change this default, so we recommend
             * that you use https://login.microsoftonline.com/common/oauth2/nativeclient.
             *
             * https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris
             */
            string redirectUri = s_nativeClientRedirectUri;

#if NETCOREAPP
            if (parameters.AuthenticationMethod != SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
            {
                redirectUri = "http://localhost";
            }
#endif
            PublicClientAppKey pcaKey = new PublicClientAppKey(parameters.Authority, redirectUri, _applicationClientId
#if NETFRAMEWORK
                                                               , _iWin32WindowFunc
#endif
#if NETSTANDARD
                                                               , _parentActivityOrWindowFunc
#endif
                                                               );

            IPublicClientApplication app = GetPublicClientAppInstance(pcaKey);

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
            {
                if (!string.IsNullOrEmpty(parameters.UserId))
                {
                    result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .WithUsername(parameters.UserId)
                             .ExecuteAsync(cancellationToken: cts.Token);
                }
                else
                {
                    result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .ExecuteAsync(cancellationToken: cts.Token);
                }
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Integrated auth mode. Expiry Time: {0}", result?.ExpiresOn);
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword)
            {
                SecureString password = new SecureString();
                foreach (char c in parameters.Password)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();

                result = await app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password)
                         .WithCorrelationId(parameters.ConnectionId)
                         .ExecuteAsync(cancellationToken: cts.Token);

                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Password auth mode. Expiry Time: {0}", result?.ExpiresOn);
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive ||
                     parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
            {
                // Fetch available accounts from 'app' instance
                System.Collections.Generic.IEnumerator <IAccount> accounts = (await app.GetAccountsAsync()).GetEnumerator();

                IAccount account = default;
                if (accounts.MoveNext())
                {
                    if (!string.IsNullOrEmpty(parameters.UserId))
                    {
                        do
                        {
                            IAccount currentVal = accounts.Current;
                            if (string.Compare(parameters.UserId, currentVal.Username, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                account = currentVal;
                                break;
                            }
                        }while (accounts.MoveNext());
                    }
                    else
                    {
                        account = accounts.Current;
                    }
                }

                if (null != account)
                {
                    try
                    {
                        // If 'account' is available in 'app', we use the same to acquire token silently.
                        // Read More on API docs: https://docs.microsoft.com/dotnet/api/microsoft.identity.client.clientapplicationbase.acquiretokensilent
                        result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken: cts.Token);

                        SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (silent) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
                    }
                    catch (MsalUiRequiredException)
                    {
                        // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application,
                        // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired),
                        // or the user needs to perform two factor authentication.
                        result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod, cts);

                        SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
                    }
                }
                else
                {
                    // If no existing 'account' is found, we request user to sign in interactively.
                    result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod, cts);

                    SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
                }
            }
            else
            {
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | {0} authentication mode not supported by ActiveDirectoryAuthenticationProvider class.", parameters.AuthenticationMethod);
                throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod);
            }

            return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
        }
        public void TestSetup()
        {
            expectedTenantId      = null;
            expectedReplyUri      = null;
            authCode              = Guid.NewGuid().ToString();
            options               = new TokenCredentialOptions();
            expectedToken         = Guid.NewGuid().ToString();
            expectedUserAssertion = Guid.NewGuid().ToString();
            expiresOn             = DateTimeOffset.Now.AddHours(1);
            result = new AuthenticationResult(
                expectedToken,
                false,
                null,
                expiresOn,
                expiresOn,
                TenantId,
                new MockAccount("username"),
                null,
                new[] { Scope },
                Guid.NewGuid(),
                null,
                "Bearer");

            mockConfidentialMsalClient = new MockMsalConfidentialClient()
                                         .WithSilentFactory(
                (_, _tenantId, _replyUri, _) =>
            {
                Assert.AreEqual(expectedTenantId, _tenantId);
                Assert.AreEqual(expectedReplyUri, _replyUri);
                return(new ValueTask <AuthenticationResult>(result));
            })
                                         .WithAuthCodeFactory(
                (_, _tenantId, _replyUri, _) =>
            {
                Assert.AreEqual(expectedTenantId, _tenantId);
                Assert.AreEqual(expectedReplyUri, _replyUri);
                return(result);
            })
                                         .WithOnBehalfOfFactory(
                (_, _, userAssertion, _, _) =>
            {
                Assert.AreEqual(expectedUserAssertion, userAssertion.Assertion);
                return(new ValueTask <AuthenticationResult>(result));
            })
                                         .WithClientFactory(
                (_, _tenantId) =>
            {
                Assert.AreEqual(expectedTenantId, _tenantId);
                return(result);
            });

            expectedCode         = Guid.NewGuid().ToString();
            mockPublicMsalClient = new MockMsalPublicClient();
            deviceCodeResult     = MockMsalPublicClient.GetDeviceCodeResult(deviceCode: expectedCode);
            mockPublicMsalClient.DeviceCodeResult = deviceCodeResult;
            var publicResult = new AuthenticationResult(
                expectedToken,
                false,
                null,
                expiresOn,
                expiresOn,
                TenantId,
                new MockAccount("username"),
                null,
                new[] { Scope },
                Guid.NewGuid(),
                null,
                "Bearer");

            mockPublicMsalClient.SilentAuthFactory = (_, tId) =>
            {
                Assert.AreEqual(expectedTenantId, tId);
                return(publicResult);
            };
            mockPublicMsalClient.DeviceCodeAuthFactory = (_, _) =>
            {
                // Assert.AreEqual(tenantId, tId);
                return(publicResult);
            };
            mockPublicMsalClient.InteractiveAuthFactory = (_, _, _, _, tenant, _, _) =>
            {
                Assert.AreEqual(expectedTenantId, tenant, "TenantId passed to msal should match");
                return(result);
            };
            mockPublicMsalClient.SilentAuthFactory = (_, tenant) =>
            {
                Assert.AreEqual(expectedTenantId, tenant, "TenantId passed to msal should match");
                return(result);
            };
            mockPublicMsalClient.ExtendedSilentAuthFactory = (_, _, _, tenant, _, _) =>
            {
                Assert.AreEqual(expectedTenantId, tenant, "TenantId passed to msal should match");
                return(result);
            };
            mockPublicMsalClient.UserPassAuthFactory = (_, tenant) =>
            {
                Assert.AreEqual(expectedTenantId, tenant, "TenantId passed to msal should match");
                return(result);
            };
            mockPublicMsalClient.RefreshTokenFactory = (_, _, _, _, tenant, _, _) =>
            {
                Assert.AreEqual(expectedTenantId, tenant, "TenantId passed to msal should match");
                return(result);
            };
        }
示例#25
0
 public override TokenCredential GetTokenCredential(TokenCredentialOptions options) => InstrumentClient(
     new InteractiveBrowserCredential(TenantId, ClientId, options, null, mockPublicMsalClient));
示例#26
0
        private CredentialPipeline(TokenCredentialOptions options)
        {
            AuthorityHost = options.AuthorityHost;

            HttpPipeline = HttpPipelineBuilder.Build(options, Array.Empty <HttpPipelinePolicy>(), Array.Empty <HttpPipelinePolicy>(), new CredentialResponseClassifier());
        }
示例#27
0
 public override TokenCredential GetTokenCredential(TokenCredentialOptions options) => InstrumentClient(
     new ClientSecretCredential(expectedTenantId, ClientId, "secret", options, null, mockConfidentialMsalClient));
示例#28
0
 public static CredentialPipeline GetInstance(TokenCredentialOptions options)
 {
     return(options is null ? s_singleton.Value : new CredentialPipeline(options));
 }
示例#29
0
 public override TokenCredential GetTokenCredential(TokenCredentialOptions options) => InstrumentClient(
     new AuthorizationCodeCredential(TenantId, ClientId, clientSecret, authCode, options, mockConfidentialMsalClient));
 public MockMsalPublicClient(CredentialPipeline pipeline, string tenantId, string clientId, string redirectUrl, TokenCredentialOptions options)
     : base(pipeline, tenantId, clientId, redirectUrl, options)
 {
 }