Add JWT verifier

This commit is contained in:
Sebastian Stenzel
2019-11-14 17:02:41 +01:00
parent 6222f96b01
commit 1717e20b61
4 changed files with 133 additions and 6 deletions
+11 -5
View File
@@ -23,26 +23,25 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- dependency versions -->
<!-- cryptomator dependencies -->
<cryptomator.cryptofs.version>1.9.0-rc2</cryptomator.cryptofs.version>
<cryptomator.jni.version>2.2.1</cryptomator.jni.version>
<cryptomator.fuse.version>1.2.1</cryptomator.fuse.version>
<cryptomator.dokany.version>1.1.11</cryptomator.dokany.version>
<cryptomator.webdav.version>1.0.10</cryptomator.webdav.version>
<!-- 3rd party dependencies -->
<javafx.version>13.0.1</javafx.version>
<commons-lang3.version>3.9</commons-lang3.version>
<jwt.version>3.8.3</jwt.version>
<easybind.version>1.0.3</easybind.version>
<guava.version>28.1-jre</guava.version>
<dagger.version>2.25.2</dagger.version>
<gson.version>2.8.6</gson.version>
<slf4j.version>1.7.29</slf4j.version>
<logback.version>1.2.3</logback.version>
<!-- test dependencies -->
<junit.jupiter.version>5.5.2</junit.jupiter.version>
<mockito.version>3.1.0</mockito.version>
<hamcrest.version>2.2</hamcrest.version>
@@ -156,6 +155,13 @@
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- EasyBind -->
<dependency>
+7 -1
View File
@@ -37,7 +37,13 @@
<dependency>
<groupId>org.fxmisc.easybind</groupId>
<artifactId>easybind</artifactId>
</dependency>
</dependency>
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
<!-- Google -->
<dependency>
@@ -0,0 +1,54 @@
package org.cryptomator.ui.preferences;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.google.common.io.BaseEncoding;
import javax.inject.Inject;
import javax.inject.Named;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Optional;
public class LicenseChecker {
private final JWTVerifier verifier;
@Inject
public LicenseChecker(@Named("licensePublicKey") String pemEncodedPublicKey) {
Algorithm algorithm = Algorithm.ECDSA512(decodePublicKey(pemEncodedPublicKey), null);
this.verifier = JWT.require(algorithm).build();
}
private static ECPublicKey decodePublicKey(String pemEncodedPublicKey) {
try {
byte[] keyBytes = BaseEncoding.base64().decode(pemEncodedPublicKey);
PublicKey key = KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(keyBytes));
if (key instanceof ECPublicKey) {
return (ECPublicKey) key;
} else {
throw new IllegalStateException("Key not an EC public key.");
}
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException("Invalid license public key", e);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
public Optional<DecodedJWT> check(String licenseKey) {
try {
return Optional.of(verifier.verify(licenseKey));
} catch (JWTVerificationException exception) {
return Optional.empty();
}
}
}
@@ -0,0 +1,61 @@
package org.cryptomator.ui.preferences;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Optional;
class LicenseCheckerTest {
private static final String PUBLIC_KEY = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ" //
+ "PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47" //
+ "6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM" //
+ "Al8G7CqwoJOsW7Kddns=";
private LicenseChecker licenseChecker;
@BeforeEach
public void setup() {
licenseChecker = new LicenseChecker(PUBLIC_KEY);
}
@Test
public void testCheckValidLicense() {
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
Optional<DecodedJWT> decoded = licenseChecker.check(license);
Assertions.assertTrue(decoded.isPresent());
Assertions.assertEquals("cryptobot@example.com", decoded.get().getSubject());
}
@Test
public void testCheckInvalidLicenseHeader() {
String license = "EyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
Optional<DecodedJWT> decoded = licenseChecker.check(license);
Assertions.assertFalse(decoded.isPresent());
}
@Test
public void testCheckInvalidLicensePayload() {
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.EyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
Optional<DecodedJWT> decoded = licenseChecker.check(license);
Assertions.assertFalse(decoded.isPresent());
}
@Test
public void testCheckInvalidLicenseSignature() {
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.aQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
Optional<DecodedJWT> decoded = licenseChecker.check(license);
Assertions.assertFalse(decoded.isPresent());
}
}