This commit has compile errors. I'm in a hurry to catch a train.

This commit is contained in:
svlada 2016-08-05 16:51:59 +02:00
parent 9cb3386e86
commit f8af4297bc
9 changed files with 130 additions and 54 deletions

View File

@ -1,9 +1,12 @@
package com.svlada.security.auth.jwt;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
@ -17,10 +20,14 @@ import com.svlada.security.auth.JwtAuthenticationToken;
import com.svlada.security.config.JwtSettings;
import com.svlada.security.exceptions.JwtExpiredTokenException;
import com.svlada.security.model.JwtToken;
import com.svlada.security.model.SafeJwtToken;
import com.svlada.security.model.UnsafeJwtToken;
import com.svlada.security.model.UserContext;
import com.svlada.security.service.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
@ -35,36 +42,37 @@ import io.jsonwebtoken.UnsupportedJwtException;
*/
@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
private final JwtSettings jwtSettings;
private final TokenAuthStrategy tokenAuthStrategy;
private final UserService userService;
private final JwtSettings jwtSettings;
@Autowired
public JwtAuthenticationProvider(JwtSettings jwtSettings, TokenAuthStrategy tokenAuthStrategy) {
this.jwtSettings = jwtSettings;
public JwtAuthenticationProvider(TokenAuthStrategy tokenAuthStrategy, UserService userService, JwtSettings jwtSettings) {
this.tokenAuthStrategy = tokenAuthStrategy;
this.userService = userService;
this.jwtSettings = jwtSettings;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UnsafeJwtToken token = ((JwtAuthenticationToken) authentication).getUnsafeToken();
SafeToken safeToken = token.authenticate(tokenAuthStrategy);
UnsafeJwtToken unsafeToken = ((JwtAuthenticationToken) authentication).getUnsafeToken();
try {
token.validateToken(jwtSettings.getTokenSigningKey());
Jws<Claims> jwsClaims = unsafeToken.parse(jwtSettings.getTokenSigningKey());
} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException | SignatureException ex) {
throw new BadCredentialsException("Invalid JWT token: ", ex);
} catch (ExpiredJwtException expiredEx) {
throw new JwtExpiredTokenException(token, "Token expired.", expiredEx);
Date expDateTime = expiredEx.getClaims().getExpiration();
if (expDate != null && tokenAuthStrategy.isExpired(expDate)) {
}
}
Claims claims = token.claims(jwtSettings.getTokenSigningKey());
ArrayList<String> rawAuthorities = claims.get("roles", ArrayList.class);
SafeJwtToken safeToken = ;
Claims claims = safeToken.getClaims();
List<GrantedAuthority> authorities = rawAuthorities.stream()
.map(authority -> new SimpleGrantedAuthority(authority)).collect(Collectors.toList());
JwtAuthenticationToken authToken = new JwtAuthenticationToken(token, authorities, claims.getSubject());
JwtAuthenticationToken authToken = new JwtAuthenticationToken(userContext, safeToken, userContext.getAuthorities());
return authToken;
}

View File

@ -0,0 +1,69 @@
package com.svlada.security.auth.jwt;
import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Component;
import com.svlada.security.config.JwtSettings;
import com.svlada.security.exceptions.JwtExpiredTokenException;
import com.svlada.security.model.JwtTokenFactory;
import com.svlada.security.model.SafeJwtToken;
import com.svlada.security.model.UnsafeJwtToken;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
/**
*
* @author vladimir.stankovic
*
* Aug 5, 2016
*/
@Component
public class RefreshTokenAuthStrategy implements TokenAuthStrategy {
private final JwtSettings jwtSettings;
private final JwtTokenFactory tokenFactory;
@Autowired
public RefreshTokenAuthStrategy(JwtSettings jwtSettings, JwtTokenFactory tokenFactory) {
this.jwtSettings = jwtSettings;
this.tokenFactory = tokenFactory;
}
@Override
public SafeJwtToken authenticate(UnsafeJwtToken token) {
try {
Jws<Claims> jwsClaims = token.parse(jwtSettings.getTokenSigningKey());
return tokenFactory.createSafeToken(token.getToken(), jwsClaims.getBody());
} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException | SignatureException ex) {
throw new BadCredentialsException("Invalid JWT token: ", ex);
} catch (ExpiredJwtException expiredEx) {
Date expDateTime = expiredEx.getClaims().getExpiration();
if (expDateTime == null) {
throw new BadCredentialsException("Expiry time is not set");
}
DateTime expirationTime = new DateTime(expiredEx.getClaims().getExpiration());
DateTime currentTime = DateTime.now();
if (Minutes.minutesBetween(currentTime, expirationTime).isGreaterThan(Minutes.minutes(jwtSettings.getTokenValidationTimeframe()))) {
throw new JwtExpiredTokenException(token, "JWT token has expired", expiredEx);
}
return refreshToken();
}
}
public SafeJwtToken refreshToken() {
return null;
}
}

