Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
// remove pac4j cookies
response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jCsrfToken", p4j_domainName, pac4jPath));
response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jCsrfTokenExpirationDate", p4j_domainName, pac4jPath));
response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jPreviousCsrfToken", p4j_domainName, pac4jPath));
response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jRequestedUrl", p4j_domainName, pac4jPath));
response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jUserProfiles", p4j_domainName, pac4jPath));
response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jUserProfiles", p4j_domainName, pac4jPath+"/websso"));
Expand Down
27 changes: 19 additions & 8 deletions gateway-provider-security-pac4j/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
<name>gateway-provider-security-pac4j</name>
<description>An extension of the gateway integrating pac4j as an authentication provider.</description>

<repositories>
<repository>
<id>shib-release</id>
<url>https://build.shibboleth.net/maven/releases</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.apache.knox</groupId>
Expand Down Expand Up @@ -99,6 +112,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-javaee</artifactId>
</dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-oauth</artifactId>
Expand All @@ -109,7 +126,7 @@
</dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-saml-opensamlv3</artifactId>
<artifactId>pac4j-saml</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
Expand All @@ -135,13 +152,7 @@
</dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>jee-pac4j</artifactId>
<exclusions>
<exclusion>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-core</artifactId>
</exclusion>
</exclusions>
<artifactId>javaee-pac4j</artifactId>
</dependency>
<dependency>
<groupId>net.shibboleth.utilities</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@

import org.pac4j.core.client.Client;
import org.pac4j.core.http.callback.PathParameterCallbackUrlResolver;
import org.pac4j.oidc.client.AzureAdClient;
import org.pac4j.oidc.client.AzureAd2Client;

