I hope you could give me a hand with the following:
I am using spring security and spring MVC to build a web app, and I need to redirect the flow to the login page, once there is a try to access a forbidden resource (403 HTTP status code).
Now, spring Security already does the work of preventing from unauthorized access to every resource I've exposed in my Restful API (#RestController), and responding with the proper 403 default page. But as I need to redirect to the login page, I need to push spring security to do a redirect instead of sending a 403. In this regard I've been trying to do the following but I haven't been able to make it works:
Setting the HttpSecurity bean to manage the exception when accessing a denied page:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().exceptionHandling().accessDeniedPage("/security/403");
}
Now, I set my controller to catch /security/403 URL
// for 403 access denied page
#RequestMapping(value = "/security/403", method = RequestMethod.GET)
public void accesssDenied() {
//Do stuff here, redirecting or whatever.
}
thanks
Create a new class that acts as an Interceptor.
This class will implement the HandlerInterceptor interface and override the following methods:
From the documentation:
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) – Intercept the execution of a handler (called just before the controller).
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) – called immediately after the controller
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler) – called just before sending response to view
In your case, use the preHandle() method to check if the client is trying to access a forbidden resource and if so, redirect the client to the login page. In fact, this is one of the most common paradigms where an Interceptor is used to handle the flow of execution.
Related
My SpringBoot application is a packaged software application, to customize it I want to manipulate the authentication object when users first login, and I expect this object would be pushed back to the user's session for subsequent connection.
I managed to use an Around advice to intercept a REST endpoint that will be triggered when first login:
#Around("execution( * com.myproject.CurrentUser.get(..)))"
public ResponseEntity getCurrentUser(ProceedingJoinPoint pjp) throws Exception {
SecurityContextHolder.getContext().setAuthentication(getNewAuthentication());
((ServletRequestAttributes) RequestContextController.currentRequestAttributes())
.getRequest().getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING.SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
ResponseEntity response = (ResponseEntity) pjp.proceed();
return response;
}
The getNewAuthentication() method is confirmed OK, it returns a PreAuthenticatedAuthenticationToken that includes additional authorities.
However in the subsequent REST calls when I check the Security Context object the authentication is still the original one.
May I know what would be the proper way to do this? I need to manipulate the authentication object at the very beginning and make sure the subsequent calls will make use of it.
Any idea?
I am using a spring SAML for intergrating spring SAML SSO. The issue I am facing right now is how to get the user name in my custom SimpleUrlAuthenticationFailureHandler.
I have created my own SimpleUrlAuthenticationFailureHandler and onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) method how do i get the access to the username over here ?
Spring Boot here. I just read this excellent Baeldung article on Spring Security and implementing basic auth with it. I'm interested in implementing it for a simple REST service (so no UI/webapp) that I need to build.
I'm particularly interested in the BasicAuthenticationEntryPoint impl. In this impl's commence override, the author:
Adds a WWW-Authenticate header to the response; and
Sets the HTTP status code on the response; and
Writes the actual response entity directly to the response; and
Sets the name of the realm
I want to follow this author's example to implement basic auth for my app, but I already have a perfectly functioning ResponseEntityExceptionHandler working for my app:
#ControllerAdvice
public class MyAppExceptionMapper extends ResponseEntityExceptionHandler {
#ExceptionHandler(IllegalArgumentException.class)
#ResponseBody
public ResponseEntity<ErrorResponse> handleIllegalArgumentExeption(IllegalArgumentException iaEx) {
return new ResponseEntity<ErrorResponse>(buildErrorResponse(iaEx,
iaEx.message,
"Please check your request and make sure it contains a valid entity/body."),
HttpStatus.BAD_REQUEST);
}
// other exceptions handled down here, etc.
// TODO: Handle Spring Security-related auth exceptions as well!
}
Is there any way to tie Spring Security and Basic Auth fails into my existing/working ResponseEntityExceptionHandler?
Ideally there's a way to tie my WebSecurityConfigurerAdapter impl into the exception handler such that failed authentication or authorization attempts throw exceptions that are then caught by my exception handler.
My motivation for doing this would be so that my exception handler is the central location for managing and configuring the HTTP response when any exception occurs, whether its auth-related or not.
Is this possible to do, if so, how? And if it is possible, would I need to still add that WWW-Authenticate to the response in my exception handler (why/why not)? Thanks in advance!
I don't think that this is possible. Spring security is applied as a ServletFilter, way before the request ever reaches any #Controller annotated class - thus exceptions thrown by Spring Security cannot be caught by an exception handler (annotated with #ControllerAdvice).
Having had a similar problem, I ended up using a custom org.springframework.security.web.AuthenticationEntryPoint which sends an error, which in turn is forwarded to a custom org.springframework.boot.autoconfigure.web.ErrorController
A client software is trying to access my Spring-MVC rest server, but it's getting a 400 (Bad Request) response every time. I know my server is fine (it's in use by many other clients), but I cannot debug the client application, so I cannot see what it is sending.
Is there a way for me to see what JSON I am receiving before Spring tries to convert it to an entity and fails? It's okay if I can only do this at debug time, I just need to be able to give support to this application's creators.
Just in case, here is the spring-mvc controller method:
#Named
#RequestMapping(value = "/taskmanager/task")
public class TaskManagerTaskRest {
#RequestMapping(value = "", method = RequestMethod.POST)
#ResponseBody
public void createTask(#RequestBody Task task, HttpServletRequest request,
HttpServletResponse response) throws CalabacinException {
// This code never gets executed because the Task json is invalid, but I don't know how I could see it.
...
...
}
}
Try to use Fiddler. It will help you to catch HTTP requests/responses. You will be able to see your JSON.
You can create and use a AbstractRequestLoggingFilter filter implementation and conditionally log the relevant parts of the request. You should use ContentCachingRequestWrapper to wrap the request.
I've wrote a web app with its brave controllers and handler mapping, everything with Spring 3.0 and controller annotations. Now turns out that I need simple and custom autentication. I don't want to use ACEGI for the moment, because I've no time to learn it. I'd like ideally that I could have a routine that gets called before every mapped handler, gets from the HttpSession the userId, checks if he is logged in and the session key and if not redirects to a login page. I've been thinking about an interceptor... the problem is that you have to use HandlerInterceptorAdapter, which has the following method:
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
that won't let me access the HttpSession associated with the request. How do I solve this?
Are you sure? You should be able to obtain the session through request.getSession().