-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Proxy for datanode rest, jwt auth filter for datanode (#17827)
* Proxy for datanode rest, jwt auth filter for datanode * fixed test * fixed test * Fixed passing request body via datanode proxy * disable entity capturing for datanode rest proxy calls * datanode rest proxy refactored to okHttp client * code cleanup, jwt token and auth filter separation * Removed unused import * code cleanup, fixed request body issue
- Loading branch information
Showing
18 changed files
with
617 additions
and
5 deletions.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
data-node/src/main/java/org/graylog/datanode/initializers/AuthTokenValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright (C) 2020 Graylog, Inc. | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the Server Side Public License, version 1, | ||
* as published by MongoDB, Inc. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* Server Side Public License for more details. | ||
* | ||
* You should have received a copy of the Server Side Public License | ||
* along with this program. If not, see | ||
* <http://www.mongodb.com/licensing/server-side-public-license>. | ||
*/ | ||
package org.graylog.datanode.initializers; | ||
|
||
public interface AuthTokenValidator { | ||
void verifyToken(String token) throws TokenVerificationException; | ||
} |
82 changes: 82 additions & 0 deletions
82
data-node/src/main/java/org/graylog/datanode/initializers/DatanodeAuthFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/* | ||
* Copyright (C) 2020 Graylog, Inc. | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the Server Side Public License, version 1, | ||
* as published by MongoDB, Inc. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* Server Side Public License for more details. | ||
* | ||
* You should have received a copy of the Server Side Public License | ||
* along with this program. If not, see | ||
* <http://www.mongodb.com/licensing/server-side-public-license>. | ||
*/ | ||
package org.graylog.datanode.initializers; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.ws.rs.container.ContainerRequestContext; | ||
import javax.ws.rs.container.ContainerRequestFilter; | ||
import javax.ws.rs.core.HttpHeaders; | ||
import javax.ws.rs.core.MediaType; | ||
import javax.ws.rs.core.MultivaluedMap; | ||
import javax.ws.rs.core.Response; | ||
import java.io.IOException; | ||
import java.util.Collections; | ||
import java.util.Optional; | ||
|
||
/** | ||
* This is an authorization filter that first try to verify presence and validity of a bearer token. If there is no | ||
* bearer token available, it will fallback to basic auth (or whatever filter is configured as fallback). | ||
* Allowing both auth methods allows easy access directly from CLI or browser and machine-machine communication from the graylog server. | ||
*/ | ||
public class DatanodeAuthFilter implements ContainerRequestFilter { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(DatanodeAuthFilter.class); | ||
private static final String AUTHENTICATION_SCHEME = "Bearer"; | ||
private final ContainerRequestFilter fallbackFilter; | ||
private final AuthTokenValidator tokenVerifier; | ||
|
||
|
||
public DatanodeAuthFilter(ContainerRequestFilter fallbackFilter, AuthTokenValidator tokenVerifier) { | ||
this.fallbackFilter = fallbackFilter; | ||
this.tokenVerifier = tokenVerifier; | ||
} | ||
|
||
private Optional<String> getBearerHeader(ContainerRequestContext requestContext) { | ||
final MultivaluedMap<String, String> headers = requestContext.getHeaders(); | ||
return headers.getOrDefault(HttpHeaders.AUTHORIZATION, Collections.emptyList()) | ||
.stream() | ||
.filter(a -> a.startsWith(AUTHENTICATION_SCHEME)) | ||
.findFirst(); | ||
} | ||
|
||
@Override | ||
public void filter(ContainerRequestContext requestContext) throws IOException { | ||
final Optional<String> header = getBearerHeader(requestContext); | ||
if (header.isEmpty()) { | ||
// no JWT token, we'll fallback to basic auth | ||
fallbackFilter.filter(requestContext); | ||
} else { | ||
final String token = header.map(h -> h.replaceFirst(AUTHENTICATION_SCHEME + " ", "")).get(); | ||
try { | ||
tokenVerifier.verifyToken(token); | ||
} catch (TokenVerificationException e) { | ||
LOG.error("Failed to verify auth token", e); | ||
abortRequest(requestContext); | ||
} | ||
} | ||
} | ||
|
||
|
||
private void abortRequest(ContainerRequestContext requestContext) { | ||
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED) | ||
.entity("Failed to parse auth header") | ||
.type(MediaType.TEXT_PLAIN_TYPE) | ||
.build()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
data-node/src/main/java/org/graylog/datanode/initializers/JwtTokenValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright (C) 2020 Graylog, Inc. | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the Server Side Public License, version 1, | ||
* as published by MongoDB, Inc. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* Server Side Public License for more details. | ||
* | ||
* You should have received a copy of the Server Side Public License | ||
* along with this program. If not, see | ||
* <http://www.mongodb.com/licensing/server-side-public-license>. | ||
*/ | ||
package org.graylog.datanode.initializers; | ||
|
||
import io.jsonwebtoken.Jwt; | ||
import io.jsonwebtoken.JwtParser; | ||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.SignatureAlgorithm; | ||
|
||
import javax.crypto.spec.SecretKeySpec; | ||
import javax.inject.Named; | ||
import javax.inject.Singleton; | ||
import java.nio.charset.StandardCharsets; | ||
import java.security.Key; | ||
import java.util.Optional; | ||
|
||
@Singleton | ||
public class JwtTokenValidator implements AuthTokenValidator { | ||
|
||
public static final String REQUIRED_SUBJECT = "admin"; | ||
public static final String REQUIRED_ISSUER = "graylog"; | ||
private final String signingKey; | ||
|
||
public JwtTokenValidator(@Named("password_secret") final String signingKey) { | ||
this.signingKey = signingKey; | ||
} | ||
|
||
@Override | ||
public void verifyToken(String token) throws TokenVerificationException { | ||
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; | ||
Key signingKey = new SecretKeySpec(this.signingKey.getBytes(StandardCharsets.UTF_8), signatureAlgorithm.getJcaName()); | ||
final JwtParser parser = Jwts.parserBuilder() | ||
.setSigningKey(signingKey) | ||
.requireSubject(REQUIRED_SUBJECT) | ||
.requireIssuer(REQUIRED_ISSUER) | ||
.build(); | ||
try { | ||
final Jwt parsed = parser.parse(token); | ||
verifySignature(parsed, signatureAlgorithm); | ||
} catch (Exception e) { | ||
throw new TokenVerificationException(e); | ||
} | ||
} | ||
|
||
private void verifySignature(Jwt token, SignatureAlgorithm expectedAlgorithm) { | ||
final SignatureAlgorithm usedAlgorithm = Optional.of(token.getHeader()) | ||
.map(h -> h.get("alg")) | ||
.map(Object::toString) | ||
.map(SignatureAlgorithm::forName) | ||
.orElseThrow(() -> new IllegalArgumentException("Token doesn't provide valid signature algorithm")); | ||
|
||
if (expectedAlgorithm != usedAlgorithm) { | ||
throw new IllegalArgumentException("Token is using unsupported signature algorithm :" + usedAlgorithm); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
data-node/src/main/java/org/graylog/datanode/initializers/TokenVerificationException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Copyright (C) 2020 Graylog, Inc. | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the Server Side Public License, version 1, | ||
* as published by MongoDB, Inc. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* Server Side Public License for more details. | ||
* | ||
* You should have received a copy of the Server Side Public License | ||
* along with this program. If not, see | ||
* <http://www.mongodb.com/licensing/server-side-public-license>. | ||
*/ | ||
package org.graylog.datanode.initializers; | ||
|
||
public class TokenVerificationException extends Exception { | ||
public TokenVerificationException(Exception cause) { | ||
super(cause); | ||
} | ||
|
||
public TokenVerificationException(String message) { | ||
super(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.