forked from joshlong-attic/boot-examples
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
93 additions
and
80 deletions.
There are no files selected for viewing
86 changes: 45 additions & 41 deletions
86
x-auth-security/src/main/java/example/xauth/TokenUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 41 additions & 39 deletions
80
x-auth-security/src/main/java/example/xauth/XAuthTokenFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} | ||
|
||
} |