copy = new ArrayList<>(authorities.size());
+ for (GrantedAuthority authority : authorities) {
+ copy.add(authority);
+ }
+ this.authorities = Collections.unmodifiableList(copy);
+ }
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return authorities;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ @Override
+ public Object getDetails() {
+ return details;
+ }
+
+ public void setDetails(Object details) {
+ this.details = details;
+ }
+
+ @Override
+ public boolean isAuthenticated() {
+ return authenticated;
+ }
+
+ @Override
+ public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
+ this.authenticated = authenticated;
+ }
+
+ @Override
+ public String getName() {
+ Object principal = getPrincipal();
+ if (principal instanceof UserDetails) {
+ return ((UserDetails) principal).getUsername();
+ }
+ return principal == null ? null : principal.toString();
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/Authentication.java b/app/common/src/main/java/stirling/software/common/security/Authentication.java
new file mode 100644
index 0000000000..9fc3d76b84
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/Authentication.java
@@ -0,0 +1,29 @@
+package stirling.software.common.security;
+
+import java.security.Principal;
+import java.util.Collection;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.Authentication}.
+ *
+ * Represents the token for an authentication request or for an authenticated principal once the
+ * request has been processed.
+ */
+public interface Authentication extends Principal {
+
+ Collection extends GrantedAuthority> getAuthorities();
+
+ Object getCredentials();
+
+ Object getDetails();
+
+ Object getPrincipal();
+
+ boolean isAuthenticated();
+
+ void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
+
+ @Override
+ String getName();
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/AuthenticationException.java b/app/common/src/main/java/stirling/software/common/security/AuthenticationException.java
new file mode 100644
index 0000000000..ee2176db83
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/AuthenticationException.java
@@ -0,0 +1,19 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.AuthenticationException}.
+ *
+ *
Abstract superclass for all exceptions related to an {@link Authentication} object being
+ * invalid for whatever reason.
+ */
+public class AuthenticationException extends RuntimeException {
+
+ public AuthenticationException(String msg) {
+ super(msg);
+ }
+
+ public AuthenticationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/BCryptPasswordEncoder.java b/app/common/src/main/java/stirling/software/common/security/BCryptPasswordEncoder.java
new file mode 100644
index 0000000000..436a553314
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/BCryptPasswordEncoder.java
@@ -0,0 +1,45 @@
+package stirling.software.common.security;
+
+import at.favre.lib.crypto.bcrypt.BCrypt;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder}.
+ *
+ *
Implementation of {@link PasswordEncoder} backed by the {@code at.favre.lib:bcrypt} library.
+ */
+public class BCryptPasswordEncoder implements PasswordEncoder {
+
+ private static final int DEFAULT_STRENGTH = 10;
+
+ private final int strength;
+
+ public BCryptPasswordEncoder() {
+ this(DEFAULT_STRENGTH);
+ }
+
+ public BCryptPasswordEncoder(int strength) {
+ this.strength = strength;
+ }
+
+ @Override
+ public String encode(CharSequence rawPassword) {
+ if (rawPassword == null) {
+ throw new IllegalArgumentException("rawPassword cannot be null");
+ }
+ return BCrypt.withDefaults().hashToString(strength, rawPassword.toString().toCharArray());
+ }
+
+ @Override
+ public boolean matches(CharSequence rawPassword, String encodedPassword) {
+ if (rawPassword == null) {
+ throw new IllegalArgumentException("rawPassword cannot be null");
+ }
+ if (encodedPassword == null || encodedPassword.isEmpty()) {
+ return false;
+ }
+ return BCrypt.verifyer()
+ .verify(rawPassword.toString().toCharArray(), encodedPassword)
+ .verified;
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/BadCredentialsException.java b/app/common/src/main/java/stirling/software/common/security/BadCredentialsException.java
new file mode 100644
index 0000000000..b212c2f2f2
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/BadCredentialsException.java
@@ -0,0 +1,18 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.authentication.BadCredentialsException}.
+ *
+ *
Thrown if an authentication request is rejected because the credentials are invalid.
+ */
+public class BadCredentialsException extends AuthenticationException {
+
+ public BadCredentialsException(String msg) {
+ super(msg);
+ }
+
+ public BadCredentialsException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/GrantedAuthority.java b/app/common/src/main/java/stirling/software/common/security/GrantedAuthority.java
new file mode 100644
index 0000000000..b297e44dde
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/GrantedAuthority.java
@@ -0,0 +1,17 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for {@code org.springframework.security.core.GrantedAuthority}.
+ *
+ *
Represents an authority granted to an {@link Authentication} object. Provided so that code
+ * migrated from Spring Boot to Quarkus compiles without Spring Security on the classpath.
+ */
+public interface GrantedAuthority {
+
+ /**
+ * Returns a textual representation of the granted authority.
+ *
+ * @return the authority string, never {@code null}
+ */
+ String getAuthority();
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/OAuth2User.java b/app/common/src/main/java/stirling/software/common/security/OAuth2User.java
new file mode 100644
index 0000000000..88b43d5839
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/OAuth2User.java
@@ -0,0 +1,20 @@
+package stirling.software.common.security;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.oauth2.core.user.OAuth2User}.
+ *
+ *
Represents a user {@link java.security.Principal} authenticated using OAuth 2.0 or OpenID
+ * Connect.
+ */
+public interface OAuth2User {
+
+ Map getAttributes();
+
+ Collection extends GrantedAuthority> getAuthorities();
+
+ String getName();
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/PasswordEncoder.java b/app/common/src/main/java/stirling/software/common/security/PasswordEncoder.java
new file mode 100644
index 0000000000..479d4323b4
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/PasswordEncoder.java
@@ -0,0 +1,20 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.crypto.password.PasswordEncoder}.
+ *
+ * Service interface for encoding passwords.
+ */
+public interface PasswordEncoder {
+
+ /**
+ * Encodes the raw password.
+ */
+ String encode(CharSequence rawPassword);
+
+ /**
+ * Verifies that the encoded password matches the raw password after it too is encoded.
+ */
+ boolean matches(CharSequence rawPassword, String encodedPassword);
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/PersistentRememberMeToken.java b/app/common/src/main/java/stirling/software/common/security/PersistentRememberMeToken.java
new file mode 100644
index 0000000000..9c7f2b9f9e
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/PersistentRememberMeToken.java
@@ -0,0 +1,41 @@
+package stirling.software.common.security;
+
+import java.util.Date;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken}.
+ *
+ *
Holds the persistent remember-me token data for a single series.
+ */
+public class PersistentRememberMeToken {
+
+ private final String username;
+ private final String series;
+ private final String tokenValue;
+ private final Date date;
+
+ public PersistentRememberMeToken(
+ String username, String series, String tokenValue, Date date) {
+ this.username = username;
+ this.series = series;
+ this.tokenValue = tokenValue;
+ this.date = date;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getSeries() {
+ return series;
+ }
+
+ public String getTokenValue() {
+ return tokenValue;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/PersistentTokenRepository.java b/app/common/src/main/java/stirling/software/common/security/PersistentTokenRepository.java
new file mode 100644
index 0000000000..5d6d4330f2
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/PersistentTokenRepository.java
@@ -0,0 +1,20 @@
+package stirling.software.common.security;
+
+import java.util.Date;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.web.authentication.rememberme.PersistentTokenRepository}.
+ *
+ *
Persists the remember-me tokens used by the persistent token based remember-me services.
+ */
+public interface PersistentTokenRepository {
+
+ void createNewToken(PersistentRememberMeToken token);
+
+ void updateToken(String series, String tokenValue, Date lastUsed);
+
+ PersistentRememberMeToken getTokenForSeries(String seriesId);
+
+ void removeUserTokens(String username);
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/SecurityContext.java b/app/common/src/main/java/stirling/software/common/security/SecurityContext.java
new file mode 100644
index 0000000000..5cab7866da
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/SecurityContext.java
@@ -0,0 +1,14 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.context.SecurityContext}.
+ *
+ *
Holds the {@link Authentication} associated with the current execution.
+ */
+public interface SecurityContext {
+
+ Authentication getAuthentication();
+
+ void setAuthentication(Authentication authentication);
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/SecurityContextHolder.java b/app/common/src/main/java/stirling/software/common/security/SecurityContextHolder.java
new file mode 100644
index 0000000000..0682446f7a
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/SecurityContextHolder.java
@@ -0,0 +1,39 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.context.SecurityContextHolder}.
+ *
+ *
Associates a {@link SecurityContext} with the current thread of execution using a
+ * {@link ThreadLocal}.
+ */
+public final class SecurityContextHolder {
+
+ private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
+
+ private SecurityContextHolder() {}
+
+ /**
+ * Returns the context for the current thread, creating an empty one if none is set.
+ */
+ public static SecurityContext getContext() {
+ SecurityContext context = CONTEXT_HOLDER.get();
+ if (context == null) {
+ context = createEmptyContext();
+ CONTEXT_HOLDER.set(context);
+ }
+ return context;
+ }
+
+ public static void setContext(SecurityContext context) {
+ CONTEXT_HOLDER.set(context);
+ }
+
+ public static void clearContext() {
+ CONTEXT_HOLDER.remove();
+ }
+
+ public static SecurityContext createEmptyContext() {
+ return new SecurityContextImpl();
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/SecurityContextImpl.java b/app/common/src/main/java/stirling/software/common/security/SecurityContextImpl.java
new file mode 100644
index 0000000000..88162059b6
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/SecurityContextImpl.java
@@ -0,0 +1,28 @@
+package stirling.software.common.security;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.context.SecurityContextImpl}.
+ *
+ * Basic concrete implementation of {@link SecurityContext}.
+ */
+public class SecurityContextImpl implements SecurityContext {
+
+ private Authentication authentication;
+
+ public SecurityContextImpl() {}
+
+ public SecurityContextImpl(Authentication authentication) {
+ this.authentication = authentication;
+ }
+
+ @Override
+ public Authentication getAuthentication() {
+ return authentication;
+ }
+
+ @Override
+ public void setAuthentication(Authentication authentication) {
+ this.authentication = authentication;
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/SessionInformation.java b/app/common/src/main/java/stirling/software/common/security/SessionInformation.java
new file mode 100644
index 0000000000..d9f03b18a0
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/SessionInformation.java
@@ -0,0 +1,47 @@
+package stirling.software.common.security;
+
+import java.util.Date;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.session.SessionInformation}.
+ *
+ *
Represents a record of a session within the application's session registry.
+ */
+public class SessionInformation {
+
+ private final Object principal;
+ private final String sessionId;
+ private Date lastRequest;
+ private boolean expired = false;
+
+ public SessionInformation(Object principal, String sessionId, Date lastRequest) {
+ this.principal = principal;
+ this.sessionId = sessionId;
+ this.lastRequest = lastRequest;
+ }
+
+ public Object getPrincipal() {
+ return principal;
+ }
+
+ public String getSessionId() {
+ return sessionId;
+ }
+
+ public Date getLastRequest() {
+ return lastRequest;
+ }
+
+ public boolean isExpired() {
+ return expired;
+ }
+
+ public void expireNow() {
+ this.expired = true;
+ }
+
+ public void refreshLastRequest() {
+ this.lastRequest = new Date();
+ }
+}
diff --git a/app/common/src/main/java/stirling/software/common/security/SessionRegistry.java b/app/common/src/main/java/stirling/software/common/security/SessionRegistry.java
new file mode 100644
index 0000000000..33bd25d35e
--- /dev/null
+++ b/app/common/src/main/java/stirling/software/common/security/SessionRegistry.java
@@ -0,0 +1,24 @@
+package stirling.software.common.security;
+
+import java.util.List;
+
+/**
+ * Migration compatibility shim for
+ * {@code org.springframework.security.core.session.SessionRegistry}.
+ *
+ *
Maintains a registry of currently known principals and their sessions.
+ */
+public interface SessionRegistry {
+
+ List