Skip to content

Commit ba60782

Browse files
committed
Upgrade pac4j extension
1 parent f3bd1e4 commit ba60782

File tree

9 files changed

+344
-148
lines changed

9 files changed

+344
-148
lines changed

extensions-core/druid-pac4j/pom.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@
3434
</parent>
3535

3636
<properties>
37-
<pac4j.version>4.5.7</pac4j.version>
37+
<pac4j.version>5.7.3</pac4j.version>
3838

3939
<!-- Following must be updated along with any updates to pac4j version. One can find the compatible version of nimbus libraries in org.pac4j:pac4j-oidc dependencies-->
4040
<nimbus.lang.tag.version>1.7</nimbus.lang.tag.version>
41-
<nimbus.jose.jwt.version>8.22.1</nimbus.jose.jwt.version>
42-
<oauth2.oidc.sdk.version>8.22</oauth2.oidc.sdk.version>
41+
<nimbus.jose.jwt.version>9.37.2</nimbus.jose.jwt.version>
42+
<oauth2.oidc.sdk.version>10.8</oauth2.oidc.sdk.version>
4343
</properties>
4444

4545
<dependencies>
@@ -73,6 +73,13 @@
7373
</exclusions>
7474
</dependency>
7575

76+
<!-- Add pac4j-javaee dependency for JEE components -->
77+
<dependency>
78+
<groupId>org.pac4j</groupId>
79+
<artifactId>pac4j-javaee</artifactId>
80+
<version>${pac4j.version}</version>
81+
</dependency>
82+
7683
<dependency>
7784
<groupId>com.nimbusds</groupId>
7885
<artifactId>lang-tag</artifactId>

extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jAuthenticator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public Filter getFilter()
8282
name,
8383
authorizerName,
8484
pac4jConfigSupplier.get(),
85+
Pac4jCallbackResource.SELF_URL,
8586
pac4jCommonConfig.getCookiePassphrase().getPassword()
8687
);
8788
}

extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jFilter.java

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,15 @@
1919

2020
package org.apache.druid.security.pac4j;
2121

22-
import com.google.common.collect.ImmutableMap;
2322
import org.apache.druid.java.util.common.logger.Logger;
2423
import org.apache.druid.server.security.AuthConfig;
2524
import org.apache.druid.server.security.AuthenticationResult;
2625
import org.pac4j.core.config.Config;
27-
import org.pac4j.core.context.JEEContext;
28-
import org.pac4j.core.context.session.SessionStore;
29-
import org.pac4j.core.engine.CallbackLogic;
3026
import org.pac4j.core.engine.DefaultCallbackLogic;
3127
import org.pac4j.core.engine.DefaultSecurityLogic;
32-
import org.pac4j.core.engine.SecurityLogic;
33-
import org.pac4j.core.http.adapter.JEEHttpActionAdapter;
34-
import org.pac4j.core.profile.UserProfile;
28+
import org.pac4j.core.exception.http.HttpAction;
29+
import org.pac4j.jee.context.JEEContext;
30+
import org.pac4j.jee.http.adapter.JEEHttpActionAdapter;
3531

3632
import javax.servlet.Filter;
3733
import javax.servlet.FilterChain;
@@ -42,41 +38,40 @@
4238
import javax.servlet.http.HttpServletRequest;
4339
import javax.servlet.http.HttpServletResponse;
4440
import java.io.IOException;
45-
import java.util.Collection;
4641

