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); } }
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); }