-
Notifications
You must be signed in to change notification settings - Fork 1.3k
JWK endpoint as filter #31
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
Conversation
@jbellmann Thanks for the PR! FYI, when you are interested on working on a specific issue please reach out to us on the issue first so that other users can see that the issue is taken. @ovidiupopa91 reached out in this comment requesting to work on this. All good either way, I just wanted to make you aware of the process. I will review this PR shortly. Thanks. |
@RequiredArgsConstructor | ||
public class JWKSetEndpoint extends OncePerRequestFilter { | ||
|
||
static final String WELL_KNOWN_JWK_URIS = "/.well-known/jwk_uris"; |
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.
wouldn't it be better if the uri was configurable and the constant especially accessbile?
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.
Thanks for the feedback @Captain-P-Goldfish. The goal is to start with the minimal amount of code to get things working. We will add custom configurations as we build things out.
try (Writer writer = response.getWriter()) { | ||
writer.write(jwkSet.toPublicJWKSet().toJSONObject().toJSONString()); | ||
} |
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.
what about error handling?
NullPointerExceptions would be pretty unpleasant
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.
Thanks for the PR @jbellmann. Please see my review comments.
|
||
import com.nimbusds.jose.jwk.JWKSet; | ||
|
||
import lombok.RequiredArgsConstructor; |
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.
Please remove lombok
as Spring Security does not use it.
public class JWKSetEndpoint extends OncePerRequestFilter { | ||
|
||
static final String WELL_KNOWN_JWK_URIS = "/.well-known/jwk_uris"; | ||
private final JWKSet jwkSet; |
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.
The JWKSet should be provided with a default set of key(s). Please see main issue comment:
The keys that are used can be generated at startup or be constants
build.gradle
Outdated
@@ -1,22 +1,38 @@ | |||
plugins { | |||
id 'java' |
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.
Please move the code into the minimal sample and remove this gradle build.
@RequiredArgsConstructor | ||
public class JWKSetEndpoint extends OncePerRequestFilter { | ||
|
||
static final String WELL_KNOWN_JWK_URIS = "/.well-known/jwk_uris"; |
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.
Thanks for the feedback @Captain-P-Goldfish. The goal is to start with the minimal amount of code to get things working. We will add custom configurations as we build things out.
} | ||
|
||
@Test | ||
void testIfRequestMatches() throws Exception { |
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.
We should setup for keys to be returned here
} | ||
|
||
protected boolean ifRequestMatches(HttpServletRequest request) { | ||
return request.getRequestURI().endsWith(WELL_KNOWN_JWK_URIS); |
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.
This will also match /stuff/.well-known/jwk_uris
, right? Is that acceptable or should it be an exact match?
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.
Please use RequestMatcher
, specifically AntPathRequestMatcher
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.
Thank you for the updates @jbellmann. Please see my review comments.
.gitignore
Outdated
@@ -12,6 +12,7 @@ build/ | |||
.settings | |||
.springBeans | |||
.sts4-cache | |||
bin/ |
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.
Please rebase on master
as bin
has been added in a recent commit.
@Bean | ||
FilterRegistrationBean<JWKSetEndpoint> registerJWKSetEndpoint() throws JOSEException { | ||
FilterRegistrationBean<JWKSetEndpoint> fb = new FilterRegistrationBean<>(); | ||
fb.setFilter(new JWKSetEndpoint(generateJwkSet())); |
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.
Let's register JWKSetEndpoint
with the Spring Security filter chain via HttpSecurity.addFilter...
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; | ||
|
||
@Configuration | ||
public class Config { |
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.
Rename to SecurityConfig
and extend WebSecurityConfigurerAdapter
|
||
import com.nimbusds.jose.jwk.JWKSet; | ||
|
||
public class JWKSetEndpoint extends OncePerRequestFilter { |
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.
Please rename to JwkSetEndpointFilter
} | ||
|
||
protected boolean ifRequestMatches(HttpServletRequest request) { | ||
return request.getRequestURI().endsWith(WELL_KNOWN_JWK_URIS); |
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.
Please use RequestMatcher
, specifically AntPathRequestMatcher
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.
Thanks for the updates @jbellmann. Please see review comments.
Before you push the updates, please rebase on master and squash to 1 commit. Our git workflow is rebase instead of merge. Thanks.
import com.nimbusds.jose.jwk.KeyUse; | ||
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; | ||
|
||
@Configuration |
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.
Replace with @EnableWebSecurity
} | ||
|
||
protected JWKSet generateJwkSet() throws JOSEException { | ||
JWK jwk = new RSAKeyGenerator(2048).keyID("minimal-ASA").keyUse(KeyUse.ENCRYPTION).generate(); |
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.
Change to KeyUse.SIGNATURE
public class FakeController { | ||
|
||
@RequestMapping("/fake") | ||
public String hello() { |
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.
Can you move this declaration in the test class instead
|
||
@Test | ||
void testRequestMatcher() { | ||
assertTrue(this.filter.ifRequestMatches(new MockHttpServletRequest(GET.name(), WELL_KNOWN_JWK_URIS))); |
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.
Can you change all the assertion checks to use AssertJ instead as that is the primary test lib we use in Spring Security.
void testRequestMatcher() { | ||
assertTrue(this.filter.ifRequestMatches(new MockHttpServletRequest(GET.name(), WELL_KNOWN_JWK_URIS))); | ||
|
||
assertFalse(this.filter.ifRequestMatches(new MockHttpServletRequest(POST.name(), WELL_KNOWN_JWK_URIS))); |
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.
We should test the doFilter()
method directly. Please change the protected
methods to private
in JwkSetEndpointFilter
. See OAuth2AuthorizationCodeGrantFilterTests
(spring-security-oauth2-client
) on how we test Filter
's.
557b3c3
to
8a7629c
Compare
8a7629c
to
01f3ee1
Compare
Thanks for all the updates @jbellmann ! FYI, I added a polish commit to get this merged. This is now in master. |
Fixes #2
Provides an JWKSet endpoint implemented as filter with basic tests.