Is there a way to "ask" spring security if the current request is secure? Because even if I am authenticated I want to detect if I am in a secure protected URL or in a anonymous / public page
Thanks in advance!
Spring Security provides JSP tag support for this. For example:
<sec:authorize url="/admin">
This content will only be visible to users who are authorized to access the "/admin" URL.
</sec:authorize>
Thymeleaf provides a Spring Security Dialect that has direct support for checking URL authorization with Spring Security. For example:
<div sec:authorize-url="/admin">
This will only be displayed if authenticated user can call the "/admin" URL.
</div>
If your technology does not support performing the check directly, you can easily use the WebInvocationPrivilegeEvaluator (this is the object that the JSP taglib and Thymeleaf use). For example, you can #Autowire an instance of WebInvocationPrivilegeEvaluator and use it directly. Obviously the syntax will vary depending on where you use it (i.e. GSP, Freemarker, etc), but here is an example in straight Java code.
#Autowired
WebInvocationPrivilegeEvaluator webPrivs;
public void useIt() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
boolean hasAdminAccess = webPrivs.isAllowed("/admin", authentication);
boolean hasAdminPostAccess = webPrivs.isAllowed(null, "/admin", "POST", authentication);
}
I think you can use your own implementation for AccessDecisionVoter then just simply override Vote method and compare intercept url using filterInvocation.getRequestUrl(); method.
#Override
public int vote(Authentication authentication, FilterInvocation filterInvocation,
Collection<ConfigAttribute> attributes) {
String requestUrl = filterInvocation.getRequestUrl();
....
}
We can mark it is as secure channel so converted to https:// url.
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" requires-channel="https" />
We can then use request.getScheme() to identify it.
I used org.springframework.security.version 3.1.4.RELEASE
Related
I implemented spring security in my web application. Now all my services are secured and can be only invoked by authorised users. Everything works on webside, but when I call function without log in doesn't work.
here is my Controller(RestController)
#RestController
public class MessageService {
#Autowired
MessageModel messageModel;
#RequestMapping(value="/message",method=RequestMethod.POST)
public Message save(#RequestBody Message message) {
return messageModel.save(message);
}
#PreAuthorize("permitAll()")
#RequestMapping(value="/messagee",method=RequestMethod.POST)
public Message savee(#RequestBody Message message) {
System.out.println("hjgjhghggfhgf");
return messageModel.savee(message);
}
}
I am using angularjs client side.
The functions are not supposed to work as they are secured by spring security. To allow a few functions to be accessed anonymously, you need to configure spring security to do so.
Depending on what configuration you are using, I would suggest the below:
If you are using XML/Java route based config, I would recommend you to do something like this:
<security:intercept-url pattern="/trusted/**" filters="none" />
<security:intercept-url pattern="/**" access="isFullyAuthenticated()" />
If you are using the #PreAuthorize annotation, I would recommend you to do something like this:
#PreAuthorize("permitAll()")
public void YourAnonymousController(){
}
Hope this is what you are looking for.
EDIT 1: Please note that you remove the route based security config. Try adding #PreAuthorize("hasRole()") on functions you want to keep secured and #PreAuthorize("permitAll()") on anonymous functions.
I am using spring boot with the spring-boot-starter-security dependency.
I have an application that will successfully login given the proper credentials. However, whenever I login I am not being redirected anywhere. How can I configure this?
Below is the form:
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
I have tried changing the th:action tag above but I wasn't able to get anywhere with it.
The MvcConfig method is below:
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/").setViewName("login");
}
Defining the redirection after a successful login needs to be applied on Spring Security, not Spring MVC.
The th:action defines the Spring Security endpoint that will process the authentication request. It does not define the redirection URL. Out of the box, Spring Boot Security will provide you the /login endpoint. By default, Spring Security will redirect after login to the secured ressource you tried to access. If you wish to always redirect to a specific URL, you can force that through the HttpSecurity configuration object.
Assuming you are using a recent version of Spring Boot, you should be able to use JavaConfig.
Here is a simple exemple :
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
// the boolean flags force the redirection even though
// the user requested a specific secured resource.
http.formLogin().defaultSuccessUrl("/success.html", true);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
}
Please note that you need to define a proprer endpoint to serve content for the /success.html URL. A static resource available by default in src/main/resources/public/ would do the trick for test purpose. I would personnally rather define a secured URL served by a Spring MVC Controller serving content with Thymeleaf. You don't want any anonymous user to be able to access the success page. Thymeleaf as some usefull features to interact with Spring Security while rendering the HTML content.
Regards,
Daniel
It works for me. Once the login has been successful, Spring security redirects to "/" and then, I checks if the user is authenticated and in this case, redirects it to my dashboard page.
#RequestMapping("/")
public String index(Model model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken))
return "dashboard";
// if it is not authenticated, then go to the index...
// other things ...
return "index";
}
You can also define the post-login re-direction dynamically. It turns out to be crazy simple.
Suppose you have a controller that has complicated conditions where you need to ensure that the user is correctly logged in.
By setting a value in the "request" cache to the current request/response, and then doing a re-direct, Spring security will forward to the cached request after the login is successful.
RequestCache requestCache = new HttpSessionRequestCache();
requestCache.saveRequest(request,response);
return "redirect:/login";
No, this doesn't seem to be documented anywhere. The only reference to it I found was the following:
SavedRequests and the RequestCache Interface
Another responsibility of ExceptionTranslationFilter responsibilities is to save the current request before invoking the AuthenticationEntryPoint. This allows the request to be restored after the user has authenticated (see previous overview of web authentication). A typical example would be where the user logs in with a form, and is then redirected to the original URL by the default SavedRequestAwareAuthenticationSuccessHandler (see below).
The RequestCache encapsulates the functionality required for storing and retrieving HttpServletRequest instances. By default the HttpSessionRequestCache is used, which stores the request in the HttpSession. The RequestCacheFilter has the job of actually restoring the saved request from the cache when the user is redirected to the original URL.
Using spring securiity, I'm faced with a requirement for a complex business decision about whether to allow anonymous access or insist on user login. Logic is too complex for "intercept-url" expressions ( intercept-url pattern='/mypattern/**'...)
E.g. assume a RESTFul books service:
https://myserver/rest/book?title=war_and_peace
https://myserver/rest/book?title=the_firm
Say "war and peace" allows anonymous access because its old and its copyrights have expired.
While "the firm" is copyrighted & requires login (so as to charge the user).
This copyright info is available in a database.
Could anyone please offer any hints as to how to achieve this in spring secuirity? thanks in advance
There are of course multiple ways that code can look like, but to get the idea:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof AnonymousAuthenticationToken && "the_firm".equals(title)) {
throw new AccessDeniedException("Requires login!");
}
Update: A more declarative way is to use annotations:
#PostAuthorize("hasPermission(returnObject, 'READ')")
public Book findBook(String title) {
// ...
}
This requires that you create a permission evaluator bean and add config:
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
#Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
When a user fails authentication, I want the username and password to be returned to the form.
I'm using the spring security core plugin with Grails and Spring Security LDAP. I've searched around for a while and have come up with zip. Any ideas?
From UsernamePasswordAuthenticationFilter javadoc:
If you want to retain the username, cache it in a customized AuthenticationFailureHandler
As for password there is no point to cache it, because it cannot be put back to form password field for security reasons.
For future reference, as the above answers are either too vague to be helpful to those of us who are just beginning to learn this framework for the first time (prompting such questions as: what's an AuthenticationFailureHandler? How do I implement one? How do I connect it to my existing infrastructure that was magically created by the <security:http> namespace handler?) or no longer work (the code to store the username in SPRING_SECURITY_LAST_USERNAME was removed from UsernamePasswordAuthenticationFilter as of version 3.1.0), here's a little more detail on the first answer:
An AuthenticationFailureHandler is used by the login process to decide what to do when authentication fails.
The default login form setup as provided by <security:http><security:form-login /></security:http> uses a SimpleUrlAuthenticationFailureHandler to perform the redirection to the login failed url (which defaults to /spring_security_login?login_error).
You can hook your own implementation in by using the authentication-failure-handler-ref attribute of your <form-login> element.
So, my implementation looks like this:
public class UsernameStoringUrlAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler
{
#Override
public void onAuthenticationFailure (HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException
{
request.getSession (true).setAttribute ("SPRING_SECURITY_LAST_USERNAME", request.getParameter ("j_username"));
super.onAuthenticationFailure (request, response, exception);
}
}
which is configured thus:
<security:form-login authentication-failure-handler-ref="authenticationFailureHandler" [...] />
...
<bean id="authenticationFailureHandler" class="my.package.UsernameStoringUrlAuthenticationFailureHandler" p:defaultFailureUrl="/LoginError" />
And then I can access the failed login username using the same approach as described in James Kleeh's answer here, but which no longer worked because of the change to the framework.
I was able to do the following to get the username back to the form: In LoginController.groovy:
render view: view, model: [postUrl: postUrl,
rememberMeParameter: config.rememberMe.parameter,
lastUsername: request.getSession().getAttribute("SPRING_SECURITY_LAST_USERNAME")]
I've got a web app that uses spring security. I'm wanting to redirect the user back to the same page they were on before log out when they log out.
Is there an easy way to do this?
Not sure which Spring version this question was referring to - but there is a useReferer property on the standard org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler since Spring 3.0.
So all you need to do is configure it like this and the logout will redirect to wherever the user came from:
<bean id="logoutSuccessHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<property name="useReferer" value="true"/>
</bean>
<security:http>
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler" />
</security:http>
What you need is a Simple LogoutSuccessHandler
#Component
public class CustomLogoutSuccessHandler extends
SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse
response, Authentication authentication)
throws IOException, ServletException {
if (authentication != null) {
System.out.println(authentication.getName());
}
response.setStatus(HttpStatus.OK.value());
response.sendRedirect(request.getHeader("referer"));
}
And later call it in your configure method i.e
.logout().logoutSuccessHandler(customLogoutSuccessHandler)
This will redirect you to referer URL.
You can add a new filter in the filter chain of the spring security. That new filter will be applied to the /logout URL. When going trough this filter you can save the current page in a field variable. And when returning through the filter. You can redirect the request to the saved URL. I think this can help. You can get the current page URL by using the Referer header in the Request object.
Just a thought:
How about we keep a stack of visited pages. may be at max 3 entries. and redirects user from logout.
Configure a Filter or extend spring security filter to maintain a stack in session about last two visited URLs
On logout configure a servlet as logout-success-url .
Now get the URL from session stack and now invalidate the session and redirect user to that page
Also you can make use of referrer header as Vijay has mentioned