private Optional<Principal> authenticate(final String token) { try { return authenticator.authenticate(token); } catch (final SecurityException ex) { LOGGER.debug("Invalid signature, ignoring JWT token: {}", ex.getMessage()); } catch (final JwtException ex) { LOGGER.warn("Problem reading JWT value: {}", ex.getMessage()); } return empty(); }
@Test public void testNullAuthenticator() { final Authenticator authenticator = new NullAuthenticator(); assertFalse(authenticator.authenticate("blah").isPresent(), "Unexpected principal found!"); assertNull(authenticator.parse("credentials"), "Credentials were not null!"); }
/** * Authenticate credentials. * @param token the token * @return the principal if present */ default Optional<Principal> authenticate(final String token) { final Claims claims = parse(token); // Use a webid claim, if one exists final Optional<Principal> webid = withWebIdClaim(claims); if (webid.isPresent()) { return webid; } // Try generating a webid from other elements return withSubjectClaim(claims); } }
@Test public void testAuthenticateKeystoreNoMatch() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final String token = buildEcToken(ks.getKey("trellis-ec", passphrase), "trellis-ec"); final Authenticator authenticator = new FederatedJwtAuthenticator(ks, asList("trellis", "foo")); assertThrows(SecurityException.class, () -> authenticator.authenticate(token), "Unexpected keystore entry!"); }
@Test public void testAuthenticateKeystoreEC() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final String token = buildEcToken(ks.getKey("trellis-ec", passphrase), "trellis-ec"); final Authenticator authenticator = new FederatedJwtAuthenticator(ks, asList("trellis-ec")); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticateKeystoreAnotherNoMatch() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final String token = buildEcToken(ks.getKey("trellis-ec", passphrase), "foo"); final Authenticator authenticator = new FederatedJwtAuthenticator(ks, asList("foo")); assertThrows(SecurityException.class, () -> authenticator.authenticate(token), "Unexpected keystore entry!"); }
@Test public void testKeyStoreException() throws Exception { final KeyStore mockKeyStore = mock(KeyStore.class, inv -> { throw new KeyStoreException("Expected"); }); final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final String token = buildEcToken(ks.getKey("trellis-ec", passphrase), "trellis-ec"); final Authenticator authenticator = new FederatedJwtAuthenticator(mockKeyStore, asList("trellis-ec")); assertThrows(SecurityException.class, () -> authenticator.authenticate(token), "Unexpectedly functional keystore!"); }
@Test public void testAuthenticateKeystoreRSA() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), "password".toCharArray()); final Key privateKey = ks.getKey("trellis", "password".toCharArray()); final String token = Jwts.builder().setSubject("https://people.apache.org/~acoburn/#i") .signWith(privateKey, SignatureAlgorithm.RS256).compact(); final Authenticator authenticator = new JwtAuthenticator( ks.getCertificate("trellis-public").getPublicKey()); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticateKeystoreEC() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), "password".toCharArray()); final Key privateKey = ks.getKey("trellis-ec", "password".toCharArray()); final String token = Jwts.builder().setSubject("https://people.apache.org/~acoburn/#i") .signWith(privateKey, SignatureAlgorithm.ES256).compact(); final Authenticator authenticator = new JwtAuthenticator( ks.getCertificate("trellis-ec").getPublicKey()); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticationTokenWebid() { final String key = "N0NuokWWb5XjMP+V3XLfyLkaSArwxNm17VeAvv7+y4+Y/DmxBLenvwOPO404lfl6UfyyEGgQ02ETDEPRMwV/+Q=="; final String token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ3ZWJpZCI6Imh0dHBzOi8vcGVvcGxlLmFwYWNoZS5vcmcvfm" + "Fjb2J1cm4vI2kiLCJzdWIiOiJhY29idXJuIiwibmFtZSI6IkFhcm9uIENvYnVybiIsImlzcyI6Imh0dHA6Ly9leGFtcGxlLm9yZy8ifQ" + ".kIHJDSzaisxfIF5fQou2e9rBInsDsl0vZ4QQ60zlZlSufm9nnmC7eL-875WPsVGzPAfptF6MrImrpFeNxdW9ZQ"; final Authenticator authenticator = new JwtAuthenticator(hmacShaKeyFor(Base64.getDecoder().decode(key))); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticateKeystore() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), "password".toCharArray()); final Key privateKey = ks.getKey("trellis", "password".toCharArray()); final String token = Jwts.builder().setSubject("https://people.apache.org/~acoburn/#i") .signWith(privateKey, SignatureAlgorithm.RS256).compact(); final Authenticator authenticator = new JwtAuthenticator( ks.getCertificate("trellis").getPublicKey()); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticateToken() { final String key = "N0NuokWWb5XjMP+V3XLfyLkaSArwxNm17VeAvv7+y4+Y/DmxBLenvwOPO404lfl6UfyyEGgQ02ETDEPRMwV/+Q=="; final String token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJodHRwczovL3Blb3BsZS5hcGFjaGUub3JnL35" + "hY29idXJuLyNpIn0.n-C7xhjVyn3WEWGfSXfuqrjXVSoAnD08sO5K8mDsBiZF6Z8lwiksGos6lR-6RjD5jI25d1yPJ47LKBWqMlMm_A"; final Authenticator authenticator = new JwtAuthenticator(hmacShaKeyFor(Base64.getDecoder().decode(key))); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticateTokenIssSub() { final String key = "N0NuokWWb5XjMP+V3XLfyLkaSArwxNm17VeAvv7+y4+Y/DmxBLenvwOPO404lfl6UfyyEGgQ02ETDEPRMwV/+Q=="; final String token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhY29idXJuIiwibmFtZSI6IkFhcm9uIENvYnVyb" + "iIsImlzcyI6Imh0dHA6Ly9leGFtcGxlLm9yZy8ifQ.4Srityp5iPScGyqvkPakD3DmtXYWhkyHjr0K6B7kpcR2ll8MC-hGpYoIDM8ar" + "ro3dyZQp0kDhPfYZ6MiAGfGTQ"; final Authenticator authenticator = new JwtAuthenticator(hmacShaKeyFor(Base64.getDecoder().decode(key))); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("http://example.org/acoburn", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticationNoPrincipal() { final String key = "w8+z9hrcbr3ktQ5WTr9xNZknke3L/RAj8r8RieriWozGu1M4RDgkpJcfTEg90pqYyadbIBLy+qFHu1JJ8O0rjw=="; final String token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhY29idXJuIiwibmFtZSI6IkFhcm9" + "uIENvYnVybiJ9.srs7gSbix8nLDuFmwYCEN0In-5pa6-59D5nqF1UgRD-hsJBS2UoieYoBJZNGGKj1hO1DaboqtuS_36bE9QGdCw"; final Authenticator authenticator = new JwtAuthenticator(hmacShaKeyFor(Base64.getDecoder().decode(key))); final Optional<Principal> result = authenticator.authenticate(token); assertFalse(result.isPresent(), "Unexpected principal!"); }
@Test public void testAuthenticateNoSub() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final Key privateKey = ks.getKey("trellis-ec", passphrase); final String token = Jwts.builder().setHeaderParam(JwsHeader.KEY_ID, "trellis-ec") .setIssuer("http://localhost").signWith(privateKey, SignatureAlgorithm.ES256).compact(); final Authenticator authenticator = new FederatedJwtAuthenticator(ks, asList("trellis-ec")); assertFalse(authenticator.authenticate(token).isPresent(), "Unexpected principal!"); }
@Test public void testAuthenticateKeystoreECWebsite() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), "password".toCharArray()); final Key privateKey = ks.getKey("trellis-ec", "password".toCharArray()); final String token = Jwts.builder().setSubject("acoburn") .claim("website", "https://people.apache.org/~acoburn/#i") .signWith(privateKey, SignatureAlgorithm.ES256).compact(); final Authenticator authenticator = new JwtAuthenticator( ks.getCertificate("trellis-ec").getPublicKey()); final Optional<Principal> result = authenticator.authenticate(token); assertTrue(result.isPresent(), "Missing principal!"); result.ifPresent(p -> assertEquals("https://people.apache.org/~acoburn/#i", p.getName(), "Incorrect webid!")); }
@Test public void testAuthenticationTokenWebidBadKey() { final String key = "2YuUlb+t36yVzrTkYLl8xBlBJSC41CE7uNF3somMDxdYDfcACv9JYIU54z17s4Ah313uKu/4Ll+vDNKpxx6v4Q=="; final String token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ3ZWJpZCI6Imh0dHBzOi8vcGVvcGxlLmFwYWNoZS5vcmcvfm" + "Fjb2J1cm4vI2kiLCJzdWIiOiJhY29idXJuIiwibmFtZSI6IkFhcm9uIENvYnVybiIsImlzcyI6Imh0dHA6Ly9leGFtcGxlLm9yZy8ifQ" + ".kIHJDSzaisxfIF5fQou2e9rBInsDsl0vZ4QQ60zlZlSufm9nnmC7eL-875WPsVGzPAfptF6MrImrpFeNxdW9ZQ"; final Authenticator authenticator = new JwtAuthenticator(hmacShaKeyFor(Base64.getDecoder().decode(key))); assertThrows(SecurityException.class, () -> authenticator.authenticate(token), "Parsed bad JWT!"); }
@Test public void testAuthenticateKeystoreNoKeyId() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final Key privateKey = ks.getKey("trellis-ec", passphrase); final String token = Jwts.builder().setSubject("https://people.apache.org/~acoburn/#i") .signWith(privateKey, SignatureAlgorithm.ES256).compact(); final Authenticator authenticator = new FederatedJwtAuthenticator(ks, asList("trellis-ec")); assertThrows(JwtException.class, () -> authenticator.authenticate(token), "Unexpected key id field!"); }
@Test public void testAuthenticateSubNoWebIss() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(getClass().getResourceAsStream("/keystore.jks"), passphrase); final Key privateKey = ks.getKey("trellis-ec", passphrase); final String token = Jwts.builder().setHeaderParam(JwsHeader.KEY_ID, "trellis-ec") .setSubject("acoburn").setIssuer("some org") .signWith(privateKey, SignatureAlgorithm.ES256).compact(); final Authenticator authenticator = new FederatedJwtAuthenticator(ks, asList("trellis-ec")); assertFalse(authenticator.authenticate(token).isPresent(), "Unexpected principal!"); }
@Test public void testGarbledToken() { final String key = "thj983z1fiqAiaV7Nv4nWpjaDi6eVTd7jOGxbs92mp8="; final String token = "blahblah"; final Authenticator authenticator = new JwtAuthenticator(hmacShaKeyFor(Base64.getDecoder().decode(key))); assertThrows(MalformedJwtException.class, () -> authenticator.authenticate(token), "Parsed bad JWT!"); } }