diff --git a/Kiss.Bff.Test/AuthorizationCheckTests.cs b/Kiss.Bff.Test/AuthorizationCheckTests.cs index ddb4935b4..0b580779b 100644 --- a/Kiss.Bff.Test/AuthorizationCheckTests.cs +++ b/Kiss.Bff.Test/AuthorizationCheckTests.cs @@ -27,6 +27,7 @@ public class AuthorizationCheckTests [ClassInitialize] public static void ClassInit(TestContext _) { + Environment.SetEnvironmentVariable("MANAGEMENTINFORMATIE_API_KEY", "eenZeerGeheimeSleutelMetMinimaal32TekensLang"); s_factory = new CustomWebApplicationFactory(); s_client = s_factory.CreateDefaultClient(); } @@ -34,16 +35,16 @@ public static void ClassInit(TestContext _) [ClassCleanup] public static void ClassCleanup() { + Environment.SetEnvironmentVariable("MANAGEMENTINFORMATIE_API_KEY", null); s_client?.Dispose(); s_factory?.Dispose(); } - public static IEnumerable GetControllersWithAuthorizeAttributeAndMethods() + public static IEnumerable GetControllersMethodsWithDefaultAuthorizeAttributes() { // Define the controllers and methods to test here var controllersWithMethodsToTest = new List<(Type controllerType, string methodName, Type[] parameterTypes)> { - (typeof(ReadContactmomentenDetails), "Get", new[] { typeof(string), typeof(string), typeof(CancellationToken), typeof(int), typeof(int) }), (typeof(GespreksresultatenController), "PutGespreksresultaat", new[] { typeof(Guid), typeof(GespreksresultaatModel), typeof(CancellationToken) }), (typeof(GespreksresultatenController), "PostGespreksresultaat", new[] { typeof(GespreksresultaatModel), typeof(CancellationToken)}), (typeof(GespreksresultatenController), "DeleteGespreksresultaat", new[] { typeof(Guid), typeof(CancellationToken)}), @@ -69,7 +70,7 @@ public static IEnumerable GetControllersWithAuthorizeAttributeAndMetho [DataRow("/api/contactmomentendetails?id=1")] [DataRow("/api/zaaksysteem/deeplinkconfig")] [DataRow("/api/KanaalToevoegen", "post")] - public async Task Test(string url, string method = "get") + public async Task CallingEnpointsWithoutCredetialsShouldResultInAUnauthorizedResponse(string url, string method = "get") { using var request = new HttpRequestMessage(new(method), url); using var response = await s_client.SendAsync(request); @@ -77,8 +78,8 @@ public async Task Test(string url, string method = "get") } [DataTestMethod] - [DynamicData(nameof(GetControllersWithAuthorizeAttributeAndMethods), DynamicDataSourceType.Method)] - public async Task TestAuthorizeAttribute(Type controllerType, string methodName, Type[] parameterTypes) + [DynamicData(nameof(GetControllersMethodsWithDefaultAuthorizeAttributes), DynamicDataSourceType.Method)] + public void TestAuthorizeAttribute(Type controllerType, string methodName, Type[] parameterTypes) { // Manually create an instance of the controller var dbContextOptions = new DbContextOptionsBuilder() @@ -100,10 +101,35 @@ public async Task TestAuthorizeAttribute(Type controllerType, string methodName, var authorizeAttribute = method.GetCustomAttributes(typeof(AuthorizeAttribute), true) .FirstOrDefault() as AuthorizeAttribute; - // Assert that the Authorize attribute exists and has the expected policy - Assert.IsNotNull(authorizeAttribute); - Assert.AreEqual(Policies.RedactiePolicy, authorizeAttribute.Policy); + // Assert that the method has the right auth attribute + Assert.AreEqual(Policies.RedactiePolicy, authorizeAttribute?.Policy); } + + + [TestMethod] + public void TestAuthorizationOfManagementInformatieEndpoint() + { + var controllerType = typeof(ReadContactmomentenDetails); + + var dbContext = new BeheerDbContext(new DbContextOptions()); + var controller = Activator.CreateInstance(controllerType, dbContext) as ControllerBase; + + Assert.IsNotNull(controller); + + var methods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + + Assert.AreEqual(2, methods.Length); + + for (var i = 0; i < methods.Length; i += 1) + { + var authorizeAttribute = methods[i].GetCustomAttributes(typeof(AuthorizeAttribute), true).FirstOrDefault() as AuthorizeAttribute; + + Assert.IsNotNull(authorizeAttribute); + Assert.AreEqual(Policies.ExternSysteemPolicy, authorizeAttribute.Policy); + } + } + } } + diff --git a/Kiss.Bff.Test/PostKlantContactenCustomProxyTests.cs b/Kiss.Bff.Test/PostKlantContactenCustomProxyTests.cs index 3da95ad28..febb8b853 100644 --- a/Kiss.Bff.Test/PostKlantContactenCustomProxyTests.cs +++ b/Kiss.Bff.Test/PostKlantContactenCustomProxyTests.cs @@ -27,8 +27,6 @@ public void Setup() _configurationMock = new Mock(); _getMedewerkerIdentificatieMock = new Mock(); - _configurationMock.Setup(config => config["KLANTCONTACTEN_BASE_URL"]).Returns("https://fakeurl.com"); - _httpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] diff --git a/Kiss.Bff/Config/AuthenticationSetup.cs b/Kiss.Bff/Config/AuthenticationSetup.cs index ca2c8e5a9..4c357373a 100644 --- a/Kiss.Bff/Config/AuthenticationSetup.cs +++ b/Kiss.Bff/Config/AuthenticationSetup.cs @@ -1,17 +1,22 @@ using System.Security.Claims; +using System.Text; using System.Text.Json.Nodes; using AngleSharp.Io; using IdentityModel; using Kiss; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.IdentityModel.Tokens; namespace Kiss { public static class Policies { public const string RedactiePolicy = "RedactiePolicy"; + public const string ExternSysteemPolicy = "ExternSysteemPolicy"; } public static class KissClaimTypes @@ -66,6 +71,8 @@ public class KissAuthOptions public string? RedacteurRole { get; set; } public string? MedewerkerIdentificatieClaimType { get; set; } public int? TruncateMedewerkerIdentificatie { get; set; } + + public string? JwtTokenAuthenticationSecret { get; set; } } public static class AuthenticationSetupExtensions @@ -155,6 +162,23 @@ public static IServiceCollection AddKissAuth(this IServiceCollection services, A }); } + + if (authOptions.JwtTokenAuthenticationSecret != null) + { + authBuilder.AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = false, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authOptions.JwtTokenAuthenticationSecret)) + }; + }); + } + + services.AddDistributedMemoryCache(); services.AddOpenIdConnectAccessTokenManagement(); @@ -168,6 +192,16 @@ public static IServiceCollection AddKissAuth(this IServiceCollection services, A new AuthorizationPolicyBuilder() .RequireRole(redacteurRole) .Build()); + + + options.AddPolicy(Policies.ExternSysteemPolicy, policy => + { + policy.RequireRole("ExternSysteem"); + policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); + }); + + + }); return services; diff --git a/Kiss.Bff/Config/JwtAuthSetup.cs b/Kiss.Bff/Config/JwtAuthSetup.cs new file mode 100644 index 000000000..9378719a8 --- /dev/null +++ b/Kiss.Bff/Config/JwtAuthSetup.cs @@ -0,0 +1,52 @@ +//using Microsoft.AspNetCore.Authentication.JwtBearer; +//using Microsoft.Extensions.DependencyInjection; +//using Microsoft.IdentityModel.Tokens; +//using System.Text; +//using Kiss; + +//namespace Microsoft.Extensions.DependencyInjection +//{ +// public static class JwtAuthSetupExtensions +// { +// public static IServiceCollection AddJwtAuth(this IServiceCollection services, Action configureOptions) +// { +// var jwtOptions = new JwtAuthOptions(); +// configureOptions(jwtOptions); + +// jwtOptions.SecretKey = jwtOptions.SecretKey ?? string.Empty; + +// services.AddAuthentication(options => +// { +// options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; +// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +// }) +// .AddJwtBearer(options => +// { +// options.TokenValidationParameters = new TokenValidationParameters +// { +// ValidateIssuer = true, +// ValidateAudience = false, +// ValidateLifetime = true, +// ValidateIssuerSigningKey = true, +// IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecretKey)) +// }; +// }); + +// services.AddAuthorization(options => +// { +// options.AddPolicy(Policies.ExternSysteemPolicy, policy => +// { +// policy.RequireRole("ExternSysteem"); +// policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); +// }); +// }); + +// return services; +// } +// } + +// public class JwtAuthOptions +// { +// public string SecretKey { get; set; } = string.Empty; +// } +//} diff --git a/Kiss.Bff/Extern/ZaakGerichtWerken/Contactmomenten/ReadContactmomentenDetails.cs b/Kiss.Bff/Extern/ZaakGerichtWerken/Contactmomenten/ReadContactmomentenDetails.cs index 5a988bab6..d4b9910e8 100644 --- a/Kiss.Bff/Extern/ZaakGerichtWerken/Contactmomenten/ReadContactmomentenDetails.cs +++ b/Kiss.Bff/Extern/ZaakGerichtWerken/Contactmomenten/ReadContactmomentenDetails.cs @@ -18,6 +18,7 @@ public ReadContactmomentenDetails(BeheerDbContext db) } [HttpGet("/api/contactmomentdetails")] + [Authorize(Policy = Policies.ExternSysteemPolicy)] public async Task Get([FromQuery] string id, CancellationToken token) { var contactmoment = await _db.ContactMomentDetails @@ -32,7 +33,7 @@ public async Task Get([FromQuery] string id, CancellationToken to } [HttpGet("/api/contactmomentendetails")] - [Authorize(Policy = Policies.RedactiePolicy)] + [Authorize(Policy = Policies.ExternSysteemPolicy)] public async Task Get( [FromQuery] string from, [FromQuery] string to, diff --git a/Kiss.Bff/Kiss.Bff.csproj b/Kiss.Bff/Kiss.Bff.csproj index 9c5550175..69015e0a0 100644 --- a/Kiss.Bff/Kiss.Bff.csproj +++ b/Kiss.Bff/Kiss.Bff.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -16,6 +16,7 @@ + diff --git a/Kiss.Bff/Program.cs b/Kiss.Bff/Program.cs index 5fe9a9b75..3266c06ae 100644 --- a/Kiss.Bff/Program.cs +++ b/Kiss.Bff/Program.cs @@ -55,8 +55,14 @@ { options.TruncateMedewerkerIdentificatie = truncate; } + options.JwtTokenAuthenticationSecret = builder.Configuration["MANAGEMENTINFORMATIE_API_KEY"]; }); + //builder.Services.AddJwtAuth(options => + //{ + // options.SecretKey = builder.Configuration["MANAGEMENTINFORMATIE_API_KEY"]; + //}); + builder.Services.AddKissProxy(); builder.Services.AddKvk(builder.Configuration["KVK_BASE_URL"], builder.Configuration["KVK_API_KEY"]); builder.Services.AddHaalCentraal(builder.Configuration["HAAL_CENTRAAL_BASE_URL"], builder.Configuration["HAAL_CENTRAAL_API_KEY"]); @@ -129,7 +135,7 @@ app.MapKissAuthEndpoints(); app.MapControllers(); app.MapKissProxy(); - app.MapHealthChecks("/healthz"); + app.MapHealthChecks("/healthz").AllowAnonymous(); app.MapFallbackToIndexHtml(); using (var scope = app.Services.CreateScope()) diff --git a/src/components/SearchResultsCaption.vue b/src/components/SearchResultsCaption.vue index 19d4eb220..66fe72c7b 100644 --- a/src/components/SearchResultsCaption.vue +++ b/src/components/SearchResultsCaption.vue @@ -41,6 +41,8 @@ const zoekTermenCaption = computed(() => { return `voor '${props.zoekTermen.handelsnaam}'.`; } else if ("kvkNummer" in props.zoekTermen) { return `voor '${props.zoekTermen.kvkNummer}'.`; + } else if ("vestigingsnummer" in props.zoekTermen) { + return `voor '${props.zoekTermen.vestigingsnummer}'.`; } else { return ""; } diff --git a/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzicht.vue b/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzicht.vue index 276961826..ca104060a 100644 --- a/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzicht.vue +++ b/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzicht.vue @@ -28,10 +28,9 @@ diff --git a/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzichtRow.vue b/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzichtRow.vue index 1ae68f46f..659493863 100644 --- a/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzichtRow.vue +++ b/src/features/bedrijf/bedrijf-zoeken/BedrijvenOverzichtRow.vue @@ -9,7 +9,7 @@ - {{ bedrijf.data?.kvkNummer || klant.data?.kvkNummer }} + {{ bedrijf.data?.kvkNummer }}
@@ -17,6 +17,7 @@ {{ bedrijf.data?.vestigingsnummer }} +
-
-