-
Notifications
You must be signed in to change notification settings - Fork 119
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
Receiver reject requests for wrong audience #3675
Changes from all commits
bfcce3f
84acd59
187959d
325b7c0
42c1a07
6dbc239
5cc362a
cf8292c
8c9494c
47196e7
99d7325
a6b05c6
503cee9
9d223c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* Copyright © 2018 Knative Authors (knative-dev@googlegroups.com) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package dev.knative.eventing.kafka.broker.core.oidc; | ||
|
||
import io.vertx.core.Future; | ||
import io.vertx.core.Vertx; | ||
import io.vertx.core.http.HttpServerRequest; | ||
import org.jose4j.jwt.JwtClaims; | ||
import org.jose4j.jwt.consumer.InvalidJwtException; | ||
import org.jose4j.jwt.consumer.JwtConsumer; | ||
import org.jose4j.jwt.consumer.JwtConsumerBuilder; | ||
import org.jose4j.jwt.consumer.JwtContext; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class TokenVerifierImpl implements TokenVerifier { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(TokenVerifierImpl.class); | ||
|
||
private final Vertx vertx; | ||
|
||
private final OIDCDiscoveryConfig oidcDiscoveryConfig; | ||
|
||
public TokenVerifierImpl(Vertx vertx, OIDCDiscoveryConfig oidcDiscoveryConfig) { | ||
this.vertx = vertx; | ||
this.oidcDiscoveryConfig = oidcDiscoveryConfig; | ||
} | ||
|
||
public Future<JwtClaims> verify(String token, String expectedAudience) { | ||
return this.vertx.<JwtClaims>executeBlocking(promise -> { | ||
Check warning on line 43 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L43
|
||
// execute blocking, as jose .process() is blocking | ||
|
||
JwtConsumer jwtConsumer = new JwtConsumerBuilder() | ||
.setVerificationKeyResolver(this.oidcDiscoveryConfig.getJwksVerificationKeyResolver()) | ||
.setExpectedAudience(expectedAudience) | ||
.setExpectedIssuer(this.oidcDiscoveryConfig.getIssuer()) | ||
.build(); | ||
Check warning on line 50 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L46-L50
|
||
|
||
try { | ||
JwtContext jwtContext = jwtConsumer.process(token); | ||
Check warning on line 53 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L53
|
||
|
||
promise.complete(jwtContext.getJwtClaims()); | ||
} catch (InvalidJwtException e) { | ||
promise.fail(e); | ||
} | ||
}); | ||
Check warning on line 59 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L55-L59
|
||
} | ||
|
||
public Future<JwtClaims> verify(final HttpServerRequest request, String expectedAudience) { | ||
String authHeader = request.getHeader("Authorization"); | ||
Check warning on line 63 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L63
|
||
if (authHeader == null || authHeader.isEmpty()) { | ||
return Future.failedFuture("Request didn't contain Authorization header"); | ||
Check warning on line 65 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L65
|
||
} | ||
|
||
if (!authHeader.startsWith("Bearer ") && authHeader.length() <= "Bearer ".length()) { | ||
return Future.failedFuture("Authorization header didn't contain Bearer token"); | ||
Check warning on line 69 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L69
|
||
} | ||
|
||
String token = authHeader.substring("Bearer ".length()); | ||
Check warning on line 72 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L72
|
||
|
||
request.pause(); | ||
return verify(token, expectedAudience).onSuccess(v -> request.resume()); | ||
Check warning on line 75 in data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java Codecov / codecov/patchdata-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/oidc/TokenVerifierImpl.java#L74-L75
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright © 2018 Knative Authors (knative-dev@googlegroups.com) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package dev.knative.eventing.kafka.broker.receiver.impl.handler; | ||
|
||
import static dev.knative.eventing.kafka.broker.core.utils.Logging.keyValue; | ||
|
||
import dev.knative.eventing.kafka.broker.core.oidc.TokenVerifier; | ||
import dev.knative.eventing.kafka.broker.receiver.IngressProducer; | ||
import io.netty.handler.codec.http.HttpResponseStatus; | ||
import io.vertx.core.Handler; | ||
import io.vertx.core.http.HttpServerRequest; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* Handler checking that the provided request contained a valid JWT. | ||
*/ | ||
public class AuthenticationHandler { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(AuthenticationHandler.class); | ||
private final TokenVerifier tokenVerifier; | ||
|
||
public AuthenticationHandler(final TokenVerifier tokenVerifier) { | ||
this.tokenVerifier = tokenVerifier; | ||
} | ||
|
||
public void handle( | ||
final HttpServerRequest request, final IngressProducer ingressInfo, final Handler<HttpServerRequest> next) { | ||
if (ingressInfo.getAudience().isEmpty()) { | ||
logger.debug("No audience for ingress set. Continue without authentication check..."); | ||
next.handle(request); | ||
return; | ||
} | ||
|
||
tokenVerifier | ||
.verify(request, ingressInfo.getAudience()) | ||
.onFailure(e -> { | ||
logger.debug("Failed to verify authentication of request: {}", keyValue("error", e.getMessage())); | ||
request.response() | ||
.setStatusCode(HttpResponseStatus.UNAUTHORIZED.code()) | ||
.end(); | ||
}) | ||
.onSuccess(jwtClaims -> { | ||
logger.debug("Request contained valid JWT. Continuing..."); | ||
next.handle(request); | ||
}); | ||
} | ||
} |
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.
Does getting JWT claims from processing the token imply that the token had the correct audience?
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.
Yes.
jwtConsumer.process(token)
fails, when the JWT does not contain the audience which was set in line 48.