Upgrade pac4j-oidc to 4.5.7 to address CVE-2021-44878 (#15522)

* Upgrade org.pac4j:pac4j-oidc to 4.5.5 to address CVE-2021-44878
* add CVE suppression and notes, since vulnerability scan still shows this CVE
* Add tests to improve coverage
This commit is contained in:
Keerthana Srikanth 2023-12-14 00:14:05 +05:30 committed by GitHub
parent 4670a7650f
commit f32dbd4131
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 26 deletions

View File

@ -34,7 +34,7 @@
</parent>
<properties>
<pac4j.version>3.8.3</pac4j.version>
<pac4j.version>4.5.7</pac4j.version>
<!-- Following must be updated along with any updates to pac4j version -->
<nimbus.lang.tag.version>1.7</nimbus.lang.tag.version>

View File

@ -23,14 +23,15 @@ import org.apache.druid.java.util.common.logger.Logger;
import org.apache.druid.server.security.AuthConfig;
import org.apache.druid.server.security.AuthenticationResult;
import org.pac4j.core.config.Config;
import org.pac4j.core.context.J2EContext;
import org.pac4j.core.context.JEEContext;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.engine.CallbackLogic;
import org.pac4j.core.engine.DefaultCallbackLogic;
import org.pac4j.core.engine.DefaultSecurityLogic;
import org.pac4j.core.engine.SecurityLogic;
import org.pac4j.core.exception.http.HttpAction;
import org.pac4j.core.http.adapter.HttpActionAdapter;
import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.profile.UserProfile;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@ -47,12 +48,12 @@ public class Pac4jFilter implements Filter
{
private static final Logger LOGGER = new Logger(Pac4jFilter.class);
private static final HttpActionAdapter<String, J2EContext> NOOP_HTTP_ACTION_ADAPTER = (int code, J2EContext ctx) -> null;
private static final HttpActionAdapter<String, JEEContext> NOOP_HTTP_ACTION_ADAPTER = (HttpAction code, JEEContext ctx) -> null;
private final Config pac4jConfig;
private final SecurityLogic<String, J2EContext> securityLogic;
private final CallbackLogic<String, J2EContext> callbackLogic;
private final SessionStore<J2EContext> sessionStore;
private final SecurityLogic<String, JEEContext> securityLogic;
private final CallbackLogic<String, JEEContext> callbackLogic;
private final SessionStore<JEEContext> sessionStore;
private final String name;
private final String authorizerName;
@ -88,7 +89,7 @@ public class Pac4jFilter implements Filter
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
J2EContext context = new J2EContext(httpServletRequest, httpServletResponse, sessionStore);
JEEContext context = new JEEContext(httpServletRequest, httpServletResponse, sessionStore);
if (Pac4jCallbackResource.SELF_URL.equals(httpServletRequest.getRequestURI())) {
callbackLogic.perform(
@ -101,7 +102,7 @@ public class Pac4jFilter implements Filter
String uid = securityLogic.perform(
context,
pac4jConfig,
(J2EContext ctx, Collection<CommonProfile> profiles, Object... parameters) -> {
(JEEContext ctx, Collection<UserProfile> profiles, Object... parameters) -> {
if (profiles.isEmpty()) {
LOGGER.warn("No profiles found after OIDC auth.");
return null;

View File

@ -25,12 +25,12 @@ import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.logger.Logger;
import org.pac4j.core.context.ContextHelper;
import org.pac4j.core.context.Cookie;
import org.pac4j.core.context.Pac4jConstants;
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.Pac4jConstants;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
@ -38,6 +38,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.Optional;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -78,7 +79,7 @@ public class Pac4jSessionStore<T extends WebContext> implements SessionStore<T>
@Nullable
@Override
public Object get(WebContext context, String key)
public Optional<Object> get(WebContext context, String key)
{
final Cookie cookie = ContextHelper.getCookie(context, PAC4J_SESSION_PREFIX + key);
Object value = null;
@ -86,7 +87,7 @@ public class Pac4jSessionStore<T extends WebContext> implements SessionStore<T>
value = uncompressDecryptBase64(cookie.getValue());
}
LOGGER.debug("Get from session: [%s] = [%s]", key, value);
return value;
return Optional.ofNullable(value);
}
@Override
@ -142,7 +143,7 @@ public class Pac4jSessionStore<T extends WebContext> implements SessionStore<T>
if (v != null && !v.isEmpty()) {
byte[] bytes = StringUtils.decodeBase64String(v);
if (bytes != null) {
return javaSerializationHelper.unserializeFromBytes(unCompress(cryptoService.decrypt(bytes)));
return javaSerializationHelper.deserializeFromBytes(unCompress(cryptoService.decrypt(bytes)));
}
}
return null;
@ -176,19 +177,19 @@ public class Pac4jSessionStore<T extends WebContext> implements SessionStore<T>
{
if (value instanceof Map<?, ?>) {
final Map<String, CommonProfile> profiles = (Map<String, CommonProfile>) value;
profiles.forEach((name, profile) -> profile.clearSensitiveData());
profiles.forEach((name, profile) -> profile.removeLoginData());
return profiles;
} else {
final CommonProfile profile = (CommonProfile) value;
profile.clearSensitiveData();
profile.removeLoginData();
return profile;
}
}
@Override
public SessionStore buildFromTrackableSession(WebContext arg0, Object arg1)
public Optional<SessionStore<T>> buildFromTrackableSession(WebContext arg0, Object arg1)
{
return null;
return Optional.empty();
}
@Override
@ -198,9 +199,9 @@ public class Pac4jSessionStore<T extends WebContext> implements SessionStore<T>
}
@Override
public Object getTrackableSession(WebContext arg0)
public Optional getTrackableSession(WebContext arg0)
{
return null;
return Optional.empty();
}
@Override

View File

@ -25,15 +25,23 @@ import org.junit.Assert;
import org.junit.Test;
import org.pac4j.core.context.Cookie;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.profile.definition.CommonProfileDefinition;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
public class Pac4jSessionStoreTest
{
private static final String COOKIE_PASSPHRASE = "test-cookie-passphrase";
@Test
public void testSetAndGet()
{
Pac4jSessionStore<WebContext> sessionStore = new Pac4jSessionStore("test-cookie-passphrase");
Pac4jSessionStore<WebContext> sessionStore = new Pac4jSessionStore(COOKIE_PASSPHRASE);
WebContext webContext1 = EasyMock.mock(WebContext.class);
EasyMock.expect(webContext1.getScheme()).andReturn("https");
@ -54,7 +62,73 @@ public class Pac4jSessionStoreTest
WebContext webContext2 = EasyMock.mock(WebContext.class);
EasyMock.expect(webContext2.getRequestCookies()).andReturn(Collections.singletonList(cookie));
EasyMock.replay(webContext2);
Assert.assertEquals("value", Objects.requireNonNull(sessionStore.get(webContext2, "key")).orElse(null));
}
Assert.assertEquals("value", sessionStore.get(webContext2, "key"));
@Test
public void testSetAndGetClearUserProfile()
{
Pac4jSessionStore<WebContext> sessionStore = new Pac4jSessionStore(COOKIE_PASSPHRASE);
WebContext webContext1 = EasyMock.mock(WebContext.class);
EasyMock.expect(webContext1.getScheme()).andReturn("https");
Capture<Cookie> cookieCapture = EasyMock.newCapture();
webContext1.addResponseCookie(EasyMock.capture(cookieCapture));
EasyMock.replay(webContext1);
CommonProfile profile = new CommonProfile();
profile.addAttribute(CommonProfileDefinition.DISPLAY_NAME, "name");
sessionStore.set(webContext1, "pac4jUserProfiles", profile);
Cookie cookie = cookieCapture.getValue();
Assert.assertTrue(cookie.isSecure());
Assert.assertTrue(cookie.isHttpOnly());
Assert.assertTrue(cookie.isSecure());
Assert.assertEquals(900, cookie.getMaxAge());
WebContext webContext2 = EasyMock.mock(WebContext.class);
EasyMock.expect(webContext2.getRequestCookies()).andReturn(Collections.singletonList(cookie));
EasyMock.replay(webContext2);
Optional<Object> value = sessionStore.get(webContext2, "pac4jUserProfiles");
Assert.assertTrue(Objects.requireNonNull(value).isPresent());
Assert.assertEquals("name", ((CommonProfile) value.get()).getAttribute(CommonProfileDefinition.DISPLAY_NAME));
}
@Test
public void testSetAndGetClearUserMultipleProfile()
{
Pac4jSessionStore<WebContext> sessionStore = new Pac4jSessionStore(COOKIE_PASSPHRASE);
WebContext webContext1 = EasyMock.mock(WebContext.class);
EasyMock.expect(webContext1.getScheme()).andReturn("https");
Capture<Cookie> cookieCapture = EasyMock.newCapture();
webContext1.addResponseCookie(EasyMock.capture(cookieCapture));
EasyMock.replay(webContext1);
CommonProfile profile1 = new CommonProfile();
profile1.addAttribute(CommonProfileDefinition.DISPLAY_NAME, "name1");
CommonProfile profile2 = new CommonProfile();
profile2.addAttribute(CommonProfileDefinition.DISPLAY_NAME, "name2");
Map<String, CommonProfile> profiles = new HashMap<>();
profiles.put("profile1", profile1);
profiles.put("profile2", profile2);
sessionStore.set(webContext1, "pac4jUserProfiles", profiles);
Cookie cookie = cookieCapture.getValue();
Assert.assertTrue(cookie.isSecure());
Assert.assertTrue(cookie.isHttpOnly());
Assert.assertTrue(cookie.isSecure());
Assert.assertEquals(900, cookie.getMaxAge());
WebContext webContext2 = EasyMock.mock(WebContext.class);
EasyMock.expect(webContext2.getRequestCookies()).andReturn(Collections.singletonList(cookie));
EasyMock.replay(webContext2);
Optional<Object> value = sessionStore.get(webContext2, "pac4jUserProfiles");
Assert.assertTrue(Objects.requireNonNull(value).isPresent());
Assert.assertEquals(2, ((Map<String, CommonProfile>) value.get()).size());
}
}

View File

@ -776,7 +776,7 @@ name: pac4j-oidc java security library
license_category: binary
module: extensions/druid-pac4j
license_name: Apache License version 2.0
version: 3.8.3
version: 4.5.7
libraries:
- org.pac4j: pac4j-oidc
@ -786,7 +786,7 @@ name: pac4j-core java security library
license_category: binary
module: extensions/druid-pac4j
license_name: Apache License version 2.0
version: 3.8.3
version: 4.5.7
libraries:
- org.pac4j: pac4j-core
@ -837,7 +837,7 @@ name: com.sun.mail javax.mail
license_category: binary
module: extensions/druid-pac4j
license_name: CDDL 1.1
version: 1.6.1
version: 1.6.2
libraries:
- com.sun.mail: javax.mail

View File

@ -331,9 +331,11 @@
</suppress>
<suppress>
<!-- pac4j-core-3.8.3 -->
<!-- 4.5.5 is a fixed version as per https://nvd.nist.gov/vuln/detail/CVE-2021-44878. -->
<!-- However, vulnerability scan still shows this CVE. Pac4j release notes mention 5.3.1 as "fully fixed" version. -->
<!-- Remove suppression once upgraded to 5.3.1. -->
<notes><![CDATA[
file name: pac4j-core-3.8.3.jar
file name: pac4j-core-4.5.7.jar
]]></notes>
<cve>CVE-2021-44878</cve>
</suppress>