using Microsoft.AspNetCore.Http; using Moq; using Strata.ContinuousImprovement.Api.Test.Integration.Setup; using Strata.ContinuousImprovement.Biz.Configuration; using Strata.ContinuousImprovement.Biz.DbContexts; using Strata.ContinuousImprovement.Biz.OpportunityTypeWorkbooks; using Strata.ContinuousImprovement.Biz.OpportunityWorkbooks; using Strata.CoreLib.Claims; using Strata.CoreLib.Claims.Extensions; using System.IdentityModel.Tokens.Jwt; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Security.Claims; using System.Text.Json; namespace Strata.ContinuousImprovement.Api.Test.Integration.Tests { public class ApiTestBase { protected StrataTokenInfo StrataTokenInfo { get; set; } protected string AccessToken { get; set; } protected IEnumerable Claims { get; set; } protected long Expires_in { get; set; } protected ClaimsIdentity ClaimsIdentity { get; set; } protected ClaimsPrincipal ClaimsPrincipal { get; set; } protected Dictionary ClaimsPrincipals { get; set; } = new Dictionary(); internal IClaimsPrincipalAccessor ClaimsPrincipalAccessor { get; set; } internal int StrataId { get; set; } internal Guid DatabaseGuid { get; set; } protected readonly string BaseAddress = "https://continuousimprovement-api.dev.stratanetwork.net"; public IConfigurationService ConfigurationService { get; set; } public CentralDbContext CentralDbContext { get; set; } public IOpportunityWorkbookService OpportunityWorkbookService { get; set; } #pragma warning disable NUnit1032 // An IDisposable field/property should be Disposed in a TearDown method public IServiceProvider ServiceProvider { get; set; } #pragma warning restore NUnit1032 // An IDisposable field/property should be Disposed in a TearDown method public OpportunityWorkbook OpportunityWorkbook { get; set; } public OpportunityTypeWorkbook OpportunityTypeWorkbook { get; set; } [OneTimeSetUp] public async Task TestSetup() { #if DEBUG //When running locally sets the profile to the CI profile so you have access to resources Environment.SetEnvironmentVariable("AWS_Profile", "sdt-continuous-improvement-service-role"); #endif var strataBearer = await StrataValidation(); await ClientValidation(); var services = ServiceCollectionFactory.Create(); await services.SetupServiceProperties(StrataId); ServiceProvider = ServiceProperties.ServiceProvider; var httpClient = new HttpClient { BaseAddress = new Uri(BaseAddress) }; httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken); CentralDbContext = (CentralDbContext)ServiceProperties.CentralDbContext; } protected HttpClient HttpClient; [SetUp] public void SetupHttpClient() { HttpClient = new HttpClient { BaseAddress = new Uri(BaseAddress) }; HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken); } [TearDown] public void TearDownHttpClient() { HttpClient.Dispose(); } #region Client Claims Validation public async Task ClientValidation() { var userInfo = new VaultUserInfo { vaultTitle = "ccicostleader", // vault ccicostleader is same as jazz ccicostleader vaultUserName = "ccicostleader", userName = "ccicostleader", fullName = "Administrator, CCI" }; return await ClientValidation(userInfo); } public async Task StrataValidation() { var userInfo = new VaultUserInfo { vaultTitle = "IDTestUser", // vault ccicostleader is same as jazz ccicostleader vaultUserName = "sdt\\IDTestUser", // vault ccicostleader is same as jazz ccicostleader userName = "sdt\\IDTestUser", fullName = "Administrator, CCI" }; return await ClientValidation(userInfo); } public async Task ClientValidation(VaultUserInfo userInfo) { var vaultInfo = await GetUserPassword(userInfo.vaultTitle); var bearerToken = await GetBearerToken(vaultInfo.Item1, vaultInfo.Item2); ClaimsIdentity = new ClaimsIdentity(Claims); ClaimsPrincipal = new ClaimsPrincipal(ClaimsIdentity); ClaimsPrincipals.Add(userInfo.vaultTitle, ClaimsPrincipal); StrataId = ClaimsPrincipal.GetStrataId(); DatabaseGuid = ClaimsPrincipal.GetDatabaseGuid(); BuildClaimsPrincipalAccessor(); return bearerToken; } internal async Task> GetUserPassword(string vaultTitle) { var client = new HttpClient { BaseAddress = new Uri("https://vault.sdt.local/") }; client.DefaultRequestHeaders.Add("apiKey", "a69d2e478c3f5b395b687ecdf34a3239"); client.DefaultRequestHeaders.Add("ignoreHTTPSErrors", "true"); var vaultResponse = await client.GetAsync($"api/searchpasswords/122?title={vaultTitle}"); vaultResponse.EnsureSuccessStatusCode(); string responseString = await vaultResponse.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(responseString)) { return new Tuple(string.Empty, string.Empty); } var jsonResponse = JsonSerializer.Deserialize>(responseString); if (jsonResponse == null) { return new Tuple(string.Empty, string.Empty); } var vaultUserInfo = jsonResponse.First(); client.Dispose(); return new Tuple(vaultUserInfo.UserName, vaultUserInfo.Password); } internal async Task GetBearerToken(string userName, string password) { var form = BuildTokenRequest(userName, password); var client = new HttpClient(); var response = await client.PostAsync("https://identity.dev.stratanetwork.net/connect/token", form); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(responseString)) { return string.Empty; } var strataTokenInfo = JsonSerializer.Deserialize(responseString); if (strataTokenInfo == null) { return string.Empty; } StrataTokenInfo = strataTokenInfo; AccessToken = strataTokenInfo.AccessToken; Expires_in = strataTokenInfo.ExpiresIn; var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadJwtToken(AccessToken); Claims = jwtToken.Claims; client.Dispose(); return AccessToken; } internal FormUrlEncodedContent BuildTokenRequest(string userName, string password) { var form = new FormUrlEncodedContent( [ new KeyValuePair("database_guid", ServiceProperties.DatabaseGuid.ToString()), new KeyValuePair("grant_type", "password"), new KeyValuePair("username", userName), new KeyValuePair("password", password), new KeyValuePair("scope", "strata.api.external offline_access"), new KeyValuePair("client_id", "IntegrationTest"), new KeyValuePair("client_secret", "UhAEQsGByTCrwPdHPLmaet_DmLEfcJVbZqGBxArdeRup_TPLrYKNpUNRHejjdnhd") ]); return form; } internal void BuildClaimsPrincipalAccessor() { try { var claimsAccessor = Mock.Of(); Mock.Get(claimsAccessor) .Setup(s => s.GetCurrentClaimsPrincipal()) .Returns(ClaimsPrincipal); ClaimsPrincipalAccessor = claimsAccessor; } catch (Exception) { throw; } } #endregion #region Helper Methods protected async Task> GetConfigurations() { string ConfigurationsEndpoint = "api/v1/configurations"; var request = new HttpRequestMessage(HttpMethod.Get, ConfigurationsEndpoint); var response = await HttpClient.SendAsync(request, CancellationToken.None); response.EnsureSuccessStatusCode(); var configurations = await response.Content.ReadFromJsonAsync>(); #pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one configurations = configurations?.OrderBy(x => x.DisplayOrder) ?? throw new ArgumentNullException(nameof(configurations)); #pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one return configurations; } #endregion } public class VaultUserInfo { public string vaultTitle { get; set; } public string vaultUserName { get; set; } public string userName { get; set; } public string fullName { get; set; } } }