public async Task FromX509Certificate2()
        {
            var tenantId = TestEnvironment.ServicePrincipalTenantId;
            var clientId = TestEnvironment.ServicePrincipalClientId;
            var cert     = new X509Certificate2(TestEnvironment.ServicePrincipalCertificatePfxPath);

            var options = InstrumentClientOptions(new TokenCredentialOptions());

            var credential = new ClientCertificateCredential(tenantId, clientId, cert, options);

            var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });

            // ensure we can initially acquire a  token
            AccessToken token = await credential.GetTokenAsync(tokenRequestContext);

            Assert.IsNotNull(token.Token);

            // ensure subsequent calls before the token expires are served from the token cache
            AccessToken cachedToken = await credential.GetTokenAsync(tokenRequestContext);

            Assert.AreEqual(token.Token, cachedToken.Token);

            // ensure new credentials don't share tokens from the cache
            var credential2 = new ClientCertificateCredential(tenantId, clientId, cert, options);

            AccessToken token2 = await credential2.GetTokenAsync(tokenRequestContext);

            // this assert is conditional because the access token is scrubbed in the recording so they will never be different
            if (Mode != RecordedTestMode.Playback && Mode != RecordedTestMode.None)
            {
                Assert.AreNotEqual(token.Token, token2.Token);
            }
        }
Пример #2
0
        public async Task VerifyClientCertificateRequestFailedAsync(bool usePemFile)
        {
            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 certificatePath    = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx");
            var certificatePathPem = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pem");
            var mockCert           = new X509Certificate2(certificatePath, "password");

            ClientCertificateCredential credential = InstrumentClient(
                usePemFile ? new ClientCertificateCredential(expectedTenantId, expectedClientId, certificatePathPem, options) : new ClientCertificateCredential(expectedTenantId, expectedClientId, mockCert, options)
                );

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

            await Task.CompletedTask;
        }
Пример #3
0
        public async Task VerifyClientCertificateRequestAsync(bool usePemFile)
        {
            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 TokenCredentialOptions()
            {
                Transport = mockTransport
            };

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

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

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

            ClientCertificateCredential credential = InstrumentClient(
                usePemFile ? new ClientCertificateCredential(expectedTenantId, expectedClientId, certificatePathPem, options) : new ClientCertificateCredential(expectedTenantId, expectedClientId, mockCert, options)
                );

            AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(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);
        }
        //MSAL doesn't cache Service Principal into msal.cache
        public override Task <IAccessToken> Authenticate(AuthenticationParameters parameters, CancellationToken cancellationToken)
        {
            var spParameters = parameters as ServicePrincipalParameters;
            var onPremise    = spParameters.Environment.OnPremise;
            var tenantId     = onPremise ? AdfsTenant :
                               (string.Equals(parameters.TenantId, OrganizationsTenant, StringComparison.OrdinalIgnoreCase) ? null : parameters.TenantId);
            var resource  = spParameters.Environment.GetEndpoint(spParameters.ResourceId) ?? spParameters.ResourceId;
            var scopes    = AuthenticationHelpers.GetScope(onPremise, resource);
            var clientId  = spParameters.ApplicationId;
            var authority = spParameters.Environment.ActiveDirectoryAuthority;

            var requestContext = new TokenRequestContext(scopes);

            var options = new ClientCertificateCredentialOptions()
            {
                AuthorityHost = new Uri(authority)
            };

            if (!string.IsNullOrEmpty(spParameters.Thumbprint))
            {
                //Service Principal with Certificate
                ClientCertificateCredential certCredential;
                if (!ClientCertCredentialMap.TryGetValue(spParameters.ApplicationId, out certCredential))
                {
                    //first time login
                    var certificate = AzureSession.Instance.DataStore.GetCertificate(spParameters.Thumbprint);
                    certCredential = new ClientCertificateCredential(tenantId, spParameters.ApplicationId, certificate, options);
                    var tokenTask = certCredential.GetTokenAsync(requestContext, cancellationToken);
                    return(MsalAccessToken.GetAccessTokenAsync(tokenTask,
                                                               () => { ClientCertCredentialMap[spParameters.ApplicationId] = certCredential; },
                                                               spParameters.TenantId,
                                                               spParameters.ApplicationId));
                }
                else
                {
                    var tokenTask = certCredential.GetTokenAsync(requestContext, cancellationToken);
                    return(MsalAccessToken.GetAccessTokenAsync(tokenTask, spParameters.TenantId, spParameters.ApplicationId));
                }
            }
            else if (spParameters.Secret != null)
            {
                // service principal with secret
                var secretCredential = new ClientSecretCredential(tenantId, spParameters.ApplicationId, spParameters.Secret.ConvertToString(), options);
                var tokenTask        = secretCredential.GetTokenAsync(requestContext, cancellationToken);
                return(MsalAccessToken.GetAccessTokenAsync(
                           tokenTask,
                           spParameters.TenantId,
                           spParameters.ApplicationId));
            }
            else
            {
                throw new MsalException(MsalError.AuthenticationFailed, string.Format(AuthenticationFailedMessage, clientId));
            }
        }
        public void IncorrectCertificate()
        {
            var tenantId = TestEnvironment.ServicePrincipalTenantId;
            var clientId = TestEnvironment.ServicePrincipalClientId;
            var certPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx");

            var options = InstrumentClientOptions(new TokenCredentialOptions());

            var credential = new ClientCertificateCredential(tenantId, clientId, new X509Certificate2(certPath), options);

            var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });

            // ensure the incorrect client claim is rejected, handled and wrapped in AuthenticationFailedException
            Assert.ThrowsAsync <AuthenticationFailedException>(async() => await credential.GetTokenAsync(tokenRequestContext));
        }
        public async Task AuthnenticateWithAssertionCallback(bool useAsyncCallback)
        {
            var tenantId = TestEnvironment.ServicePrincipalTenantId;
            var clientId = TestEnvironment.ServicePrincipalClientId;
            var cert     = new X509Certificate2(TestEnvironment.ServicePrincipalCertificatePfxPath);

            var options = InstrumentClientOptions(new ClientAssertionCredentialOptions());

            ClientAssertionCredential credential;

            if (useAsyncCallback)
            {
                Func <CancellationToken, Task <string> > assertionCallback = (ct) => Task.FromResult(CreateClientAssertionJWT(options.AuthorityHost, clientId, tenantId, cert));

                credential = InstrumentClient(new ClientAssertionCredential(tenantId, clientId, assertionCallback, options));
            }
            else
            {
                Func <string> assertionCallback = () => CreateClientAssertionJWT(options.AuthorityHost, clientId, tenantId, cert);

                credential = InstrumentClient(new ClientAssertionCredential(tenantId, clientId, assertionCallback, options));
            }

            var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(new Uri(TestEnvironment.AuthorityHostUrl)) });

            // ensure we can initially acquire a  token
            AccessToken token = await credential.GetTokenAsync(tokenRequestContext);

            Assert.IsNotNull(token.Token);

            // ensure subsequent calls before the token expires are served from the token cache
            AccessToken cachedToken = await credential.GetTokenAsync(tokenRequestContext);

            Assert.AreEqual(token.Token, cachedToken.Token);

            // ensure new credentials don't share tokens from the cache
            var credential2 = new ClientCertificateCredential(tenantId, clientId, cert, options);

            AccessToken token2 = await credential2.GetTokenAsync(tokenRequestContext);

            // this assert is conditional because the access token is scrubbed in the recording so they will never be different
            if (Mode != RecordedTestMode.Playback && Mode != RecordedTestMode.None)
            {
                Assert.AreNotEqual(token.Token, token2.Token);
            }
        }
        public async Task IncludeX5CCliamHeader()
        {
            var tenantId = TestEnvironment.ServicePrincipalTenantId;
            var clientId = TestEnvironment.ServicePrincipalClientId;
            var certPath = TestEnvironment.ServicePrincipalSniCertificatePath;

            var options = InstrumentClientOptions(new ClientCertificateCredentialOptions {
                IncludeX5CCliamHeader = true
            });

            var credential = new ClientCertificateCredential(tenantId, clientId, certPath, options);

            var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });

            // ensure we can initially acquire a  token
            AccessToken token = await credential.GetTokenAsync(tokenRequestContext);

            Assert.IsNotNull(token.Token);
        }
