<commit_before>﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.ServiceModel.Security;
using System.Text;
using System.Threading.Tasks;
using D2L.Security.AuthTokenProvisioning.Default;
using D2L.Security.AuthTokenProvisioning.Invocation;
using Moq;
using NUnit.Framework;

namespace D2L.Security.AuthTokenProvisioning.Tests.Unit.Default {
	
	[TestFixture]
	internal sealed class AuthTokenProviderTests {

		// since the provider tries to deserialize the assertion grant response, 
		// we need one containing valid JSON
		private const string ASSERTION_GRANT_RESPONSE = "{\"access_token\":\"bogus\",\"expires_in\":3600}";

		private static readonly ProvisioningParameters PROVISIONING_PARAMS = new ProvisioningParameters(
			"some_client_id",
			"some_client_secret",
			new string[] { "https://api.brightspace.com/auth/lores.manage" },
			"some_tenant_id",
			"some_tenant_url"
			);

		[Test]
		public void b() {
			byte[] privateKey;
			byte[] publicKey;

			MakeKeyPair( out privateKey, out publicKey );

			string signedToken = CreateAndSignToken( privateKey );
			JwtSecurityToken signatureCheckedToken = CheckSignatureAndGetToken( signedToken, publicKey );
		}

		private static string CreateAndSignToken( byte[] signingKey ) {
			InvocationParameters actualInvocationParams = null;
			Mock<IAuthServiceInvoker> invokerMock = new Mock<IAuthServiceInvoker>();
			invokerMock
				.Setup( x => x.ProvisionAccessToken( It.IsAny<InvocationParameters>() ) )
				.Callback<InvocationParameters>( x => actualInvocationParams = x )
				.Returns( ASSERTION_GRANT_RESPONSE );

			using( RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider( 2048 ) ) {
				rsaService.PersistKeyInCsp = false;
				rsaService.ImportCspBlob( signingKey );

				RsaSecurityKey rsaSecurityKey = new RsaSecurityKey( rsaService );
				SigningCredentials signingCredentials =
					new SigningCredentials( rsaSecurityKey, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest );

				IAuthTokenProvider provider = new AuthTokenProvider(
					signingCredentials,
					invokerMock.Object
					);


				provider.ProvisionAccessToken( PROVISIONING_PARAMS );

				return actualInvocationParams.Assertion;
			}
		}

		private static JwtSecurityToken CheckSignatureAndGetToken( string signedToken, byte[] publicKey ) {
			using( RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider( 2048 ) ) {
				rsaService.PersistKeyInCsp = false;
				rsaService.ImportCspBlob( publicKey );

				RsaSecurityToken rsaScurityToken = new RsaSecurityToken( rsaService );
				SecurityKey securityKey = rsaScurityToken.SecurityKeys[0];

				TokenValidationParameters validationParameters = CreateTokenValidationParameters( securityKey );

				ISecurityTokenValidator tokenHandler = CreateTokenHandler();

				SecurityToken securityToken;
				ClaimsPrincipal principal = tokenHandler.ValidateToken( signedToken, validationParameters, out securityToken );

				return (JwtSecurityToken)securityToken;
			}
		}

		private static void MakeKeyPair( out byte[] privateKey, out byte[] publicKey ) {
			using( RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider( 2048 ) ) {
				rsaService.PersistKeyInCsp = false;

				privateKey = rsaService.ExportCspBlob( true );
				publicKey = rsaService.ExportCspBlob( false );
			}
		}

		private static ISecurityTokenValidator CreateTokenHandler() {
			SecurityTokenHandlerConfiguration tokenHandlerConfiguration =
				new SecurityTokenHandlerConfiguration();
			tokenHandlerConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;
			tokenHandlerConfiguration.CertificateValidator = X509CertificateValidator.None;

			JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
			tokenHandler.Configuration = tokenHandlerConfiguration;

			return tokenHandler;
		}

