package com.brahalla.Cerberus.security;
import com.brahalla.Cerberus.model.security.CerberusUser;
import io.jsonwebtoken.*;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mobile.device.Device;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
@Component
public class TokenUtils {
private final Logger logger = Logger.getLogger(this.getClass());
private final String AUDIENCE_UNKNOWN = "unknown";
private final String AUDIENCE_WEB = "web";
private final String AUDIENCE_MOBILE = "mobile";
private final String AUDIENCE_TABLET = "tablet";
@Value("${cerberus.token.secret}")
private String secret;
@Value("${cerberus.token.expiration}")
private Long expiration;
public String getUsernameFromToken(String token) {
String username;
try {
final Claims claims = this.getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
public Date getCreatedDateFromToken(String token) {
Date created;
try {
final Claims claims = this.getClaimsFromToken(token);
created = new Date((Long) claims.get("created"));
} catch (Exception e) {
created = null;
}
return created;
}
public Date getExpirationDateFromToken(String token) {
Date expiration;
try {
final Claims claims = this.getClaimsFromToken(token);
expiration = claims.getExpiration();
} catch (Exception e) {
expiration = null;
}
return expiration;
}
public String getAudienceFromToken(String token) {
String audience;
try {
final Claims claims = this.getClaimsFromToken(token);
audience = (String) claims.get("audience");
} catch (Exception e) {
audience = null;
}
return audience;
}
private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(this.secret.getBytes("UTF-8"))
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
private Date generateCurrentDate() {
return new Date(System.currentTimeMillis());
}
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + this.expiration * 1000);
}
private Boolean isTokenExpired(String token) {
final Date expiration = this.getExpirationDateFromToken(token);
return expiration.before(this.generateCurrentDate());
}
private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
private String generateAudience(Device device) {
String audience = this.AUDIENCE_UNKNOWN;
if (device.isNormal()) {
audience = this.AUDIENCE_WEB;
} else if (device.isTablet()) {
audience = AUDIENCE_TABLET;
} else if (device.isMobile()) {
audience = AUDIENCE_MOBILE;
}
return audience;
}
private Boolean ignoreTokenExpiration(String token) {
String audience = this.getAudienceFromToken(token);
return (this.AUDIENCE_TABLET.equals(audience) || this.AUDIENCE_MOBILE.equals(audience));
}
public String generateToken(UserDetails userDetails, Device device) {
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("sub", userDetails.getUsername());
claims.put("audience", this.generateAudience(device));
claims.put("created", this.generateCurrentDate());
return this.generateToken(claims);
}
private String generateToken(Map<String, Object> claims) {
try {
return Jwts.builder()
.setClaims(claims)
.setExpiration(this.generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, this.secret.getBytes("UTF-8"))
.compact();
} catch (UnsupportedEncodingException ex) {
//didn't want to have this method throw the exception, would rather log it and sign the token like it was before
logger.warn(ex.getMessage());
return Jwts.builder()
.setClaims(claims)
.setExpiration(this.generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, this.secret)
.compact();
}
}
public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
final Date created = this.getCreatedDateFromToken(token);
return (!(this.isCreatedBeforeLastPasswordReset(created, lastPasswordReset)) && (!(this.isTokenExpired(token)) || this.ignoreTokenExpiration(token)));
}
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = this.getClaimsFromToken(token);
claims.put("created", this.generateCurrentDate());
refreshedToken = this.generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
public Boolean validateToken(String token, UserDetails userDetails) {
CerberusUser user = (CerberusUser) userDetails;
final String username = this.getUsernameFromToken(token);
final Date created = this.getCreatedDateFromToken(token);
final Date expiration = this.getExpirationDateFromToken(token);
return (username.equals(user.getUsername()) && !(this.isTokenExpired(token)) && !(this.isCreatedBeforeLastPasswordReset(created, user.getLastPasswordReset())));
}
}