Esempio n. 1
0
        public async Task AuthenticateWithAuthCodeMockAsync()
        {
            var expectedToken = Guid.NewGuid().ToString();
            var authCode      = Guid.NewGuid().ToString();
            var clientId      = Guid.NewGuid().ToString();
            var tenantId      = Guid.NewGuid().ToString();
            var clientSecret  = Guid.NewGuid().ToString();

            MockResponse response = CreateAuthorizationResponse(expectedToken);

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

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

            AuthorizationCodeCredential cred = InstrumentClient(new AuthorizationCodeCredential(tenantId, clientId, clientSecret, authCode, options));

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

            Assert.AreEqual(token.Token, expectedToken);

            AccessToken token2 = await cred.GetTokenAsync(new TokenRequest(new string[] { "https://managemnt.azure.com/.default" }));

            Assert.AreEqual(token.Token, expectedToken);
        }
        public async Task AuthenticateWithDeviceCodeMockVerifyCallbackCancellationAsync()
        {
            var expectedCode = Guid.NewGuid().ToString();

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

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

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

            var cancelSource = new CancellationTokenSource(1000);

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

            Task <AccessToken> getTokenTask = cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" }), cancelSource.Token);

            try
            {
                AccessToken token = await getTokenTask;

                Assert.Fail();
            }
            catch (TaskCanceledException)
            {
            }
        }
        public async Task VerifyClientCertificateRequestAsync()
        {
            var response = new MockResponse(200);

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

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

            var mockTransport = new MockTransport(response);

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

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

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

            var certificatePath = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx");
            var mockCert        = new X509Certificate2(certificatePath, "password");

            AadIdentityClient client = InstrumentClient(new AadIdentityClient(options: options));

            AccessToken actualToken = await client.AuthenticateAsync(expectedTenantId, expectedClientId, mockCert, MockScopes.Default);

            Assert.AreEqual(expectedToken, actualToken.Token);

            MockRequest request = mockTransport.SingleRequest;

            Assert.IsTrue(request.Content.TryComputeLength(out long contentLen));

            var content = new byte[contentLen];

            await request.Content.WriteToAsync(new MemoryStream(content), default);

            Assert.IsTrue(TryParseFormEncodedBody(content, out Dictionary <string, string> parsedBody));

            Assert.IsTrue(parsedBody.TryGetValue("response_type", out string responseType) && responseType == "token");

            Assert.IsTrue(parsedBody.TryGetValue("grant_type", out string grantType) && grantType == "client_credentials");

            Assert.IsTrue(parsedBody.TryGetValue("client_assertion_type", out string assertionType) && assertionType == "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");

            Assert.IsTrue(parsedBody.TryGetValue("client_id", out string actualClientId) && actualClientId == expectedClientId);

            Assert.IsTrue(parsedBody.TryGetValue("scope", out string actualScope) && actualScope == MockScopes.Default.ToString());

            Assert.IsTrue(parsedBody.TryGetValue("client_assertion", out string clientAssertion));

            // var header
            VerifyClientAssertion(clientAssertion, expectedTenantId, expectedClientId, mockCert);
        }
        public async Task VerifyCloudShellMsiRequestWithClientIdMockAsync()
        {
            using (new TestEnvVar("MSI_ENDPOINT", "https://mock.msi.endpoint/"))
                using (new TestEnvVar("MSI_SECRET", null))
                {
                    var response = new MockResponse(200);

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

                    response.SetContent($"{{ \"access_token\": \"{expectedToken}\", \"expires_on\": {(DateTimeOffset.UtcNow + TimeSpan.FromSeconds(3600)).ToUnixTimeSeconds()} }}");

                    var mockTransport = new MockTransport(response);

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

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

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

                    Assert.AreEqual(expectedToken, actualToken.Token);

                    MockRequest request = mockTransport.Requests[0];

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

                    Assert.IsTrue(request.Content.TryComputeLength(out long contentLen));

                    var content = new byte[contentLen];

                    MemoryStream contentBuff = new MemoryStream(content);

                    request.Content.WriteTo(contentBuff, default);

                    string body = Encoding.UTF8.GetString(content);

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

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

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

                    Assert.AreEqual("true", actMetadata);
                }
        }
        public async Task VerifyClientClientSecretRequestAsync()
        {
            var response = new MockResponse(200);

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

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

            var mockTransport = new MockTransport(response);

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

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

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

            var expectedClientSecret = "secret";

            AadIdentityClient client = InstrumentClient(new AadIdentityClient(options: options));

            AccessToken actualToken = await client.AuthenticateAsync(expectedTenantId, expectedClientId, expectedClientSecret, MockScopes.Default);

            Assert.AreEqual(expectedToken, actualToken.Token);

            MockRequest request = mockTransport.SingleRequest;

            Assert.IsTrue(request.Content.TryComputeLength(out long contentLen));

            var content = new byte[contentLen];

            await request.Content.WriteToAsync(new MemoryStream(content), default);

            Assert.IsTrue(TryParseFormEncodedBody(content, out Dictionary <string, string> parsedBody));

            Assert.IsTrue(parsedBody.TryGetValue("response_type", out string responseType) && responseType == "token");

            Assert.IsTrue(parsedBody.TryGetValue("grant_type", out string grantType) && grantType == "client_credentials");

            Assert.IsTrue(parsedBody.TryGetValue("client_id", out string actualClientId) && actualClientId == expectedClientId);

            Assert.IsTrue(parsedBody.TryGetValue("client_secret", out string actualClientSecret) && actualClientSecret == "secret");

            Assert.IsTrue(parsedBody.TryGetValue("scope", out string actualScope) && actualScope == MockScopes.Default.ToString());
        }
        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 AzureCredentialOptions()
            {
                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);
        }
        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 AzureCredentialOptions()
            {
                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));
        }
        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 AzureCredentialOptions()
                    {
                        Transport = mockTransport
                    };

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

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

                    Assert.AreEqual(expectedToken, actualToken.Token);

                    MockRequest request = mockTransport.Requests[0];

                    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($"client_id=mock-client-id"));

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

                    Assert.AreEqual("mock-msi-secret", actSecretValue);
                }
        }
        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 AzureCredentialOptions()
                    {
                        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);
                }
        }
Esempio n. 10
0
        internal static TokenCredential CreateCredential(IConfiguration configuration, AzureCredentialOptions identityClientOptions = null)
        {
            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.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);
        }