Best way to handle multiply roles in spring security [duplicate] - spring

This question already has answers here:
AuthenticationSuccessHandler in Spring Security
(2 answers)
Closed 3 years ago.
I'm building a web application as a pet project using spring modules and hibernate.
I want to redirect users with different authorities to different pages.
So far I have my WebSecurityConfigurerAdapter:
#EnableWebSecurity
public class ConfigSecurity extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncod encodde = new PasswordEncod();
auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncod());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/curator").authenticated();
http.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll().and().csrf().disable();
}
}
and custom UserDetails service :
public class MyUserDetailsService implements UserDetailsService {
UserDao dao = new UserDaoImpl();
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
System.out.println(s);
User user = dao.getByUsername(s);
System.out.println(user.toString());
return
new org.springframework.security.core.userdetails
.User(
user.getUsername(),
user.getPassword(),
buildUserAuthority(user));
}
private List<GrantedAuthority> buildUserAuthority(User user) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (UserRole userRole : user.getUserRoles()) {
setAuths.add(new SimpleGrantedAuthority(userRole.toString()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
}
I want to make a login page that will redirect the customer to the default user or admin page depending on his authorities but I don't understand which would be the best practice to do so. I've thought about making a controller that will do the job but I think that there is a better solution. Am I doing ok, maybe you could suggest me some improvements or the ways to do it?

For redirection follow this - spring security redirect based on role. But for your situation once you have configured :
antMatchers("/curator").authenticated()
...
antMatchers("/some-action-**").access("hasAuthority('ADMIN')")
Simply use Spring Security Tags to hide the links. Say for example, use security tag to hide links for normal users where some admin role is required. If above is configured properly, normal users will get access denied even if they try to access the secured URL. Let Spring-Security do the hard (security) work for you. For the full blown example you can refer this, this and finally this.

Related

Change URL of application according to logged in user in Spring boot

I have been working a spring boot project for a while now. I am accessing my app's login with local url like localhost:8080/XYZapp/login then after a successful login my url changes to localhost:8080/XYZapp/authenticated (which is my dashboard).
All this working fine but now I want my URL to change dynamically acc. to logged in user like localhost:8080/XYZapp/abcCompany/authenticated. This abcCompany should change every time according to loggedin user.
I have googled it on some references and on SO but could not found much luck.
There are a couple of things that you will need to do.
The first has already been mentioned in the comments, which is to use an AuthenticationSuccessHandler:
#Component
public TenantAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) {
if (authentication.getPrincipal() instanceof MyUser) {
MyUser user = (MyUser) authentication.getPrincipal();
String uri = "/XYZapp/" + user.getTenantName() + "/authenticated";
AuthenticationSuccessHandler handler =
new SimpleUrlAuthenticationSuccessHandler(uri);
handler.onAuthenticationSuccess(handler);
}
// throw exception
}
}
Which you can then wire in your DSL:
#Autowire
AuthenticationSuccessHandler tenantAuthenticationSuccessHandler;
// ...
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(this.tenantAuthenticationSuccessHandler);
Of course, you might consider caching the SimpleUrlAuthenticationSuccessHandler instances so you aren't creating one for every single login.
Second, you'll likely need to be able to know the name of the tenant (e.g. abcCompany) based on the user that gets looked up.
So, you'll likely need a custom UserDetailsService so that you can retrieve that extra information from your datastore:
public class MyUser {
String tenantName;
// ...
}
// ...
#Component
public class MyUserUserDetailsService implements UserDetailsService {
public UserDetails findUserByUsername(String username) {
// query some backing store, Spring Data repository, etc.
return myUser;
}
private static class MyUserUserDetails extends MyUser implements UserDetails {
// ...
}
}

disable spring formlogin and basic auth

