コード例 #1
0
        public async Task RunTestWithClientSecretAsync(string clientID, string authority, string secret)
        {
            var popConfig = new PoPAuthenticationConfiguration(new Uri(ProtectedUrl));

            popConfig.HttpMethod = HttpMethod.Get;

            var confidentialApp = ConfidentialClientApplicationBuilder
                                  .Create(clientID)
                                  .WithExperimentalFeatures()
                                  .WithAuthority(PublicCloudTestAuthority)
                                  .WithClientSecret(secret)
                                  .WithTestLogging()
                                  .Build();

            var result = await confidentialApp.AcquireTokenForClient(s_keyvaultScope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                ProtectedUrl,
                HttpMethod.Get,
                result).ConfigureAwait(false);
        }
コード例 #2
0
        public async Task PopTestWithRSAAsync()
        {
            var confidentialApp = ConfidentialClientApplicationBuilder
                                  .Create(PublicCloudConfidentialClientID)
                                  .WithExperimentalFeatures()
                                  .WithAuthority(PublicCloudTestAuthority)
                                  .WithClientSecret(s_publicCloudCcaSecret)
                                  .Build();

            //RSA provider
            var popConfig = new PoPAuthenticationConfiguration(new Uri(ProtectedUrl));

            popConfig.PopCryptoProvider = new RSACertificatePopCryptoProvider(GetCertificate());
            popConfig.HttpMethod        = HttpMethod.Get;

            var result = await confidentialApp.AcquireTokenForClient(s_keyvaultScope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                ProtectedUrl,
                HttpMethod.Get,
                result).ConfigureAwait(false);
        }
コード例 #3
0
        public AcquireTokenInteractiveParameterBuilder WithProofOfPossession(string nonce, HttpMethod httpMethod, Uri requestUri)
        {
            ValidateUseOfExperimentalFeature();
            ClientApplicationBase.GuardMobileFrameworks();

            if (!ServiceBundle.Config.IsBrokerEnabled)
            {
                throw new MsalClientException(MsalError.BrokerRequiredForPop, MsalErrorMessage.BrokerRequiredForPop);
            }

            var broker = ServiceBundle.PlatformProxy.CreateBroker(ServiceBundle.Config, null);

            if (!broker.IsPopSupported)
            {
                throw new MsalClientException(MsalError.BrokerDoesNotSupportPop, MsalErrorMessage.BrokerDoesNotSupportPop);
            }

            PoPAuthenticationConfiguration popConfig = new PoPAuthenticationConfiguration(requestUri);

            if (string.IsNullOrEmpty(nonce))
            {
                throw new ArgumentNullException(nameof(nonce));
            }

            popConfig.Nonce      = nonce;
            popConfig.HttpMethod = httpMethod;

            CommonParameters.PopAuthenticationConfiguration = popConfig;
            CommonParameters.AuthenticationScheme           = new PopBrokerAuthenticationScheme();

            return(this);
        }
コード例 #4
0
        public async Task POP_WithMissingNonceForPCA_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                PublicClientApplication app =
                    PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithBrokerPreview()
                    .WithExperimentalFeatures()
                    .WithHttpManager(httpManager)
                    .BuildConcrete();

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl));
                var popConfig = new PoPAuthenticationConfiguration(request);
                var provider  = PoPProviderFactory.GetOrCreateProvider();

                await AssertException.TaskThrowsAsync <ArgumentNullException>(() =>
                                                                              app.AcquireTokenInteractive(TestConstants.s_scope.ToArray())
                                                                              .WithAuthority(TestConstants.AuthorityUtidTenant)
                                                                              .WithProofOfPossession(null, HttpMethod.Get, new Uri(app.Authority))
                                                                              .ExecuteAsync())
                .ConfigureAwait(false);

                await AssertException.TaskThrowsAsync <ArgumentNullException>(() =>
                                                                              app.AcquireTokenSilent(TestConstants.s_scope.ToArray(), "loginHint")
                                                                              .WithAuthority(TestConstants.AuthorityUtidTenant)
                                                                              .WithProofOfPossession(null, HttpMethod.Get, new Uri(app.Authority))
                                                                              .ExecuteAsync())
                .ConfigureAwait(false);
            }
        }
コード例 #5
0
        public async Task POP_ShrValidation_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithHttpManager(httpManager)
                    .WithExperimentalFeatures(true)
                    .BuildConcrete();

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl));
                var popConfig = new PoPAuthenticationConfiguration(request);
                var provider  = PoPProviderFactory.GetOrCreateProvider();

                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .WithAuthority(TestConstants.AuthorityUtidTenant)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                // access token parsing can be done with MSAL's id token parsing logic
                var claims = IdToken.Parse(result.AccessToken).ClaimsPrincipal;

                Assert.IsTrue(!string.IsNullOrEmpty(claims.FindAll("nonce").Single().Value));
                AssertSingedHttpRequestClaims(provider, claims);
            }
        }
