Skip to content
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

Provide EC signature verification support in JWTSignatureValidator #25

Merged
merged 9 commits into from
Jan 28, 2020

Conversation

mstruk
Copy link
Contributor

@mstruk mstruk commented Jan 15, 2020

This PR attempts to address: strimzi/strimzi-kafka-operator#2327

Signed-off-by: Marko Strukelj marko.strukelj@gmail.com

@mstruk mstruk added this to the 0.3.0 milestone Jan 15, 2020
Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
@@ -36,6 +40,10 @@

public class JWTSignatureValidator implements TokenValidator {

static {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will add BC as a security provider for a whole bunch of algorithms, not just ECDSA, right? And we don't know whether the user of the library trusts BC? So maybe we should only register when we encounter a token using EC and only if there's not existing EC provision already registered? That would allow a user who really cares to register some other provider for EC and we'd just pick it up.

Also, I don't think we can assume that there aren't other providers already registered in some specific order. Adding at index 1 might then mean BC is chosen instead of their preferred provider. So maybe if/when we do add BC, we should always add at the end (which is still a bit racy, but less likely to be a problem in practice)?

Copy link
Contributor Author

@mstruk mstruk Jan 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. That is a dilemma. The thing is that for EC, the Keycloak helper library that we use requests ECDSA which is provided by Bouncycastle, but is otherwise not available in JDK. To make make matters worse, there's usage of both "EC" and "ECDSA" in the code. That means if Bouncycastle is not installed in first place what will happen is that when "EC" is requested it would use Sun's provider, and when "ECDSA" is requested the Bouncycastle provider would be used - unless the provider is bumped to first position among security providers. Multiple impls might work together fine or they might not.

We could add a configuration: oauth.crypto.bouncycastle.provider.enable to require explicitly enabling the provider before we install it. And another - oauth.crypto.bouncycastle.provider.position which, if set to 0 or negative number would install the provider at the end, otherwise at the position specified - or at the end if position is beyond number of providers.

I'm not sure about lazy enabling it upon detection of EC. That may hide any potential issues to long after Kafka broker has started.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing that the helper library has no mechanism for selecting algorithm impls with a given provider?

It not really clear to me whether the "EC" signature algo is actually the same thing as "ECDSA" (in which case Keycloak's use of EC starts to look like a bug). But I guess we need to provide something which works with the version of the library which actually exists. So I suppose System properties like oauth.crypto.bouncycastle.provider.enable would at least provide a mechanism, even if it's less than ergonomic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the Keycloak code is what it is, and it does not explicitly request BouncyCastle provider. With the patched Keycloak library that requests "EC" instead of "ECDSA" things work fine without BouncyCastle. But that would require a patch that probably won't make it into the master, and will only be released later while we would like a fix ASAP.

Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
…astle` and `oauth.crypto.provider.bouncycastle.position`

Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
@mstruk
Copy link
Contributor Author

mstruk commented Jan 16, 2020

I made installing BouncyCastle provider optional. It is required for EC signature verification to work, though.

It can be installed as the last security provider by passing to JAAS config of org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule the parameter:

oauth.crypto.provider.bouncycastle="true"

Position in the providers list can be controlled with another parameter:

oauth.crypto.provider.bouncycastle.position="0"

Alternatively, these can be set as a system properties or as ENV vars called OAUTH_CRYPTO_PROVIDER_BOUNCYCASTLE and OAUTH_CRYPTO_PROVIDER_BOUNCYCASTLE_POSITION.

@mstruk mstruk requested a review from scholzj January 17, 2020 08:47
@scholzj
Copy link
Member

scholzj commented Jan 19, 2020

@ppatierno Do you plan to review this or can it be merged?

Copy link
Member

@ppatierno ppatierno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Just left a couple of comments but maybe we don't need to review again.

sb.append(" - " + p.toString() + " [" + p.getClass().getName() + "]\n");
sb.append(" " + p.getInfo() + "\n");
}
log.debug(sb.toString());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should log all the installed security providers but it happens only if the outer if (enableBouncyCastleProvider && !bouncyInstalled.getAndSet(true)) is true. Is it really what we want? Shouldn't we log the installed security providers anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the way I intended. Usually you're not really interested in security providers, you're working with what's packaged and enabled in JDK. If you really want to see the providers for some reason, you can just enable bouncy castle provider in the config, and it will be added at the end, not overwriting any existing providers, but you'll also see them all listed.

@ppatierno
Copy link
Member

@scholzj I approved but left a couple of comments. Maybe changes are not needed but I will let @mstruk to decide.

Signed-off-by: Marko Strukelj <marko.strukelj@gmail.com>
@scholzj scholzj merged commit 20e8342 into strimzi:master Jan 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants