Upgrade to ACS v23.x, Jakarta, jdk17

This commit is contained in:
2024-08-22 14:21:39 -04:00
committed by Axel Faust
parent 0044ce3f6b
commit 6f7910aa93
22 changed files with 1052 additions and 108 deletions

View File

@@ -21,7 +21,7 @@
<parent>
<groupId>de.acosix.alfresco.keycloak</groupId>
<artifactId>de.acosix.alfresco.keycloak.parent</artifactId>
<version>1.1.0-rc7</version>
<version>1.2.0-rc1</version>
</parent>
<artifactId>de.acosix.alfresco.keycloak.repo</artifactId>
@@ -44,12 +44,12 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
@@ -71,12 +71,17 @@
<groupId>org.jboss.resteasy</groupId>
<artifactId>*</artifactId>
</exclusion>
<!-- use default from Alfresco Repository -->
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-adapter-spi</artifactId>
<artifactId>keycloak-jakarta-servlet-adapter-spi</artifactId>
<exclusions>
<!-- don't include activation standalone JAR - rely on JDK inclusion since Java 6 -->
<exclusion>
@@ -105,7 +110,7 @@
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-filter-adapter</artifactId>
<artifactId>keycloak-jakarta-servlet-filter-adapter</artifactId>
<exclusions>
<!-- don't include activation standalone JAR - rely on JDK inclusion since Java 6 -->
<exclusion>
@@ -233,7 +238,8 @@
<goal>shade</goal>
</goals>
<configuration>
<createSourcesJar>true</createSourcesJar>
<!-- generating using `sources` classifier, which conflicts with the main `sources` -->
<createSourcesJar>false</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
<artifactSet>

View File

@@ -6,7 +6,7 @@ cache.${moduleId}.ssoToSessionCache.maxIdleSeconds=0
cache.${moduleId}.ssoToSessionCache.cluster.type=fully-distributed
cache.${moduleId}.ssoToSessionCache.backup-count=1
cache.${moduleId}.ssoToSessionCache.eviction-policy=LRU
cache.${moduleId}.ssoToSessionCache.merge-policy=com.hazelcast.map.merge.PutIfAbsentMapMergePolicy
cache.${moduleId}.ssoToSessionCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
cache.${moduleId}.ssoToSessionCache.readBackupData=false
# explicitly not clearable - should be cleared via Keycloak back-channel action
cache.${moduleId}.ssoToSessionCache.clearable=false
@@ -19,7 +19,7 @@ cache.${moduleId}.sessionToSsoCache.maxIdleSeconds=0
cache.${moduleId}.sessionToSsoCache.cluster.type=fully-distributed
cache.${moduleId}.sessionToSsoCache.backup-count=1
cache.${moduleId}.sessionToSsoCache.eviction-policy=LRU
cache.${moduleId}.sessionToSsoCache.merge-policy=com.hazelcast.map.merge.PutIfAbsentMapMergePolicy
cache.${moduleId}.sessionToSsoCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
cache.${moduleId}.sessionToSsoCache.readBackupData=false
# explicitly not clearable - should be cleared via Keycloak back-channel action
cache.${moduleId}.sessionToSsoCache.clearable=false
@@ -32,7 +32,7 @@ cache.${moduleId}.principalToSessionCache.maxIdleSeconds=0
cache.${moduleId}.principalToSessionCache.cluster.type=fully-distributed
cache.${moduleId}.principalToSessionCache.backup-count=1
cache.${moduleId}.principalToSessionCache.eviction-policy=LRU
cache.${moduleId}.principalToSessionCache.merge-policy=com.hazelcast.map.merge.PutIfAbsentMapMergePolicy
cache.${moduleId}.principalToSessionCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
cache.${moduleId}.principalToSessionCache.readBackupData=false
# explicitly not clearable - should be cleared via Keycloak back-channel action
cache.${moduleId}.principalToSessionCache.clearable=false
@@ -45,7 +45,7 @@ cache.${moduleId}.sessionToPrincipalCache.maxIdleSeconds=0
cache.${moduleId}.sessionToPrincipalCache.cluster.type=fully-distributed
cache.${moduleId}.sessionToPrincipalCache.backup-count=1
cache.${moduleId}.sessionToPrincipalCache.eviction-policy=LRU
cache.${moduleId}.sessionToPrincipalCache.merge-policy=com.hazelcast.map.merge.PutIfAbsentMapMergePolicy
cache.${moduleId}.sessionToPrincipalCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
cache.${moduleId}.sessionToPrincipalCache.readBackupData=false
# explicitly not clearable - should be cleared via Keycloak back-channel action
cache.${moduleId}.sessionToPrincipalCache.clearable=false
@@ -58,7 +58,7 @@ cache.${moduleId}.ticketTokenCache.maxIdleSeconds=0
cache.${moduleId}.ticketTokenCache.cluster.type=fully-distributed
cache.${moduleId}.ticketTokenCache.backup-count=1
cache.${moduleId}.ticketTokenCache.eviction-policy=LRU
cache.${moduleId}.ticketTokenCache.merge-policy=com.hazelcast.map.merge.PutIfAbsentMapMergePolicy
cache.${moduleId}.ticketTokenCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy
cache.${moduleId}.ticketTokenCache.readBackupData=false
# dangerous to be cleared, as roles / claims can no longer be mapped
# would always be better to just invalidate the tickets themselves