コード例 #6
0
        public async Task RunTestWithClientSecretAsync(string clientID, string authority, string secret)
        {
            var popConfig = new PoPAuthenticationConfiguration(new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b"));

            popConfig.HttpMethod = HttpMethod.Get;

            var confidentialClientAuthority = authority;

            var confidentialApp = ConfidentialClientApplicationBuilder
                                  .Create(clientID)
                                  .WithExperimentalFeatures()
                                  .WithAuthority(new Uri(confidentialClientAuthority), true)
                                  .WithClientSecret(secret)
                                  .WithTestLogging()
                                  .Build();

            var result = await confidentialApp.AcquireTokenForClient(s_keyvaultScope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                clientID,
                popConfig, result).ConfigureAwait(false);
        }
コード例 #7
0
        public async Task PopTestWithECDAsync()
        {
            var confidentialClientAuthority = PublicCloudTestAuthority;

            var confidentialApp = ConfidentialClientApplicationBuilder
                                  .Create(PublicCloudConfidentialClientID)
                                  .WithExperimentalFeatures()
                                  .WithAuthority(new Uri(confidentialClientAuthority), true)
                                  .WithClientSecret(s_publicCloudCcaSecret)
                                  .Build();

            //ECD Provider
            var popConfig = new PoPAuthenticationConfiguration(new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b"));

            popConfig.PopCryptoProvider = new ECDCertificatePopCryptoProvider();
            popConfig.HttpMethod        = HttpMethod.Post;

            var result = await confidentialApp.AcquireTokenForClient(s_keyvaultScope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                popConfig, result).ConfigureAwait(false);
        }
コード例 #8
0
        public async Task PopTest_ExternalWilsonSigning_Async()
        {
            var confidentialApp = ConfidentialClientApplicationBuilder
                                  .Create(PublicCloudConfidentialClientID)
                                  .WithExperimentalFeatures()
                                  .WithAuthority(PublicCloudTestAuthority)
                                  .WithClientSecret(s_publicCloudCcaSecret)
                                  .Build();

            // Create an RSA key Wilson style (SigningCredentials)
            var key            = CreateRsaSecurityKey();
            var popCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256);

            var popConfig = new PoPAuthenticationConfiguration()
            {
                PopCryptoProvider = new SigningCredentialsToPopCryptoProviderAdapter(popCredentials, true),
                SignHttpRequest   = false,
            };

            var result = await confidentialApp.AcquireTokenForClient(s_keyvaultScope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            Assert.AreEqual(
                TokenSource.IdentityProvider,
                result.AuthenticationResultMetadata.TokenSource);

            SignedHttpRequestDescriptor signedHttpRequestDescriptor =
                new SignedHttpRequestDescriptor(
                    result.AccessToken,
                    new IdentityModel.Protocols.HttpRequestData()
            {
                Uri    = new Uri(ProtectedUrl),
                Method = HttpMethod.Post.ToString()
            },
                    popCredentials);
            var    signedHttpRequestHandler = new SignedHttpRequestHandler();
            string req = signedHttpRequestHandler.CreateSignedHttpRequest(signedHttpRequestDescriptor);

            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                ProtectedUrl,
                HttpMethod.Post,
                req, "pop").ConfigureAwait(false);

            var result2 = await confidentialApp.AcquireTokenForClient(s_keyvaultScope)
                          .WithProofOfPossession(popConfig)
                          .ExecuteAsync(CancellationToken.None)
                          .ConfigureAwait(false);

            Assert.AreEqual(
                TokenSource.Cache,
                result2.AuthenticationResultMetadata.TokenSource);
        }
コード例 #9
0
        /// <summary>
        ///  Modifies the token acquisition request so that the acquired token is a Proof of Possession token (PoP), rather than a Bearer token.
        ///  PoP tokens are similar to Bearer tokens, but are bound to the HTTP request and to a cryptographic key, which MSAL can manage on Windows.
        ///  See https://aka.ms/msal-net-pop
        /// </summary>
        /// <param name="popAuthenticationConfiguration">Configuration properties used to construct a proof of possession request.</param>
        /// <returns>The builder.</returns>
        /// <remarks>
        /// <list type="bullet">
        /// <item><description>An Authentication header is automatically added to the request</description></item>
        /// <item><description>The PoP token is bound to the HTTP request, more specifically to the HTTP method (GET, POST, etc.) and to the Uri (path and query, but not query parameters).</description></item>
        /// <item><description>MSAL creates, reads and stores a key in memory that will be cycled every 8 hours.</description></item>
        /// <item><description>This is an experimental API. The method signature may change in the future without involving a major version upgrade.</description></item>
        /// </list>
        /// </remarks>
        public T WithProofOfPossession(PoPAuthenticationConfiguration popAuthenticationConfiguration)
        {
            ValidateUseOfExperimentalFeature();

            CommonParameters.PopAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

            CommonParameters.AuthenticationScheme = new PopAuthenticationScheme(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);

            return(this as T);
        }
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]  // hide confidential client on mobile
#endif
        public AcquireTokenSilentParameterBuilder WithProofOfPossession(PoPAuthenticationConfiguration popAuthenticationConfiguration)
        {
            ClientApplicationBase.GuardMobileFrameworks();
            ValidateUseOfExperimentalFeature();

            CommonParameters.PopAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

            CommonParameters.AuthenticationScheme = new PopAuthenticationScheme(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);

            return(this);
        }
        public void ValidatePopRequestAndToken()
        {
            using (var harness = CreateTestHarness())
            {
                // Arrange
                Uri uri = new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b");
                PoPAuthenticationConfiguration popConfig = new PoPAuthenticationConfiguration(uri);
                popConfig.HttpMethod = HttpMethod.Post;

                var popCryptoProvider = Substitute.For <IPoPCryptoProvider>();
                var serviceBundle     = Substitute.For <IServiceBundle>();
                popCryptoProvider.CannonicalPublicKeyJwk.Returns(JWK);
                popCryptoProvider.CryptographicAlgorithm.Returns("RS256");
                popConfig.PopCryptoProvider = popCryptoProvider;
                const string             AtSecret = "secret";
                MsalAccessTokenCacheItem msalAccessTokenCacheItem = TokenCacheHelper.CreateAccessTokenItem();
                msalAccessTokenCacheItem.Secret = AtSecret;

                // Act
                PopAuthenticationScheme authenticationScheme = new PopAuthenticationScheme(popConfig, harness.ServiceBundle);
                var tokenParams    = authenticationScheme.GetTokenRequestParams();
                var popTokenString = authenticationScheme.FormatAccessToken(msalAccessTokenCacheItem);
                JwtSecurityToken decodedPopToken = new JwtSecurityToken(popTokenString);

                // Assert
                Assert.AreEqual("PoP", authenticationScheme.AuthorizationHeaderPrefix);
                Assert.AreEqual(JWT, authenticationScheme.KeyId);
                Assert.AreEqual(2, tokenParams.Count);
                Assert.AreEqual("pop", tokenParams["token_type"]);

                // This is the base64 URL encoding of the JWK containing only the KeyId
                Assert.AreEqual("eyJraWQiOiJOemJMc1hoOHVEQ2NkLTZNTndYRjRXXzdub1dYRlpBZkhreFpzUkdDOVhzIn0", tokenParams["req_cnf"]);
                Assert.AreEqual("RS256", decodedPopToken.Header.Alg);
                Assert.AreEqual(JWT, decodedPopToken.Header.Kid);
                Assert.AreEqual("pop", decodedPopToken.Header.Typ);
                Assert.AreEqual("RS256", decodedPopToken.SignatureAlgorithm);

                AssertSimpleClaim(decodedPopToken, "at", AtSecret);
                AssertSimpleClaim(decodedPopToken, "m", HttpMethod.Post.ToString());
                AssertSimpleClaim(decodedPopToken, "u", "www.contoso.com");
                AssertSimpleClaim(decodedPopToken, "p", "/path1/path2");

                string nonce = AssertSimpleClaim(decodedPopToken, "nonce");
                Assert.IsFalse(string.IsNullOrEmpty(nonce));
                string jwk = AssertSimpleClaim(decodedPopToken, "cnf");
                var    jwkFromPopAssertion = JToken.Parse(jwk);

                var initialJwk = JToken.Parse(JWK);
                Assert.IsTrue(jwkFromPopAssertion["jwk"].DeepEquals(initialJwk));
            }
        }
        /// <summary>
        /// Creates POP tokens, i.e. tokens that are bound to an HTTP request and are digitally signed.
        /// </summary>
        /// <remarks>
        /// Currently the signing credential algorithm is hard-coded to RSA with SHA256. Extensibility should be done
        /// by integrating Wilson's SigningCredentials
        /// </remarks>
        public PoPAuthenticationScheme(PoPAuthenticationConfiguration popAuthenticationConfiguration, IServiceBundle serviceBundle)
        {
            if (serviceBundle == null)
            {
                throw new ArgumentNullException(nameof(serviceBundle));
            }

            _popAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

            _popAuthenticationConfiguration.PopCryptoProvider = _popAuthenticationConfiguration.PopCryptoProvider ?? serviceBundle.PlatformProxy.GetDefaultPoPCryptoProvider();

            var keyThumbprint = ComputeThumbprint(_popAuthenticationConfiguration.PopCryptoProvider.CannonicalPublicKeyJwk);

            KeyId = Base64UrlHelpers.Encode(keyThumbprint);
        }
