Skip to content

Instantly share code, notes, and snippets.

@asoftwareguy
Created July 5, 2011 13:32
Show Gist options
  • Save asoftwareguy/1064840 to your computer and use it in GitHub Desktop.
Save asoftwareguy/1064840 to your computer and use it in GitHub Desktop.
Blog - Spring Security 2.x with multiple credentials
package example.multicred;
import java.util.Set;
import org.springframework.security.GrantedAuthority;
/**
* Handler interface for granting authorities.
*
*/
public interface AuthorityGranter {
/**
* Grant authorities based on the given
* {@link MultipleCredentialAuthenticationToken}.
*
* @param _multipleCredentialAuthenticationToken
* the {@link MultipleCredentialAuthenticationToken} based on which
* to grant authorities.
* @return a set of {@link GrantedAuthority} items
*/
public Set grantAuthorities(MultipleCredentialAuthenticationToken _multipleCredentialAuthenticationToken);
}
package example.multicred;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
/**
* Exception thrown when no authorities have been granted for a given
* {@link Authentication}.
*
*
*/
public class AuthorityGranterUndefinedException extends AuthenticationException {
public AuthorityGranterUndefinedException() {
super("No authoritiy granter is defined!");
}
public AuthorityGranterUndefinedException(String msg, Object extraInformation) {
super(msg, extraInformation);
}
public AuthorityGranterUndefinedException(String msg, Throwable t) {
super(msg, t);
}
public AuthorityGranterUndefinedException(String msg) {
super(msg);
}
}
package example.multicred;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.ui.FilterChainOrder;
import org.springframework.util.Assert;
public class MultipleCredentialAuthenticationFilter extends AbstractProcessingFilter {
private String principalParameter;
private List credentialParameters;
@Override
public Authentication attemptAuthentication(HttpServletRequest _request) throws AuthenticationException {
String principal = obtainPrincipal(_request);
MultipleCredentials credentials = obtainCredentials(_request);
if (principal == null) {
principal = "";
}
principal = principal.trim();
if (principal.isEmpty()) {
throw new BadCredentialsException("Invalid Credentials");
}
MultipleCredentialAuthenticationToken authRequest = new MultipleCredentialAuthenticationToken(principal, credentials);
// Allow subclasses to set the "details" property
setDetails(_request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private String obtainPrincipal(HttpServletRequest request) {
Assert.notNull(principalParameter, "principalParameter must be defined!");
return request.getParameter(principalParameter);
}
private MultipleCredentials obtainCredentials(HttpServletRequest request) {
Assert.notNull(credentialParameters, "credentialParameters must be defined!");
MultipleCredentials multipleCredentials = new MultipleCredentials();
for (String credentialParameter : credentialParameters) {
multipleCredentials.add(credentialParameter, request.getParameter(credentialParameter));
}
return multipleCredentials;
}
protected void setDetails(HttpServletRequest request, MultipleCredentialAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public int getOrder() {
return FilterChainOrder.AUTHENTICATION_PROCESSING_FILTER;
}
@Override
public String getDefaultFilterProcessesUrl() {
return "/multi_security_check";
}
public void setPrincipalParameter(String principalParameter) {
this.principalParameter = principalParameter;
}
public void setCredentialParameters(List credentialParameters) {
this.credentialParameters = credentialParameters;
}
}
package example.multicred;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.providers.AuthenticationProvider;
/**
* This is an {@link AuthenticationProvider} that uses multiple credentials to
* authenticate the user. Authorities can be granted by supplying a
* {@link AuthorityGranter} function.
*
*
*/
public class MultipleCredentialAuthenticationProvider implements AuthenticationProvider {
private MultipleCredentialAuthenticationService multipleCredentialAuthenticationService;
private List<AuthorityGranter> authorityGranters;
public Authentication authenticate(Authentication _authentication) throws AuthenticationException {
MultipleCredentialAuthenticationToken attemptAuthenticationToken = (MultipleCredentialAuthenticationToken) _authentication;
MultipleCredentialAuthenticationToken resultAuthenticationToken = null;
boolean authenticated = multipleCredentialAuthenticationService.authenticate((String) attemptAuthenticationToken.getPrincipal(), (MultipleCredentials) attemptAuthenticationToken.getCredentials());
if (authenticated) {
GrantedAuthority[] grantedAuthorities = createGrantedAuthorityArray(attemptAuthenticationToken);
resultAuthenticationToken = new MultipleCredentialAuthenticationToken((String) attemptAuthenticationToken.getPrincipal(), (MultipleCredentials) attemptAuthenticationToken.getCredentials(), grantedAuthorities);
} else {
throw new BadCredentialsException("Bad Credentials");
}
return resultAuthenticationToken;
}
/**
* Create the {@link GrantedAuthority} array, using any registered
* {@link AuthorityGranter}.
*
* @return a {@link GrantedAuthority} array; will be empty if no authorities
* have been granted
*/
private GrantedAuthority[] createGrantedAuthorityArray(MultipleCredentialAuthenticationToken _multipleCredentialAuthenticationToken) throws AuthorityGranterUndefinedException {
GrantedAuthority[] grantedAuthorityArray = null;
Set grantedAuthoritySet = new HashSet();
if (authorityGranters != null) {
for (AuthorityGranter authorityGranter : authorityGranters) {
grantedAuthoritySet.addAll(authorityGranter.grantAuthorities(_multipleCredentialAuthenticationToken));
}
} else {
throw new AuthorityGranterUndefinedException();
}
if (!grantedAuthoritySet.isEmpty()) {
grantedAuthorityArray = grantedAuthoritySet.toArray(new GrantedAuthority[grantedAuthoritySet.size()]);
}
return grantedAuthorityArray;
}
public boolean supports(Class _clazz) {
return MultipleCredentialAuthenticationToken.class.isAssignableFrom(_clazz);
}
public void setMultipleCredentialAuthenticationService(MultipleCredentialAuthenticationService multipleCredentialAuthenticationService) {
this.multipleCredentialAuthenticationService = multipleCredentialAuthenticationService;
}
public void setAuthorityGranters(List authorityGranters) {
this.authorityGranters = authorityGranters;
}
}
package example.multicred;
/**
* Multiple credential authentication service interface.
*
*/
public interface MultipleCredentialAuthenticationService {
/**
* Authenticate using the provided principal and credentials.
*
* @param _principal
* the principal to use to authenticate
* @param _credentials
* the credentials to use to authenticate
* @return <code>true</code> iff authentication is successful,
* <code>false</code> otherwise
*/
public boolean authenticate(String _principal, MultipleCredentials _credentials);
}
package example.multicred.impl;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.xml.rpc.ServiceException;
import example.multicred.MultipleCredentialAuthenticationService;
import example.multicred.MultipleCredentials;
public class MultipleCredentialAuthenticationServiceImpl implements MultipleCredentialAuthenticationService {
public boolean authenticate(String _principal, MultipleCredentials _credentials) {
String prin1 = _principal;
String cred1 = _credentials.getCredential("j_cred1");
String cred2 = _credentials.getCredential("j_cred2");
String cred3 = _credentials.getCredential("j_cred3");
// do something to authenticate
// ...
return authenticated;
}
}
package example.multicred;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.providers.AbstractAuthenticationToken;
public class MultipleCredentialAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 1L;
private String principal;
private MultipleCredentials credentials;
/**
* This constructor can be safely used by any code that wishes to create a
* <code>MultipleCredentialAuthenticationToken</code>, as the
* {@link #isAuthenticated()} will return <code>false</code>.
*
*/
public MultipleCredentialAuthenticationToken(String _principal, MultipleCredentials _credentials) {
super(null);
this.principal = _principal;
this.credentials = _credentials;
setAuthenticated(false);
}
/**
* This constructor should only be used by <code>AuthenticationManager</code>
* or <code>AuthenticationProvider</code> implementations that are satisfied
* with producing a trusted (ie {@link #isAuthenticated()} = <code>true</code>
* ) authentication token.
*
*/
public MultipleCredentialAuthenticationToken(String _principal, MultipleCredentials _credentials, GrantedAuthority[] _authorities) {
super(_authorities);
this.principal = _principal;
this.credentials = _credentials;
super.setAuthenticated(true); // must use super, as we override
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean _isAuthenticated) throws IllegalArgumentException {
if (_isAuthenticated) {
throw new IllegalArgumentException("Cannot set this token to trusted - use constructor containing GrantedAuthority[]s instead");
}
super.setAuthenticated(false);
}
}
package example.multicred;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Model object for storing multiple credentials.
*
*/
public class MultipleCredentials {
private Map<String, String> credentials = new HashMap<String, String>();
public void add(String _credentialName, String _credentialValue) {
if (_credentialName != null && !_credentialName.isEmpty() && _credentialValue != null && !_credentialValue.isEmpty()) {
credentials.put(_credentialName, _credentialValue);
}
}
public String getCredential(String _credentialName) {
String returnValue = null;
if (_credentialName != null && !_credentialName.isEmpty()) {
returnValue = credentials.get(_credentialName);
}
return returnValue;
}
public Map getCredentials() {
return Collections.unmodifiableMap(credentials);
}
}
package example.multicred.impl;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import example.multicred.AuthorityGranter;
import example.multicred.MultipleCredentialAuthenticationToken;
/**
* AuthorityGranter example implementation. Grants ROLE_USER without regard.
*
*
*/
public class RoleUserAuthorityGranterImpl implements AuthorityGranter {
@Override
public Set<GrantedAuthority> grantAuthorities(MultipleCredentialAuthenticationToken _multipleCredentialAuthenticationToken) {
// grant ROLE_USER
Set grantedAuthorities = new HashSet();
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
return grantedAuthorities;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
<security:http auto-config="false" access-denied-page="/login.htm?msg=access_denied"
entry-point-ref="authenticationEntryPoint"
session-fixation-protection="newSession">
<security:intercept-url pattern="/login.htm"
filters="none" />
<security:intercept-url pattern="/**.htm"
access="ROLE_USER" />
<security:logout logout-url="/logout"
logout-success-url="/login.htm?msg=logout_success"
invalidate-session="true" />
</security:http>
<security:authentication-manager alias="authenticationManager" />
<bean id="multipleCredentialAuthenticationFilter"
class="example.multicred.MultipleCredentialAuthenticationFilter">
<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
<property name="authenticationManager" ref="authenticationManager" />
<property name="defaultTargetUrl" value="/home.htm" />
<property name="authenticationFailureUrl" value="/login.htm?msg=auth_failure" />
<property name="filterProcessesUrl" value="/multi_security_check" />
<property name="alwaysUseDefaultTargetUrl" value="true" />
<property name="principalParameter" value="j_prin" />
<property name="credentialParameters">
<util:list>
<value>j_cred1</value>
<value>j_cred2</value>
<value>j_cred3</value>
</util:list>
</property>
</bean>
<bean id="authenticationEntryPoint"
class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.htm" />
<property name="forceHttps" value="false" />
</bean>
<bean id="multipleCredentialAuthenticationProvider"
class="example.multicred.MultipleCredentialAuthenticationProvider">
<security:custom-authentication-provider />
<property name="multipleCredentialAuthenticationService" ref="multipleCredentialAuthenticationService" />
<property name="authorityGranters">
<util:list>
<ref bean="roleUserAuthorityGranter" />
</util:list>
</property>
</bean>
<bean id="multipleCredentialAuthenticationService"
class="example.multicred.impl.MultipleCredentialAuthenticationServiceImpl" />
<bean id="roleUserAuthorityGranter" class="example.multicred.impl.RoleUserAuthorityGranterImpl" />
</beans>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment