diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebConfiguration.java b/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebConfiguration.java
index 653b4a7..2becedf 100644
--- a/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebConfiguration.java
+++ b/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebConfiguration.java
@@ -3,6 +3,8 @@ package de.twomartens.wahlrecht.configuration;
import de.twomartens.wahlrecht.interceptor.HeaderInterceptorRest;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.CorsRegistration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -15,14 +17,17 @@ public class WebConfiguration implements WebMvcConfigurer {
private final HeaderInterceptorRest headerInterceptorRest;
@Override
- public void addInterceptors(InterceptorRegistry registry) {
+ public void addInterceptors(@NonNull InterceptorRegistry registry) {
registry.addInterceptor(headerInterceptorRest);
}
@Override
- public void addCorsMappings(CorsRegistry registry) {
+ public void addCorsMappings(@NonNull CorsRegistry registry) {
CorsRegistration registration = registry.addMapping("/**");
- registration.allowedOrigins("*");
+ registration.allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(),
+ HttpMethod.PUT.name(), HttpMethod.OPTIONS.name());
+ registration.allowCredentials(true);
+ registration.allowedOrigins("http://localhost:4200");
}
}
diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebSecurityConfiguration.java b/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebSecurityConfiguration.java
index e2ca501..d82f41d 100644
--- a/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebSecurityConfiguration.java
+++ b/module-server/src/main/java/de/twomartens/wahlrecht/configuration/WebSecurityConfiguration.java
@@ -1,12 +1,12 @@
package de.twomartens.wahlrecht.configuration;
+import de.twomartens.wahlrecht.security.SpringPolicyEnforcerFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import org.keycloak.adapters.authorization.integration.jakarta.ServletPolicyEnforcerFilter;
import org.keycloak.adapters.authorization.spi.ConfigurationResolver;
import org.keycloak.adapters.authorization.spi.HttpRequest;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
@@ -16,6 +16,7 @@ import org.keycloak.util.JsonSerialization;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
import org.springframework.lang.NonNull;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -53,6 +54,10 @@ public class WebSecurityConfiguration {
.requestMatchers(PERMITTED_PATHS.toArray(new String[0]))
.permitAll()
.and()
+ .authorizeHttpRequests()
+ .requestMatchers(HttpMethod.OPTIONS)
+ .permitAll()
+ .and()
.authorizeHttpRequests()
.anyRequest()
.authenticated()
@@ -67,15 +72,20 @@ public class WebSecurityConfiguration {
return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri).build();
}
- private ServletPolicyEnforcerFilter createPolicyEnforcerFilter() {
- return new ServletPolicyEnforcerFilter(new ConfigurationResolver() {
+ private SpringPolicyEnforcerFilter createPolicyEnforcerFilter() {
+ return new SpringPolicyEnforcerFilter(new ConfigurationResolver() {
@Override
public PolicyEnforcerConfig resolve(HttpRequest request) {
try {
PolicyEnforcerConfig policyEnforcerConfig = JsonSerialization.readValue(
getClass().getResourceAsStream("/policy-enforcer.json"), PolicyEnforcerConfig.class);
policyEnforcerConfig.setCredentials(Map.of("secret", clientSecret));
- policyEnforcerConfig.setPaths(PATHS);
+ if (request.getMethod().equals(HttpMethod.OPTIONS.name())) {
+ // always allow options request
+ policyEnforcerConfig.setEnforcementMode(EnforcementMode.DISABLED);
+ } else {
+ policyEnforcerConfig.setPaths(PATHS);
+ }
return policyEnforcerConfig;
} catch (IOException e) {
diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/security/SpringPolicyEnforcer.java b/module-server/src/main/java/de/twomartens/wahlrecht/security/SpringPolicyEnforcer.java
new file mode 100644
index 0000000..77b5172
--- /dev/null
+++ b/module-server/src/main/java/de/twomartens/wahlrecht/security/SpringPolicyEnforcer.java
@@ -0,0 +1,86 @@
+package de.twomartens.wahlrecht.security;
+
+import java.util.Collections;
+import java.util.List;
+import lombok.extern.slf4j.Slf4j;
+import org.keycloak.AuthorizationContext;
+import org.keycloak.adapters.authorization.PolicyEnforcer;
+import org.keycloak.adapters.authorization.spi.HttpRequest;
+import org.keycloak.adapters.authorization.spi.HttpResponse;
+import org.keycloak.authorization.client.ClientAuthorizationContext;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode;
+import org.keycloak.representations.idm.authorization.Permission;
+
+/**
+ * Allows any request, even from anonymous, if enforcement mode is disabled. For remaining requests,
+ * it refers to the original PolicyEnforcer.
+ */
+@Slf4j
+public class SpringPolicyEnforcer {
+
+ private final PolicyEnforcer policyEnforcer;
+ private final PolicyEnforcerConfig policyEnforcerConfig;
+
+ public SpringPolicyEnforcer(PolicyEnforcer policyEnforcer, PolicyEnforcerConfig policyEnforcerConfig) {
+ this.policyEnforcer = policyEnforcer;
+ this.policyEnforcerConfig = policyEnforcerConfig;
+ }
+
+ public AuthorizationContext enforce(HttpRequest request, HttpResponse response) {
+ if (log.isDebugEnabled()) {
+ log.debug("Policy enforcement is enabled. Enforcing policy decisions for path [{}].", request.getURI());
+ }
+
+ AuthorizationContext context = authorize(request, response);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Policy enforcement result for path [{}] is : {}", request.getURI(), context.isGranted() ? "GRANTED" : "DENIED");
+ log.debug("Returning authorization context with permissions:");
+ for (Permission permission : context.getPermissions()) {
+ log.debug(permission.toString());
+ }
+ }
+
+ return context;
+ }
+
+ private AuthorizationContext authorize(HttpRequest request, HttpResponse response) {
+ EnforcementMode enforcementMode = policyEnforcerConfig.getEnforcementMode();
+
+ if (EnforcementMode.DISABLED.equals(enforcementMode)) {
+ return createAuthorizedContext();
+ }
+
+ return policyEnforcer.enforce(request, response);
+ }
+
+ private AuthorizationContext createAuthorizedContext() {
+ return new ClientAuthorizationContext(policyEnforcer.getAuthzClient()) {
+ @Override
+ public boolean hasPermission(String resourceName, String scopeName) {
+ return true;
+ }
+
+ @Override
+ public boolean hasResourcePermission(String resourceName) {
+ return true;
+ }
+
+ @Override
+ public boolean hasScopePermission(String scopeName) {
+ return true;
+ }
+
+ @Override
+ public List