コード例 #13
0
        /// <summary>
        ///  Modifies the token acquisition request so that the acquired token is a Proof of Possession token (PoP), rather than a Bearer token.
        ///  PoP tokens are similar to Bearer tokens, but are bound to the HTTP request and to a cryptographic key, which MSAL can manage on Windows.
        ///  See https://aka.ms/msal-net-pop
        /// </summary>
        /// <param name="popAuthenticationConfiguration">Configuration properties used to construct a proof of possession request.</param>
        /// <remarks>
        /// <list type="bullet">
        /// <item> An Authentication header is automatically added to the request</item>
        /// <item> The PoP token is bound to the HTTP request, more specifically to the HTTP method (GET, POST, etc.) and to the Uri (path and query, but not query parameters). </item>
        /// <item> MSAL creates, reads and stores a key in memory that will be cycled every 8 hours.</item>
        /// <item>This is an experimental API. The method signature may change in the future without involving a major version upgrade.</item>
        /// </list>
        /// </remarks>
        public T WithProofOfPossession(PoPAuthenticationConfiguration popAuthenticationConfiguration)
        {
            if (!ServiceBundle.Config.ExperimentalFeaturesEnabled)
            {
                throw new MsalClientException(
                          MsalError.ExperimentalFeature,
                          MsalErrorMessage.ExperimentalFeature(nameof(WithProofOfPossession)));
            }

            CommonParameters.PopAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

            CommonParameters.AddApiTelemetryFeature(ApiTelemetryFeature.WithPoPScheme);
            CommonParameters.AuthenticationScheme = new PoPAuthenticationScheme(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);

            return(this as T);
        }