4742
public class Pac4jFilter implements Filter
4843
{
4944
private static final Logger LOGGER = new Logger(Pac4jFilter.class);
5045

5146
private final Config pac4jConfig;
52-
private final SecurityLogic<Object, JEEContext> securityLogic;
53-
private final CallbackLogic<Object, JEEContext> callbackLogic;
54-
private final SessionStore<JEEContext> sessionStore;
55-
47+
private final Pac4jSessionStore sessionStore;
48+
private final String callbackPath;
5649
private final String name;
5750
private final String authorizerName;
5851

59-
public Pac4jFilter(String name, String authorizerName, Config pac4jConfig, String cookiePassphrase)
52+
public Pac4jFilter(
53+
String name,
54+
String authorizerName,
55+
Config pac4jConfig,
56+
String callbackPath,
57+
String cookiePassphrase
58+
)
6059
{
6160
this.pac4jConfig = pac4jConfig;
62-
this.securityLogic = new DefaultSecurityLogic<>();
63-
this.callbackLogic = new DefaultCallbackLogic<>();
64-
61+
this.callbackPath = callbackPath;
6562
this.name = name;
6663
this.authorizerName = authorizerName;
67-
68-
this.sessionStore = new Pac4jSessionStore<>(cookiePassphrase);
64+
this.sessionStore = new Pac4jSessionStore(cookiePassphrase);
6965
}
7066

7167
@Override
7268
public void init(FilterConfig filterConfig)
7369
{
7470
}
7571

76-
7772
@Override
7873
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
79-
throws IOException, ServletException
74+
throws IOException, ServletException
8075
{
8176
// If there's already an auth result, then we have authenticated already, skip this or else caller
8277
// could get HTTP redirect even if one of the druid authenticators in chain has successfully authenticated.
@@ -85,38 +80,59 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
8580
return;
8681
}
8782

88-
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
89-
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
90-
JEEContext context = new JEEContext(httpServletRequest, httpServletResponse, sessionStore);
83+
HttpServletRequest request = (HttpServletRequest) servletRequest;
84+
HttpServletResponse response = (HttpServletResponse) servletResponse;
85+
JEEContext context = new JEEContext(request, response);
86+
87+
if (request.getRequestURI().equals(callbackPath)) {
88+
DefaultCallbackLogic callbackLogic = new DefaultCallbackLogic();
89+
String originalUrl = (String) request.getSession().getAttribute("pac4j.originalUrl");
90+
String redirectUrl = originalUrl != null ? originalUrl : "/";
9191

92-
if (Pac4jCallbackResource.SELF_URL.equals(httpServletRequest.getRequestURI())) {
9392
callbackLogic.perform(
94-
context,
95-
pac4jConfig,
96-
JEEHttpActionAdapter.INSTANCE,
97-
"/",
98-
true, false, false, null);
93+
context,
94+
sessionStore,
95+
pac4jConfig,
96+
JEEHttpActionAdapter.INSTANCE,
97+
redirectUrl, // Redirect to original URL or root
98+
null,
99+
null
100+
);
99101
} else {
100-
UserProfile profile = (UserProfile) securityLogic.perform(
101-
context,
102-
pac4jConfig,
103-
(JEEContext ctx, Collection<UserProfile> profiles, Object... parameters) -> {
104-
if (profiles.isEmpty()) {
105-
LOGGER.warn("No profiles found after OIDC auth.");
106-
return null;
107-
} else {
108-
return profiles.iterator().next();
109-
}
110-
},
111-
JEEHttpActionAdapter.INSTANCE,
112-
null, "none", null, null);
113-
// Changed the Authorizer from null to "none".
114-
// In the older version, if it is null, it simply grant access and returns authorized.
115-
// But in the newer pac4j version, it uses CsrfAuthorizer as default, And because of this, It was returning 403 in API calls.
116-
if (profile != null && profile.getId() != null) {
117-
AuthenticationResult authenticationResult = new AuthenticationResult(profile.getId(), authorizerName, name, ImmutableMap.of("profile", profile));
118-
servletRequest.setAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT, authenticationResult);
119-
filterChain.doFilter(servletRequest, servletResponse);
102+
DefaultSecurityLogic securityLogic = new DefaultSecurityLogic();
103+
try {
104+
securityLogic.perform(
105+
context,
106+
sessionStore,
107+
pac4jConfig,
108+
(ctx, session, profiles, parameters) -> {
109+
try {
110+
// Extract user ID from pac4j profiles and create AuthenticationResult
111+
if (profiles != null && !profiles.isEmpty()) {
112+
String uid = profiles.iterator().next().getId();
113+
if (uid != null) {
114+
AuthenticationResult authenticationResult = new AuthenticationResult(uid, authorizerName, name, null);
115+
servletRequest.setAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT, authenticationResult);
116+
filterChain.doFilter(servletRequest, servletResponse);
117+
}
118+
} else {
119+
LOGGER.warn("No profiles found after OIDC auth.");
120+
// Don't continue the filter chain - let pac4j handle the authentication failure
121+
}
122+
}
123+
catch (IOException | ServletException e) {
124+
throw new RuntimeException(e);
125+
}
126+
return null;
127+
},
128+
JEEHttpActionAdapter.INSTANCE,
129+
null,
130+
"none", // Use "none" instead of authorizerName to avoid CSRF issues
131+
null
132+
);
133+
}
134+
catch (HttpAction e) {
135+
JEEHttpActionAdapter.INSTANCE.adapt(e, context);
120136
}
121137
}
122138
}
@@ -125,4 +141,4 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
125141
public void destroy()
126142
{
127143
}
128-
}
144+
}

0 commit comments

Comments
 (0)