I have the following spring boot 2.0 config but I am still getting the basic auth login screen. I DO NOT want to disable all spring security like almost every post on the internet suggests. I only want to stop the form login page and basic auth so I can use my own.
I have seen all the suggestions with permitAll and exclude = {SecurityAutoConfiguration.class} and a few others that I can't remember anymore. Those are not what I want. I want to use spring security but I wan my config not Spring Boots. Yes I know many people are going to say this is a duplicate but I disagree because all the other answers are to disable spring security completely and not just stop the stupid login page.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class CustomSecurity extends WebSecurityConfigurerAdapter {
private final RememberMeServices rememberMeService;
private final AuthenticationProvider customAuthProvider;
#Value("${server.session.cookie.secure:true}")
private boolean useSecureCookie;
#Inject
public CustomSecurity(RememberMeServices rememberMeService, AuthenticationProvider customAuthProvider) {
super(true);
this.rememberMeService = rememberMeService;
this.bouncerAuthProvider = bouncerAuthProvider;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/**").antMatchers("/webjars/**").antMatchers("/swagger-resources/**")
.antMatchers("/swagger-ui.html");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().formLogin().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).headers().frameOptions().disable();
http.authenticationProvider(customAuthProvider).authorizeRequests().antMatchers("/health").permitAll()
.anyRequest().authenticated();
http.rememberMe().rememberMeServices(rememberMeService).useSecureCookie(useSecureCookie);
http.exceptionHandling().authenticationEntryPoint(new ForbiddenEntryPoint());
}
}
If you want to redirect to your own login page, i can show your sample code and configuration
remove the http.httpBasic().disable().formLogin().disable();, you should set your own login page to redirect instead of disable form login
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/my_login").permitAll().and().authorizeRequests().anyRequest().authenticated();
http.formLogin().loginPage("/my_login");
}
then create your own LoginController
#Controller
public class LoginController {
#RequestMapping("/my_login")
public ModelAndView myLogin() {
return new ModelAndView("login");
}
}
you can specified the login with thymeleaf view resolver

Add custom UserDetailsService to Spring Security OAuth2 app

How do I add the custom UserDetailsService below to this Spring OAuth2 sample?
The default user with default password is defined in the application.properties file of the authserver app.
However, I would like to add the following custom UserDetailsService to the demo package of the authserver app for testing purposes:
package demo;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Service;
#Service
class Users implements UserDetailsManager {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String password;
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
if (username.equals("Samwise")) {
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT");
password = "TheShire";
}
else if (username.equals("Frodo")){
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT");
password = "MyRing";
}
else{throw new UsernameNotFoundException("Username was not found. ");}
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
#Override
public void createUser(UserDetails user) {// TODO Auto-generated method stub
}
#Override
public void updateUser(UserDetails user) {// TODO Auto-generated method stub
}
#Override
public void deleteUser(String username) {// TODO Auto-generated method stub
}
#Override
public void changePassword(String oldPassword, String newPassword) {
// TODO Auto-generated method stub
}
#Override
public boolean userExists(String username) {
// TODO Auto-generated method stub
return false;
}
}
As you can see, this UserDetailsService is not autowired yet, and it purposely uses insecure passwords because it is only designed for testing purposes.
What specific changes need to be made to the GitHub sample app so that a user can login as username=Samwise with password=TheShire, or as username=Frodo with password=MyRing? Do changes need to be made to AuthserverApplication.java or elsewhere?
SUGGESTIONS:
The Spring OAuth2 Developer Guide says to use a GlobalAuthenticationManagerConfigurer to configure a UserDetailsService globally. However, googling those names produces less than helpful results.
Also, a different app that uses internal spring security INSTEAD OF OAuth uses the following syntax to hook up the UserDetailsService, but I am not sure how to adjust its syntax to the current OP:
#Order(Ordered.HIGHEST_PRECEDENCE)
#Configuration
protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
#Autowired
private Users users;
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(users);
}
}
I tried using #Autowire inside the OAuth2AuthorizationConfig to connect Users to the AuthorizationServerEndpointsConfigurer as follows:
#Autowired//THIS IS A TEST
private Users users;//THIS IS A TEST
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter())
.userDetailsService(users)//DetailsService)//THIS LINE IS A TEST
;
}
But the Spring Boot logs indicate that the user Samwise was not found, which means that the UserDetailsService was not successfully hooked up. Here is the relevant excerpt from the Spring Boot logs:
2016-04-20 15:34:39.998 DEBUG 5535 --- [nio-9999-exec-9] o.s.s.a.dao.DaoAuthenticationProvider :
User 'Samwise' not found
2016-04-20 15:34:39.998 DEBUG 5535 --- [nio-9999-exec-9]
w.a.UsernamePasswordAuthenticationFilter :
Authentication request failed:
org.springframework.security.authentication.BadCredentialsException:
Bad credentials
What else can I try?
I ran into a similar issue when developing my oauth server with Spring Security. My situation was slightly different, as I wanted to add a UserDetailsService to authenticate refresh tokens, but I think my solution will help you as well.
Like you, I first tried specifying the UserDetailsService using the AuthorizationServerEndpointsConfigurer, but this does not work. I'm not sure if this is a bug or by design, but the UserDetailsService needs to be set in the AuthenticationManager in order for the various oauth2 classes to find it. This worked for me:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
Users userDetailsService;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// other stuff to configure your security
}
}
I think if you changed the following starting at line 73, it may work for you:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
You would also of course need to add #Autowired Users userDetailsService; somewhere in WebSecurityConfigurerAdapter
Other things I wanted to mention:
This may be version specific, I'm on spring-security-oauth2 2.0.12
I can't cite any sources for why this is the way it is, I'm not even sure if my solution is a real solution or a hack.
The GlobalAuthenticationManagerConfigurer referred to in the guide is almost certainly a typo, I can't find that string anywhere in the source code for anything in Spring.
My requirement was to get a database object off the back of the oauth2 email attribute. I found this question as I assumed that I need to create a custom user details service. Actually I need to implment the OidcUser interface and hook into that process.
Initially I thought it was the OAuth2UserService, but I've set up my AWS Cognito authentication provider so that it's open id connect..
//inside WebSecurityConfigurerAdapter
http
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(new CustomOidcUserServiceImpl());
...
public class CustomOidcUserServiceImpl implements OAuth2UserService<OidcUserRequest, OidcUser> {
private OidcUserService oidcUserService = new OidcUserService();
#Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
OidcUser oidcUser = oidcUserService.loadUser(userRequest);
return new CustomUserPrincipal(oidcUser);
}
}
...
public class CustomUserPrincipal implements OidcUser {
private OidcUser oidcUser;
//forward all calls onto the included oidcUser
}
The custom service is where any bespoke logic can go.
I plan on implementing UserDetails interface on my CustomUserPrincipal so that I can have different authentication mechanisms for live and test to facilitate automated ui testing.
I ran into the same issue and originally had the same solution as Manan Mehta posted. Just recently, some version combination of spring security and spring oauth2 resulted in any attempt to refresh tokens resulting in an HTTP 500 error stating that UserDetailsService is required in my logs.
The relevant stack trace looks like:
java.lang.IllegalStateException: UserDetailsService is required.
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:463)
at org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper.loadUserDetails(UserDetailsByNameServiceWrapper.java:68)
at org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider.authenticate(PreAuthenticatedAuthenticationProvider.java:103)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.springframework.security.oauth2.provider.token.DefaultTokenServices.refreshAccessToken(DefaultTokenServices.java:150)
You can see at the bottom that the DefaultTokenServices is attempting to refresh the token. It then calls into an AuthenticationManager to re-authenticate (in case the user revoked permission or the user was deleted, etc.) but this is where it all unravels. You see at the top of the stack trace that UserDetailsServiceDelegator is what gets the call to loadUserByUsername instead of my beautiful UserDetailsService. Even though inside my WebSecurityConfigurerAdapter I set the UserDetailsService, there are two other WebSecurityConfigurerAdapters. One for the ResourceServerConfiguration and one for the AuthorizationServerSecurityConfiguration and those configurations never get the UserDetailsService that I set.
In tracing all the way through Spring Security to piece together what is going on, I found that there is a "local" AuthenticationManagerBuilder and a "global" AuthenticationManagerBuilder and we need to set it on the global version in order to have this information passed to these other builder contexts.
So, the solution I came up with was to get the "global" version in the same way the other contexts were getting the global version. Inside my WebSecurityConfigurerAdapter I had the following:
#Autowired
public void setApplicationContext(ApplicationContext context) {
super.setApplicationContext(context);
AuthenticationManagerBuilder globalAuthBuilder = context
.getBean(AuthenticationManagerBuilder.class);
try {
globalAuthBuilder.userDetailsService(userDetailsService);
} catch (Exception e) {
e.printStackTrace();
}
}
And this worked. Other contexts now had my UserDetailsService. I leave this here for any brave soldiers who stumble upon this minefield in the future.
For anyone got UserDetailsService is required error when doing refresh token, and you confirm you already have UserDetailsService bean.
try add this:
#Configuration
public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter {
private UserDetailsService userDetailsService;
public GlobalSecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
This is my try and error, maybe not work for you.
By the way, if you give up "guess" which bean will pick by spring, you can extends AuthorizationServerConfigurerAdapter and WebSecurityConfigurerAdapter and config all stuff by yourself, but I think it's lose power of spring autoconfig.
Why I need config everything if I just need customize some config?

Spring Security: Authenticate against multiple LDAP servers & DAO-based authentication

I'm working on a Springboot application which has a requirement to support authentication locally (through a DAO-based provider) and through multiple LDAP servers (administratively configured, stored in the database).
With a single LDAP provider my configure method looks like:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
auth.ldapAuthentication()
.userSearchBase(userSearchBase)
.groupSearchBase(groupSearchBase)
.userSearchFilter(userSearchFilter)
.userDetailsContextMapper(new DaoUserDetailsContextMapper())
.contextSource().url(url+"/"+base)
.managerPassword(managerPassword)
.managerDn(managerDn);
}
Through other similar posts it appears this could be accomplished through creating multiple LDAP providers, and Spring security will cycle through each one until a successful login is found. I have the associated LDAP configuration record associated as a foreign key on the User table.
Is there a more efficient way to try the specific LDAP endpoint associated with the user, or is it best to let Spring iterate through the available providers?
Thanks for any input!
after long search in my way, I found something interesting about how Spring Security authentification works (there is a video : https://youtu.be/caCJAJC41Rk?t=781)
After that, you can use the system that Spring has implemented which is to override the supports(class<?> authenticationClass) method. This method works as "Can you, AuthenticationProvider, manage this kind of AuthenticationClass ?" if true, the provider will try to authenticate the user, if not, never execute any tasks.
In that way, you can implement your own CustomAuthentificationProvider which implements the AuthenticationProvider interface.
public class LocalUserAuthenticationProvider implements AuthenticationProvider {
private final UserRepository;
public LocalUserAuthenticationProvider(UserRepository userRepository){
this.userRepository = userRepository;
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
/*my jobs*/
throws new AuthenticationException("Cannot authenticate");
}
#Override
public boolean supports(Class<?> aClass) {
return MyUsernameAuthenticationToken.class.isAssignableFrom(aClass);
}
}
with your own AuthenticationToken
public class StringUsernameAuthenticationToken extends UsernamePasswordAuthenticationToken {
public StringUsernameAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
public StringUsernameAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}
Actually I don't find any solutions with the LDAP authentication in the AuthenticationManagerBuilder implemented by Spring Security (ref : https://spring.io/guides/gs/authenticating-ldap/)
Hope this could help people