View File

@@ -0,0 +1,12 @@
logger.acosix-alfresco-keycloak.name=${project.artifactId}
logger.acosix-alfresco-keycloak.level=INFO
logger.acosix-alfresco-keycloak-deps.name=${project.artifactId}.deps
logger.acosix-alfresco-keycloak-deps.level=ERROR
logger.acosix-alfresco-keycloak-deps-keycloak.name=${project.artifactId}.deps.keycloak
logger.acosix-alfresco-keycloak-deps-keycloak.level=ERROR
logger.acosix-alfresco-keycloak-deps-jboss.name=${project.artifactId}.deps.jboss
logger.acosix-alfresco-keycloak-deps-jboss.level=ERROR

View File

@@ -21,16 +21,16 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.alfresco.repo.SessionUser;
import org.alfresco.repo.cache.SimpleCache;

View File

@@ -17,8 +17,8 @@ package de.acosix.alfresco.keycloak.repo.authentication;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationException;

View File

@@ -17,13 +17,13 @@ package de.acosix.alfresco.keycloak.repo.authentication;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.alfresco.repo.SessionUser;
import org.alfresco.repo.web.scripts.bean.LoginPost;

View File

@@ -17,12 +17,12 @@ package de.acosix.alfresco.keycloak.repo.authentication;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter;

View File