public class AzureADClientConfigurationDecorator implements ClientConfigurationDecorator {
private static final String AZURE_AD_CLIENT_CLASS_NAME = AzureAdClient.class.getSimpleName();
private static final String AZURE_AD_CLIENT_CLASS_NAME = AzureAd2Client.class.getSimpleName();

@Override
public void decorateClients(List<Client> clients, Map<String, String> properties) {
for (Client client : clients) {
if (AZURE_AD_CLIENT_CLASS_NAME.equalsIgnoreCase(client.getName())) {
// special handling for Azure AD, use path separators instead of query params
((AzureAdClient) client).setCallbackUrlResolver(new PathParameterCallbackUrlResolver());
((AzureAd2Client) client).setCallbackUrlResolver(new PathParameterCallbackUrlResolver());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private void setNameIdPolicyFormat(Map<String, String> properties, final SAML2Cl
private void setKeyStoreType(Map<String, String> properties, final SAML2Client saml2Client) {
final String keyStoreType = properties.get(KEYSTORE_TYPE);
if (StringUtils.isNotBlank(keyStoreType)) {
saml2Client.getConfiguration().setKeystoreType(keyStoreType);
saml2Client.getConfiguration().setKeyStoreType(keyStoreType);
log.pac4jSamlKeystoreType(keyStoreType);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,15 @@
import org.pac4j.config.client.PropertiesConstants;
import org.pac4j.core.client.Client;
import org.pac4j.core.config.Config;
import org.pac4j.core.context.session.JEESessionStore;
import org.pac4j.core.context.FrameworkParameters;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.http.client.indirect.IndirectBasicAuthClient;
import org.pac4j.http.credentials.authenticator.test.SimpleTestUsernamePasswordAuthenticator;
import org.pac4j.jee.context.session.JEESessionStore;
import org.pac4j.jee.filter.CallbackFilter;
import org.pac4j.jee.filter.SecurityFilter;
import org.pac4j.oidc.client.AzureAdClient;
import org.pac4j.oidc.client.AzureAd2Client;
import org.pac4j.saml.client.SAML2Client;

import javax.servlet.Filter;
Expand Down Expand Up @@ -186,7 +187,7 @@ public void init( FilterConfig filterConfig ) throws ServletException {
add the callback parameter to know it's a callback,
Azure AD does not honor query param so we add callback param as path element.
*/
if (AzureAdClient.class.getSimpleName().equals(clientNameParameter) || (
if (AzureAd2Client.class.getSimpleName().equals(clientNameParameter) || (
!StringUtils.isBlank(oidcType) && PAC4J_OICD_TYPE_AZURE
.equals(oidcType))) {
pac4jCallbackUrl = pac4jCallbackUrl + URL_PATH_SEPARATOR + PAC4J_CALLBACK_PARAMETER;
Expand Down Expand Up @@ -252,12 +253,12 @@ public void init( FilterConfig filterConfig ) throws ServletException {

if(!StringUtils.isBlank(sessionStoreVar) && JEESessionStore.class.getName().contains(sessionStoreVar) ) {
/* NOTE: this is a final variable, and will be used by all requests in Knox */
sessionStore = JEESessionStore.INSTANCE;
sessionStore = new JEESessionStore();
} else {
sessionStore = new KnoxSessionStore(cryptoService, clusterName, domainSuffix, sessionStoreConfigs);
}

config.setSessionStore(sessionStore);
config.setSessionStoreFactory((FrameworkParameters parameters) -> sessionStore);

SessionInvalidators.KNOX_SSO_INVALIDATOR.registerSessionInvalidator(this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.pac4j.core.config.Config;
import org.pac4j.core.context.JEEContext;
import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.context.FrameworkParameters;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.profile.ProfileManager;
import org.pac4j.core.profile.UserProfile;
import org.pac4j.core.util.Pac4jConstants;
import org.pac4j.jee.context.JEEContext;
import org.pac4j.jee.context.JEEFrameworkParameters;

import javax.security.auth.Subject;
import javax.servlet.Filter;
Expand All @@ -46,6 +50,7 @@
import java.io.IOException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.LinkedHashMap;
import java.util.Optional;

/**
Expand Down Expand Up @@ -84,13 +89,18 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo

final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final JEEContext context = new JEEContext(request, response, ((Config)request.getAttribute(PAC4J_CONFIG)).getSessionStore());
final ProfileManager<CommonProfile> manager = new ProfileManager<>(context);
final Optional<CommonProfile> optional = manager.get(true);
final JEEContext context = new JEEContext(request, response);
Config pac4jConfig = ((Config)request.getAttribute(PAC4J_CONFIG));
FrameworkParameters frameworkParameters = new JEEFrameworkParameters(request, response);
SessionStore sessionStore = pac4jConfig.getSessionStoreFactory().newSessionStore(frameworkParameters);
final ProfileManager manager = new ProfileManager(context, sessionStore);
final Optional<UserProfile> optional = manager.getProfile();
if (optional.isPresent()) {
CommonProfile profile = optional.get();
UserProfile profile = optional.get();
logger.debug("User authenticated as: {}", profile);
manager.remove(true);
//manager.removeProfiles(); would only work if session existed, but our session store does not support sessions
sessionStore.set(context, Pac4jConstants.USER_PROFILES, new LinkedHashMap<String, UserProfile>());
context.setRequestAttribute(Pac4jConstants.USER_PROFILES, new LinkedHashMap<String, UserProfile>());
String id = null;
if (idAttribute != null) {
Object attribute = profile.getAttribute(idAttribute);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,19 @@
import org.apache.knox.gateway.util.Urls;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.pac4j.core.context.ContextHelper;
import org.pac4j.core.context.WebContextHelper;
import org.pac4j.core.context.Cookie;
import org.pac4j.core.context.JEEContext;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.util.JavaSerializationHelper;
import org.pac4j.core.util.serializer.JavaSerializer;
import org.pac4j.core.util.Pac4jConstants;
import org.pac4j.jee.context.JEEContext;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
Expand All @@ -66,15 +65,15 @@
*
* @since 0.8.0
*/
public class KnoxSessionStore<C extends WebContext> implements SessionStore<C> {
public class KnoxSessionStore implements SessionStore {

private static final Logger logger = LogManager.getLogger(KnoxSessionStore.class);

public static final String PAC4J_PASSWORD = "pac4j.password";

public static final String PAC4J_SESSION_PREFIX = "pac4j.session.";

private final JavaSerializationHelper javaSerializationHelper;
private final JavaSerializer javaSerializer;

private final CryptoService cryptoService;

Expand All @@ -85,14 +84,14 @@ public class KnoxSessionStore<C extends WebContext> implements SessionStore<C> {
final Map<String, String> sessionStoreConfigs;

public KnoxSessionStore(final CryptoService cryptoService, final String clusterName, final String domainSuffix) {
this(cryptoService, clusterName, domainSuffix, new HashMap());
this(cryptoService, clusterName, domainSuffix, new HashMap<>());
}

public KnoxSessionStore(final CryptoService cryptoService,
final String clusterName,
final String domainSuffix,
final Map<String, String> sessionStoreConfigs) {
javaSerializationHelper = new JavaSerializationHelper();
this.javaSerializer = new JavaSerializer();
this.cryptoService = cryptoService;
this.clusterName = clusterName;
this.domainSuffix = domainSuffix;
Expand All @@ -101,11 +100,11 @@ public KnoxSessionStore(final CryptoService cryptoService,


@Override
public String getOrCreateSessionId(WebContext context) {
return null;
public Optional<String> getSessionId(WebContext context, boolean createSession) {
return Optional.empty();
}

private Serializable uncompressDecryptBase64(final String v) {
private Object uncompressDecryptBase64(final String v) {
if (v != null && !v.isEmpty()) {
byte[] bytes = Base64.decodeBase64(v);
EncryptionResult result = EncryptionResult.fromByteArray(bytes);
Expand All @@ -116,7 +115,7 @@ private Serializable uncompressDecryptBase64(final String v) {
result.salt);
if (clear != null) {
try {
return javaSerializationHelper.deserializeFromBytes(unCompress(clear));
return javaSerializer.deserializeFromBytes(unCompress(clear));
} catch (IOException e) {
throw new TechnicalException(e);
}
Expand All @@ -127,7 +126,7 @@ private Serializable uncompressDecryptBase64(final String v) {

@Override
public Optional<Object> get(WebContext context, String key) {
final Cookie cookie = ContextHelper.getCookie(context, PAC4J_SESSION_PREFIX + key);
final Cookie cookie = WebContextHelper.getCookie(context, PAC4J_SESSION_PREFIX + key);
Object value = null;
if (cookie != null) {
value = uncompressDecryptBase64(cookie.getValue());
Expand All @@ -141,13 +140,13 @@ private String compressEncryptBase64(final Object o) {
|| (o instanceof Map<?,?> && ((Map<?,?>)o).isEmpty())) {
return null;
} else {
byte[] bytes = javaSerializationHelper.serializeToBytes((Serializable) o);
byte[] bytes = javaSerializer.serializeToBytes(o);

/* compress the data */
try {
bytes = compress(bytes);

if(bytes.length > 3000) {
if (bytes.length > 3000) {
logger.warn("Cookie too big, it might not be properly set");
}

Expand Down Expand Up @@ -186,7 +185,7 @@ public void set(WebContext context, String key, Object value) {
throw new TechnicalException(e);
}
setCookieHeader.setSecure(true);
if(ContextHelper.isHttpsOrSecure(context)) {
if (WebContextHelper.isHttpsOrSecure(context)) {
setCookieHeader.setHttpOnly(true);
}

Expand Down Expand Up @@ -293,7 +292,7 @@ private Object clearUserProfile(final Object value) {
}

@Override
public Optional<SessionStore<C>> buildFromTrackableSession(WebContext arg0, Object arg1) {
public Optional<SessionStore> buildFromTrackableSession(WebContext arg0, Object arg1) {
return Optional.empty();
}

Expand All @@ -303,7 +302,7 @@ public boolean destroySession(WebContext arg0) {
}

@Override
public Optional getTrackableSession(WebContext arg0) {
public Optional<Object> getTrackableSession(WebContext arg0) {
return Optional.empty();
}

Expand Down
Loading