diff --git a/loadbalancer/nginx.conf b/loadbalancer/nginx.conf index ab5ceb1f..9b04c23d 100644 --- a/loadbalancer/nginx.conf +++ b/loadbalancer/nginx.conf @@ -23,6 +23,12 @@ http { client_max_body_size 50M; + # Set timeout to 1 hour (helps when debugging) + proxy_connect_timeout 3600; + proxy_send_timeout 3600; + proxy_read_timeout 3600; + send_timeout 3600; + sendfile on; upstream localtest { diff --git a/src/Clients/CdnAltinnOrgs/AltinnOrgsClient.cs b/src/Clients/CdnAltinnOrgs/AltinnOrgsClient.cs new file mode 100644 index 00000000..14076320 --- /dev/null +++ b/src/Clients/CdnAltinnOrgs/AltinnOrgsClient.cs @@ -0,0 +1,26 @@ +#nullable enable +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; + +namespace LocalTest.Clients.CdnAltinnOrgs; + +/// +/// Access data from https://altinncdn.no/orgs/altinn-orgs.json +/// +public class AltinnOrgsClient +{ + private static JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions(JsonSerializerDefaults.Web); + private readonly HttpClient _client; + + public AltinnOrgsClient(HttpClient client) + { + _client = client; + } + + public async Task GetCdnOrgs() + { + var orgsJson = await _client.GetByteArrayAsync("https://altinncdn.no/orgs/altinn-orgs.json"); + return JsonSerializer.Deserialize(orgsJson, JSON_OPTIONS) ?? throw new JsonException("altinn-orgs respones was \"null\""); + } +} diff --git a/src/Clients/CdnAltinnOrgs/Models.cs b/src/Clients/CdnAltinnOrgs/Models.cs new file mode 100644 index 00000000..9bcd6cf5 --- /dev/null +++ b/src/Clients/CdnAltinnOrgs/Models.cs @@ -0,0 +1,42 @@ +#nullable enable +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace LocalTest.Clients.CdnAltinnOrgs; + +public class CdnOrgs +{ + [JsonPropertyName("orgs")] + public Dictionary? Orgs { get; set; } +} + +public class CdnOrg +{ + [JsonPropertyName("name")] + public CdnOrgName? Name { get; set; } + + [JsonPropertyName("logo")] + public string? Logo { get; set; } + + [JsonPropertyName("orgnr")] + public string? Orgnr { get; set; } + + [JsonPropertyName("homepage")] + public string? Homepage { get; set; } + + [JsonPropertyName("environments")] + public List? Environments { get; set; } + +} + +public class CdnOrgName +{ + [JsonPropertyName("nb")] + public string? Nb { get; set; } + + [JsonPropertyName("nn")] + public string? Nn { get; set; } + + [JsonPropertyName("en")] + public string? En { get; set; } +} diff --git a/src/Configuration/Authentication/GeneralSettings.cs b/src/Configuration/Authentication/GeneralSettings.cs index 2311de4e..6dd48674 100644 --- a/src/Configuration/Authentication/GeneralSettings.cs +++ b/src/Configuration/Authentication/GeneralSettings.cs @@ -105,11 +105,11 @@ public string GetClaimsIdentity /// /// Gets the jwt cookie validity time from kubernetes environment variables and appsettings if environment variable is not set /// - public string GetJwtCookieValidityTime + public int GetJwtCookieValidityTime { get { - return Environment.GetEnvironmentVariable("GeneralSettings__GetJwtCookieValidityTime") ?? JwtCookieValidityTime; + return Convert.ToInt32(Environment.GetEnvironmentVariable("GeneralSettings__GetJwtCookieValidityTime") ?? JwtCookieValidityTime); } } diff --git a/src/Controllers/Authentication/AuthenticationController.cs b/src/Controllers/Authentication/AuthenticationController.cs index 91458701..3d850e82 100644 --- a/src/Controllers/Authentication/AuthenticationController.cs +++ b/src/Controllers/Authentication/AuthenticationController.cs @@ -44,7 +44,7 @@ public async Task RefreshJWTCookie() ClaimsPrincipal principal = HttpContext.User; _logger.LogInformation("Refreshing token...."); - string token = _authenticationService.GenerateToken(principal, Convert.ToInt32(_generalSettings.JwtCookieValidityTime)); + string token = _authenticationService.GenerateToken(principal); _logger.LogInformation("End of refreshing token"); return await Task.FromResult(Ok(token)); } @@ -69,8 +69,8 @@ public async Task GenerateOrgToken( identity.AddClaims(claims); ClaimsPrincipal principal = new ClaimsPrincipal(identity); - string token = _authenticationService.GenerateToken(principal, Convert.ToInt32(_generalSettings.JwtCookieValidityTime)); - + string token = _authenticationService.GenerateToken(principal); + return await Task.FromResult(Ok(token)); } @@ -91,8 +91,8 @@ public async Task GenerateAppToken( identity.AddClaims(claims); ClaimsPrincipal principal = new ClaimsPrincipal(identity); - string token = _authenticationService.GenerateToken(principal, Convert.ToInt32(_generalSettings.JwtCookieValidityTime)); - + string token = _authenticationService.GenerateToken(principal); + return await Task.FromResult(Ok(token)); } } diff --git a/src/Controllers/HomeController.cs b/src/Controllers/HomeController.cs index f996fdd7..dcd8f1ff 100644 --- a/src/Controllers/HomeController.cs +++ b/src/Controllers/HomeController.cs @@ -78,6 +78,7 @@ public async Task Index() model.StaticTestDataPath = _localPlatformSettings.LocalTestingStaticTestDataPath; model.LocalAppUrl = _localPlatformSettings.LocalAppUrl; var defaultAuthLevel = _localPlatformSettings.LocalAppMode == "http" ? await GetAppAuthLevel(model.TestApps) : 2; + model.AppModeIsHttp = _localPlatformSettings.LocalAppMode == "http"; model.AuthenticationLevels = GetAuthenticationLevels(defaultAuthLevel); model.LocalFrontendUrl = HttpContext.Request.Cookies[FRONTEND_URL_COOKIE_NAME]; @@ -111,21 +112,9 @@ public async Task LogInTestUser(StartAppModel startAppModel) if (startAppModel.AuthenticationLevel != "-1") { UserProfile profile = await _userProfileService.GetUser(startAppModel.UserId); + int authenticationLevel = Convert.ToInt32(startAppModel.AuthenticationLevel); - List claims = new List(); - string issuer = _generalSettings.Hostname; - claims.Add(new Claim(ClaimTypes.NameIdentifier, profile.UserId.ToString(), ClaimValueTypes.String, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.UserId, profile.UserId.ToString(), ClaimValueTypes.String, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.UserName, profile.UserName, ClaimValueTypes.String, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.PartyID, profile.PartyId.ToString(), ClaimValueTypes.Integer32, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.AuthenticationLevel, startAppModel.AuthenticationLevel, ClaimValueTypes.Integer32, issuer)); - claims.AddRange(await _claimsService.GetCustomClaims(profile.UserId, issuer)); - - ClaimsIdentity identity = new ClaimsIdentity(_generalSettings.GetClaimsIdentity); - identity.AddClaims(claims); - ClaimsPrincipal principal = new ClaimsPrincipal(identity); - - string token = _authenticationService.GenerateToken(principal, int.Parse(_generalSettings.GetJwtCookieValidityTime)); + string token = await _authenticationService.GenerateTokenForProfile(profile, authenticationLevel); CreateJwtCookieAndAppendToResponse(token); } @@ -134,6 +123,43 @@ public async Task LogInTestUser(StartAppModel startAppModel) // Ensure that the documentstorage in LocalTestingStorageBasePath is updated with the most recent app data await _applicationRepository.Update(app); + if(_localPlatformSettings.LocalAppMode == "http") + { + // Instantiate a prefill if a file attachment exists. + var prefill = Request.Form.Files.FirstOrDefault(); + if (prefill != null) + { + var instance = new Instance{ + AppId = app.Id, + Org = app.Org, + InstanceOwner = new(), + DataValues = new(), + }; + + var owner = prefill.FileName.Split(".")[0]; + if (owner.Length == 9) + { + instance.InstanceOwner.OrganisationNumber = owner; + } + else if (owner.Length == 12) + { + instance.InstanceOwner.PersonNumber = owner; + } + else + { + throw new Exception($"instance owner must be specified as part of the prefill filename. 9 digigts for OrganisationNumber, 12 for PersonNumber (eg 897069631.xml, not {prefill.FileName})"); + } + + var xmlDataId = app.DataTypes.First(dt => dt.AppLogic is not null).Id; + + using var reader = new StreamReader(prefill.OpenReadStream()); + var content = await reader.ReadToEndAsync(); + var newInstance = await _localApp.Instantiate(app.Id, instance, content, xmlDataId); + + return Redirect($"{_generalSettings.GetBaseUrl}/{app.Id}/#/instance/{newInstance.Id}"); + } + } + return Redirect($"/{app.Id}/"); } @@ -151,19 +177,8 @@ public async Task GetTestUserToken(int userId) return NotFound(); } - List claims = new List(); - string issuer = _generalSettings.Hostname; - claims.Add(new Claim(AltinnCoreClaimTypes.UserId, profile.UserId.ToString(), ClaimValueTypes.String, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.UserName, profile.UserName, ClaimValueTypes.String, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.PartyID, profile.PartyId.ToString(), ClaimValueTypes.Integer32, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.AuthenticationLevel, "2", ClaimValueTypes.Integer32, issuer)); - - ClaimsIdentity identity = new ClaimsIdentity(_generalSettings.GetClaimsIdentity); - identity.AddClaims(claims); - ClaimsPrincipal principal = new ClaimsPrincipal(identity); - // Create a test token with long duration - string token = _authenticationService.GenerateToken(principal, 1337); + string token = await _authenticationService.GenerateTokenForProfile(profile, 2); return Ok(token); } @@ -172,26 +187,12 @@ public async Task GetTestUserToken(int userId) /// /// /// - public async Task GetTestOrgToken(string id, [FromQuery] string orgNumber = "") + public async Task GetTestOrgToken(string id, [FromQuery] string orgNumber = null) { - List claims = new List(); - string issuer = _generalSettings.Hostname; - claims.Add(new Claim(AltinnCoreClaimTypes.Org, id.ToLower(), ClaimValueTypes.String, issuer)); - claims.Add(new Claim(AltinnCoreClaimTypes.AuthenticationLevel, "2", ClaimValueTypes.Integer32, issuer)); - claims.Add(new Claim("urn:altinn:scope", "altinn:serviceowner/instances.read", ClaimValueTypes.String, issuer)); - if (!string.IsNullOrEmpty(orgNumber)) - { - claims.Add(new Claim(AltinnCoreClaimTypes.OrgNumber, orgNumber, ClaimValueTypes.String, issuer)); - } - - ClaimsIdentity identity = new ClaimsIdentity(_generalSettings.GetClaimsIdentity); - identity.AddClaims(claims); - ClaimsPrincipal principal = new ClaimsPrincipal(identity); - // Create a test token with long duration - string token = _authenticationService.GenerateToken(principal, 1337); + string token = await _authenticationService.GenerateTokenForOrg(id, orgNumber); - return await Task.FromResult(Ok(token)); + return Ok(token); } /// diff --git a/src/Models/StartAppModel.cs b/src/Models/StartAppModel.cs index 50953464..0174d12f 100644 --- a/src/Models/StartAppModel.cs +++ b/src/Models/StartAppModel.cs @@ -89,5 +89,10 @@ public class StartAppModel /// List of possible authentication levels /// public IEnumerable AuthenticationLevels { get; set; } + + /// + /// Modify site conditionally on the app mode + /// + public bool AppModeIsHttp { get; set; } } } diff --git a/src/Services/Authentication/Implementation/AuthenticationService.cs b/src/Services/Authentication/Implementation/AuthenticationService.cs index b738bf99..a1711ac4 100644 --- a/src/Services/Authentication/Implementation/AuthenticationService.cs +++ b/src/Services/Authentication/Implementation/AuthenticationService.cs @@ -1,39 +1,105 @@ +#nullable enable using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; - +using System.Threading.Tasks; +using AuthSettings = Altinn.Platform.Authentication.Configuration.GeneralSettings; +using Altinn.Platform.Profile.Models; +using LocalTest.Clients.CdnAltinnOrgs; using LocalTest.Services.Authentication.Interface; - +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using LocalTest.Configuration; +using AltinnCore.Authentication.Constants; +using Altinn.Platform.Authorization.Services.Interface; + +namespace LocalTest.Services.Authentication.Implementation; -namespace LocalTest.Services.Authentication.Implementation +public class AuthenticationService : IAuthentication { - public class AuthenticationService : IAuthentication + private readonly AltinnOrgsClient _orgsClient; + private readonly AuthSettings _authSettings; + private readonly GeneralSettings _generalSettings; + private readonly IClaims _claimsService; + + public AuthenticationService(AltinnOrgsClient orgsClient, IOptions authSettings, IOptions generalSettings, IClaims claimsService) + { + _orgsClient = orgsClient; + _authSettings = authSettings.Value; + _generalSettings = generalSettings.Value; + _claimsService = claimsService; + } + /// + public string GenerateToken(ClaimsPrincipal principal) { - /// - public string GenerateToken(ClaimsPrincipal principal, int cookieValidityTime) + List certificates = new List { - List certificates = new List - { - new X509Certificate2("jwtselfsignedcert.pfx", "qwer1234") // lgtm [cs/hardcoded-credentials] - }; + new X509Certificate2("jwtselfsignedcert.pfx", "qwer1234") // lgtm [cs/hardcoded-credentials] + }; - TimeSpan tokenExpiry = new TimeSpan(0, cookieValidityTime, 0); + TimeSpan tokenExpiry = new TimeSpan(0, _authSettings.GetJwtCookieValidityTime, 0); - JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); - SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor - { - Subject = new ClaimsIdentity(principal.Identity), - Expires = DateTime.UtcNow.AddSeconds(tokenExpiry.TotalSeconds), - SigningCredentials = new X509SigningCredentials(certificates[0]) - }; + JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); + SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(principal.Identity), + Expires = DateTime.UtcNow.AddSeconds(tokenExpiry.TotalSeconds), + SigningCredentials = new X509SigningCredentials(certificates[0]) + }; + + SecurityToken token = tokenHandler.CreateToken(tokenDescriptor); + string serializedToken = tokenHandler.WriteToken(token); - SecurityToken token = tokenHandler.CreateToken(tokenDescriptor); - string serializedToken = tokenHandler.WriteToken(token); + return serializedToken; + } + + /// + public async Task GenerateTokenForOrg(string org, string? orgNumber = null) + { + if (orgNumber is null) + { + var orgs = await _orgsClient.GetCdnOrgs(); + orgNumber = (orgs.Orgs?.TryGetValue(org, out var value) == true ? value : null)?.Orgnr; + } - return serializedToken; + List claims = new List(); + string issuer = _generalSettings.Hostname; + claims.Add(new Claim(AltinnCoreClaimTypes.Org, org.ToLower(), ClaimValueTypes.String, issuer)); + // 3 is the default level for altinn tokens form Maskinporten + claims.Add(new Claim(AltinnCoreClaimTypes.AuthenticationLevel, "3", ClaimValueTypes.Integer32, issuer)); + claims.Add(new Claim("urn:altinn:scope", "altinn:serviceowner/instances.read", ClaimValueTypes.String, issuer)); + if (!string.IsNullOrEmpty(orgNumber)) + { + claims.Add(new Claim(AltinnCoreClaimTypes.OrgNumber, orgNumber, ClaimValueTypes.String, issuer)); } + + ClaimsIdentity identity = new ClaimsIdentity(_generalSettings.GetClaimsIdentity); + identity.AddClaims(claims); + ClaimsPrincipal principal = new ClaimsPrincipal(identity); + + // Create a test token with long duration + return GenerateToken(principal); + } + + /// + public async Task GenerateTokenForProfile(UserProfile profile, int authenticationLevel) + { + List claims = new List(); + string issuer = _generalSettings.Hostname; + claims.Add(new Claim(ClaimTypes.NameIdentifier, profile.UserId.ToString(), ClaimValueTypes.String, issuer)); + claims.Add(new Claim(AltinnCoreClaimTypes.UserId, profile.UserId.ToString(), ClaimValueTypes.String, issuer)); + claims.Add(new Claim(AltinnCoreClaimTypes.UserName, profile.UserName, ClaimValueTypes.String, issuer)); + claims.Add(new Claim(AltinnCoreClaimTypes.PartyID, profile.PartyId.ToString(), ClaimValueTypes.Integer32, issuer)); + claims.Add(new Claim(AltinnCoreClaimTypes.AuthenticationLevel, authenticationLevel.ToString(), ClaimValueTypes.Integer32, issuer)); + claims.AddRange(await _claimsService.GetCustomClaims(profile.UserId, issuer)); + + ClaimsIdentity identity = new ClaimsIdentity(_generalSettings.GetClaimsIdentity); + identity.AddClaims(claims); + ClaimsPrincipal principal = new ClaimsPrincipal(identity); + + return GenerateToken(principal); } } + diff --git a/src/Services/Authentication/Interface/IAuthentication.cs b/src/Services/Authentication/Interface/IAuthentication.cs index a932677e..ed664234 100644 --- a/src/Services/Authentication/Interface/IAuthentication.cs +++ b/src/Services/Authentication/Interface/IAuthentication.cs @@ -1,8 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; +#nullable enable using System.Security.Claims; using System.Threading.Tasks; +using Altinn.Platform.Profile.Models; namespace LocalTest.Services.Authentication.Interface { @@ -12,8 +11,21 @@ public interface IAuthentication /// Creates a JWT token based on claims principal. /// /// The claims principal. - /// Token validity time in minutes. - /// - public string GenerateToken(ClaimsPrincipal principal, int cookieValidityTime); + /// JWT token + public string GenerateToken(ClaimsPrincipal principal); + + /// + /// Generate a JWT token with claims for an application owner org + /// + /// Three letter application owner name (eg, TST ) + /// Optional Organization number for the application owner. Will be fetched if not provided + /// JWT token + public Task GenerateTokenForOrg(string org, string? orgNumber = null); + + /// + /// Get JWT token for user profile + /// + /// JWT token + public Task GenerateTokenForProfile(UserProfile profile, int authenticationLevel); } } diff --git a/src/Services/LocalApp/Implementation/LocalAppFile.cs b/src/Services/LocalApp/Implementation/LocalAppFile.cs index 80d9adbf..c15e3678 100644 --- a/src/Services/LocalApp/Implementation/LocalAppFile.cs +++ b/src/Services/LocalApp/Implementation/LocalAppFile.cs @@ -100,6 +100,11 @@ public async Task> GetApplications() return null; } + public Task Instantiate(string appId, Instance instance, string xmlPrefill, string xmlDataId) + { + throw new NotImplementedException(); + } + private string GetAppPath(string appId) { return Path.Join(_localPlatformSettings.AppRepositoryBasePath, appId.Split('/').Last()); diff --git a/src/Services/LocalApp/Implementation/LocalAppHttp.cs b/src/Services/LocalApp/Implementation/LocalAppHttp.cs index fe0c6d26..79013f03 100644 --- a/src/Services/LocalApp/Implementation/LocalAppHttp.cs +++ b/src/Services/LocalApp/Implementation/LocalAppHttp.cs @@ -2,12 +2,16 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Security.Claims; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Microsoft.Extensions.Caching.Memory; -using Newtonsoft.Json; using Altinn.Platform.Storage.Interface.Models; +using LocalTest.Services.Authentication.Interface; +using AltinnCore.Authentication.Constants; using LocalTest.Configuration; using LocalTest.Services.LocalApp.Interface; @@ -19,12 +23,17 @@ public class LocalAppHttp : ILocalApp public const string XACML_CACHE_KEY = "/api/v1/meta/authorizationpolicy/"; public const string APPLICATION_METADATA_CACHE_KEY = "/api/v1/applicationmetadata?checkOrgApp=false"; public const string TEXT_RESOURCE_CACE_KEY = "/api/v1/texts"; + private readonly GeneralSettings _generalSettings; + private readonly IAuthentication _authenticationService; private readonly HttpClient _httpClient; private readonly IMemoryCache _cache; - public LocalAppHttp(IHttpClientFactory httpClientFactory, IOptions localPlatformSettings, IMemoryCache cache) + public LocalAppHttp(IOptions generalSettings, IAuthentication authenticationService, IHttpClientFactory httpClientFactory, IOptions localPlatformSettings, IMemoryCache cache) { + _generalSettings = generalSettings.Value; + _authenticationService = authenticationService; _httpClient = httpClientFactory.CreateClient(); _httpClient.BaseAddress = new Uri(localPlatformSettings.Value.LocalAppUrl); + _httpClient.Timeout = TimeSpan.FromHours(1); _cache = cache; } public async Task GetXACMLPolicy(string appId) @@ -44,7 +53,7 @@ public LocalAppHttp(IHttpClientFactory httpClientFactory, IOptions(content); + return JsonSerializer.Deserialize(content, new JsonSerializerOptions{PropertyNameCaseInsensitive = true} ); } public async Task GetTextResource(string org, string app, string language) @@ -55,7 +64,7 @@ public LocalAppHttp(IHttpClientFactory httpClientFactory, IOptions(content); + var textResource = JsonSerializer.Deserialize(content, new JsonSerializerOptions{PropertyNameCaseInsensitive = true}); if (textResource != null) { textResource.Id = $"{org}-{app}-{language}"; @@ -79,5 +88,30 @@ public async Task> GetApplications() return ret; } + + public async Task Instantiate(string appId, Instance instance, string xmlPrefill, string xmlDataId) + { + var requestUri = $"{appId}/instances"; + var serializedInstance = JsonSerializer.Serialize(instance, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }); + + var content = new MultipartFormDataContent(); + content.Add(new StringContent(serializedInstance, System.Text.Encoding.UTF8, "application/json"), "instance"); + if (!string.IsNullOrWhiteSpace(xmlPrefill) && xmlDataId is not null) + { + content.Add(new StringContent(xmlPrefill, System.Text.Encoding.UTF8, "application/xml"), xmlDataId); + } + + using var message = new HttpRequestMessage(HttpMethod.Post, requestUri); + message.Content = content; + message.Headers.Authorization = new ("Bearer", await _authenticationService.GenerateTokenForOrg(appId.Split("/")[0])); + var response = await _httpClient.SendAsync(message); + var stringResponse = await response.Content.ReadAsStringAsync(); + if (!response.IsSuccessStatusCode) + { + throw new HttpRequestException(stringResponse); + } + + return JsonSerializer.Deserialize(stringResponse, new JsonSerializerOptions{PropertyNameCaseInsensitive = true}); + } } } diff --git a/src/Services/LocalApp/Interface/ILocalApp.cs b/src/Services/LocalApp/Interface/ILocalApp.cs index e2b025f8..a6615830 100644 --- a/src/Services/LocalApp/Interface/ILocalApp.cs +++ b/src/Services/LocalApp/Interface/ILocalApp.cs @@ -15,5 +15,7 @@ public interface ILocalApp Task> GetApplications(); Task GetTextResource(string org, string app, string language); + + Task Instantiate(string appId, Instance instance, string xmlPrefill, string xmlDataId); } } diff --git a/src/Startup.cs b/src/Startup.cs index f59b6f6e..624b2fc3 100644 --- a/src/Startup.cs +++ b/src/Startup.cs @@ -21,7 +21,7 @@ using Altinn.Platform.Storage.Repository; using AltinnCore.Authentication.Constants; using AltinnCore.Authentication.JwtCookie; - +using LocalTest.Clients.CdnAltinnOrgs; using LocalTest.Configuration; using LocalTest.Services.Authentication.Implementation; using LocalTest.Services.Authentication.Interface; @@ -95,6 +95,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddHttpClient(); + services.AddHttpClient(); services.AddSingleton(); services.AddSingleton(); services.AddTransient(); diff --git a/src/Views/Home/Index.cshtml b/src/Views/Home/Index.cshtml index f5a51793..f4bc29a4 100644 --- a/src/Views/Home/Index.cshtml +++ b/src/Views/Home/Index.cshtml @@ -32,8 +32,9 @@ } else {
No application running on @Model.LocalAppUrl

- Please start your an app on this adress. + Please start your an app on this adress. Typically run the following command in an app directory.

+
dotnet run
} } else {
@@ -65,7 +66,7 @@
 
     

Testing app: @Model.Org/@Model.App

- @using (Html.BeginForm("LogInTestUser", "Home", FormMethod.Post, new { Class = "form-signin" })) + @using (Html.BeginForm("LogInTestUser", "Home", FormMethod.Post, new { Class = "form-signin", enctype = "multipart/form-data" })) { @Html.AntiForgeryToken();
@@ -80,6 +81,13 @@ @Html.DropDownListFor(model => model.AuthenticationLevel, Model.AuthenticationLevels, new { Class = "form-control" })
+ @if(Model.AppModeIsHttp) + { +
+ + +
+ } }