Skip to content

Commit e9f7818

Browse files
committed
oidc: remove pac4j dependency
1 parent 3fca064 commit e9f7818

File tree

13 files changed

+338
-226
lines changed

13 files changed

+338
-226
lines changed

server/plugins/oidc/pom.xml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,6 @@
1515
<name>${project.groupId}:${project.artifactId}</name>
1616

1717
<dependencies>
18-
<dependency>
19-
<groupId>org.pac4j</groupId>
20-
<artifactId>pac4j-core</artifactId>
21-
</dependency>
22-
<dependency>
23-
<groupId>org.pac4j</groupId>
24-
<artifactId>pac4j-oidc</artifactId>
25-
</dependency>
26-
2718
<dependency>
2819
<groupId>com.walmartlabs.concord.server</groupId>
2920
<artifactId>concord-server-sdk</artifactId>
@@ -79,6 +70,11 @@
7970
<artifactId>config</artifactId>
8071
<scope>provided</scope>
8172
</dependency>
73+
<dependency>
74+
<groupId>com.fasterxml.jackson.core</groupId>
75+
<artifactId>jackson-databind</artifactId>
76+
<scope>provided</scope>
77+
</dependency>
8278

8379
<dependency>
8480
<groupId>org.junit.jupiter</groupId>

server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcAuthFilter.java

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* *****
55
* Concord
66
* -----
7-
* Copyright (C) 2020 Ivan Bodrov
7+
* Copyright (C) 2017 - 2025 Walmart Inc.
88
* -----
99
* Licensed under the Apache License, Version 2.0 (the "License");
1010
* you may not use this file except in compliance with the License.
@@ -20,59 +20,49 @@
2020
* =====
2121
*/
2222

23-
import org.pac4j.core.config.Config;
24-
import org.pac4j.core.context.JEEContext;
25-
import org.pac4j.core.exception.http.RedirectionAction;
26-
import org.pac4j.core.util.Pac4jConstants;
27-
import org.pac4j.oidc.client.OidcClient;
28-
2923
import javax.inject.Inject;
30-
import javax.inject.Named;
3124
import javax.servlet.*;
3225
import javax.servlet.http.HttpServletRequest;
3326
import javax.servlet.http.HttpServletResponse;
3427
import java.io.IOException;
28+
import java.util.UUID;
3529

