Skip to content

Commit e46859e

Browse files
authored
Merge pull request #3989 from martin-kuba/fix_tomcat_header_security_hole
fix(core): changed reading of OIDC claims from HTTP headers to reques…
2 parents cf6d1ed + f1030ce commit e46859e

File tree

2 files changed

+20
-18
lines changed

2 files changed

+20
-18
lines changed

perun-rpc/src/main/java/cz/metacentrum/perun/rpc/Api.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public class Api extends HttpServlet {
102102
private static final String SSL_CLIENT_SUBJECT_DN = "SSL_CLIENT_S_DN";
103103
private static final String SSL_CLIENT_CERT = "SSL_CLIENT_CERT";
104104
private static final String SUCCESS = "SUCCESS";
105-
private static final String OIDC_CLAIM_SUB = "OIDC_CLAIM_sub";
105+
public static final String OIDC_CLAIM_SUB = "OIDC_CLAIM_sub";
106106
private static final String OIDC_CLAIM_CLIENT_ID = "OIDC_CLAIM_client_id";
107107
private static final String OIDC_CLAIM_SCOPE = "OIDC_CLAIM_scope";
108108
private static final String OIDC_CLAIM_ISS = "OIDC_CLAIM_iss";
@@ -124,7 +124,7 @@ public void init() {
124124
// we do not init anything
125125
}
126126

127-
private static String getStringAttribute(HttpServletRequest req, String attributeName) {
127+
public static String getStringAttribute(HttpServletRequest req, String attributeName) {
128128
return (String) req.getAttribute(attributeName);
129129
}
130130

@@ -134,8 +134,8 @@ private static String getExtSourceName(HttpServletRequest req, Deserializer des)
134134
if (isNotEmpty(shibIdentityProvider)) {
135135
return getOriginalIdP(shibIdentityProvider, sourceIdpEntityId);
136136
} else {
137-
if (isNotEmpty(req.getHeader(OIDC_CLAIM_SUB))) {
138-
String iss = req.getHeader(OIDC_CLAIM_ISS);
137+
if (isNotEmpty(getStringAttribute(req, OIDC_CLAIM_SUB))) {
138+
String iss = getStringAttribute(req, OIDC_CLAIM_ISS);
139139
if(iss!=null) {
140140
String extSourceName = BeansUtils.getCoreConfig().getOidcIssuersExtsourceNames().get(iss);
141141
if(extSourceName!=null) {
@@ -197,7 +197,7 @@ private static String getActor(HttpServletRequest req, Deserializer des) {
197197
if (isNotEmpty(remoteUser)) {
198198
actor = remoteUser;
199199
}
200-
} else if (isNotEmpty(req.getHeader(OIDC_CLAIM_SUB))) {
200+
} else if (isNotEmpty(getStringAttribute(req, OIDC_CLAIM_SUB))) {
201201
actor = remoteUser;
202202
} else if (getStringAttribute(req, EXTSOURCE) != null) {
203203
actor = getExtLogin(req, getStringAttribute(req, EXTSOURCE), remoteUser);
@@ -254,10 +254,10 @@ private static PerunPrincipal setupPerunPrincipal(HttpServletRequest req, Deseri
254254
}
255255
}
256256

257-
// If OIDC_CLAIM_sub header is present, it means user authenticated via OAuth2 with MITRE.
258-
else if (isNotEmpty(req.getHeader(OIDC_CLAIM_SUB))) {
259-
String iss = req.getHeader(OIDC_CLAIM_ISS);
260-
extLogin = req.getHeader(OIDC_CLAIM_SUB);
257+
// If OIDC_CLAIM_sub header is present, it means user authenticated via OAuth2
258+
else if (isNotEmpty(getStringAttribute(req, OIDC_CLAIM_SUB))) {
259+
String iss = getStringAttribute(req, OIDC_CLAIM_ISS);
260+
extLogin = getStringAttribute(req, OIDC_CLAIM_SUB);
261261
additionalInformations.put(ISSUER, iss);
262262
additionalInformations.put(ACCESS_TOKEN, req.getHeader(OIDC_ACCESS_TOKEN));
263263
//this is configurable, as the OIDC server has the source of sub claim also configurable
@@ -273,14 +273,14 @@ else if (isNotEmpty(req.getHeader(OIDC_CLAIM_SUB))) {
273273
extSourceLoaString = "-1";
274274

275275
// store auth_time to additional information
276-
String authTimestamp = req.getHeader(OIDC_CLAIM_AUTH_TIME);
276+
String authTimestamp = getStringAttribute(req, OIDC_CLAIM_AUTH_TIME);
277277
if (isNotEmpty(authTimestamp)) {
278278
Instant authReadableTimestamp = Instant.ofEpochSecond(Long.parseLong(authTimestamp));
279279
additionalInformations.put(AUTH_TIME, authReadableTimestamp.toString());
280280
}
281281

282282
// store MFA flag to additional information
283-
String acr = req.getHeader(OIDC_CLAIM_ACR);
283+
String acr = getStringAttribute(req, OIDC_CLAIM_ACR);
284284
if (isNotEmpty(acr) && acr.equals(BeansUtils.getCoreConfig().getIntrospectionEndpointMfaAcrValue())) {
285285
additionalInformations.put(ACR_MFA, "mfa");
286286
}
@@ -421,10 +421,10 @@ else if (Objects.equals(req.getAttribute(SSL_CLIENT_VERIFY), SUCCESS)) {
421421

422422
private PerunClient setupPerunClient(HttpServletRequest req) {
423423

424-
if (isNotEmpty(req.getHeader(OIDC_CLAIM_SUB))) {
425-
String clientId = req.getHeader(OIDC_CLAIM_CLIENT_ID);
426-
List<String> scopes = Arrays.asList(req.getHeader(OIDC_CLAIM_SCOPE).split(" "));
427-
log.debug("detected OIDC/OAuth2 client {} with scopes {} for sub {}", clientId, scopes, req.getHeader(OIDC_CLAIM_SUB));
424+
if (isNotEmpty(getStringAttribute(req, OIDC_CLAIM_SUB))) {
425+
String clientId = getStringAttribute(req, OIDC_CLAIM_CLIENT_ID);
426+
List<String> scopes = Arrays.asList(getStringAttribute(req, OIDC_CLAIM_SCOPE).split(" "));
427+
log.debug("detected OIDC/OAuth2 client {} with scopes {} for sub {}", clientId, scopes, getStringAttribute(req, OIDC_CLAIM_SUB));
428428
return new PerunClient(clientId, scopes);
429429
}
430430

perun-rpc/src/main/java/cz/metacentrum/perun/rpc/csrf/CsrfFilter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@
3333
import javax.servlet.http.HttpServletResponse;
3434

3535
import cz.metacentrum.perun.core.impl.PerunAppsConfig;
36+
import cz.metacentrum.perun.rpc.Api;
3637
import org.apache.commons.lang3.StringUtils;
3738
import org.apache.http.HttpStatus;
3839
import org.slf4j.Logger;
3940
import org.slf4j.LoggerFactory;
4041
import org.springframework.web.util.WebUtils;
4142

43+
import static cz.metacentrum.perun.rpc.Api.OIDC_CLAIM_SUB;
44+
import static cz.metacentrum.perun.rpc.Api.getStringAttribute;
45+
4246
/**
4347
* This is an implementation of CSRF protection based on Spring framework solution.
4448
*
@@ -66,8 +70,6 @@ public final class CsrfFilter implements Filter {
6670
private static final String CSRF_REQUEST_ATTR_NAME = CsrfToken.class.getName();
6771
private static final String CSRF_ENABLED_REQUEST_ATTR_NAME = "CSRF_PROTECTION_ENABLED";
6872

69-
private static final String OIDC_CLAIM_SUB = "OIDC_CLAIM_sub";
70-
7173
public CsrfFilter() {
7274
}
7375

@@ -84,7 +86,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
8486

8587
// Perform CSRF check only if CSRF protection is enabled and its not OIDC endpoint
8688
boolean isCsrfProtectionEnabled = Boolean.parseBoolean((String) request.getAttribute(CSRF_ENABLED_REQUEST_ATTR_NAME));
87-
if (isCsrfProtectionEnabled && StringUtils.isEmpty(request.getHeader(OIDC_CLAIM_SUB))) {
89+
if (isCsrfProtectionEnabled && StringUtils.isEmpty(getStringAttribute(request, OIDC_CLAIM_SUB))) {
8890

8991
log.trace("Processing CSRF filter.");
9092

0 commit comments

Comments
 (0)