コード例 #14
0
        public void PopConfig()
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl));
            var popConfig = new PoPAuthenticationConfiguration(request);

            Assert.AreEqual(HttpMethod.Get, popConfig.HttpMethod);
            Assert.AreEqual("www.contoso.com", popConfig.HttpHost);
            Assert.AreEqual("/path1/path2", popConfig.HttpPath);

            request   = new HttpRequestMessage(HttpMethod.Post, new Uri(ProtectedUrlWithPort));
            popConfig = new PoPAuthenticationConfiguration(request);

            Assert.AreEqual(HttpMethod.Post, popConfig.HttpMethod);
            Assert.AreEqual("www.contoso.com:5555", popConfig.HttpHost);
            Assert.AreEqual("/path1/path2", popConfig.HttpPath);
        }
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]  // hide confidential client on mobile
#endif
        public AcquireTokenSilentParameterBuilder WithProofOfPossession(PoPAuthenticationConfiguration popAuthenticationConfiguration)
        {
            ConfidentialClientApplication.GuardMobileFrameworks();

            if (!ServiceBundle.Config.ExperimentalFeaturesEnabled)
            {
                throw new MsalClientException(
                          MsalError.ExperimentalFeature,
                          MsalErrorMessage.ExperimentalFeature(nameof(WithProofOfPossession)));
            }

            CommonParameters.PopAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

            CommonParameters.AddApiTelemetryFeature(ApiTelemetryFeature.WithPoPScheme);
            CommonParameters.AuthenticationScheme = new PoPAuthenticationScheme(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);

            return(this);
        }
        public void NullArgsTest()
        {
            using (var harness = CreateTestHarness())
            {
                Uri                            uri               = new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b");
                HttpMethod                     method            = HttpMethod.Post;
                HttpRequestMessage             httpRequest       = new HttpRequestMessage(method, uri);
                var                            popCryptoProvider = Substitute.For <IPoPCryptoProvider>();
                PoPAuthenticationConfiguration config            = null;

                AssertException.Throws <ArgumentNullException>(() => new PoPAuthenticationScheme(config, harness.ServiceBundle));

                config = new PoPAuthenticationConfiguration(uri);
                config.PopCryptoProvider = new InMemoryCryptoProvider();

                AssertException.Throws <ArgumentNullException>(() => new PoPAuthenticationScheme(config, null));
                AssertException.Throws <ArgumentNullException>(() => new PoPAuthenticationConfiguration(null));
            }
        }
