Skip to content

Commit

Permalink
implementing token audience feature for #5, tokens requested from mob…
Browse files Browse the repository at this point in the history
…ile devices ignore expiration
  • Loading branch information
daniel-cottone committed Jan 23, 2016
1 parent 8c329a3 commit 062da12
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 15 deletions.
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.mobile</groupId>
<artifactId>spring-mobile-device</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.mobile.device.Device;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
Expand All @@ -25,6 +28,8 @@
@RequestMapping("${cerberus.route.authentication}")
public class AuthenticationController {

private final Logger logger = Logger.getLogger(this.getClass());

@Value("${cerberus.token.header}")
private String tokenHeader;

Expand All @@ -38,7 +43,7 @@ public class AuthenticationController {
private UserDetailsService userDetailsService;

@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> authenticationRequest(@RequestBody AuthenticationRequest authenticationRequest) throws AuthenticationException {
public ResponseEntity<?> authenticationRequest(@RequestBody AuthenticationRequest authenticationRequest, Device device) throws AuthenticationException {

// Perform the authentication
Authentication authentication = this.authenticationManager.authenticate(
Expand All @@ -51,7 +56,7 @@ public ResponseEntity<?> authenticationRequest(@RequestBody AuthenticationReques

// Reload password post-authentication so we can generate token
UserDetails userDetails = this.userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
String token = this.tokenUtils.generateToken(userDetails);
String token = this.tokenUtils.generateToken(userDetails, device);

// Return the token
return ResponseEntity.ok(new AuthenticationResponse(token));
Expand All @@ -60,8 +65,12 @@ public ResponseEntity<?> authenticationRequest(@RequestBody AuthenticationReques
@RequestMapping(value = "${cerberus.route.authentication.refresh}", method = RequestMethod.GET)
public ResponseEntity<?> authenticationRequest(HttpServletRequest request) {
String token = request.getHeader(this.tokenHeader);
String refreshedToken = this.tokenUtils.refreshToken(token);
return ResponseEntity.ok(new AuthenticationResponse(refreshedToken));
if (this.tokenUtils.isTokenExpired(token)) {
return ResponseEntity.badRequest().body("Token Expired");
} else {
String refreshedToken = this.tokenUtils.refreshToken(token);
return ResponseEntity.ok(new AuthenticationResponse(refreshedToken));
}
}

}
63 changes: 52 additions & 11 deletions src/main/java/com/brahalla/Cerberus/security/TokenUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import io.jsonwebtoken.*;

import java.util.HashMap;
import java.util.Map;

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;

Expand All @@ -11,6 +15,11 @@
@Component
public class TokenUtils {

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;

Expand Down Expand Up @@ -39,6 +48,17 @@ public Date getExpirationDateFromToken(String token) {
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 {
Expand All @@ -56,17 +76,38 @@ private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + this.expiration * 1000);
}

public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setExpiration(this.generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, this.secret)
.compact();
public Boolean isTokenExpired(String token) {
final Date expiration = this.getExpirationDateFromToken(token);
return (expiration.before(new Date(System.currentTimeMillis())) && !(this.ignoreTokenExpiration(token)));
}

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));
return this.generateToken(claims);
}

public String generateToken(String subject) {
private String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setSubject(subject)
.setClaims(claims)
.setExpiration(this.generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, this.secret)
.compact();
Expand All @@ -76,17 +117,17 @@ public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = this.getClaimsFromToken(token);
refreshedToken = this.generateToken(claims.getSubject());
refreshedToken = this.generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}

public boolean validateToken(String token, UserDetails userDetails) {
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = this.getUsernameFromToken(token);
final Date expiration = this.getExpirationDateFromToken(token);
return (username.equals(userDetails.getUsername()) && expiration.after(new Date(System.currentTimeMillis())));
return (username.equals(userDetails.getUsername()) && !(this.isTokenExpired(token)));
}

}

0 comments on commit 062da12

Please sign in to comment.