@@ -23,7 +23,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.alfresco.util.Pair;
import org.keycloak.adapters.servlet.ServletHttpFacade;
@@ -39,7 +39,7 @@ import org.keycloak.adapters.spi.HttpFacade;
public class ResponseHeaderCookieCaptureServletHttpFacade extends ServletHttpFacade
{
protected final Map<Pair<String, String>, javax.servlet.http.Cookie> cookies = new HashMap<>();
protected final Map<Pair<String, String>, jakarta.servlet.http.Cookie> cookies = new HashMap<>();
protected final Map<String, List<String>> headers = new HashMap<>();
@@ -71,7 +71,7 @@ public class ResponseHeaderCookieCaptureServletHttpFacade extends ServletHttpFac
/**
* @return the cookies
*/
public List<javax.servlet.http.Cookie> getCookies()
public List<jakarta.servlet.http.Cookie> getCookies()
{
return new ArrayList<>(this.cookies.values());
}
@@ -157,7 +157,7 @@ public class ResponseHeaderCookieCaptureServletHttpFacade extends ServletHttpFac
public void setCookie(final String name, final String value, final String path, final String domain, final int maxAge,
final boolean secure, final boolean httpOnly)
{
final javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie(name, value);
final jakarta.servlet.http.Cookie cookie = new jakarta.servlet.http.Cookie(name, value);
cookie.setPath(path);
if (domain != null)
{

View File

@@ -4,37 +4,40 @@ import com.fasterxml.jackson.core.JsonParseException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import org.alfresco.util.ParameterCheck;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.keycloak.OAuth2Constants;
import org.keycloak.TokenVerifier;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.adapters.ServerRequest.HttpFailure;
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
import org.keycloak.adapters.rotation.AdapterTokenVerifier.VerifiedTokens;
import org.keycloak.common.VerificationException;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.Time;
import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.protocol.oidc.client.authentication.ClientCredentialsProviderUtils;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.util.JsonSerialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.acosix.alfresco.keycloak.repo.util.NameValueMapAdapter;
import de.acosix.alfresco.keycloak.repo.util.RefreshableAccessTokenHolder;
/**
@@ -282,12 +285,20 @@ public class AccessTokenClient
final HttpPost post = new HttpPost(KeycloakUriBuilder.fromUri(this.deployment.getAuthServerBaseUrl())
.path(ServiceUrlConstants.TOKEN_PATH).build(this.deployment.getRealm()));
final List<NameValuePair> formParams = new ArrayList<>();
final List<NameValuePair> formParams = new LinkedList<>();
postParamProvider.accept(formParams);
final List<Header> headers = new LinkedList<>();
ClientCredentialsProviderUtils.setClientCredentials(this.deployment, post, formParams);
ClientCredentialsProviderUtils.setClientCredentials(
this.deployment.getAdapterConfig(),
this.deployment.getClientAuthenticator(),
new NameValueMapAdapter<>(headers, BasicHeader.class),
new NameValueMapAdapter<>(formParams, BasicNameValuePair.class));
for (Header header : headers)
post.addHeader(header);
final UrlEncodedFormEntity form = new UrlEncodedFormEntity(formParams, "UTF-8");
post.setEntity(form);

View File

@@ -0,0 +1,151 @@
package de.acosix.alfresco.keycloak.repo.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.apache.http.NameValuePair;
public class NameValueMapAdapter<T extends NameValuePair> implements Map<String, String> {
private final List<? extends NameValuePair> pairs;
private final Class<T> type;
public NameValueMapAdapter(List<? extends NameValuePair> pairs, Class<T> type) {
this.pairs = pairs;
this.type = type;
}
@Override
public void clear() {
this.pairs.clear();
}
@Override
public boolean containsKey(Object key) {
for (NameValuePair pair : this.pairs)
if (pair.getName().equals(key))
return true;
return false;
}
@Override
public boolean containsValue(Object value) {
for (NameValuePair pair : this.pairs)
if (pair.getValue().equals(value))
return true;
return false;
}
@Override
public Set<Entry<String, String>> entrySet() {
Set<Entry<String, String>> set = new HashSet<Entry<String, String>>();
for (NameValuePair pair : this.pairs) {
set.add(new Entry<String, String>() {
@Override
public String getKey() {
return pair.getName();
}
@Override
public String getValue() {
return pair.getValue();
}
@Override
public String setValue(String value) {
throw new UnsupportedOperationException();
}
});
}
return set;
}
@Override
public String get(Object key) {
for (NameValuePair pair : this.pairs)
if (pair.getName().equals(key))
return pair.getValue();
return null;
}
@Override
public boolean isEmpty() {
return this.pairs.isEmpty();
}
@Override
public Set<String> keySet() {
Set<String> set = new HashSet<>();
for (NameValuePair pair : this.pairs)
set.add(pair.getName());
return set;
}
@Override
public String put(String key, String value) {
ListIterator<NameValuePair> i = (ListIterator<NameValuePair>) this.pairs.listIterator();
while (i.hasNext()) {
NameValuePair pair = i.next();
if (pair.getName().equals(key)) {
i.remove();
i.add(this.newNameValuePair(key, value));
return pair.getValue();
}
}
i.add(this.newNameValuePair(key, value));
return null;
}
@Override
public void putAll(Map<? extends String, ? extends String> m) {
for (Entry<? extends String, ? extends String> e : m.entrySet())
this.put(e.getKey(), e.getValue());
}
@Override
public String remove(Object key) {
ListIterator<NameValuePair> i = (ListIterator<NameValuePair>) this.pairs.listIterator();
while (i.hasNext()) {
NameValuePair pair = i.next();
if (pair.getName().equals(key)) {
i.remove();
return pair.getValue();
}
}
return null;
}
@Override
public int size() {
return this.pairs.size();
}
@Override
public Collection<String> values() {
List<String> list = new ArrayList<>(this.pairs.size());
for (NameValuePair pair : this.pairs)
list.add(pair.getValue());
return list;
}
private T newNameValuePair(String key, String value) {
try {
Constructor<T> constructor = this.type.getConstructor(String.class, String.class);
return constructor.newInstance(key, value);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new AlfrescoRuntimeException(e.getMessage(), e);
}
}
}