30+
// TODO can be implemented as a JAX-RS resource
3631
public class OidcAuthFilter implements Filter {
3732

3833
public static final String URL = "/api/service/oidc/auth";
34+
private static final String SESSION_STATE_KEY = "OIDC_STATE";
35+
private static final String SESSION_REDIRECT_KEY = "OIDC_REDIRECT_URL";
3936

4037
private final PluginConfiguration pluginConfig;
41-
private final Config oidcConfig;
42-
private final OidcClient<?> client;
38+
private final OidcService oidcService;
4339

4440
@Inject
45-
public OidcAuthFilter(PluginConfiguration pluginConfig, @Named("oidc") Config oidcConfig, OidcClient<?> client) {
41+
public OidcAuthFilter(PluginConfiguration pluginConfig, OidcService oidcService) {
4642
this.pluginConfig = pluginConfig;
47-
this.oidcConfig = oidcConfig;
48-
this.client = client;
49-
50-
if (pluginConfig.isEnabled() && !client.isInitialized()) {
51-
client.init();
52-
}
43+
this.oidcService = oidcService;
5344
}
5445

5546
@Override
56-
@SuppressWarnings("unchecked")
5747
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException {
58-
HttpServletRequest req = (HttpServletRequest) request;
59-
HttpServletResponse resp = (HttpServletResponse) response;
48+
var req = (HttpServletRequest) request;
49+
var resp = (HttpServletResponse) response;
6050

6151
if (!pluginConfig.isEnabled()) {
6252
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "OIDC disabled");
6353
return;
6454
}
6555

66-
JEEContext context = new JEEContext(req, resp);
67-
68-
String redirectUrl = req.getParameter("from");
69-
context.getSessionStore().set(context, Pac4jConstants.REQUESTED_URL, redirectUrl);
56+
var redirectUrl = req.getParameter("from");
57+
var state = UUID.randomUUID().toString();
58+
var callbackUrl = pluginConfig.getUrlBase() + OidcCallbackFilter.URL + "?client_name=oidc";
7059

71-
RedirectionAction action = client.getRedirectionActionBuilder()
72-
.getRedirectionAction(context)
73-
.orElseThrow(() -> new IllegalStateException("Can't get a redirection action for the request"));
60+
var session = req.getSession(true);
61+
session.setAttribute(SESSION_STATE_KEY, state);
62+
session.setAttribute(SESSION_REDIRECT_KEY, redirectUrl);
7463

75-
oidcConfig.getHttpActionAdapter().adapt(action, context);
64+
var authUrl = oidcService.buildAuthorizationUrl(callbackUrl, state);
65+
resp.sendRedirect(authUrl);
7666
}
7767

7868
@Override

server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcAuthenticationHandler.java

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* *****
55
* Concord
66
* -----
7-
* Copyright (C) 2017 - 2020 Walmart Inc.
7+
* Copyright (C) 2017 - 2025 Walmart Inc.
88
* -----
99
* Licensed under the Apache License, Version 2.0 (the "License");
1010
* you may not use this file except in compliance with the License.
@@ -22,35 +22,32 @@
2222

2323
import com.walmartlabs.concord.server.boot.filters.AuthenticationHandler;
2424
import org.apache.shiro.authc.AuthenticationToken;
25-
import org.pac4j.core.context.JEEContext;
26-
import org.pac4j.core.credentials.TokenCredentials;
27-
import org.pac4j.core.profile.ProfileManager;
28-
import org.pac4j.oidc.config.OidcConfiguration;
29-
import org.pac4j.oidc.credentials.authenticator.UserInfoOidcAuthenticator;
30-
import org.pac4j.oidc.profile.OidcProfile;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
3127

3228
import javax.inject.Inject;
3329
import javax.servlet.ServletRequest;
3430
import javax.servlet.ServletResponse;
3531
import javax.servlet.http.HttpServletRequest;
3632
import javax.servlet.http.HttpServletResponse;
3733
import java.io.IOException;
38-
import java.util.Optional;
3934

4035
public class OidcAuthenticationHandler implements AuthenticationHandler {
4136

37+
private static final Logger log = LoggerFactory.getLogger(OidcAuthenticationHandler.class);
4238
private static final String FORM_URL_PATTERN = "/forms/.*";
4339

4440
private static final String AUTHORIZATION_HEADER = "Authorization";
4541
private static final String HEADER_PREFIX = "Bearer";
42+
private static final String SESSION_PROFILE_KEY = "OIDC_USER_PROFILE";
4643

4744
private final PluginConfiguration cfg;
48-
private final OidcConfiguration oidcCfg;
45+
private final OidcService oidcService;
4946

5047
@Inject
51-
public OidcAuthenticationHandler(PluginConfiguration cfg, OidcConfiguration oidcCfg) {
48+
public OidcAuthenticationHandler(PluginConfiguration cfg, OidcService oidcService) {
5249
this.cfg = cfg;
53-
this.oidcCfg = oidcCfg;
50+
this.oidcService = oidcService;
5451
}
5552

5653
@Override
@@ -59,33 +56,32 @@ public AuthenticationToken createToken(ServletRequest request, ServletResponse r
5956
return null;
6057
}
6158

62-
HttpServletRequest req = (HttpServletRequest) request;
63-
HttpServletResponse resp = (HttpServletResponse) response;
64-
JEEContext context = new JEEContext(req, resp);
59+
var req = (HttpServletRequest) request;
6560

66-
Optional<OidcProfile> profile;
67-
68-
// check the token first
69-
String header = req.getHeader(AUTHORIZATION_HEADER);
70-
if (header != null) {
71-
String[] as = header.split(" ");
72-
if (as.length != 2 || !as[0].equals(HEADER_PREFIX)) {
61+
var header = req.getHeader(AUTHORIZATION_HEADER);
62+
if (header == null) {
63+
var session = req.getSession(false);
64+
if (session == null) {
7365
return null;
7466
}
7567

76-
TokenCredentials credentials = new TokenCredentials(as[1].trim());
77-
78-
UserInfoOidcAuthenticator authenticator = new UserInfoOidcAuthenticator(oidcCfg);
79-
authenticator.validate(credentials, context);
68+
var profile = (UserProfile) session.getAttribute(SESSION_PROFILE_KEY);
69+
return new OidcToken(profile);
70+
}
8071

81-
// we know that UserInfoOidcAuthenticator produces OidcProfile, so we can cast to it here
82-
profile = Optional.ofNullable((OidcProfile) credentials.getUserProfile());
83-
} else {
84-
ProfileManager<OidcProfile> profileManager = new ProfileManager<>(context);
85-
profile = profileManager.get(true);
72+
var as = header.split(" ");
73+
if (as.length != 2 || !as[0].equals(HEADER_PREFIX)) {
74+
return null;
8675
}
8776

88-
return profile.map(OidcToken::new).orElse(null);
77+
var accessToken = as[1].trim();
78+
try {
79+
var profile = oidcService.validateToken(accessToken);
80+
return new OidcToken(profile);
81+
} catch (IOException e) {
82+
log.warn("Token validation failed: {}", e.getMessage());
83+
return null;
84+
}
8985
}
9086

9187
@Override
@@ -94,8 +90,8 @@ public boolean onAccessDenied(ServletRequest request, ServletResponse response)
9490
return false;
9591
}
9692

97-
HttpServletRequest req = (HttpServletRequest) request;
98-
HttpServletResponse resp = (HttpServletResponse) response;
93+
var req = (HttpServletRequest) request;
94+
var resp = (HttpServletResponse) response;
9995

10096
if (req.getRequestURI().matches(FORM_URL_PATTERN)) {
10197
resp.sendRedirect(resp.encodeRedirectURL(OidcAuthFilter.URL + "?from=" + req.getRequestURL()));

server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcCallbackFilter.java

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* *****
55
* Concord
66
* -----
7-
* Copyright (C) 2020 Ivan Bodrov
7+
* Copyright (C) 2017 - 2025 Walmart Inc.
88
* -----
99
* Licensed under the Apache License, Version 2.0 (the "License");
1010
* you may not use this file except in compliance with the License.
@@ -20,99 +20,92 @@
2020
* =====
2121
*/
2222

23-
import org.pac4j.core.config.Config;
24-
import org.pac4j.core.context.JEEContext;
25-
import org.pac4j.core.context.session.SessionStore;
26-
import org.pac4j.core.engine.CallbackLogic;
27-
import org.pac4j.core.exception.TechnicalException;
28-
import org.pac4j.core.util.Pac4jConstants;
2923
import org.slf4j.Logger;
3024
import org.slf4j.LoggerFactory;
3125

3226
import javax.inject.Inject;
33-
import javax.inject.Named;
34-
import javax.servlet.*;
27+
import javax.servlet.Filter;
28+
import javax.servlet.FilterChain;
29+
import javax.servlet.ServletRequest;
30+
import javax.servlet.ServletResponse;
3531
import javax.servlet.http.HttpServletRequest;
3632
import javax.servlet.http.HttpServletResponse;
37-
import javax.servlet.http.HttpSession;
3833
import java.io.IOException;
3934

4035
public class OidcCallbackFilter implements Filter {
4136

4237
private static final Logger log = LoggerFactory.getLogger(OidcCallbackFilter.class);
4338

4439
public static final String URL = "/api/service/oidc/callback";
40+
private static final String SESSION_STATE_KEY = "OIDC_STATE";
41+
private static final String SESSION_REDIRECT_KEY = "OIDC_REDIRECT_URL";
42+
private static final String SESSION_PROFILE_KEY = "OIDC_USER_PROFILE";
4543

4644
private final PluginConfiguration cfg;
47-
private final Config pac4jConfig;
45+
private final OidcService oidcService;
4846

4947
@Inject
50-
public OidcCallbackFilter(PluginConfiguration cfg,
51-
@Named("oidc") Config pac4jConfig) {
52-
48+
public OidcCallbackFilter(PluginConfiguration cfg, OidcService oidcService) {
5349
this.cfg = cfg;
54-
this.pac4jConfig = pac4jConfig;
50+
this.oidcService = oidcService;
5551
}
5652

5753
@Override
58-
@SuppressWarnings("unchecked")
5954
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException {
60-
HttpServletRequest req = (HttpServletRequest) request;
61-
HttpServletResponse resp = (HttpServletResponse) response;
55+
var req = (HttpServletRequest) request;
56+
var resp = (HttpServletResponse) response;
6257

6358
if (!cfg.isEnabled()) {
6459
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "OIDC disabled");
6560
return;
6661
}
6762

68-
JEEContext context = new JEEContext(req, resp, pac4jConfig.getSessionStore());
63+
var session = req.getSession(false);
64+
if (session == null) {
65+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "No session");
66+
return;
67+
}
6968

70-
String postLoginUrl = removeRequestedUrl(context);
69+
var postLoginUrl = (String) session.getAttribute(SESSION_REDIRECT_KEY);
7170
if (postLoginUrl == null || postLoginUrl.trim().isEmpty()) {
7271
postLoginUrl = cfg.getAfterLoginUrl();
7372
}
7473

75-
String error = req.getParameter("error");
74+
var error = req.getParameter("error");
7675
if (error != null) {
77-
String derivedError = "unknown";
76+
var derivedError = "unknown";
7877
if ("access_denied".equals(error)) {
7978
derivedError = "oidc_access_denied";
8079
}
8180
resp.sendRedirect(resp.encodeRedirectURL(cfg.getOnErrorUrl() + "?from=" + postLoginUrl + "&error=" + derivedError));
8281
return;
8382
}
8483

85-
try {
86-
CallbackLogic<?, JEEContext> callback = pac4jConfig.getCallbackLogic();
87-
callback.perform(context, pac4jConfig, pac4jConfig.getHttpActionAdapter(), postLoginUrl, true, false, true, OidcPluginModule.CLIENT_NAME);
88-
} catch (TechnicalException e) {
89-
log.warn("OIDC callback error: {}", e.getMessage());
90-
HttpSession session = req.getSession(false);
91-
if (session != null) {
92-
session.invalidate();
93-
}
84+
var code = req.getParameter("code");
85+
var state = req.getParameter("state");
86+
var expectedState = (String) session.getAttribute(SESSION_STATE_KEY);
87+
88+
if (code == null || state == null || !state.equals(expectedState)) {
89+
log.warn("Invalid callback parameters: code={}, state={}, expectedState={}", code != null, state, expectedState);
90+
session.invalidate();
9491
resp.sendRedirect(resp.encodeRedirectURL(OidcAuthFilter.URL + "?from=" + postLoginUrl));
92+
return;
9593
}
96-
}
9794

98-
@Override
99-
public void init(FilterConfig filterConfig) {
100-
// do nothing
101-
}
95+
try {
96+
var redirectUri = cfg.getUrlBase() + URL + "?client_name=oidc";
97+
var profile = oidcService.exchangeCodeForProfile(code, redirectUri);
10298

103-
@Override
104-
public void destroy() {
105-
// do nothing
106-
}
99+
session.setAttribute(SESSION_PROFILE_KEY, profile);
100+
session.removeAttribute(SESSION_STATE_KEY);
101+
session.removeAttribute(SESSION_REDIRECT_KEY);
102+
103+
resp.sendRedirect(resp.encodeRedirectURL(postLoginUrl));
107104

108-
@SuppressWarnings("unchecked")
109-
private static String removeRequestedUrl(JEEContext context) {
110-
SessionStore<JEEContext> sessionStore = context.getSessionStore();
111-
Object result = sessionStore.get(context, Pac4jConstants.REQUESTED_URL).orElse(null);
112-
sessionStore.set(context, Pac4jConstants.REQUESTED_URL, "");
113-
if (result instanceof String) {
114-
return (String) result;
105+
} catch (Exception e) {
106+
log.warn("OIDC callback error: {}", e.getMessage());
107+
session.invalidate();
108+
resp.sendRedirect(resp.encodeRedirectURL(OidcAuthFilter.URL + "?from=" + postLoginUrl));
115109
}
116-
return null;
117110
}
118111
}

0 commit comments

Comments
 (0)