From 1cb5b9e26c15ee2168961c1f579c92df625d1e5e Mon Sep 17 00:00:00 2001 From: Barry de Graaff <4353213+barrydegraaff@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:39:16 +0200 Subject: [PATCH] ZCS-12859 implement CSRF in GraphQL endpoint Re-implemented based on review comments from SD --- .../graphql/utilities/GQLAuthUtilities.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/java/com/zimbra/graphql/utilities/GQLAuthUtilities.java b/src/java/com/zimbra/graphql/utilities/GQLAuthUtilities.java index 6bb6f9e..4c73db5 100644 --- a/src/java/com/zimbra/graphql/utilities/GQLAuthUtilities.java +++ b/src/java/com/zimbra/graphql/utilities/GQLAuthUtilities.java @@ -31,8 +31,10 @@ import com.zimbra.common.soap.Element; import com.zimbra.common.soap.HeaderConstants; import com.zimbra.common.soap.SoapProtocol; +import com.zimbra.common.util.Constants; import com.zimbra.common.util.L10nUtil; import com.zimbra.common.util.L10nUtil.MsgKey; +import com.zimbra.common.util.StringUtil; import com.zimbra.common.util.ZimbraCookie; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Account; @@ -42,6 +44,8 @@ import com.zimbra.cs.account.ZimbraAuthToken; import com.zimbra.cs.account.ZimbraJWToken; import com.zimbra.cs.service.AuthProvider; +import com.zimbra.cs.servlet.util.CsrfUtil; +import com.zimbra.cs.servlet.CsrfFilter; import com.zimbra.graphql.models.RequestContext; import com.zimbra.soap.DocumentHandler; import com.zimbra.soap.SoapEngine; @@ -200,7 +204,7 @@ public static ZimbraSoapContext getZimbraSoapContext(RequestContext rctxt) final Map headers = new HashMap(1); headers.put("Authorization", req.getHeader("Authorization")); final AuthToken token = getAuthToken(cookies, headers); - if (isValidToken(token)) { + if (isValidToken(token) && isValidCsrf(token, req)) { return new ZimbraSoapContext(token, token.getAccountId(), SoapProtocol.Soap12, SoapProtocol.Soap12); } @@ -209,4 +213,30 @@ public static ZimbraSoapContext getZimbraSoapContext(RequestContext rctxt) throw ServiceException.PERM_DENIED(L10nUtil.getMessage(MsgKey.errMustAuthenticate)); } + /** + * CSRF implementation + */ + private static boolean isValidCsrf(AuthToken authToken, HttpServletRequest req) { + boolean doCsrfCheck = false; + if (req.getAttribute(CsrfFilter.CSRF_TOKEN_CHECK) != null) { + doCsrfCheck = (Boolean) req.getAttribute(CsrfFilter.CSRF_TOKEN_CHECK); + } else if (authToken != null && authToken.isCsrfTokenEnabled()) { + doCsrfCheck = true; + } + + if(doCsrfCheck) { + String csrfToken = req.getHeader(Constants.CSRF_TOKEN); + if (StringUtil.isNullOrEmpty(csrfToken)) { + ZimbraLog.extensions.debug("No CSRF token received."); + return false; + } + + //check for valid CSRF token + if (!CsrfUtil.isValidCsrfToken(csrfToken, authToken)) { + ZimbraLog.extensions.debug("CSRF check FAILED."); + return false; + } + } + return true; + } }