I am trying to convert a Spring Security 3 #Secured("admin") annotation into Spring Security 4 compatible fashion.
This is my usersService.java
#PreAuthorize("hasAuthority('admin')")
public List<User> getAllUsers() {
return usersDao.getAllUsers();
}
Then in security-context.xml I have:
<security:intercept-url pattern="/admin" access="permitAll" />
...
<security:global-method-security pre-post-annotations="enabled" />
getAllUsers() is called by a LoginController.java
#RequestMapping("/admin")
public String showAdmin(Model model) {
List<User> users = usersService.getAllUsers();
model.addAttribute("users", users);
return "admin";
}
In mySql database, there are two tables, users and authorities. authorities has 2 columns, username and authority. administrator has authority admin.
Now if I trie to access /admin, I will be redirected to /login, but after I log in with administrator, I still get "access denied".
I think I must have missed something very basic but as I am new to Spring, I could not figure it out. Any help would be appreciated. Thanks.
Update: I tried changing the annotation to #PreAuthorize("hasRole('ROLE_ADMIN')") and I also changed the "authority" column in mySql for admin from "admin" to "ROLE_ADMIN" but it still gives me 403. I did not have much faith on this because before this error, I had to change hasRole('admin') in securityContext.xml to hasAuthority('admin').
Although it's late, nevertheless
hasRole(...) set a prefix for the the content - the default one is ROLE_
hasAuthority(...) checks the content WITHOUT a prefix, i.e. just the pure content
You should add in Spring security
#EnableGlobalMethodSecurity(prePostEnabled = true)
Try this #PreAuthorize("hasRole('ROLE_ADMIN')")
Related
I am using #Secured("ADMIN"), my role definition is also ADMIN (not ROLE_ADMIN). When I access the API, I am not getting the expected value, it says access denied.
Below is the code, how I have overridden ROLE_ value
#PostMapping("/users")
#Loggable
#Secured({"Administrator"})
public ResponseEntity<?> createUser( #Valid #RequestBody User userRequest) {
.....
}
Implemented CustomAccessDecisionManager where the role prefix (setRolePrefix("")) was set to empty and the CustomDecisionManager was configured in my security configuration file.
The empty role prefix is working fine, the code is below for that
.authorizeRequests().anyRequest().authenticated()
.accessDecisionManager(customAD()).hasRole("ADMIN")
But it's not working when I use #Secured.
My DB contains role as USER1, USER2.
Any help is greatly appreciated. Thank you.
When I have spring security settings as below:
<http pattern="/ui/**" auto-config="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/ui/login*" access="isAnonymous() or hasRole('USER')" requires-channel="${web.channel}" />
<intercept-url pattern="/ui/**" access="hasRole('USER')" requires-channel="${web.channel}" />
<form-login login-page="/ui/login" login-processing-url="/ui/j_spring_security_check" default-target-url="/ui/dashboard" />
<logout logout-url="/ui/logout" logout-success-url="/ui/login" />
</http>
my controller is ignored and both methods are never invoked. I've tried adding breakpoints inside both of them but the execution never stops. I have also tried adding System.out.println() to them and nothing was written to system output, so I am pretty sure both methods are either not mapped or just never invoked.
#Controller
public class MyController {
#RequestMapping(value = { "/ui", "/ui/login"}, method = GET)
public String indexNoTrailingSlash() {
return index();
}
#RequestMapping(value = "/", method = GET)
public String index() {
return "redirect:/ui/dashboard";
}
}
Security works fine and thanks to default-target-url="/ui/dashboard" in the xml I do get to my dashboard page after successful login. What I want to achieve is, however, that a user is redirected to dashboard also if he's already logged in. I've tried to follow this answer and that's what I need the controller for. Is there a way either to map these methods so I can use my controller for redirecting or to somehow redirect with just spring security?
Thanks :)
If the answer link you included is what you look for, do the following for your case.
return new ModelAndView("redirect:/");
It will redirect to your index() method.
I have a web application built using Java Spring MVC.
I'm just setting up spring security connecting to an LDAP server for authentication.
I've successfully set it up so that I am able to login to my application but I can't find anything to help me in mapping an AD group to a user role within Java as I can only get a 403 forbidden page i.e. I've been authenticated but don't have permissions yet.
I currently have:
<http auto-config="true">
<intercept-url pattern="/**" access="ROLE_USER" />
</http>
<ldap-server id="ldapServer" url="LDAPURL" manager-dn="USER" manager-password="PASSWORD" />
<authentication-manager >
<ldap-authentication-provider
group-search-base="OU=GROUPS"
group-search-filter="sAMAccountName={0}"
user-search-base="OU=USERS"
user-search-filter="sAMAccountName={0}"
/>
</authentication-manager>
Say that user was a part of the AD group g-group-UK-user I then want to be able to map that AD group to ROLE_USER so that user can then see the whole web app.
I can only seem to find very simple examples where the groups are either ADMIN or USER in which case the prefix ROLE is just added to the group or the other method seems to be using UserDetailContextMapper but I can't find a clear use of this.
To do this I used the following within authentication manager:
user-context-mapper-ref="customUserContextMapper"
I then used the following class to check if that user belongs to a certain AD group and then assign the ROLE_USER role to their authorities:
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities)
{
Attributes attributes = ctx.getAttributes();
Object[] groups = new Object[100];
groups = ctx.getObjectAttributes("memberOf");
LOGGER.debug("Attributes: {}", attributes);
Set<GrantedAuthority> authority = new HashSet<GrantedAuthority>();
for(Object group: groups)
{
if (group.toString().toLowerCase().contains("AD_GROUP_NAME".toLowerCase()) == true)
{
authority.add(new SimpleGrantedAuthority("ROLE_USER"));
break;
}
}
User userDetails = new User(username, "", false, false, false, false, authority);
return userDetails;
}
Please note that the class is a little more complicated than usual because of the LDAP server I was connecting which has a different structure than usual in that the groups a user has access to are stored in an attribute under the user and not the other way round in which a group would have as an attribute all the users that belong to it.
I have an Vaadin 7 application working with Spring and currently there is one ADMIN role that can log in into the system and see all views. Now I need to add another role let's say CO_ADMIN and allow user with this role to view part of views. What is the best way to achieve this?
Thanks
If you use spring security you can make a helper class with the following methods:
public static boolean hasRole(String role) {
return getPrincipal().getAuthorities().contains(new SimpleGrantedAuthority(role));
}
public static UserDetails getPrincipal() {
return (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
Then you can define what roles each part of your view needs programatically:
Panel panel = new Panel("securedpanel");
if (SecurityUtils.hasRole("ADMIN")) {
//panel.setVisible(false);
panel.setEnabled(false);
}
If you want to secure the whole view, you can enable the #Secured annotation in the spring security config xml:
<global-method-security secured-annotations="enabled" />
With #Secured enabled you can annotate your views like this:
#Secured("{ADMIN}")
This way if the user navigates to the view, it responds with 403 permission denied. You can extend your navigator to handle this by redirecting to another view or define an errorhandler for your application.
My requirement is as below:
In our application the user's credentials are validated against the database(not using spring security since it is a legacy application) for the first time. If the user is a valid user, he will be logged into the application. Once the user logs into the application he can make few rest calls. Now, I want to once again validate the user's credentials by using spring security before making any rest call. Here, the challenge is we should not redesign the database schemas. We need to use a stored procedure which validates the user. This particular stored procedure returns an error message if authentication fails, otherwise nothing is returned. There are no roles defined in this case. Just simple authentication using a stored procedure. Now, I want to accomplish this whole thing by spring security. May be writing a java class/ custom spring framework's class and in which the stored procedure is called and using that class in spring security configuration files. Can anybody suggest ideas on how to start up with please?
I have implemented AuthenticationProvider. The following is the *security.xml.
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/rest/*" access="permitAll"></intercept-url>
</http>
<authentication-manager >
<authentication-provider ref="csAuthenticationProvider" />
</authentication-manager>
But, the security framework is looking for roles. In my case there are no roles defined. As I said earlier, the user is authenticated for the first time without using spring framework. If the user wants to make any rest call, the spring security needs to re authenticate the user. It doesn't mean that the user needs to re enter credentials. The user's credentials are available in the rest call/request since he is already authenticated. The only thing needs to be done is I need to use the credentials by using request and re validate using the stored procedure. of course, using AuthenticationProvider may be a good idea, but the parameter "Authentication authentication" of the authenticate(Authentication authentication) method is not useful for me since I need to call my own stored procedure call again. for time being, I did not used the Authentication object, but instead used the stored procedure calling code in the authenticate() method. But, strangely, authenticate() method is not getting called. I am surprised and in confusion. Does any body has any ideas on where I am doing wrong?
Sounds like you need to implement an Authentication Provider. Here's a pretty simple example that I think you could adapt to call your stored procedure.
http://danielkaes.wordpress.com/2013/02/20/custom-authentication-provider-in-spring/
You can implement your own UserDetailsService and configure spring to use it.
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsServiceImpl"/>
</security:authentication-manager>
You need to create a custom UserDetailsService implementation, that will check against the DB.
Here is an example UserDetailsService implementation that does just that:
#Service("userService")
public class UserDetailsServiceImpl implements UserDetailsService, InitializingBean {
#Autowired
private AccountService accountService;
public void afterPropertiesSet() throws Exception {
}
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
username = username.toLowerCase();
try {
Account account = accountService.loadUserAccountByEmail(username);
if (account == null) {
throw new UsernameNotFoundException("Could not find email: " + username + "in the DB.");
}
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
for (Role r : account.getRoles()) {
auths.add(new SimpleGrantedAuthority(r.getRole()));
}
ApplicationUser user = null;
try {
user = new ApplicationUser(new Long(account.getId()), username, account.getPassword(), true, true, true, true, auths);
} catch (Exception ex) {
ex.printStackTrace();
}
return user;
} catch (Exception e) {
e.printStackTrace();
throw new UsernameNotFoundException(username + "not found", e);
}
}
}
Which I config in code like so:
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsServiceImpl)
.passwordEncoder(bCryptPasswordEncoder());
}
(you can also see a blog post I wrote about switching from xml to #annotation config for spring security referncing that project here: http://automateddeveloper.blogspot.co.uk/2014/02/spring-4-xml-to-annotation-configuration.html)