Пример #8
0
        public void VerifyBadCertificateFileBehavior()
        {
            var tenantId = Guid.NewGuid().ToString();
            var clientId = Guid.NewGuid().ToString();

            TokenRequestContext tokenContext = new TokenRequestContext(MockScopes.Default);

            ClientCertificateCredential missingFileCredential   = new ClientCertificateCredential(tenantId, clientId, Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "notfound.pem"));
            ClientCertificateCredential invalidPemCredential    = new ClientCertificateCredential(tenantId, clientId, Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert-invalid-data.pem"));
            ClientCertificateCredential unknownFormatCredential = new ClientCertificateCredential(tenantId, clientId, Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.unknown"));
            ClientCertificateCredential encryptedCredential     = new ClientCertificateCredential(tenantId, clientId, Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx"));

            Assert.Throws <CredentialUnavailableException>(() => missingFileCredential.GetToken(tokenContext));
            Assert.Throws <CredentialUnavailableException>(() => invalidPemCredential.GetToken(tokenContext));
            Assert.Throws <CredentialUnavailableException>(() => unknownFormatCredential.GetToken(tokenContext));
            Assert.Throws <CredentialUnavailableException>(() => encryptedCredential.GetToken(tokenContext));
            Assert.ThrowsAsync <CredentialUnavailableException>(async() => await missingFileCredential.GetTokenAsync(tokenContext));
            Assert.ThrowsAsync <CredentialUnavailableException>(async() => await invalidPemCredential.GetTokenAsync(tokenContext));
            Assert.ThrowsAsync <CredentialUnavailableException>(async() => await unknownFormatCredential.GetTokenAsync(tokenContext));
            Assert.ThrowsAsync <CredentialUnavailableException>(async() => await encryptedCredential.GetTokenAsync(tokenContext));
        }
Пример #9
0
        public async Task VerifyClientCertificateCredentialExceptionAsync(bool usePemFile)
        {
            string expectedInnerExMessage = Guid.NewGuid().ToString();

            var mockAadClient = new MockAadIdentityClient(() => { throw new MockClientException(expectedInnerExMessage); });

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

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

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

            ClientCertificateCredential credential = InstrumentClient(
                usePemFile ? new ClientCertificateCredential(expectedTenantId, expectedClientId, certificatePathPem, CredentialPipeline.GetInstance(null), mockAadClient) : new ClientCertificateCredential(expectedTenantId, expectedClientId, mockCert, CredentialPipeline.GetInstance(null), mockAadClient)
                );

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

            Assert.IsNotNull(ex.InnerException);

            Assert.IsInstanceOf(typeof(MockClientException), ex.InnerException);

            Assert.AreEqual(expectedInnerExMessage, ex.InnerException.Message);

            await Task.CompletedTask;
        }
 public async override ValueTask <AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
 {
     return(await _credential.GetTokenAsync(requestContext, cancellationToken));
 }