		private static TokenValidationParameters CreateTokenValidationParameters( SecurityKey securityKey ) {
			TokenValidationParameters validationParameters = new TokenValidationParameters();
			validationParameters.IssuerSigningKey = securityKey;
			validationParameters.ValidateIssuerSigningKey = true;
			validationParameters.ValidateLifetime = false;
			validationParameters.ValidateIssuer = false;
			validationParameters.ValidateAudience = false;
			validationParameters.ValidateActor = false;
			
			return validationParameters;
		}<commit_msg>Cleanup and async test<commit_after>﻿using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Claims;
using System.Security.Cryptography;
using System.ServiceModel.Security;
using System.Threading.Tasks;
using D2L.Security.AuthTokenProvisioning.Default;
using D2L.Security.AuthTokenProvisioning.Invocation;
using Moq;
using NUnit.Framework;

namespace D2L.Security.AuthTokenProvisioning.Tests.Unit.Default {
	
	[TestFixture]
	internal sealed class AuthTokenProviderTests {

		// since the provider tries to deserialize the assertion grant response, 
		// we need one containing valid JSON
		private const string ASSERTION_GRANT_RESPONSE = "{\"access_token\":\"bogus\",\"expires_in\":3600}";

		private static readonly ProvisioningParameters PROVISIONING_PARAMS = new ProvisioningParameters(
			"some_client_id",
			"some_client_secret",
			new string[] { "https://api.brightspace.com/auth/lores.manage" },
			"some_tenant_id",
			"some_tenant_url"
			) {
			UserId = "some_user_id"
		};

		[Test]
		public void ProvisionAccessToken_AssertionTokenIsSigned() {
			byte[] privateKey;
			byte[] publicKey;
			MakeKeyPair( out privateKey, out publicKey );

			InvocationParameters actualInvocationParams = null;
			Mock<IAuthServiceInvoker> invokerMock = new Mock<IAuthServiceInvoker>();
			invokerMock
				.Setup( x => x.ProvisionAccessToken( It.IsAny<InvocationParameters>() ) )
				.Callback<InvocationParameters>( x => actualInvocationParams = x )
				.Returns( ASSERTION_GRANT_RESPONSE );

			SignToken( invokerMock.Object, privateKey );
			string signedToken = actualInvocationParams.Assertion;

			JwtSecurityToken signatureCheckedToken = CheckSignatureAndGetToken( signedToken, publicKey );
			Assert.AreEqual( PROVISIONING_PARAMS.UserId, signatureCheckedToken.Subject );
		}

		[Test]
		public async void ProvisionAccessTokenAsync_AssertionTokenIsSigned() {
			byte[] privateKey;
			byte[] publicKey;
			MakeKeyPair( out privateKey, out publicKey );

			InvocationParameters actualInvocationParams = null;
			Mock<IAuthServiceInvoker> invokerMock = new Mock<IAuthServiceInvoker>();
			invokerMock
				.Setup( x => x.ProvisionAccessTokenAsync( It.IsAny<InvocationParameters>() ) )
				.Callback<InvocationParameters>( x => actualInvocationParams = x )
				.Returns( () => Task.FromResult<string>( ASSERTION_GRANT_RESPONSE ) );

			await SignTokenAsync( invokerMock.Object, privateKey );
			string signedToken = actualInvocationParams.Assertion;

			JwtSecurityToken signatureCheckedToken = CheckSignatureAndGetToken( signedToken, publicKey );
			Assert.AreEqual( PROVISIONING_PARAMS.UserId, signatureCheckedToken.Subject );
		}

