Skip to content

Commit

Permalink
updated attributions
Browse files Browse the repository at this point in the history
  • Loading branch information
joshlong committed Jan 20, 2014
1 parent 5d9bb77 commit cc18bcc
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 80 deletions.
86 changes: 45 additions & 41 deletions x-auth-security/src/main/java/example/xauth/TokenUtils.java
@@ -1,49 +1,53 @@
package example.xauth;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.codec.Hex;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
* @author Philip W. Sorst (philip@sorst.net)
* @author Josh Long (josh@joshlong.com)
*/
class TokenUtils {

public static final String MAGIC_KEY = "obfuscate";

public String createToken(UserDetails userDetails) {
long expires = System.currentTimeMillis() + 1000L * 60 * 60;
return userDetails.getUsername() + ":" + expires + ":" + computeSignature(userDetails, expires);
}

public String computeSignature(UserDetails userDetails, long expires) {
StringBuilder signatureBuilder = new StringBuilder();
signatureBuilder.append(userDetails.getUsername()).append(":");
signatureBuilder.append(expires).append(":");
signatureBuilder.append(userDetails.getPassword()).append(":");
signatureBuilder.append(TokenUtils.MAGIC_KEY);

MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No MD5 algorithm available!");
}
return new String(Hex.encode(digest.digest(signatureBuilder.toString().getBytes())));
}

public String getUserNameFromToken(String authToken) {
if (null == authToken) {
return null;
}
String[] parts = authToken.split(":");
return parts[0];
}

public boolean validateToken(String authToken, UserDetails userDetails) {
String[] parts = authToken.split(":");
long expires = Long.parseLong(parts[1]);
String signature = parts[2];
String signatureToMatch = computeSignature(userDetails, expires);
return expires >= System.currentTimeMillis() && signature.equals(signatureToMatch);
}
public static final String MAGIC_KEY = "obfuscate";

public String createToken(UserDetails userDetails) {
long expires = System.currentTimeMillis() + 1000L * 60 * 60;
return userDetails.getUsername() + ":" + expires + ":" + computeSignature(userDetails, expires);
}

public String computeSignature(UserDetails userDetails, long expires) {
StringBuilder signatureBuilder = new StringBuilder();
signatureBuilder.append(userDetails.getUsername()).append(":");
signatureBuilder.append(expires).append(":");
signatureBuilder.append(userDetails.getPassword()).append(":");
signatureBuilder.append(TokenUtils.MAGIC_KEY);

MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No MD5 algorithm available!");
}
return new String(Hex.encode(digest.digest(signatureBuilder.toString().getBytes())));
}

public String getUserNameFromToken(String authToken) {
if (null == authToken) {
return null;
}
String[] parts = authToken.split(":");
return parts[0];
}

public boolean validateToken(String authToken, UserDetails userDetails) {
String[] parts = authToken.split(":");
long expires = Long.parseLong(parts[1]);
String signature = parts[2];
String signatureToMatch = computeSignature(userDetails, expires);
return expires >= System.currentTimeMillis() && signature.equals(signatureToMatch);
}
}
Expand Up @@ -20,6 +20,9 @@
/**
* This controller generates the token that must be present in subsequent REST
* invocations.
*
* @author Philip W. Sorst (philip@sorst.net)
* @author Josh Long (josh@joshlong.com)
*/
@RestController
public class UserXAuthTokenController {
Expand Down
Expand Up @@ -6,6 +6,10 @@
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
* @author Philip W. Sorst (philip@sorst.net)
* @author Josh Long (josh@joshlong.com)
*/
public class XAuthTokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

private UserDetailsService detailsService;
Expand Down
80 changes: 41 additions & 39 deletions x-auth-security/src/main/java/example/xauth/XAuthTokenFilter.java
@@ -1,54 +1,56 @@
package example.xauth;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
* sifts through all incoming requests and installs a Spring Security principal
* if a header corresponding to a valid user is found.
* Sifts through all incoming requests and installs a Spring Security principal
* if a header corresponding to a valid user is found.
*
* @author Philip W. Sorst (philip@sorst.net)
* @author Josh Long (josh@joshlong.com)
*/
public class XAuthTokenFilter extends GenericFilterBean {

private final UserDetailsService detailsService;
private final TokenUtils tokenUtils = new TokenUtils();
private String xAuthTokenHeaderName = "x-auth-token";

public XAuthTokenFilter( UserDetailsService userDetailsService) {
this.detailsService = userDetailsService;
}

@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain filterChain) throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) arg0;
String authToken = httpServletRequest.getHeader(this.xAuthTokenHeaderName);

if (StringUtils.hasText(authToken)) {
String username = this.tokenUtils.getUserNameFromToken(authToken);

UserDetails details = this.detailsService.loadUserByUsername(username);

if (this.tokenUtils.validateToken(authToken, details)) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(details, details.getPassword(), details.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
}
}
filterChain.doFilter(arg0, arg1);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private final UserDetailsService detailsService;
private final TokenUtils tokenUtils = new TokenUtils();
private String xAuthTokenHeaderName = "x-auth-token";

public XAuthTokenFilter(UserDetailsService userDetailsService) {
this.detailsService = userDetailsService;
}

@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain filterChain) throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) arg0;
String authToken = httpServletRequest.getHeader(this.xAuthTokenHeaderName);

if (StringUtils.hasText(authToken)) {
String username = this.tokenUtils.getUserNameFromToken(authToken);

UserDetails details = this.detailsService.loadUserByUsername(username);

if (this.tokenUtils.validateToken(authToken, details)) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(details, details.getPassword(), details.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
}
}
filterChain.doFilter(arg0, arg1);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}

}

0 comments on commit cc18bcc

Please sign in to comment.