/** * Build a jwks-based authenticator. * @param url the location of the public jwks keys */ public JwksAuthenticator(final String url) { this.keys = buildKeys(url); }
@Override public String toString() { return getName(); } }
/** * 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); } }
public static Authenticator getJwtAuthenticator(final JwtAuthConfiguration config) { final Authenticator jwksAuthenticator = OAuthUtils.buildAuthenticatorWithJwk( config.getJwks()); if (nonNull(jwksAuthenticator)) { return jwksAuthenticator; } final Authenticator keystoreAuthenticator = OAuthUtils.buildAuthenticatorWithTruststore( config.getKeyStore(), config.getKeyStorePassword().toCharArray(), config.getKeyIds()); if (nonNull(keystoreAuthenticator)) { return keystoreAuthenticator; } final Authenticator sharedKeyAuthenticator = OAuthUtils.buildAuthenticatorWithSharedSecret(config.getKey()); if (nonNull(sharedKeyAuthenticator)) { return sharedKeyAuthenticator; } return new NullAuthenticator(); }
@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 testNullAuthenticator() { final Authenticator authenticator = new NullAuthenticator(); assertFalse(authenticator.authenticate("blah").isPresent(), "Unexpected principal found!"); assertNull(authenticator.parse("credentials"), "Credentials were not null!"); }
@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 testOAuthJwkBuilder() { final String url = "https://www.trellisldp.org/tests/jwks.json"; final Authenticator authenticator = OAuthUtils.buildAuthenticatorWithJwk(url); assertTrue(authenticator instanceof JwksAuthenticator); }
@Test public void testAuthenticateJwksNoKeyid() throws Exception { final String webid = "https://people.apache.org/~acoburn/#i"; final Key key = KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(modulus, exponent)); final String token = Jwts.builder().setSubject(webid).signWith(key).compact(); final Authenticator authenticator = new JwksAuthenticator(url); assertThrows(JwtException.class, () -> authenticator.authenticate(token), "Unexpected principal!"); }
@Override public void filter(final ContainerRequestContext requestContext) throws IOException { final boolean secure = ofNullable(requestContext.getSecurityContext()).filter(SecurityContext::isSecure) .isPresent(); getOAuthToken(requestContext) .map(token -> authenticate(token) .<RuntimeException>orElseThrow(() -> new NotAuthorizedException(challenge))) .ifPresent(principal -> requestContext .setSecurityContext(new OAuthSecurityContext(secure, principal))); }
@Test public void testBuilderSimpleDefault() { assertNull(OAuthUtils.buildAuthenticatorWithSharedSecret(null)); assertNull(OAuthUtils.buildAuthenticatorWithSharedSecret("")); }
/** * Create an OAuth filter. */ @Inject public OAuthFilter() { this(buildAuthenticator()); }
@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 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!"); } }
@Test public void testOAuthJwkBuilderNull() { assertNull(OAuthUtils.buildAuthenticatorWithJwk(null)); }
@Test public void testAuthenticateJwksInvalidKeyLocation() throws Exception { final String webid = "https://people.apache.org/~acoburn/#i"; final Key key = KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(modulus, exponent)); final String token = Jwts.builder().setHeaderParam(JwsHeader.KEY_ID, keyid).setSubject(webid) .signWith(key).compact(); final Authenticator authenticator = new JwksAuthenticator("https://www.trellisldp.org/tests/non-existent"); assertThrows(SecurityException.class, () -> authenticator.authenticate(token), "Unexpected principal!"); } }
@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 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 testOAuthJwkBuilderNotUrl() { assertNull(OAuthUtils.buildAuthenticatorWithJwk("some text")); }
@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!"); }