How to redirect UsernameNotFoundException from PreAuthenticatedAuthenticationProvider when using multiple AuthenticationProviders?

Using Spring Security 4.02, can anyone help with some tips on how I can handle UsernameNotFoundException from PreAuthenticatedAuthenticationProvider when using multiple AuthenticationProviders so that authenticated requests, with the correct header, but which are unauthorized, are sent to a specific URL instead of the forms-login page?
Let me explain further what I'm trying to accomplish for accessing a web app being secured by SSO behind a proxy. Not all users who are authenticated by SSO will have access to this app. So I need to account for 3 access scenarios:
authenticated user (header is present) is authorized (username/roles are present in app's db)
authenticated user (header is present) is unauthorized (username/roles are not present in app's db)
unauthenticated user with username/roles present in app's db
The actions when accessing the website should be:
authenticated/authorized user proceeds directly to target URL
authenticated/unauthorized user is redirected to error/info page
unauthenticated user is redirected to forms-login page for authentication
With my current configuration, scenarios 1 & 3 appear to be working as desired. For scenario 2 I've tried setting RequestHeaderAuthenticationFilter#setExceptionIfHeaderMissing to both true and false.
If setExceptionIfHeaderMissing=false, authenticated/unauthorized request is handled by ExceptionTranslationFilter where AccessDeniedException is thrown and user is redirected to forms-login page.
If setExceptionIfHeaderMissing=true, authenticated/unauthorized request encounters PreAuthenticatedCredentialsNotFoundException from AbstractPreAuthenticatedProcessingFilter.doAuthenticate and HTTP 500 is returned.
So I've read and reread the Spring Security reference and api documents and scoured the web and just can't quite figure out what I need to do. I think I somehow need to enable some kind of filter or handler to trap the PreAuthenticatedCredentialsNotFoundException with a redirected response. But I can't seem to wrap my head around how to implement that with all the spring tools available. Can someone please offer some specifics? Many thanks in advance!!
Here is my configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String AUTHENTICATION_HEADER_NAME = "PKE_SUBJECT";
#Autowired
CustomUserDetailsServiceImpl customUserDetailsServiceImpl;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
auth.userDetailsService(customUserDetailsServiceImpl);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().and()
.authorizeRequests()
.antMatchers("/javax.faces.resource/**", "/resources/**", "/templates/**", "/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/public/welcome.xhtml")
.and()
.addFilter(requestHeaderAuthenticationFilter());
}
#Bean PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() throws Exception {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
return provider;
}
#Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setPrincipalRequestHeader(AUTHENTICATION_HEADER_NAME);
filter.setAuthenticationManager(authenticationManagerBean());
filter.setExceptionIfHeaderMissing(true);
return filter;
}
#Bean
public UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>
userDetailsServiceWrapper() throws Exception {
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper
= new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>();
wrapper.setUserDetailsService(customUserDetailsServiceImpl);
return wrapper;
}
}
My customized UserDetailsService:
#Service("customUserDetailsService")
public class CustomUserDetailsServiceImpl implements UserDetailsService {
#Autowired
UserRepo userRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetailDO userDetail = userRepo.getUserDetailById(username);
if(userDetail == null) {
throw new UsernameNotFoundException("user is not authorized for this application");
}
List<UserRoleDO> roles = userRepo.getRolesByUsername(username);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
if(CollectionUtils.isNotEmpty(roles)) {
for(UserRoleDO role : roles) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRole());
authorities.add(authority);
}
}
UserDetails user = new User(username, "N/A", authorities);
return user;
}
}
I realized that I did not need to handle the exception. What I did was to shift my thinking on this. I realized that even if the username was not found by the customUserDetailsService, the request was still an authenticated request since the request is trusted to be authenticated by the SSO and the proxy server.
So instead of returning a UsernameNotFoundException I returned the org.springframework.security.core.userdetails.User with an empty Authorities collection. And because the RequestHeaderAuthenticationFilter.setExceptionIfHeaderMissing = false by default, no exception is thrown and then the authenticated request is passed to the access filter where it is determined that the request has no authorization to access any resources. So instead of redirecting to the next authentication filter which would be the forms login provider, a 403 Access Denied http status is returned which I can then override to redirect to a user-friendly error page.

Resources