		private static void SignToken( IAuthServiceInvoker serviceInvoker, byte[] signingKey ) {

			using( RSACryptoServiceProvider rsaService = MakeCryptoServiceProvider() ) {
				rsaService.ImportCspBlob( signingKey );

				RsaSecurityKey rsaSecurityKey = new RsaSecurityKey( rsaService );
				SigningCredentials signingCredentials =	new SigningCredentials( 
					rsaSecurityKey, 
					SecurityAlgorithms.RsaSha256Signature, 
					SecurityAlgorithms.Sha256Digest 
					);

				IAuthTokenProvider provider = new AuthTokenProvider(
					signingCredentials,
					serviceInvoker
					);

				provider.ProvisionAccessToken( PROVISIONING_PARAMS );
			}
		}

		private async static Task SignTokenAsync( IAuthServiceInvoker serviceInvoker, byte[] signingKey ) {

			using( RSACryptoServiceProvider rsaService = MakeCryptoServiceProvider() ) {
				rsaService.ImportCspBlob( signingKey );

				RsaSecurityKey rsaSecurityKey = new RsaSecurityKey( rsaService );
				SigningCredentials signingCredentials = new SigningCredentials(
					rsaSecurityKey,
					SecurityAlgorithms.RsaSha256Signature,
					SecurityAlgorithms.Sha256Digest
					);

				IAuthTokenProvider provider = new AuthTokenProvider(
					signingCredentials,
					serviceInvoker
					);

				await provider.ProvisionAccessTokenAsync( PROVISIONING_PARAMS );
			}
		}

		private static JwtSecurityToken CheckSignatureAndGetToken( string signedToken, byte[] publicKey ) {
			using( RSACryptoServiceProvider rsaService = MakeCryptoServiceProvider() ) {
				rsaService.ImportCspBlob( publicKey );

				RsaSecurityToken rsaScurityToken = new RsaSecurityToken( rsaService );
				SecurityKey securityKey = rsaScurityToken.SecurityKeys[0];

				TokenValidationParameters validationParameters = CreateTokenValidationParameters( securityKey );
				ISecurityTokenValidator tokenHandler = CreateTokenHandler();

				SecurityToken securityToken;
				ClaimsPrincipal principal = tokenHandler.ValidateToken( signedToken, validationParameters, out securityToken );

				return (JwtSecurityToken)securityToken;
			}
		}

		private static void MakeKeyPair( out byte[] privateKey, out byte[] publicKey ) {
			using( RSACryptoServiceProvider rsaService = MakeCryptoServiceProvider() ) {
				privateKey = rsaService.ExportCspBlob( true );
				publicKey = rsaService.ExportCspBlob( false );
			}
		}

		private static RSACryptoServiceProvider MakeCryptoServiceProvider() {
			RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider( 2048 );
			rsaService.PersistKeyInCsp = false;
			return rsaService;
		}

		private static ISecurityTokenValidator CreateTokenHandler() {
			SecurityTokenHandlerConfiguration tokenHandlerConfiguration =
				new SecurityTokenHandlerConfiguration();
			tokenHandlerConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;
			tokenHandlerConfiguration.CertificateValidator = X509CertificateValidator.None;

			JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
			tokenHandler.Configuration = tokenHandlerConfiguration;

			return tokenHandler;
		}

		private static TokenValidationParameters CreateTokenValidationParameters( SecurityKey securityKey ) {
			TokenValidationParameters validationParameters = new TokenValidationParameters();
			validationParameters.IssuerSigningKey = securityKey;
			validationParameters.ValidateIssuerSigningKey = true;
			validationParameters.ValidateLifetime = false;
			validationParameters.ValidateIssuer = false;
			validationParameters.ValidateAudience = false;
			validationParameters.ValidateActor = false;
			
			return validationParameters;
		}
{'fraction_non_alphanumeric': 0.07450545387317434, 'fraction_numerical': 0.005731188759474949, 'mean_word_length': 5.375368296994696, 'pattern_counts': {'":': 4, '<': 16, '<?xml version=': 0, '>': 23, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2567979', 'n_tokens_mistral': 3441, 'n_tokens_neox': 2929, 'n_words': 607}