I have about Spring Security from various resources and I know how filters and authentication managers work separately but I am not sure of the exact sequence in which a request works with them. If I am not wrong, in short the request first goes through the filters and the filters call their respective authentication managers.
I want to allow two kinds of authentication - one with JWT tokens and another with username and password. Below is the extract from security.xml
Security.xml
<http pattern="/api/**" create-session="stateless" realm="protected-apis" authentication-manager-ref="myAuthenticationManager" >
<csrf disabled="true"/>
<http-basic entry-point-ref="apiEntryPoint" />
<intercept-url pattern="/api/my_api/**" requires-channel="any" access="isAuthenticated()" /> <!-- make https only. -->
<custom-filter ref="authenticationTokenProcessingFilter" position = "FORM_LOGIN_FILTER"/>
</http>
<beans:bean id="authenticationTokenProcessingFilter"
class="security.authentication.TokenAuthenticationFilter">
<beans:constructor-arg value="/api/my_api/**" type="java.lang.String"/>
</beans:bean>
<authentication-manager id="myAuthenticationManager">
<authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>
<beans:bean id="myAuthenticationProvider"
class="security.authentication.myAuthenticationProvider" />
MyAuthenticationProvider.java
public class MyAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Code
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
TokenAuthenticationFilter.java
public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
protected TokenAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl); //defaultFilterProcessesUrl - specified in applicationContext.xml.
super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(defaultFilterProcessesUrl)); //Authentication will only be initiated for the request url matching this pattern
setAuthenticationManager(new NoOpAuthenticationManager());
setAuthenticationSuccessHandler(new TokenSimpleUrlAuthenticationSuccessHandler());
setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
}
/**
* Attempt to authenticate request
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException,
IOException,
ServletException {
String tid = request.getHeader("authorization");
logger.info("token found:"+tid);
AbstractAuthenticationToken userAuthenticationToken = authUserByToken(tid,request);
if(userAuthenticationToken == null) throw new AuthenticationServiceException("Invalid Token");
return userAuthenticationToken;
}
/**
* authenticate the user based on token
* @return
*/
private AbstractAuthenticationToken authUserByToken(String token,HttpServletRequest request) throws
JsonProcessingException {
if(token==null) return null;
AbstractAuthenticationToken authToken =null;
boolean isValidToken = validate(token);
if(isValidToken){
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
authToken = new UsernamePasswordAuthenticationToken("", token, authorities);
}
else{
BaseError error = new BaseError(401, "UNAUNTHORIZED");
throw new AuthenticationServiceException(error.getStatusMessage());
}
return authToken;
}
private boolean validate(String token) {
if(token.startsWith("TOKEN ")) return true;
return false;
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
super.doFilter(req, res, chain);
}
}
Through myAuthenticationProvider
I want username-password based authentication & through the custom filter I want to check for JWT tokens. Can someone let me know if I am going in the right direction?