コード例 #17
0
        private async Task BearerAndPoP_CanCoexist_Async()
        {
            // Arrange
            var popConfig = new PoPAuthenticationConfiguration(new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b"));

            popConfig.HttpMethod = HttpMethod.Get;

            //SecureString securePassword = new NetworkCredential("", user.GetOrFetchPassword()).SecurePassword;
            string clientId = PublicCloudConfidentialClientID;

            var pca = ConfidentialClientApplicationBuilder
                      .Create(PublicCloudConfidentialClientID)
                      .WithExperimentalFeatures()
                      .WithClientSecret(s_publicCloudCcaSecret)
                      .WithTestLogging()
                      .WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs).Build();

            ConfigureInMemoryCache(pca);

            // Act - acquire both a PoP and a Bearer token
            Trace.WriteLine("Getting a PoP token");
            AuthenticationResult result = await pca
                                          .AcquireTokenForClient(s_keyvaultScope)
                                          .WithExtraQueryParameters(GetTestSliceParams())
                                          .WithProofOfPossession(popConfig)
                                          .ExecuteAsync()
                                          .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(clientId, popConfig, result).ConfigureAwait(false);

            Trace.WriteLine("Getting a Bearer token");
            result = await pca
                     .AcquireTokenForClient(s_keyvaultScope)
                     .ExecuteAsync()
                     .ConfigureAwait(false);

            Assert.AreEqual("Bearer", result.TokenType);
            Assert.AreEqual(
                2,
                (pca as ConfidentialClientApplication).AppTokenCacheInternal.Accessor.GetAllAccessTokens().Count());
        }
コード例 #18
0
        private async Task BearerAndPoP_CanCoexist_Async()
        {
            // Arrange
            var popConfig = new PoPAuthenticationConfiguration(new Uri(ProtectedUrl));

            popConfig.HttpMethod = HttpMethod.Get;

            var pca = ConfidentialClientApplicationBuilder
                      .Create(PublicCloudConfidentialClientID)
                      .WithExperimentalFeatures()
                      .WithClientSecret(s_publicCloudCcaSecret)
                      .WithTestLogging()
                      .WithAuthority(PublicCloudTestAuthority).Build();

            ConfigureInMemoryCache(pca);

            // Act - acquire both a PoP and a Bearer token
            Trace.WriteLine("Getting a PoP token");
            AuthenticationResult result = await pca
                                          .AcquireTokenForClient(s_keyvaultScope)
                                          .WithProofOfPossession(popConfig)
                                          .ExecuteAsync()
                                          .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                ProtectedUrl,
                HttpMethod.Get,
                result).ConfigureAwait(false);

            Trace.WriteLine("Getting a Bearer token");
            result = await pca
                     .AcquireTokenForClient(s_keyvaultScope)
                     .ExecuteAsync()
                     .ConfigureAwait(false);

            Assert.AreEqual("Bearer", result.TokenType);
            Assert.AreEqual(
                2,
                (pca as ConfidentialClientApplication).AppTokenCacheInternal.Accessor.GetAllAccessTokens().Count());
        }
コード例 #19
0
        public async Task POP_NoHttpRequest_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithHttpManager(httpManager)
                    .WithExperimentalFeatures(true)
                    .BuildConcrete();

                // no HTTP method binding, but custom nonce
                var popConfig = new PoPAuthenticationConfiguration()
                {
                    Nonce = CustomNonce
                };
                var provider = PoPProviderFactory.GetOrCreateProvider();

                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .WithAuthority(TestConstants.AuthorityUtidTenant)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                // access token parsing can be done with MSAL's id token parsing logic
                var claims = IdToken.Parse(result.AccessToken).ClaimsPrincipal;

                Assert.AreEqual(CustomNonce, claims.FindAll("nonce").Single().Value);
                AssertTsAndJwkClaims(provider, claims);

                Assert.IsFalse(claims.FindAll("m").Any());
                Assert.IsFalse(claims.FindAll("u").Any());
                Assert.IsFalse(claims.FindAll("p").Any());
            }
        }
コード例 #20
0
        /// <summary>
        /// This calls a special endpoint that validates any POP token against a configurable HTTP request.
        /// The HTTP request is configured through headers.
        /// </summary>
        private async Task VerifyPoPTokenAsync(string clientId, PoPAuthenticationConfiguration popConfig, AuthenticationResult result)
        {
            var httpClient = new HttpClient();
            HttpResponseMessage response;
            var request = new HttpRequestMessage(HttpMethod.Post, PoPValidatorEndpoint);

            var authHeader = new AuthenticationHeaderValue(result.TokenType, result.AccessToken);

            request.Headers.Add("Secret", _popValidationEndpointSecret);
            request.Headers.Add("Authority", "https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/");
            request.Headers.Add("ClientId", clientId);
            request.Headers.Authorization = authHeader;

            // the URI the POP token is bound to
            request.Headers.Add("ShrUri", popConfig.RequestUri.ToString());

            // the method the POP token in bound to
            request.Headers.Add("ShrMethod", popConfig.HttpMethod.ToString());

            response = await httpClient.SendAsync(request).ConfigureAwait(false);

            Assert.IsTrue(response.IsSuccessStatusCode);
        }
コード例 #21
0
        public static AcquireTokenForClientParameterBuilder WithPoPSignedRequest(
            this AcquireTokenForClientParameterBuilder builder,
            SigningCredentials popCredentials) // TODO: this only supports RSA for now
        {
            if (builder is null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (popCredentials is null)
            {
                throw new ArgumentNullException(nameof(popCredentials));
            }

            var popAuthenticationConfiguration
                = new PoPAuthenticationConfiguration()
                {
                SignHttpRequest   = false,
                PopCryptoProvider = new SigningCredentialsToPopCryptoProviderAdapter(popCredentials, assertNotSigned: true)
                };

            return(builder.WithProofOfPossession(popAuthenticationConfiguration));
        }
        public async Task ValidateKeyExpirationAsync()
        {
            using (var harness = CreateTestHarness())
            {
                harness.HttpManager.AddInstanceDiscoveryMockHandler();
                PoPAuthenticationConfiguration popConfig = new PoPAuthenticationConfiguration(new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b"));
                popConfig.HttpMethod = HttpMethod.Get;

                var app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                          .WithHttpManager(harness.HttpManager)
                          .WithExperimentalFeatures()
                          .WithClientSecret("some-secret")
                          .BuildConcrete();

                TokenCacheHelper.PopulateCache(app.AppTokenCacheInternal.Accessor);

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(
                    authority: TestConstants.AuthorityCommonTenant,
                    responseMessage: MockHelpers.CreateSuccessfulClientCredentialTokenResponseMessage(token: $"header.{Guid.NewGuid()}.signature", tokenType: "pop"));

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(
                    authority: TestConstants.AuthorityCommonTenant,
                    responseMessage: MockHelpers.CreateSuccessfulClientCredentialTokenResponseMessage(token: $"header.{Guid.NewGuid()}.signature", tokenType: "pop"));

                Guid            correlationId = Guid.NewGuid();
                TestTimeService testClock     = new TestTimeService();
                PoPProviderFactory.TimeService = testClock;

                var result = await app.AcquireTokenForClient(TestConstants.s_scope)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync(CancellationToken.None)
                             .ConfigureAwait(false);

                var initialToken = result.AccessToken;

                //Advance time 7 hours. Should still be the same key and token
                testClock.MoveToFuture(TimeSpan.FromHours(7));
                PoPProviderFactory.TimeService = testClock;

                result = await app.AcquireTokenForClient(TestConstants.s_scope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.AreEqual(GetAccessTokenFromPopToken(result.AccessToken), GetAccessTokenFromPopToken(initialToken));
                Assert.AreEqual(GetModulusFromPopToken(result.AccessToken), GetModulusFromPopToken(initialToken));
                Assert.IsTrue(result.AuthenticationResultMetadata.TokenSource == TokenSource.Cache);

                //Advance time 2 hours. Should be a different key
                testClock.MoveToFuture(TimeSpan.FromHours(2));
                PoPProviderFactory.TimeService = testClock;

                result = await app.AcquireTokenForClient(TestConstants.s_scope)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.AreNotEqual(GetModulusFromPopToken(result.AccessToken), GetModulusFromPopToken(initialToken));
                Assert.AreNotEqual(GetAccessTokenFromPopToken(result.AccessToken), GetAccessTokenFromPopToken(initialToken));
                Assert.IsTrue(result.AuthenticationResultMetadata.TokenSource == TokenSource.IdentityProvider);
            }
        }
コード例 #23
0
        public async Task CacheKey_Includes_POPKid_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithHttpManager(httpManager)
                    .WithExperimentalFeatures(true)
                    .BuildConcrete();
                var testTimeService = new TestTimeService();
                PoPProviderFactory.TimeService = testTimeService;

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl));
                var popConfig   = new PoPAuthenticationConfiguration(request);
                var cacheAccess = app.AppTokenCache.RecordAccess();

                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                Trace.WriteLine("1. AcquireTokenForClient ");
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .WithAuthority(TestConstants.AuthorityUtidTenant)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                // Assert
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                string expectedKid    = GetKidFromJwk(PoPProviderFactory.GetOrCreateProvider().CannonicalPublicKeyJwk);
                string actualCacheKey = cacheAccess.LastBeforeAccessNotificationArgs.SuggestedCacheKey;
                Assert.AreEqual(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "{0}{1}_{2}_AppTokenCache",
                        expectedKid,
                        TestConstants.ClientId,
                        TestConstants.Utid),
                    actualCacheKey);

                // Arrange - force a new key by moving to the future
                (PoPProviderFactory.TimeService as TestTimeService).MoveToFuture(
                    PoPProviderFactory.KeyRotationInterval.Add(TimeSpan.FromMinutes(10)));

                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                Trace.WriteLine("1. AcquireTokenForClient again, after time passes - expect POP key rotation");
                result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                         .WithAuthority(TestConstants.AuthorityUtidTenant)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync()
                         .ConfigureAwait(false);

                // Assert
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                string expectedKid2    = GetKidFromJwk(PoPProviderFactory.GetOrCreateProvider().CannonicalPublicKeyJwk);
                string actualCacheKey2 = cacheAccess.LastBeforeAccessNotificationArgs.SuggestedCacheKey;
                Assert.AreEqual(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "{0}{1}_{2}_AppTokenCache",
                        expectedKid2,
                        TestConstants.ClientId,
                        TestConstants.Utid),
                    actualCacheKey2);

                Assert.AreNotEqual(actualCacheKey, actualCacheKey2);
            }
        }
コード例 #24
0
        private async Task AcquireAndAcquireSilent_MultipleKeys_Async(LabResponse labResponse)
        {
            var popConfig1 = new PoPAuthenticationConfiguration(new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b"));

            popConfig1.HttpMethod = HttpMethod.Get;
            var popConfig2 = new PoPAuthenticationConfiguration(new Uri("https://www.bing.com/path3/path4?queryParam5=c&queryParam6=d"));

            popConfig2.HttpMethod = HttpMethod.Post;

            var          user           = labResponse.User;
            SecureString securePassword = new NetworkCredential("", user.GetOrFetchPassword()).SecurePassword;

            var pca = ConfidentialClientApplicationBuilder.Create(PublicCloudConfidentialClientID)
                      .WithExperimentalFeatures()
                      .WithTestLogging()
                      .WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
                      .WithClientSecret(s_publicCloudCcaSecret).Build();

            ConfigureInMemoryCache(pca);

            var result = await pca
                         .AcquireTokenForClient(s_keyvaultScope)
                         .WithExtraQueryParameters(GetTestSliceParams())
                         .WithProofOfPossession(popConfig1)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                popConfig1, result).ConfigureAwait(false);

            // recreate the pca to ensure that the silent call is served from the cache, i.e. the key remains stable
            pca = ConfidentialClientApplicationBuilder
                  .Create(PublicCloudConfidentialClientID)
                  .WithExperimentalFeatures()
                  .WithClientSecret(s_publicCloudCcaSecret)
                  .WithHttpClientFactory(new NoAccessHttpClientFactory()) // token should be served from the cache, no network access necessary
                  .Build();
            ConfigureInMemoryCache(pca);

#pragma warning disable CS0618 // Type or member is obsolete
            var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

#pragma warning restore CS0618 // Type or member is obsolete
            result = await pca
                     .AcquireTokenSilent(s_keyvaultScope, accounts.Single())
                     .WithProofOfPossession(popConfig1)
                     .ExecuteAsync()
                     .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                popConfig1, result).ConfigureAwait(false);

            // Call some other Uri - the same pop assertion can be reused, i.e. no need to call Evo
            result = await pca
                     .AcquireTokenSilent(s_keyvaultScope, accounts.Single())
                     .WithProofOfPossession(popConfig2)
                     .ExecuteAsync()
                     .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                popConfig2, result).ConfigureAwait(false);
        }
        public async Task ValidateKeyExpirationAsync()
        {
            using (var harness = CreateTestHarness())
            {
                harness.HttpManager.AddInstanceDiscoveryMockHandler();
                PoPAuthenticationConfiguration popConfig = new PoPAuthenticationConfiguration(new Uri("https://www.contoso.com/path1/path2?queryParam1=a&queryParam2=b"));
                popConfig.HttpMethod        = HttpMethod.Get;
                popConfig.PopCryptoProvider = new InMemoryCryptoProvider();

                var app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                          .WithHttpManager(harness.HttpManager)
                          .WithExperimentalFeatures()
                          .WithClientSecret("some-secret")
                          .BuildConcrete();

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(
                    TestConstants.AuthorityCommonTenant,
                    null,
                    null,
                    false,
                    MockHelpers.CreateSuccessResponseMessage(MockHelpers.GetPopTokenResponse()));

                Guid      correlationId = Guid.NewGuid();
                TestClock testClock     = new TestClock();
                testClock.TestTime = DateTime.UtcNow;
                var provider = PoPProviderFactory.GetOrCreateProvider(testClock);

                await app.AcquireTokenForClient(TestConstants.s_scope)
                .WithProofOfPossession(popConfig)
                .ExecuteAsync(CancellationToken.None)
                .ConfigureAwait(false);

                var JWK = provider.CannonicalPublicKeyJwk;
                //Advance time 7 hours. Should still be the same key
                testClock.TestTime = testClock.TestTime + TimeSpan.FromSeconds(60 * 60 * 7);

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(
                    TestConstants.AuthorityCommonTenant,
                    null,
                    null,
                    false,
                    MockHelpers.CreateSuccessResponseMessage(MockHelpers.GetPopTokenResponse()));

                provider = PoPProviderFactory.GetOrCreateProvider(testClock);
                await app.AcquireTokenForClient(TestConstants.s_scope)
                .WithProofOfPossession(popConfig)
                .ExecuteAsync(CancellationToken.None)
                .ConfigureAwait(false);

                Assert.IsTrue(JWK == provider.CannonicalPublicKeyJwk);
                //Advance time 2 hours. Should be a different key
                testClock.TestTime = testClock.TestTime + TimeSpan.FromSeconds(60 * 60 * 2);

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(
                    TestConstants.AuthorityCommonTenant,
                    null,
                    null,
                    false,
                    MockHelpers.CreateSuccessResponseMessage(MockHelpers.GetPopTokenResponse()));

                provider = PoPProviderFactory.GetOrCreateProvider(testClock);
                await app.AcquireTokenForClient(TestConstants.s_scope)
                .WithProofOfPossession(popConfig)
                .ExecuteAsync(CancellationToken.None)
                .ConfigureAwait(false);

                Assert.IsTrue(JWK != provider.CannonicalPublicKeyJwk);
            }
        }
