diff options
author | Harald Musum <musum@oath.com> | 2018-07-09 18:03:06 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-09 18:03:06 +0200 |
commit | 3a6cb611e4f1ec8a86f3699c8ddb742e7eac0bdb (patch) | |
tree | 30cf4aa444da5966d53a143d9f06a065673df96c /vespa-athenz | |
parent | 8cd3b8e9cfe6eb8bf16b2619ef63e1d0f59a1eb0 (diff) |
Revert "Move NTokenValidator to vespa-athenz + load pub keys from file"
Diffstat (limited to 'vespa-athenz')
6 files changed, 49 insertions, 232 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzPublicKey.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzPublicKey.java new file mode 100644 index 00000000000..1c810e3e9c9 --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzPublicKey.java @@ -0,0 +1,49 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.athenz.api; + +import java.security.PublicKey; +import java.util.Objects; + +/** + * @author bjorncs + */ +public class AthenzPublicKey { + + private final PublicKey publicKey; + private final String keyId; + + public AthenzPublicKey(PublicKey publicKey, String keyId) { + this.publicKey = publicKey; + this.keyId = keyId; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public String getKeyId() { + return keyId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AthenzPublicKey that = (AthenzPublicKey) o; + return Objects.equals(publicKey, that.publicKey) && + Objects.equals(keyId, that.keyId); + } + + @Override + public int hashCode() { + return Objects.hash(publicKey, keyId); + } + + @Override + public String toString() { + return "AthenzPublicKey{" + + "publicKey=" + publicKey + + ", keyId='" + keyId + '\'' + + '}'; + } +} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/AthenzConfTruststore.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/AthenzConfTruststore.java deleted file mode 100644 index 9d9a19d55cb..00000000000 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/AthenzConfTruststore.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.athenz.utils.ntoken; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.yahoo.athenz.auth.util.Crypto; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Path; -import java.security.PublicKey; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -/** - * A {@link AthenzTruststore} that is backed by athenz.conf - * - * @author bjorncs - */ -public class AthenzConfTruststore implements AthenzTruststore { - - private final Map<String, PublicKey> publicKeys; - - public AthenzConfTruststore(Path athenzConfFile) { - this.publicKeys = loadPublicKeys(athenzConfFile); - } - - @Override - public Optional<PublicKey> getPublicKey(String keyId) { - return Optional.of(publicKeys.get(keyId)); - } - - private static Map<String, PublicKey> loadPublicKeys(Path athenzConfFile) { - try { - Map<String, PublicKey> publicKeys = new HashMap<>(); - ObjectMapper mapper = new ObjectMapper(); - JsonNode root = mapper.readTree(athenzConfFile.toFile()); - ArrayNode keysArray = (ArrayNode) root.get("ztsPublicKeys"); - for (JsonNode keyEntry : keysArray) { - String keyId = keyEntry.get("id").textValue(); - String encodedPublicKey = keyEntry.get("key").textValue(); - PublicKey publicKey = Crypto.loadPublicKey(Crypto.ybase64DecodeString(encodedPublicKey)); - publicKeys.put(keyId, publicKey); - } - return publicKeys; - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } -} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/AthenzTruststore.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/AthenzTruststore.java deleted file mode 100644 index 3139e6b847f..00000000000 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/AthenzTruststore.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.athenz.utils.ntoken; - -import java.security.PublicKey; -import java.util.Optional; - -/** - * A truststore that contains all ZMS and ZTS public keys - * - * @author bjorncs - */ -public interface AthenzTruststore { - Optional<PublicKey> getPublicKey(String keyId); -} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/NTokenValidator.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/NTokenValidator.java deleted file mode 100644 index 85c62bc07ff..00000000000 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/NTokenValidator.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.athenz.utils.ntoken; - -import com.yahoo.athenz.auth.token.PrincipalToken; -import com.yahoo.log.LogLevel; -import com.yahoo.vespa.athenz.api.AthenzDomain; -import com.yahoo.vespa.athenz.api.AthenzPrincipal; -import com.yahoo.vespa.athenz.api.NToken; -import com.yahoo.vespa.athenz.utils.AthenzIdentities; - -import java.nio.file.Path; -import java.security.PublicKey; -import java.time.Duration; -import java.util.logging.Logger; - -/** - * Validates the content of an NToken: - * 1) Verifies that the token is signed by Athenz - * 2) Verifies that the token is not expired - * - * @author bjorncs - */ -public class NTokenValidator { - // Max allowed skew in token timestamp (only for creation, not expiry timestamp) - private static final long ALLOWED_TIMESTAMP_OFFSET = Duration.ofMinutes(5).getSeconds(); - - private static final Logger log = Logger.getLogger(NTokenValidator.class.getName()); - private final AthenzTruststore truststore; - - - public NTokenValidator(AthenzTruststore truststore) { - this.truststore = truststore; - } - - public NTokenValidator(Path athenzConfFile) { - this(new AthenzConfTruststore(athenzConfFile)); - } - - public AthenzPrincipal validate(NToken token) throws InvalidTokenException { - PrincipalToken principalToken = new PrincipalToken(token.getRawToken()); - String keyId = principalToken.getKeyId(); - PublicKey zmsPublicKey = truststore.getPublicKey(keyId) - .orElseThrow(() -> { - String message = "NToken has an unknown keyId: " + keyId; - log.log(LogLevel.WARNING, message); - return new InvalidTokenException(message); - }); - validateSignatureAndExpiration(principalToken, zmsPublicKey); - return new AthenzPrincipal( - AthenzIdentities.from( - new AthenzDomain(principalToken.getDomain()), - principalToken.getName()), - token); - } - - private static void validateSignatureAndExpiration(PrincipalToken token, PublicKey zmsPublicKey) throws InvalidTokenException { - StringBuilder errorMessageBuilder = new StringBuilder(); - if (!token.validate(zmsPublicKey, (int) ALLOWED_TIMESTAMP_OFFSET, true, errorMessageBuilder)) { - String message = "NToken is expired or has invalid signature: " + errorMessageBuilder.toString(); - log.log(LogLevel.WARNING, message); - throw new InvalidTokenException(message); - } - } - - public static class InvalidTokenException extends RuntimeException { - public InvalidTokenException(String message) { - super(message); - } - } - -} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/package-info.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/package-info.java deleted file mode 100644 index 8760c02d27d..00000000000 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/ntoken/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @author bjorncs - */ -@ExportPackage -package com.yahoo.vespa.athenz.utils.ntoken; - -import com.yahoo.osgi.annotation.ExportPackage;
\ No newline at end of file diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/ntoken/NTokenValidatorTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/ntoken/NTokenValidatorTest.java deleted file mode 100644 index 0e70993792f..00000000000 --- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/ntoken/NTokenValidatorTest.java +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.athenz.utils.ntoken; - -import com.yahoo.athenz.auth.token.PrincipalToken; -import com.yahoo.vespa.athenz.api.AthenzIdentity; -import com.yahoo.vespa.athenz.api.AthenzPrincipal; -import com.yahoo.vespa.athenz.api.AthenzUser; -import com.yahoo.vespa.athenz.api.NToken; -import com.yahoo.vespa.athenz.tls.KeyAlgorithm; -import com.yahoo.vespa.athenz.tls.KeyUtils; -import com.yahoo.vespa.athenz.utils.ntoken.NTokenValidator.InvalidTokenException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.security.KeyPair; -import java.security.PrivateKey; -import java.time.Instant; -import java.util.Optional; - -import static org.junit.Assert.assertEquals; - -/** - * @author bjorncs - */ -public class NTokenValidatorTest { - - private static final KeyPair TRUSTED_KEY = KeyUtils.generateKeypair(KeyAlgorithm.RSA); - private static final KeyPair UNKNOWN_KEY = KeyUtils.generateKeypair(KeyAlgorithm.RSA); - private static final AthenzIdentity IDENTITY = AthenzUser.fromUserId("myuser"); - - @Rule - public ExpectedException exceptionRule = ExpectedException.none(); - - @Test - public void valid_token_is_accepted() throws InvalidTokenException { - NTokenValidator validator = new NTokenValidator(createTruststore()); - NToken token = createNToken(IDENTITY, Instant.now(), TRUSTED_KEY.getPrivate(), "0"); - AthenzPrincipal principal = validator.validate(token); - assertEquals("user.myuser", principal.getIdentity().getFullName()); - } - - @Test - public void invalid_signature_is_not_accepted() throws InvalidTokenException { - NTokenValidator validator = new NTokenValidator(createTruststore()); - NToken token = createNToken(IDENTITY, Instant.now(), UNKNOWN_KEY.getPrivate(), "0"); - exceptionRule.expect(InvalidTokenException.class); - exceptionRule.expectMessage("NToken is expired or has invalid signature"); - validator.validate(token); - } - - @Test - public void expired_token_is_not_accepted() throws InvalidTokenException { - NTokenValidator validator = new NTokenValidator(createTruststore()); - NToken token = createNToken(IDENTITY, Instant.ofEpochMilli(1234) /*long time ago*/, TRUSTED_KEY.getPrivate(), "0"); - exceptionRule.expect(InvalidTokenException.class); - exceptionRule.expectMessage("NToken is expired or has invalid signature"); - validator.validate(token); - } - - @Test - public void unknown_keyId_is_not_accepted() throws InvalidTokenException { - NTokenValidator validator = new NTokenValidator(createTruststore()); - NToken token = createNToken(IDENTITY, Instant.now(), TRUSTED_KEY.getPrivate(), "unknown-key-id"); - exceptionRule.expect(InvalidTokenException.class); - exceptionRule.expectMessage("NToken has an unknown keyId"); - validator.validate(token); - } - - private static AthenzTruststore createTruststore() { - return keyId -> keyId.equals("0") ? Optional.of(TRUSTED_KEY.getPublic()) : Optional.empty(); - } - - private static NToken createNToken(AthenzIdentity identity, Instant issueTime, PrivateKey privateKey, String keyId) { - PrincipalToken token = new PrincipalToken.Builder("U1", identity.getDomain().getName(), identity.getName()) - .keyId(keyId) - .salt("1234") - .host("host") - .ip("1.2.3.4") - .issueTime(issueTime.getEpochSecond()) - .expirationWindow(1000) - .build(); - token.sign(privateKey); - return new NToken(token.getSignedToken()); - } - -} |