I have USER, ROLE and USER_ROLE tables and a bunch Spring controllers ... is there an Spring annotation I can add to the controller methods that will specify the role(s) a user should have to be able to access it?
I guess it's going to be Spring security? Is that straighforward to wire up to an existing user/role schema?
I'm using Spring 2.5.4.
Spring Security is going to be your easiest way to do it. What you're asking for specifically is Method Security Expressions. You can achieve this by using the following:
#PreAuthorize("hasRole('ROLE_ADMIN')")
public void deleteUser(User user) {
...
}
It's pretty straightforward to set up Spring Security with a database backend. I'd take a look at the DAOAuthenticationProvider as a starting point.
Spring Security annotations, as follows:
#Secured({"ROLE_1", "ROLE_2"})
public String mySecuredHander() {
return "foo";
}
Related
how to make a specific GraphQL query as public API in spring boot security?
In REST API, we can specify the URL as public like the following code
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring().requestMatchers(CorsUtils::isPreFlightRequest)
.antMatchers("/actuator/**", "/graphiql/**", "/voyager/**", "/vendor/**");
}
How to do the same for specific GraphQL query or mutation,
query {
listEmployee(){
id
}
}
GraphQL uses a single endpoint for all queries and mutations. This is one of the main differences when compared to REST.
That means you cannot control its security at the URL level if you want a query or mutation to have different security settings than others as they all have the same URL. Instead every query and mutation is backed by their own resolver method. You can control security at the method level using #PreAuthorize etc… (More info).
I have a Spring Boot application that uses MyBatis with H2.
I know I can inject the #Mapper wherever I need, to call the database operation through MyBatis.
What I don't know is where or what should I configure/override in Spring Boot to make sure I receive the login information that the user just entered? So if the user exists, I can redirect them to wherever I want, otherwise show an error.
All the examples I find work only with static username/password through overriding:
public void configure(AuthenticationManagerBuilder auth).
Also, how and what do I for logout?
To setup authentication, you will need to implement your own AuthenticationProvider, and #Override the authenticate method per your requirements.
For my case, I had to #Autowired the MyBatis Mapper interface, and use this mapper (Make DB calls) in the authenticate method to decide whether or not to authenticate the user.
in my spring application I have some aspects for controller methods where I do some security checks. beacause of I need several checks more often I wrapped them into static helper methods of a "sercurityUtil" class.:
public abstract class SecurityUtils {
public static Authentication getCurrentAuthentication(){
return SecurityContextHolder.getContext().getAuthentication();
}
public static ChroniosUser getAuthenticatedUser(){
return (ChroniosUser) getCurrentAuthentication().getPrincipal();
}
public static boolean authenticationHasRole(Authentication authentication, Role role){
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleIdentifier());
return authentication.getAuthorities().contains(grantedAuthority);
}
public static boolean authenticatedUserIsAdmin(){
Authentication authentication = getCurrentAuthentication();
return authenticationHasRole(authentication, ADMIN);
}
...
}
is this a valid and good approach?
or shut I wrap these helper functions into a spring service?
thank you.
PS: I know that I can use #PreAuthorize ... but my aspects are more complex.
The short answer is :
Yes it seems to be a valid and good approach.
The long answer is :
It's up to you.
Spring Security documentation states that its infrastructure is based entirely on standard servlet filters and has no strong links to any particuler web technology, including Spring MVC
Spring Security’s web infrastructure is based entirely on standard
servlet filters. It doesn’t use servlets or any other servlet-based
frameworks (such as Spring MVC) internally, so it has no strong links
to any particular web technology. It deals in HttpServletRequest s and
HttpServletResponse s and doesn’t care whether the requests come from
a browser, a web service client, an HttpInvoker or an AJAX application
[Spring Security Reference - 1. The Security Filter Chain]
Its use is based nearly entirely on the SecurityContextHolder. The examples provided are through static methods :
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
As you can see, it's not a Spring Bean/Service/Component. SecurityContextHolder itself looks like a utility class.
Now you can create a Spring Service to expose it or you can use it through a classic Util class depending on what is more practical to you and for your application.
I'm trying to use this tutorial to create a spring mvc user login page.
The tutorial is great but one thing is not clear, on the second page he talks about the UserRepository interface. The interface methods return User. What I'm confused about is of the User he's referring to is the User object part of the spring framework? The reason I ask if because I want to have an email address field which is not there in the User object which is part of the Spring security framework.
Also, in his implementation of the UserLoginService he has a method:
#Override
public User getLoggedUser() {
User loggedUser = null;
AuthenticationUserDetails userDetails = getLoggedUserDetails();
if (userDetails != null) {
loggedUser = userRepository.findById(userDetails.getId());
}
return loggedUser;
}
the trouble is that the AuthenticationUserDetails does not have a getId() method, which makes me think he intends us to extend Spring's User to create our own Account entity or something.
I want to use Hibernate to create my Account and Role entities and so far every tutorial I've found seems to be before Spring MVC 3 or just giving bits and pieces.
Can anyone provide clarification on this or refer me to a good tutorial for User Login with Spring Security and SpringMVC?
The User is a Spring Security UserDetails object. If you want to extend the object to add more fields, implement the UserDetailsService interface and extend the UserDetails object with your own fields. Then configure Spring Security to use your service, as follows:
<security:authentication-manager>
<security:authentication-provider user-service-ref="myDetailsService" />
</security:authentication-manager>
For our current project, we are integrating JSF and the Spring Framework. I'd like to use Spring Security to handle authentication and authorization. So far, I have implemented a custom PasswordEncoder and AccessDecisionVoter which are working fine. Now I'm trying to secure methods using the #Secured annotation (among others) but I can't get that to work as I would expect it to do.
It seems that the #Secured annotation works for bean methods called directly from the JSF layer, only. Here's a simplified example:
#Named("foobarBean")
#Scope("access")
public class FoobarBean
{
#Secured("PERMISSION_TWO")
public void dummy()
{
}
#Secured("PERMISSION_ONE")
public String save()
{
dummy();
}
}
The method save() is called from the JSF layer like this:
<h:commandButton id="save" action="#{foobarBean.save}" />
Our AccessDecisionVoter is then asked to vote on PERMISSION_ONE but not on PERMISSION_TWO. Is this working as designed (I hope not) or am I doing something wrong (what could that be?).
I'd post more code or config but I'm not sure which part is relevant, and I don't want to clutter this post.
It is a simple problem of Proxy AOP! If you use Proxy AOP for Security, then the Proxy can only intercept calles that go through the proxy. If one method invoke an other method of the same bean directly, then there is no proxy that can intercept this call. -- And this is the reason why only the the Security Annotation of save() is taken in account.
One solution would be using AspectJ AOP instead of Proxy AOP. (It is supported by Spring (Security) too.)
Yes, That is how the AccessDecisionVoter works. It takes all roles allowed on a resource(method in your case) and vote for those roles form the current authenticated user's role. If the Role is matched, then only the permission is granted.
In your case also, the only Role defined for the save method is PERMISSION_ONE so the security system will check against this role only. If logged in user has that role, this method will be executed.