I'm trying to add a new user using Spring Security programmatically using this answer. But unfortunately I get issue.
Code:
SecurityConfig:
private JdbcUserDetailsManager employeeDetailsManager;
#Bean(name = "employeeDetailsManager")
public JdbcUserDetailsManager getEmployeeDetailsManager() {
return employeeDetailsManager;
}
Application:
private static void createUser(ApplicationContext context){
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("supervisor"));
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
UserDetails user = new User("supervisor1", passwordEncoder.encode("supervisor1"), authorities);
JdbcUserDetailsManager userDetailsManager = (JdbcUserDetailsManager) context.getBean("employeeDetailsManager");
userDetailsManager.createUser(user);//Exception!
Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
On the line userDetailsManager.createUser(user) I get exception:
java.sql.SQLSyntaxErrorException: user lacks privilege or object not
found: USERS
And I understand why I get it: I really don't have a table Users. Instead of this I have table Employees, so I need to save new user in this table.
So how can I fix this error and create and save user to the table Employees?
There are fields constant storing the query.
for example, you have to
setCreateUserSql(String createUserSql)
before using createUser method.
http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/apidocs/org/springframework/security/provisioning/JdbcUserDetailsManager.html
Please refer to the constant and make sure you filled in correctly.
Related
In Java tests, #WithMockUser initialize the current user to a fake user. How to modify this user inside my test method (so after the mocked user is created) ?
Example
#Test
#WithMockUser(roles = {"USER"})
void myTest() {
// add to the current user the "ADMIN" role
}
The final aim is to use #ParameterizedTest to run a test one time per authentication provided in parameter (for example: run the same test for "ADMIN" user, for "USER" user and for "MANAGER" user).
I've tried this:
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ADMIN"));
Authentication authentication = new UsernamePasswordAuthenticationToken("username", "password", authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
But the spring context seems to not reload, so my current user has no "ADMIN" role if I check it after those lines.
We can dynamically update a logged-in user's authorities, without having to log out and log in, by resetting the Authentication object (security token) in the Spring SecurityContextHolder by using this code.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> updatedAuthorities = new ArrayList<>(auth.getAuthorities());
updatedAuthorities.add(...); //add your role here [e.g., new SimpleGrantedAuthority("ROLE_NEW_ROLE")]
Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities);
SecurityContextHolder.getContext().setAuthentication(newAuth);
But this code doesn't update authorities in database and I want to update the authorities in database tables of OAuth oauth_access_token and oauth_refresh_token tables. Actually I am working on a social app where user authorities change frequently.
Does Spring provide this feature out of the box?
Or do you have any custom Logic?
You can use TokenStore::storeAccessToken
This worked for my app, when autorities can be chaneged without user logout/login
private final TokenStore tokenStore;
public void updateAuthorities() {
var auth = (OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> newAuthorities = <Your autorities list>;
var newAuth = new UsernamePasswordAuthenticationToken(
auth.getPrincipal(),
auth.getCredentials(),
newAuthorities
);
newAuth.setDetails(auth.getDetails());
var oauth2Auth = new OAuth2Authentication(auth.getOAuth2Request(), newAuth);
oauth2Auth.setDetails(auth.getDetails());
oauth2Auth.setAuthenticated(true);
OAuth2AccessToken existingAccessToken = this.tokenStore.getAccessToken(auth);
tokenStore.storeAccessToken(existingAccessToken, oauth2Auth);
SecurityContextHolder.getContext().setAuthentication(oauth2Auth);
}
I have been following Baeldung's Spring 2FA tutorial to implement 2FA. I have created a CustomAuthenticationProvider as instructed, however it's not behaving as expected.
The odd thing is that after login, a username format that I'm not familiar with is displayed when using Principal.getName():
com.appname.models.User#69080b62
As parts of the application rely on this for fetching details, this isn't appropriate but I'm struggling to understand where I've gone wrong. I have done some research but without the correct nomenclature and the name of the format, I'm struggling to find the appropriate result.
public Authentication authenticate(Authentication auth) throws AuthenticationException {
User user = userRepository.findByUsername(auth.getName());
if(user == null) {
throw new BadCredentialsException("Invalid username or password");
}
if(user.getTwoFactor()) {
//as per tutorial
}
//this returns the "correct" username
System.out.println(user.getUsername());
final Authentication result = super.authenticate(auth);
//I suspect it's here that the issue is occurring, though any pointers in the right direction would be appreciated
return new UsernamePasswordAuthenticationToken(user, result.getCredentials(), result.getAuthorities());
}
I'm expecting the actual username rather than...however it is currently being returned - i.e. an email address of a user.
I have "solved" the problem by changing the last few lines to:
final Authentication result = super.authenticate(auth);
UserDetails userDetails = userDetailsService.loadUserByUsername(auth.getName());
return new UsernamePasswordAuthenticationToken(userDetails,
result.getCredentials(), userDetails.getAuthorities());
...where userDetailsService points to a simple implementation of the Spring Security UserDetailsService which returns a Spring Security UserDetails object, like so:
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username);
if(user == null) throw new UsernameNotFoundException(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Role role : user.getRoles()) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), user.getEnabled(), user.getNonExpired(),
user.getCredentialsNonExpired(), user.getNonLocked(), grantedAuthorities);
}
This works elsewhere in my application so I figured it might work here as well. I believe I could have left the final argument as result.getAuthorities(). I think I can also refactor so I'm not hitting the database twice, but for now I'm just glad that it works.
I'm not 100% sure why my relatively simple User model would not return the username as the Principal name, it may be that there is some more work which should be done to my User object to explicitly mark the username String as the principal name.
If anyone is interested in any further updates, or can provide any more information for anyone else experiencing uncertainty on this issue, please leave a comment or provide another (likely better) answer.
I am doing a project on library management system in spring boot security.
In order to calculate the fines for the issued books according to the roles i wan the current user role after borrowing a book.
Current user name, role book_id and fine will be stored in other table.
I am able to get the current users username, but not able to get role the current user.
Could someone please help me out!
//Part of Controller class
#RequestMapping("/homepage/borrowBook")
public String addBookings(Bookings bk, HttpServletRequest rqst) {
rqst.setAttribute("mode", "MODE_BORROW");
return "homepage";
}
#PostMapping("/homepage/save-borrow")
public String saveBorrow(Bookings bk, HttpServletRequest rqst, Authentication auth) {
rqst.setAttribute("mode", "MODE_BORROW");
if (BookRepo.exists(bk.getBook_id())) {
bk.setUser(auth.getName());
/////here i want the current user authority to be saved/checked.
bookingsRepo.save(bk);
return "homepage";
} else {
rqst.setAttribute("error", "Book doesn't exist");
return "homepage";
}
}
You can use Authentication.getAuthorities() to get the roles of the currently logged in user.
You can get the authorities using the SecurityContextHolder or through the inject Authentication object at your controller.
Find below through the SecurityContextHolder
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Collection<SimpleGrantedAuthority> list = (Collection<SimpleGrantedAuthority>) auth.getAuthorities();
for (SimpleGrantedAuthority permission : list) {
System.out.println(permission.getAuthority());
}
If you need any other information about the logged in user, you can access the UserDetails as follows
User userDetails = (User) auth.getPrincipal();
I wrote functionality using Spring Security SwitchUserFilter. In application I can switch user using /j_spring_security_switch_user?j_username=xxx URL and go back to previous using /j_spring_security_exit_user.
I also implemented several methods that depends on fact of switching user, so I want to write unit tests for them.
Therefore my question is how can I switch user in jUnit tests environment?
I wrote method which is preparing user with SwitchUserGrantedAuthority and log him in. It seems working fine for my testing purposes, but any tips and comments would be very appreciated.
#SuppressWarnings({ "rawtypes", "unchecked" })
private User logAdminAsUser(User admin, String roleName) {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken(admin, null, "ROLE_ADMIN"));
Authentication adminAuth = SecurityContextHolder.getContext().getAuthentication();
SwitchUserGrantedAuthority switchUserGrantedAuthority =
new SwitchUserGrantedAuthority("ROLE_ADMIN", adminAuth);
List authorities = new LinkedList();
authorities.add(switchUserGrantedAuthority);
User user = populator.storeUser("ROLE_USER");
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken(user, null, authorities));
return user;
}
If you want an integrational test, you should consider using a custom http client, or if your test logic depends on it, even GUI drivers like Selenium.
If we are talking about unit tests, refer to Springs
http://spring.io/blog/2014/05/07/preview-spring-security-test-method-security
documentation, they support testing heavily, #WithMockUser annotation appears to be what you are looking for, it allows you to specify with which role or user this test should be runned.
I used this:
private void switchUser(User user, String roleName)
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<GrantedAuthority> authorities =
new ArrayList<>();
GrantedAuthority ga = new SimpleGrantedAuthority(roleName);
authorities.add(ga);
Authentication result = new UsernamePasswordAuthenticationTokenExt(
user,
authentication.getCredentials(),
null,
System.currentTimeMillis()
);
SecurityContextHolder.getContext().setAuthentication( result );
}
where User is the new user, and the roleName is the new authority to set (of course this method can be modified get more params, etc.)