password in jwt payload (#823)

* make sure we don't put the password in the jwt payload

* Made sure password doesn't appear in jwt payload

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Chris Mckay 6 years ago committed by Lucas Saldanha
parent c3df0d0238
commit caa5acfa72
  1. 8
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpService.java
  2. 100
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java

@ -92,6 +92,7 @@ public class JsonRpcHttpService {
private final LabelledMetric<OperationTimer> requestTimer;
@VisibleForTesting public final Optional<JWTAuth> jwtAuthProvider;
@VisibleForTesting public final Optional<JWTAuthOptions> jwtAuthOptions;
private final Optional<AuthProvider> credentialAuthProvider;
private HttpServer httpServer;
@ -212,6 +213,7 @@ public class JsonRpcHttpService {
this.vertx = vertx;
this.jsonRpcMethods = methods;
this.credentialAuthProvider = credentialAuthProvider;
this.jwtAuthOptions = jwtOptions;
jwtAuthProvider = jwtOptions.map(options -> JWTAuth.create(vertx, options));
}
@ -441,7 +443,11 @@ public class JsonRpcHttpService {
final JWTOptions options =
new JWTOptions().setExpiresInMinutes(5).setAlgorithm("RS256");
final String token = jwtAuthProvider.get().generateToken(user.principal(), options);
final JsonObject jwtContents =
new JsonObject()
.put("permissions", user.principal().getValue("permissions"))
.put("username", user.principal().getValue("username"));
final String token = jwtAuthProvider.get().generateToken(jwtContents, options);
final JsonObject responseBody = new JsonObject().put("token", token);
final HttpServerResponse response = routingContext.response();

@ -31,20 +31,35 @@ import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.KeyStoreOptions;
import io.vertx.ext.auth.PubSecKeyOptions;
import io.vertx.ext.auth.SecretOptions;
import io.vertx.ext.auth.User;
import io.vertx.ext.auth.jwt.JWTAuth;
import io.vertx.ext.auth.jwt.JWTAuthOptions;
import io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl;
import io.vertx.ext.jwt.JWK;
import io.vertx.ext.jwt.JWT;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@ -227,4 +242,89 @@ public class JsonRpcHttpServiceLoginTest {
});
}
}
private JWT makeJwt(final JWTAuthOptions config)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
final KeyStoreOptions keyStoreOptions = config.getKeyStore();
if (keyStoreOptions != null) {
final KeyStore ks = KeyStore.getInstance(keyStoreOptions.getType());
// synchronize on the class to avoid the case where multiple file accesses will overlap
synchronized (JWTAuthProviderImpl.class) {
final Buffer keystore = vertx.fileSystem().readFileBlocking(keyStoreOptions.getPath());
try (InputStream in = new ByteArrayInputStream(keystore.getBytes())) {
ks.load(in, keyStoreOptions.getPassword().toCharArray());
}
}
return new JWT(ks, keyStoreOptions.getPassword().toCharArray());
} else {
// no key file attempt to load pem keys
final JWT jwt = new JWT();
final List<PubSecKeyOptions> keys = config.getPubSecKeys();
if (keys != null) {
for (final PubSecKeyOptions pubSecKey : config.getPubSecKeys()) {
if (pubSecKey.isSymmetric()) {
jwt.addJWK(new JWK(pubSecKey.getAlgorithm(), pubSecKey.getPublicKey()));
} else {
jwt.addJWK(
new JWK(
pubSecKey.getAlgorithm(),
pubSecKey.isCertificate(),
pubSecKey.getPublicKey(),
pubSecKey.getSecretKey()));
}
}
}
// TODO: remove once the deprecation ends!
final List<SecretOptions> secrets = config.getSecrets();
if (secrets != null) {
for (final SecretOptions secret : secrets) {
jwt.addSecret(secret.getType(), secret.getSecret());
}
}
final List<JsonObject> jwks = config.getJwks();
if (jwks != null) {
for (final JsonObject jwk : jwks) {
jwt.addJWK(new JWK(jwk));
}
}
return jwt;
}
}
@Test
public void loginDoesntPopulateJWTPayloadWithPassword()
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
final RequestBody body =
RequestBody.create(JSON, "{\"username\":\"user\",\"password\":\"pegasys\"}");
final Request request = new Request.Builder().post(body).url(baseUrl + "/login").build();
try (final Response resp = client.newCall(request).execute()) {
assertThat(resp.code()).isEqualTo(200);
assertThat(resp.message()).isEqualTo("OK");
assertThat(resp.body().contentType()).isNotNull();
assertThat(resp.body().contentType().type()).isEqualTo("application");
assertThat(resp.body().contentType().subtype()).isEqualTo("json");
final String bodyString = resp.body().string();
assertThat(bodyString).isNotNull();
assertThat(bodyString).isNotBlank();
final JsonObject respBody = new JsonObject(bodyString);
final String token = respBody.getString("token");
assertThat(token).isNotNull();
final JWT jwt = makeJwt(service.jwtAuthOptions.get());
final JsonObject jwtPayload = jwt.decode(token);
final String jwtPayloadString = jwtPayload.encode();
assertThat(jwtPayloadString.contains("password")).isFalse();
assertThat(jwtPayloadString.contains("pegasys")).isFalse();
}
}
}

Loading…
Cancel
Save