-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow for OPTIONS requests to be passed through auth filters #1244
Allow for OPTIONS requests to be passed through auth filters #1244
Conversation
* Browsers do not (by spec) pass authorization content in OPTIONS requests * This causes all preflight checks in the browser to fail when making a request to an authenticated endpoint when doing so with CORS enabled * The change makes it possible to utilize a JWT from within the browser via fetch with CORS -- allowing for the separation of the frontend from the backend
src/server/src/main/java/io/cassandrareaper/resources/RequestUtils.java
Outdated
Show resolved
Hide resolved
…vironment variable to trigger the allow of all options requests
So, it turns out that this still isn't sufficient to get through the CSRF protections in browsers because of the way the cookies that Shiro creates are created. I'm still working on that aspect of things, I think it's just a shiro configuration to be made, but it's elusive to say the least. Going to make this a draft for the moment while I sort that out. |
public final class RequestUtils { | ||
public static final String ENABLE_CORS_ENV_VAR_NAME = "REAPER_ENABLE_CROSS_ORIGIN"; | ||
|
||
private RequestUtils() {} | ||
|
||
public static boolean isOptionsRequest(ServletRequest request) { | ||
if (request != null && request instanceof HttpServletRequest) { | ||
if (((HttpServletRequest) request).getMethod().equalsIgnoreCase(HttpMethod.OPTIONS)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
@VisibleForTesting | ||
static boolean isCorsEnabled(String corsEnabledEnvVarValue) { | ||
if (corsEnabledEnvVarValue != null) { | ||
return Boolean.parseBoolean(corsEnabledEnvVarValue.trim().toLowerCase()); | ||
} | ||
return false; | ||
} | ||
|
||
public static boolean isCorsEnabled() { | ||
String corsEnabledEnvVarValue = System.getenv(ENABLE_CORS_ENV_VAR_NAME); | ||
return isCorsEnabled(corsEnabledEnvVarValue); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reviewing this and thinking about another requirement we have (which is to shut down the sessions despite being active after the configured timeout), I'm of the opinion that we shouldn't rely on env variable.
We can statically set a isCorsEnabled
variable in RequestUtils which will be initialized in the ReaperApplication.java initialization phase, and feed on the corresponding config setting: config.isEnableCrossOrigin()
public final class RequestUtils { | |
public static final String ENABLE_CORS_ENV_VAR_NAME = "REAPER_ENABLE_CROSS_ORIGIN"; | |
private RequestUtils() {} | |
public static boolean isOptionsRequest(ServletRequest request) { | |
if (request != null && request instanceof HttpServletRequest) { | |
if (((HttpServletRequest) request).getMethod().equalsIgnoreCase(HttpMethod.OPTIONS)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
@VisibleForTesting | |
static boolean isCorsEnabled(String corsEnabledEnvVarValue) { | |
if (corsEnabledEnvVarValue != null) { | |
return Boolean.parseBoolean(corsEnabledEnvVarValue.trim().toLowerCase()); | |
} | |
return false; | |
} | |
public static boolean isCorsEnabled() { | |
String corsEnabledEnvVarValue = System.getenv(ENABLE_CORS_ENV_VAR_NAME); | |
return isCorsEnabled(corsEnabledEnvVarValue); | |
} | |
} | |
public final class RequestUtils { | |
private static boolean isCorsEnabled = false; | |
private RequestUtils() {} | |
public static void setCorsEnabled(boolean enabled) { | |
isCorsEnabled = enabled; | |
} | |
public static boolean isCorsEnabled() { | |
return isCorsEnabled; | |
} | |
public static boolean isOptionsRequest(ServletRequest request) { | |
if (request != null && request instanceof HttpServletRequest) { | |
if (((HttpServletRequest) request).getMethod().equalsIgnoreCase(HttpMethod.OPTIONS)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} |
Initialization can be done as follows in ReaperApplication.java:
if (config.isAccessControlEnabled()) {
RequestUtils.setCorsEnabled(config.isEnableCrossOrigin());
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setMaxInactiveInterval((int) config.getAccessControl().getSessionTimeout().getSeconds());
environment.getApplicationContext().setSessionHandler(sessionHandler);
environment.servlets().setSessionHandler(sessionHandler);
environment.jersey().register(new ShiroExceptionMapper());
environment.jersey().register(new LoginResource());
environment.jersey().register(new ShiroJwtProvider(context));
}
wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so the latest commit switches to initializing with config property instead of directly using the env variable... duh, I should have seen that to start 😔 so thanks for that suggestion!
But, I wasn't sure why you suggested tangling up the enabling of CORS within the isAccessControlEnabled() block as you mention here?
I initialized things in place with the other CORS related configuration that already happened within ReaperApplication.java's startup code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But, I wasn't sure why you suggested tangling up the enabling of CORS within the isAccessControlEnabled() block as you mention here?
I was under the impression that we needed it to allow OPTIONS calls when auth is enabled. Isn't it what you were trying to do here?
Either way, I'm fine with initializing it outside of that block 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah, the two can be unrelated.
src/server/src/main/java/io/cassandrareaper/resources/auth/ShiroJwtVerifyingFilter.java
Outdated
Show resolved
Hide resolved
…tils.java Co-authored-by: Alexander Dejanovski <alex.dejanovski@datastax.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome sauce DiNoto 🥳
Thanks!
Fixes #1245
I think this behavior should probably be considered a bug, so I tied the behavior to the already in-use environment variable
REAPER_ENABLE_CROSS_ORIGIN
which when set totrue
will cause all OPTIONS requests to be allowed without an auth check.