I have a Spring Boot application with Spring Security configured as follows:
#EnableWebSecurity
public class AppSecurityConfiguration {
#Configuration
#Order(Constants.DEVSTACK_SECURITY_ORDER - 1)
static class WebHttpSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* Configures Application WebSecurity which involves the full Security pipeline (?)
*
* #param web WebSecurity
*/
#Override
public void configure(WebSecurity web) {
web.ignoring()
// Allow requests to HealthCheck Endpoint without Bearer Token
.antMatchers("/api/healthCheck", "/v3/api-docs/**", "/configuration/**", "/swagger-ui.html",
"/swagger-ui/**", "/webjars/**", "/api/v1/browser/**", "/swagger-resources/**")
// Allow OPTIONS request without Bearer Token (for pre-flight requests)
.antMatchers(HttpMethod.OPTIONS, "/**");
}
/**
* Configures HttpSecurity
*
* #param http HttpSecurity
* #throws Exception if an error occurs
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//Authorize INSECURE request to this endpoint (so Swagger can pull the data)
.antMatcher("/v2/api-docs")
.authorizeRequests()
.anyRequest()
.permitAll();
}
}
}
Here in this Configuration class I'm ignoring certain endpoints from passing through Spring Security, most of them are for Swagger documentation so you can ignore it.
My problem is inside the configure(HttpSecurity) method. I don't know why but the way I wrote it it just works. When I try to understand what I just configured I read it like this:
For every request to "/v2/api-docs", authorize the requests
For any other requests, permit them all.
Now I want to add a Custom Filter to the Spring Security Filter Chain.
This is the Filter class:
public class MyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
log.debug("MyFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
Whenever I try to add the filter to my HttpSecurity, I end up with Spring Security setting my Principal to 'anonymousUser'.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new MyFilter(), WebAsyncManagerIntegrationFilter.class);
}
I've tried many different things like:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new MyFilter(), WebAsyncManagerIntegrationFilter.class)
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.disable()
.formLogin()
.disable();
}
But it still returns 'anonymousUser' when I try to get the user's Principal.
I don't know why having it configured like this works?!?!
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//Authorize INSECURE request to this endpoint (so Swagger can pull the data)
.antMatcher("/v2/api-docs")
.authorizeRequests()
.anyRequest()
.permitAll();
}
Can someone enlighten me and explain me like i'm five years old? Sometimes I just think I'm too stupid to understand Spring
Thanks
It should be:
http
.authorizeRequests()
.antMatchers("/v2/api-docs")
.permitAll()
.and()
.authorizeRequests().antMatchers("/**").authenticated()
Related
I have the following Spring Security configuration:
httpSecurity
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/**").fullyAuthenticated()
.and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
The authenticationTokenFilterBean() is applied even on endpoints that do not match /api/** expression. I also tried adding the following configuration code:
#Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/some_endpoint");
}
but this still did not solve my problem. How can I tell Spring Security to apply filters only on endpoints that match the secured URI expression?
I have an application with the same requirement and to solve it I basically restricted Spring Security to a given ant match patter (using antMatcher) as follows:
http
.antMatcher("/api/**")
.authorizeRequests() //
.anyRequest().authenticated() //
.and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
You can read it as follows: for http only invoke these configurations on requests matching the ant pattern /api/** authorizing any request to authenticated users and add filter authenticationTokenFilterBean() before UsernamePasswordAuthenticationFilter. For all others requests this configuration has no effect.
GenericFilterBean has a following method :
/**
* Can be overridden in subclasses for custom filtering control,
* returning {#code true} to avoid filtering of the given request.
* <p>The default implementation always returns {#code false}.
* #param request current HTTP request
* #return whether the given request should <i>not</i> be filtered
* #throws ServletException in case of errors
*/
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return false;
}
So in your filter that extends GenericFilterBean you can override that method and implement logic to run the filter only on the routes that you would like.
My Requirement was to exclude the endpoint matching /api/auth/**, to achieve the same I have configured my WebSecurityConfig spring configuration component as follows:
/**
* The purpose of this method is to exclude the URL's specific to Login, Swagger UI and static files.
* Any URL that should be excluded from the Spring security chain should be added to the ignore list in this
* method only
*/
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/auth/**","/v2/api-docs",
"/configuration/ui",
"/swagger-resources",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js");
}
/**
* The purpose of this method is to define the HTTP configuration that defines how an HTTP request is
* going to be treated by the Spring Security chain. All the request URL's (excluding the URL's added
* in WebSecurity configuration ignore list) matching this configuration have to pass through the
* custom Spring security filter defined in this method
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
/**
* The purpose of this method is to create a new instance of JWTAuthenticationFilter
* and return the same from the method body. It must be ensured that this filter should
* not be configured as a Spring bean or registered into the Spring Application context
* failing which the below filter shall be registered as a default web filter, and thus
* all the URL's even the excluded ones shall be intercepted by the below filter
*/
public JWTAuthenticationFilter authenticationTokenFilterBean() {
return new JWTAuthenticationFilter();
}
We recently updated to Spring Boot 3.0.0 which uses Spring Security 6.0.0 and ran into a similar issue when a filter was applied to all requests, although the authorizeHttpRequests() was used with specific paths defined.
Turned out, if you want the HttpSecurity to be configured for a specific path, you need to use securityMatcher() at the beginning.
So it will be something like this:
private SecurityFilterChain configureFilterChain(HttpSecurity http, String pattern, String... roles) throws Exception {
return http
.securityMatcher(pattern)
.authorizeHttpRequests(auth -> auth.requestMatchers(AntPathRequestMatcher.antMatcher(pattern)).hasAnyRole(roles))
.addFilterBefore(new TokenFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPointImpl())
.accessDeniedHandler(new AccessDeniedHandlerImpl())
.and()
.csrf().disable()
.build();
}
So in this case, TokenFilter will be applied to only requests which have this pattern.
If you use the
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
You can define in the constructor the specific path it will apply to:
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
super("/api/**");
this.setAuthenticationManager(authenticationManager);
}
#Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return super.requiresAuthentication(request, response);
}
The requiresAuthentication method will be used to know if that endpoint needs authentication.
I think I've found a way to solve it. I have JwtTokenAuthenticationProcessingFilter which is an AbstractAuthenticationProcessingFilter. I want it to authenticate request if there is token in the head but do not block the request if failed. All you need is to rewrite the doFilter and invoke the chain.doFilter no matter what the authentication result is(invoking unsuccessfulAuthentication is optional). Here is part of my code.
public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
private final TokenExtractor tokenExtractor;
#Autowired
public JwtTokenAuthenticationProcessingFilter(TokenExtractor tokenExtractor, RequestMatcher matcher) {
super(matcher);
this.tokenExtractor = tokenExtractor;
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!this.requiresAuthentication(request, response)) {
chain.doFilter(request, response);
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Request is to process authentication");
}
boolean success = true;
Authentication authResult = null;
try {
authResult = this.attemptAuthentication(request, response);
} catch (InternalAuthenticationServiceException var8) {
this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
success = false;
} catch (AuthenticationException var9) {
success = false;
}
if (success && null != authResult) {
this.successfulAuthentication(request, response, chain, authResult);
}
// Please ensure that chain.doFilter(request, response) is invoked upon successful authentication. You want
// processing of the request to advance to the next filter, because very last one filter
// FilterSecurityInterceptor#doFilter is responsible to actually invoke method in your controller that is
// handling requested API resource.
chain.doFilter(request, response);
}
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
String tokenPayload = request.getHeader(WebSecurityConfig.AUTHENTICATION_HEADER_NAME);
RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(tokenPayload));
return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
SecurityContextHolder.setContext(context);
}
}
Update at Apr 22
To register the filter, just add the following code to the WebSecurityConfig
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationProvider mJwtAuthenticationProvider;
#Autowired
public WebSecurityConfig(JwtAuthenticationProvider jwtAuthenticationProvider) {
this.mJwtAuthenticationProvider = jwtAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// When multiple authentication providers are defined, the providers will be queried in the order they’re
// declared.
auth.authenticationProvider(mJwtAuthenticationProvider);
}
}
In the code, I only revealed the critical part about adding the filter.
All this implementation was inspired by this site. Give credit to the author Vladimir Stankovic for his detail explanation.
As they describe us here, the WebSecurityConfigurerAdapter will deprecated in a while.
I try to refactor the implementation of WebSecurityConfigurerAdapter with SecurityFilterChain due to I want to implement an JWT pattern.
The main consideration which I faced is that the configure in returns void.
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManagerBean(), accessTokenExpiredInDays, refreshTokenExpiredInDays, jwtSecret);
customAuthenticationFilter.setFilterProcessesUrl("/api/login");
http
.csrf().disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.authorizeRequests()
.antMatchers("/error").permitAll();
http
.authorizeRequests()
.antMatchers("/api/login/**", "/api/token/refresh/**").permitAll();
http
.authorizeRequests()
.anyRequest().authenticated();
http
.addFilter(customAuthenticationFilter);
http
.addFilterBefore(new CustomAuthorizationFilter(jwtSecret), UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();
}
Note that Spring Security has built-in support for JWT authentication and there is no need to create a custom filter.
You can find an example provided by the Spring Security team here.
However, if you do choose to create a custom filter, the recommended way to configure it is by creating a custom DSL.
This is the same way that Spring Security does it internally.
I've rewritten your configuration below using a custom DSL.
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.authorizeRequests()
.antMatchers("/error").permitAll();
http
.authorizeRequests()
.antMatchers("/api/login/**", "/api/token/refresh/**").permitAll();
http
.authorizeRequests()
.anyRequest().authenticated();
// apply the custom DSL which adds the custom filter
http
.apply(customDsl());
http
.addFilterBefore(new CustomAuthorizationFilter(jwtSecret), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
#Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager =
http.getSharedObject(AuthenticationManager.class);
CustomAuthenticationFilter filter =
new CustomAuthenticationFilter(authenticationManager, accessTokenExpiredInDays, refreshTokenExpiredInDays, jwtSecret);
filter.setFilterProcessesUrl("/api/login");
http.addFilter(filter);
}
public static MyCustomDsl customDsl() {
return new MyCustomDsl();
}
}
This configuration, as well as other examples, are described in the Spring blog post on migrating away from the WebSecurityConfigurerAdapter.
I'm trying to add web security in spring but I don't want the filter to apply to certain things. How is that done in java?
Overall, what I want to do is this:
/ and /login should not show a HTTP Basic authentication prompt to login, while everything else should go through the filter and pop up a login prompt window.
Through various example I found through spring I was able to come up with this as for a start but it obviously doesn't work:
#Configuration
#EnableWebMvcSecurity
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().antMatcher("/").authorizeRequests().anyRequest().permitAll();
http.csrf().disable().antMatcher("/**").authorizeRequests().anyRequest().hasRole("ADMIN").and().httpBasic();
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
}
Rewrite your configure(HttpSecurity http) method like the following:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.anyRequest().hasRole("ADMIN")
.and()
.csrf()
.disable();
}
"/" and "/login" SHOULD NOT show a httpbasic authentication prompt to
login, while everything else SHOULD go through the filter and pop up a
login prompt window.
If you seriously planning to use HTTP Basic, I guess you wouldn't need a separate /login handler, since browser-based clients can use the default browser based pop up and other clients can send HTTP Basic requests through Authorization header.
I have a problem with default behaviour in spring security with authorize requests provided with Java Config.
http
....
.authorizeRequests()
.antMatchers("/api/test/secured/*").authenticated()
When I do a call to for example /api/test/secured/user without login (with anonymous user), it returns 403 Forbidden. Is there an easy way to change status to 401 Unauthorized when anonymous user wants to get secured by authenticated() or #PreAuthorize resource?
As of Spring Boot 2 class Http401AuthenticationEntryPoint has been removed (see Spring Boot Issue 10725).
Instead of Http401AuthenticationEntryPoint use HttpStatusEntryPoint with HttpStatus.UNAUTHORIZED:
http.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
With spring security 4.x there is already a class for that
org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
Spring boot also includes one
org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint
and both benefits that they require the developer to use spec compliant as 401 responses requires that header WWW-Authenticate must be set, example 401 response could be:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"
So in your security configuration you define and autowire a bean of class
So for instance with spring boot app:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Bean
public Http401AuthenticationEntryPoint securityException401EntryPoint(){
return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
}
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").anonymous()
.antMatchers("/").anonymous()
.antMatchers("/api/**").authenticated()
.and()
.csrf()
.disable()
.headers()
.frameOptions().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.logout()
.permitAll()
.exceptionHandling().authenticationEntryPoint(securityException401EntryPoint());
}
the relevant line is:
.exceptionHandling().authenticationEntryPoint(securityException401EntryPoint());
I've got solution here:
http
.authenticationEntryPoint(authenticationEntryPoint)
AuthenticationEntryPoint source code:
#Component
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {
private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);
/**
* Always returns a 401 error code to the client.
*/
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException,
ServletException {
log.debug("Pre-authenticated entry point called. Rejecting access");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
}
}
A simple approach in Spring Boot 2 using lambda expressions:
#Override
public void configure(HttpSecurity http) throws Exception {
http.
...
.exceptionHandling()
.authenticationEntryPoint((request, response, e) -> {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");
response.getWriter().write("{ \"error\": \"You are not authenticated.\" }");
})
...
}
You need to extend AuthenticationEntryPoint to do customization based upon the exceptions.
#ControllerAdvice
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
// 401
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed");
}
#ExceptionHandler (value = {AccessDeniedException.class})
public void commence(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
// 401
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Failed : " + accessDeniedException.getMessage());
}
}
Specify the above custom AuthenticationEntryPoint in your SecurityConfig like below:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity (prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new MyAuthenticationEntryPoint());
}
}
Who interested in mechanism of work. If you don't set http.exceptionHandling().authenticationEntryPoint() spring will use defaultAuthenticationEntryPoint() and method ExceptionHandlingConfigurer.createDefaultEntryPoint() will return new Http403ForbiddenEntryPoint()
So, just create Http401UnauthorizedEntryPoint(). Above answers how to do it, didn't duplicate it.
P.S. It's actual for Spring Security 5.2.5.RELEASE
In Specific
I want to have HTTP Basic authentication ONLY for a specific URL pattern.
In Detail
I'm creating an API interface for my application and that needs to be authenticated by simple HTTP basic authentication. But other web pages should not be using HTTP basic but rather a the normal form login.
Current Configuration - NOT Working
#Override
protected void configure(HttpSecurity http) throws Exception {
http //HTTP Security
.csrf().disable() //Disable CSRF
.authorizeRequests() //Authorize Request Configuration
.antMatchers("/connect/**").permitAll()
.antMatchers("/", "/register").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/api/**").hasRole("API")
.anyRequest().authenticated()
.and() //HTTP basic Authentication only for API
.antMatcher("/api/**").httpBasic()
.and() //Login Form configuration for all others
.formLogin().loginPage("/login").permitAll()
.and() //Logout Form configuration
.logout().permitAll();
}
Waited for 2 days and didn't get any help here. But my research provided me a solution :)
Solution
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasAnyRole("ADMIN", "API")
.and()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class FormWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //HTTP with Disable CSRF
.authorizeRequests() //Authorize Request Configuration
.antMatchers("/connect/**").permitAll()
.antMatchers("/", "/register").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and() //Login Form configuration for all others
.formLogin()
.loginPage("/login").permitAll()
.and() //Logout Form configuration
.logout().permitAll();
}
}
}
I dunno if it can be helpful but I couldn't implement the above solution. I found a workaround defining a single Security
#Configuration class
extending
WebSecurityConfigurerAdapter
with both httpBasic() and formLogin() configured. Then I created a custom
CustomAuthEntryPoint implements AuthenticationEntryPoint
that has this logic in the commence method:
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException
{
String urlContext = UtilityClass.extractUrlContext(request);
if (!urlContext.equals(API_URL_PREFIX))
{
String redirectUrl = "urlOfFormLogin"
response.sendRedirect(request.getContextPath() + redirectUrl);
}
else
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
Dunno which is the "best practice strategy" about this issue