getAdditionalGroupProperties();
diff --git a/src/main/java/org/tailormap/api/security/TailormapUserDetailsImpl.java b/src/main/java/org/tailormap/api/security/TailormapUserDetailsImpl.java
index 0db39e66..0303601d 100644
--- a/src/main/java/org/tailormap/api/security/TailormapUserDetailsImpl.java
+++ b/src/main/java/org/tailormap/api/security/TailormapUserDetailsImpl.java
@@ -5,30 +5,77 @@
*/
package org.tailormap.api.security;
+import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import org.jspecify.annotations.NonNull;
import org.springframework.security.core.GrantedAuthority;
-class TailormapUserDetailsImpl implements TailormapUserDetails {
+/**
+ * Internal {@link TailormapUserDetails} implementation.
+ *
+ * Do not use this class directly; always depend on the {@link TailormapUserDetails} interface instead. This class is
+ * {@code public} only to support JSON/session deserialization (e.g. by Jackson / Spring Session). Changing its
+ * visibility back to package-private would break that deserialization.
+ */
+public class TailormapUserDetailsImpl implements TailormapUserDetails {
@Serial
private static final long serialVersionUID = 1L;
- private Collection authorities;
- private String username;
- private String password;
- private ZonedDateTime validUntil;
- private boolean enabled;
- private String organisation;
+ private final Collection authorities;
+ private final String username;
+ private final String password;
+ private final ZonedDateTime validUntil;
+ private final boolean enabled;
+ private final String organisation;
private final Collection additionalProperties = new ArrayList<>();
private final Collection additionalGroupProperties = new ArrayList<>();
+ /**
+ * Constructor for Jackson deserialization.
+ *
+ * @param authorities the authorities
+ * @param username the username
+ * @param password the password
+ * @param validUntil the valid until date
+ * @param enabled whether the user is enabled
+ * @param organisation the organisation
+ * @param additionalProperties the additional properties
+ * @param additionalGroupProperties the additional group properties
+ */
+ @SuppressWarnings("unused")
+ TailormapUserDetailsImpl(
+ @JsonProperty("authorities") Collection authorities,
+ @JsonProperty("username") String username,
+ @JsonProperty("password") String password,
+ @JsonProperty("validUntil") ZonedDateTime validUntil,
+ @JsonProperty("enabled") boolean enabled,
+ @JsonProperty("organisation") String organisation,
+ @JsonProperty("additionalProperties") Collection additionalProperties,
+ @JsonProperty("additionalGroupProperties")
+ Collection additionalGroupProperties) {
+ this.authorities = authorities;
+ this.username = username;
+ this.password = password;
+ this.validUntil = validUntil;
+ this.enabled = enabled;
+ this.organisation = organisation;
+ if (additionalProperties != null) {
+ this.additionalProperties.addAll(additionalProperties);
+ }
+ if (additionalGroupProperties != null) {
+ this.additionalGroupProperties.addAll(additionalGroupProperties);
+ }
+ }
+
@Override
- public Collection extends GrantedAuthority> getAuthorities() {
+ @NonNull public Collection extends GrantedAuthority> getAuthorities() {
return authorities;
}
@@ -38,7 +85,7 @@ public String getPassword() {
}
@Override
- public String getUsername() {
+ @NonNull public String getUsername() {
return username;
}
@@ -59,11 +106,11 @@ public String getOrganisation() {
@Override
public Collection getAdditionalProperties() {
- return additionalProperties;
+ return Collections.unmodifiableCollection(additionalProperties);
}
@Override
public Collection getAdditionalGroupProperties() {
- return additionalGroupProperties;
+ return Collections.unmodifiableCollection(additionalGroupProperties);
}
}
diff --git a/src/main/java/org/tailormap/api/security/TailormapUserDetailsImplMixin.java b/src/main/java/org/tailormap/api/security/TailormapUserDetailsImplMixin.java
new file mode 100644
index 00000000..cc3a186a
--- /dev/null
+++ b/src/main/java/org/tailormap/api/security/TailormapUserDetailsImplMixin.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 B3Partners B.V.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package org.tailormap.api.security;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import java.time.ZonedDateTime;
+import java.util.Collection;
+import org.springframework.security.core.GrantedAuthority;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
+@JsonAutoDetect(
+ fieldVisibility = JsonAutoDetect.Visibility.ANY,
+ getterVisibility = JsonAutoDetect.Visibility.NONE,
+ isGetterVisibility = JsonAutoDetect.Visibility.NONE)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public abstract class TailormapUserDetailsImplMixin {
+
+ @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+ public TailormapUserDetailsImplMixin(
+ @SuppressWarnings("unused") @JsonProperty("authorities") Collection authorities,
+ @SuppressWarnings("unused") @JsonProperty("username") String username,
+ @SuppressWarnings("unused") @JsonProperty("password") String password,
+ @SuppressWarnings("unused") @JsonProperty("validUntil") ZonedDateTime validUntil,
+ @SuppressWarnings("unused") @JsonProperty("enabled") boolean enabled,
+ @SuppressWarnings("unused") @JsonProperty("organisation") String organisation,
+ @SuppressWarnings("unused") @JsonProperty("additionalProperties")
+ Collection additionalProperties,
+ @SuppressWarnings("unused") @JsonProperty("additionalGroupProperties")
+ Collection additionalGroupProperties) {
+ // mixin constructor only for Jackson; no implementation
+ }
+
+ /** prevents serializing the password. */
+ @JsonIgnore
+ public abstract String getPassword();
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 4423f5ef..32d8d8af 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -36,7 +36,7 @@ spring.datasource.username=planmonitor-wonen
spring.datasource.password=planmonitor-wonen
# Actuator
-management.endpoints.enabled-by-default=true
+management.endpoints.access.default=read_only
management.endpoints.web.base-path=/api/planmonitorwonen/actuator
management.endpoints.web.exposure.include=info,health,prometheus,loggers,logfile,mappings
@@ -63,5 +63,7 @@ logging.level.org.springframework.boot.autoconfigure=INFO
logging.level.org.springframework.test.context=INFO
logging.level.org.springframework.security.web.authentication=DEBUG
-logging.level.nl.b3p.planmonitorwonen.api=DEBUG
+logging.group.planmonitorwonen=nl.b3p.planmonitorwonen.api
+logging.group.auth=org.tailormap.api.security,nl.b3p.planmonitorwonen.api.configuration.JdbcSessionConfiguration
+logging.group.geotools=org.geotools