View File

@ -1,6 +1,7 @@
package com.svlada.security.auth.jwt;
import com.svlada.security.model.SafeJwtToken;
import com.svlada.security.model.UnsafeJwtToken;
/**
*
@ -9,5 +10,5 @@ import com.svlada.security.model.SafeJwtToken;
* Aug 5, 2016
*/
public interface TokenAuthStrategy {
public SafeJwtToken authenticate(String token);
public SafeJwtToken authenticate(UnsafeJwtToken token);
}

View File

@ -21,6 +21,19 @@ public class JwtSettings {
*/
private String tokenSigningKey;
/**
* {@link JwtToken} can be refreshed during this timeframe.
*/
private Integer tokenValidationTimeframe;
public Integer getTokenValidationTimeframe() {
return tokenValidationTimeframe;
}
public void setTokenValidationTimeframe(Integer tokenValidationTimeframe) {
this.tokenValidationTimeframe = tokenValidationTimeframe;
}
public Integer getTokenExpirationTime() {
return tokenExpirationTime;
}

View File

@ -14,6 +14,7 @@ import com.svlada.security.config.JwtSettings;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.lang.Collections;
/**
@ -39,24 +40,18 @@ public class JwtTokenFactory {
* @param roles
* @return
*/
public SafeJwtToken createSafeToken(UserContext userContext, final Collection<GrantedAuthority> roles) {
public SafeJwtToken createSafeToken(UserContext userContext) {
if (StringUtils.isBlank(userContext.getUsername())) {
throw new IllegalArgumentException("Cannot create JWT Token without username");
}
if (Collections.isEmpty(roles)) {
throw new IllegalArgumentException("Cannot create JWT Token without roles");
}
DateTime currentTime = new DateTime();
Claims claims = Jwts.claims();
claims.put("roles", AuthorityUtils.authorityListToSet(roles));
Claims claims = Jwts.claims().setSubject(userContext.getUsername());
String token = Jwts.builder()
.setClaims(claims)
.setIssuer(settings.getTokenIssuer())
.setSubject(userContext.getUsername())
.setIssuedAt(currentTime.toDate())
.setExpiration(currentTime.plusMinutes(settings.getTokenExpirationTime()).toDate())
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey())
@ -65,6 +60,11 @@ public class JwtTokenFactory {
return new SafeJwtToken(token, claims);
}
public SafeJwtToken createSafeToken(String token, Claims claims) {
return new SafeJwtToken(token, claims);
}
/**
* Unsafe version of JWT token is created.
*

View File

@ -1,8 +1,7 @@
package com.svlada.security.model;
import com.svlada.security.auth.jwt.TokenAuthStrategy;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
public class UnsafeJwtToken implements JwtToken {
@ -16,22 +15,8 @@ public class UnsafeJwtToken implements JwtToken {
* Validates JWT Token signature.
*
*/
public void validateToken(String signingKey) {
Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token);
}
/**
* Extract Claims object from the rawToken.
*
* @param signingKey
* @return
*/
public Claims parseClaims(String signingKey) {
return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token).getBody();
}
public SafeJwtToken authenticate(TokenAuthStrategy strategy) {
return strategy.authenticate(this.token);
public Jws<Claims> parse(String signingKey) {
return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token);
}
@Override

View File

@ -12,12 +12,10 @@ import org.springframework.security.core.GrantedAuthority;
*/
public class UserContext {
private final String username;
private final String email;
private final List<GrantedAuthority> authorities;
public UserContext(String username, String email, List<GrantedAuthority> authorities) {
public UserContext(String username, List<GrantedAuthority> authorities) {
this.username = username;
this.email = email;
this.authorities = authorities;
}
@ -25,10 +23,6 @@ public class UserContext {
return username;
}
public String getEmail() {
return email;
}
public List<GrantedAuthority> getAuthorities() {
return authorities;
}

View File

@ -22,6 +22,12 @@ public class UserService {
public UserContext loadUser(String username, String password) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(UserRole.ADMIN.authority()));
return new UserContext(username, "svlada@gmail.com", authorities);
return new UserContext(username, authorities);
}
public UserContext loadUser(String username) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(UserRole.ADMIN.authority()));
return new UserContext(username, authorities);
}
}