private Jwt extractToken(String authHeader) { List<ExtractionResult> result = extractors .stream() .map(extractor -> { ExtractionResult vr = extractor.canExtract(authHeader); return vr.isExtractionPossible() ? extractor.extract(authHeader) : vr; }) .collect(Collectors.toList()); ExtractionResult extractionResult = result .stream() .filter(ExtractionResult::hasJwt) .findFirst() .orElseThrow(() -> new InvalidTokenException("Could not extract JWT from token")); return extractionResult.getJwt(); }
protected void validateJwtToken(String token, String username) { Assert.assertNotNull(token); Assert.assertFalse(token.isEmpty()); int i = token.lastIndexOf('.'); Assert.assertTrue(i > 0); String withoutSignature = token.substring(0, i + 1); Jwt<Header, Claims> jwsClaims = Jwts.parser().parseClaimsJwt(withoutSignature); Claims claims = jwsClaims.getBody(); String subject = claims.getSubject(); Assert.assertEquals(username, subject); }
/** * {@inheritDoc} */ @Override public Jwt parse(String token, Symmetric issuer) { Jwt jwt; try { jwt = Jwts.parser() .setAllowedClockSkewSeconds(issuer.getSkewSeconds()) .setSigningKey(issuer.getSigningKey()) .parseClaimsJws(token); return jwt; } catch (Exception e) { LOGGER.error(e.getMessage(), e); throw new InvalidTokenException(e.getMessage()); } }
/** * {@inheritDoc} */ @Override public void validate(Jwt jwt, HttpServletRequest request) { if (!(jwt instanceof Jws)) { throw new InvalidTokenException("Only signed JWT are supported"); } Jws<Claims> jws = (Jws) jwt; String issuer = jws.getBody().getIssuer(); Optional<TenantEO> tenantEO = repository.findByHash(request.getHeader(HEADER_VALUE_X_TENANT)); if (!tenantEO.isPresent()){ throw new InvalidTokenException("Tenant not registered"); } String realm = issuer.substring(issuer.lastIndexOf("/")+1, issuer.length()); if (!tenantEO.get().sameRealm(realm)) { throw new InvalidTokenException("The issue does not match the configured REALM for the Tenant"); } if (!tenantEO.get().getName().equals(jws.getBody().getAudience())) { throw new InvalidTokenException("The token has been issued for some other audience, is the token leaked or replayed?"); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("{} has been translated into [{}]", HEADER_VALUE_X_TENANT, tenantEO.get().getName()); } request.setAttribute(HEADER_VALUE_X_TENANT, tenantEO.get().getName()); }
/** * {@inheritDoc} * * - Extract JWT from header * - Validate JWT */ @Override public void doFilter(HttpServletRequest request, HttpServletResponse response) { String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); if (authHeader != null && isBearer(authHeader)) { LOGGER.debug("Authorization Header detected, start extracting and validating..."); Jwt jwt = extractToken(authHeader); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Extracted JWT: [{}]", jwt); } validator.ifPresent(jwtValidator -> jwtValidator.validate(jwt, request)); } }
@Override public Map<String, Object> onPlaintextJwt(@SuppressWarnings("rawtypes") Jwt<Header, String> jwt) { if (config.getRequireSigned()) { super.onPlaintextJwt(jwt); } return Collections.emptyMap(); }
/** * Performs local and Keycloak accounts linking * * @return typically Response that redirect user for OAuth provider site */ @GET @Path("authenticate") public Response authenticate( @Required @QueryParam("oauth_provider") String oauthProvider, @Required @QueryParam("redirect_after_login") String redirectAfterLogin, @Context HttpServletRequest request) throws ForbiddenException, BadRequestException { Jwt jwtToken = (Jwt) request.getAttribute("token"); if (jwtToken == null) { throw new BadRequestException("No token provided."); } DefaultClaims claims = (DefaultClaims) jwtToken.getBody(); final String clientId = claims.getAudience(); final String nonce = UUID.randomUUID().toString(); final String sessionState = claims.get("session_state", String.class); MessageDigest md; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } final String input = nonce + sessionState + clientId + oauthProvider; byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8)); final String hash = Base64.getUrlEncoder().encodeToString(check); request.getSession().setAttribute("hash", hash); // TODO: for what? String accountLinkUrl = UriBuilder.fromUri(keycloakConfiguration.get().get(AUTH_SERVER_URL_SETTING)) .path("/realms/{realm}/broker/{provider}/link") .queryParam("nonce", nonce) .queryParam("hash", hash) .queryParam("client_id", clientId) .queryParam("redirect_uri", redirectAfterLogin) .build(keycloakConfiguration.get().get(REALM_SETTING), oauthProvider) .toString(); return Response.temporaryRedirect(URI.create(accountLinkUrl)).build(); }
@Override public Jwt<Header, String> parsePlaintextJwt(String plaintextJwt) { return parse(plaintextJwt, new JwtHandlerAdapter<Jwt<Header, String>>() { @Override public Jwt<Header, String> onPlaintextJwt(Jwt<Header, String> jwt) { return jwt; } }); }
@Override public Jwt<Header, Claims> parseClaimsJwt(String claimsJwt) { try { return parse(claimsJwt, new JwtHandlerAdapter<Jwt<Header, Claims>>() { @Override public Jwt<Header, Claims> onClaimsJwt(Jwt<Header, Claims> jwt) { return jwt; } }); } catch (IllegalArgumentException iae) { throw new UnsupportedJwtException("Signed JWSs are not supported.", iae); } }
@SuppressWarnings("rawtypes") public String getIdentityId(final String keycloakToken) throws JsonProcessingException, IOException { Jwt<Header, Claims> jwt = getJwt(keycloakToken); return jwt.getBody().getSubject(); }
@SuppressWarnings("rawtypes") public String getSessionState(final String keycloakToken) throws JsonProcessingException, IOException { Jwt<Header, Claims> jwt = getJwt(keycloakToken); return jwt.getBody().get(SESSION_STATE).toString(); }
@SuppressWarnings("rawtypes") private Jwt<Header, Claims> getJwt(final String keycloakToken) { String jwt = keycloakToken.replaceFirst(TOKEN_PREFIX, ""); String tokenWithoutSignature = getJWSWithoutSignature(jwt); return Jwts.parser().parseClaimsJwt(tokenWithoutSignature); }
public static Map<String, Object> getTokenBody(String jwsToken) { String jwtToken = jwsToken.substring(0, jwsToken.lastIndexOf(".") + 1); Jwt<Header, Claims> untrusted = Jwts.parser().parseClaimsJwt(jwtToken); return untrusted.getBody(); }
/** * Extraction was possible with the given result {@code jwt} */ public ExtractionResult(Jwt<?,?> jwt) { this(); this.jwt = jwt; }
public Jwt<?,?> getJwt() { return jwt; }
@Override public Map<String, Object> onClaimsJwt(@SuppressWarnings("rawtypes") Jwt<Header, Claims> jwt) { return config.getRequireSigned() ? super.onClaimsJwt(jwt) : jwt.getBody(); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest) request; final String token = tokenExtractor.getToken(httpRequest); if (shouldSkipAuthentication(httpRequest, token)) { filterChain.doFilter(request, response); return; } final HttpSession session = httpRequest.getSession(); Subject subject = (Subject) session.getAttribute("che_subject"); if (subject == null || !subject.getToken().equals(token)) { Jwt jwtToken = (Jwt) httpRequest.getAttribute("token"); if (jwtToken == null) { throw new ServletException("Cannot detect or instantiate user."); } Claims claims = (Claims) jwtToken.getBody(); try { User user = getOrCreateUser( claims.getSubject(), claims.get("email", String.class), claims.get("preferred_username", String.class)); subject = new AuthorizedSubject( new SubjectImpl(user.getName(), user.getId(), token, false), permissionChecker); session.setAttribute("che_subject", subject); } catch (ServerException | ConflictException e) { throw new ServletException( "Unable to identify user " + claims.getSubject() + " in Che database", e); } } try { EnvironmentContext.getCurrent().setSubject(subject); filterChain.doFilter(addUserInRequest(httpRequest, subject), response); } finally { EnvironmentContext.reset(); } }
/** * Validate the given {@code jwt}. * * @param jwt The JWT to validate * @param request The current http request */ void validate(Jwt jwt, HttpServletRequest request);