This commit has compile errors. I'm in a hurry to catch a train.
This commit is contained in:
parent
9cb3386e86
commit
f8af4297bc
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user