コード例 #26
0
        private async Task MultipleKeys_Async()
        {
            var cryptoProvider = new RSACertificatePopCryptoProvider(GetCertificate());

            var popConfig1 = new PoPAuthenticationConfiguration(new Uri(ProtectedUrl));

            popConfig1.HttpMethod        = HttpMethod.Get;
            popConfig1.PopCryptoProvider = cryptoProvider;
            const string OtherProtectedUrl = "https://www.bing.com/path3/path4?queryParam5=c&queryParam6=d";
            var          popConfig2        = new PoPAuthenticationConfiguration(new Uri(OtherProtectedUrl));

            popConfig2.HttpMethod        = HttpMethod.Post;
            popConfig2.PopCryptoProvider = cryptoProvider;

            var cca = ConfidentialClientApplicationBuilder.Create(PublicCloudConfidentialClientID)
                      .WithExperimentalFeatures()
                      .WithTestLogging()
                      .WithAuthority(PublicCloudTestAuthority)
                      .WithClientSecret(s_publicCloudCcaSecret).Build();

            ConfigureInMemoryCache(cca);

            var result = await cca
                         .AcquireTokenForClient(s_keyvaultScope)
                         .WithProofOfPossession(popConfig1)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                ProtectedUrl,
                HttpMethod.Get,
                result).ConfigureAwait(false);

            // recreate the pca to ensure that the silent call is served from the cache, i.e. the key remains stable
            cca = ConfidentialClientApplicationBuilder
                  .Create(PublicCloudConfidentialClientID)
                  .WithExperimentalFeatures()
                  .WithAuthority(PublicCloudTestAuthority)
                  .WithClientSecret(s_publicCloudCcaSecret)
                  .WithHttpClientFactory(new NoAccessHttpClientFactory()) // token should be served from the cache, no network access necessary
                  .Build();
            ConfigureInMemoryCache(cca);

            result = await cca
                     .AcquireTokenForClient(s_keyvaultScope)
                     .WithProofOfPossession(popConfig1)
                     .ExecuteAsync()
                     .ConfigureAwait(false);

            Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
            Assert.AreEqual("pop", result.TokenType);

            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                ProtectedUrl,
                HttpMethod.Get,
                result).ConfigureAwait(false);

            // Call some other Uri - the same pop assertion can be reused, i.e. no need to call Evo
            result = await cca
                     .AcquireTokenForClient(s_keyvaultScope)
                     .WithProofOfPossession(popConfig2)
                     .ExecuteAsync()
                     .ConfigureAwait(false);

            Assert.AreEqual("pop", result.TokenType);
            Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);

            await VerifyPoPTokenAsync(
                PublicCloudConfidentialClientID,
                OtherProtectedUrl,
                HttpMethod.Post,
                result).ConfigureAwait(false);
        }