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

@ -413,7 +413,7 @@ public class AjaxAwareAuthenticationFailureHandler implements AuthenticationFail
#### WebSecurityConfig - Initial version to support AJAX based login
This is first version of WebSecurityConfig. We will add more configuration to it once we start with showcase of JWT Authentication flow.
This is first version of WebSecurityConfig. We will add more configuration to it once we start with showcase of JWT Authentication flow.
```
@Configuration

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 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);
List<GrantedAuthority> authorities = rawAuthorities.stream()
.map(authority -> new SimpleGrantedAuthority(authority)).collect(Collectors.toList());
JwtAuthenticationToken authToken = new JwtAuthenticationToken(token, authorities, claims.getSubject());
SafeJwtToken safeToken = ;
Claims claims = safeToken.getClaims();
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())
@ -64,6 +59,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,24 +15,10 @@ public class UnsafeJwtToken implements JwtToken {
* Validates JWT Token signature.
*
*/
public void validateToken(String signingKey) {
Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token);
public Jws<Claims> parse(String signingKey) {
return 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);
}
@Override
public String getToken() {
return token;

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);
}
}