How can I pre-generate a BCrypt hashed password for my Spring Boot application? - spring-boot

I have a Spring Boot application (code here) with a security configuration that utilizes a BCryptPasswordEncoder:
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
I'd like to pre-generate a couple of passwords to initialize my database, for testing or for logging in on a developer machine. (Not for production.) My database is PostgreSQL and the schema is based on the Spring Security default schema, with a users table and an authorities table. My SQL statement looks like this:
insert into users (username, password, enabled) values ('joe','$2y$12$XodbOuISPCPQijlY8MIRUepDeURhxDe09/4VQU0Cno5zkTEKjZouO',true);
I don't know much about how the BCrypt hashing algorithm works, but I generated this password hash (for the password "test") using a free online BCrypt hash generator that looks legitimate. Nevertheless, I cannot log in to my Spring Boot application. The error in the logs is "bad credentials". What gives?
PS: This is a follow-up to this other question.

You can use online BCrypt generator but the thing is that the online generator might generate different regex from your Spring Segurity enconder.
For example the online generator can generate BCrypt with regex “$2y” and your Spring Boot enconder generate with “$2a” regex. If this happen you will get always bad credencials.
I strongly recommend you to generate your passwords using Spring Boot BCrypt Enconder.
#SpringBootApplication
public class QuartzJdbcJobStoreBciApplication extends SpringBootServletInitializer{
public static void main(String[] args {
SpringApplication.run(QuartzJdbcJobStoreBciApplication.class, args);
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password [] = {"Password1", "Password2", "Password3"};
for(int i = 0; i < password.length; i++)
System.out.println(passwordEncoder.encode(password[i]));
}
}

The problem turned out to be the prefix $2y in the hash. This is supposed to represent a version of the BCrypt algorithm but, according to Wikipedia, the prefix is not standard. To be clear, that online generator isn't using a non-standard algorithm, just a non-standard label.
Incidentally, the next section of the hash, $12, indicates the number of rounds of hashing, and even though it's not the same as the Spring default (10 rounds), it doesn't cause the problem.
The solution is to simply change the y for an a. $2a is the standard prefix for a BCrypt hash. You don't need to find a different BCrypt generator or anything, just edit the string.
This works:
insert into users (username, password, enabled) values ('joe','$2a$12$XodbOuISPCPQijlY8MIRUepDeURhxDe09/4VQU0Cno5zkTEKjZouO',true);

Related

Update online user-data from outside the session (without reauthentication)

There are several scenarios, where I want to update the user/principal data such that the changes are reflected while the user stays logged in (I do not want to force re-authentication)
From "within" the session this is not a Problem:
#PostMapping("/updateInfo")
fun updateMyData(
#AuthenticationPrincipal user: AppUser,
#Valid #RequestBody newInfo: UpdateDataRequest
): ResponseEntity<TestUserInfo> {
val testInfo = TestUserInfo(user, newInfo)
user.info = testInfo
val updatedUser = users.save(user)
return ResponseEntity.ok(updatedUser.info!!)
}
When I allow the user to for example change the their own data, I can easily access and change the #AuthenticationPrincipal - in successive requests i can observe that the data is updated.
This is different when I need to change the user data from 'outside' the session.
use cases
There are 2 use cases for this:
a). an administrator changes user-data
b). the user confirms his email address
Now a). clearly happens from within another http-session where the principal is a user with some admin privileges.
For b). you might ask, why this doesn't happen within a session: I want a simple one-time confirmation link, i.e. a get request. I cannot assume, that the user is logged in via a session on the device the confirmation link is opened. It wouldn't feel right to me, to do a separate preauthentication provider or something to get the user authenticated - then there will an unnecessary session opened on a browser that is never used again.
So in both cases, when I fetch the user via a JPArepository, update data, and save it back, the change is up to date in the databse - but the logged-in users don't know of that change, because their user data is stored in the http session and doesn't know that it needs to be updated.
Note that I am not using redis/spring-session anything - this is just a plain http session, so from my understanding I can not use FindByIndexNameSessionRepository.
What I have tried
In spring-security issue #3849 it was suggested by rwinch to override SecurityContextRepository - however, there is no further information on how to do that exactly - I tried to understand the interface but couldn't get much further there.
I tried to get through the responses tothe followinf SO post:
How to reload authorities on user update with Spring Security (ignoring answers using redis.)
the most upvoted answer by leo doesn't help, as mentioned in the comments there
Aure77 suggests using SessionRegistry, which I tried to use also following bealdung - but to no avail: I cannot the right session, getallprincipals() is always empty when there is an active session for a logged in user. In case I had the right session I'm still not even sure how to move on from there, as Aure just suggests using expireNow() which forces reauthentication - I want to avoid that.
alexkasko suggests something similar - from his I am thinking that maybe spring boot uses a thread-local securityContextRepository by default, and thats why i have no principals. He the suggests something that i haven'T yet understood - also the answers are quite old (2012) and I don'T feel very secure about trying to understand and apply that
TwiN suggests using a HandlerInterceptor. Hasler Choo suggests a modified version with a hashset that seems to be more close to what i need. As described below - it has its problems though.
HandlerInterceptor based approach
This is the only solution so far that I could successfully implement - but it doesn't seem very flexible. My implementation so far will only cover user-role changes.
Configuration:
#Configuration
class WebMvcConfig : WebMvcConfigurer {
#Autowired
private lateinit var updateUserDataInterceptor : UpdateUserDataInterceptor
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(updateUserDataInterceptor)
}
}
The HandlerInterceptor:
#Component
class UpdateUserDataInterceptor(
#Autowired
private val users: AppUserRepository
) : HandlerInterceptor {
private val usersToUpdate = ConcurrentHashMap.newKeySet<Long>()
fun markUpdate(user: AppUser) = usersToUpdate.add(user.id)
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
val auth = SecurityContextHolder.getContext().authentication
(auth.principal as? AppUser)?.apply {
synchronized(usersToUpdate) {
if (id in usersToUpdate) {
role = users.findById(id).get().role
usersToUpdate.remove(id)
}
}
}
return true
}
}
Instead of just updating the role, what I would rather like, is just replace the entire principle - but the principal is final in the Authentication object.
So whenever a would wnat something else than the role updated, this has to specifically be mentioned here.
Remaining questions:
Are there other solutions than the HandlerInterceptor?
Is there a HandlerInterceptor based solution, that allows me to fully update the principal object
I am not considering single instance applications
1. Three factors in play
How quickly you want the changes reflected ( current session and current request vs current session and next request vs next session)
Do you have to keep the response time minimally affected by using distributed memory or cache?
Do you want to cut the cost (cannot use distributed memory) at the expense of response time?
Now you can you choose one option from first factor. But with second and third factors, you optimise one factor at the expensive of other one. Or you try to find a balance like your attempt to keep a list of affected users in memory and then hit the database for those affected.
( Unfortunately your optimisation to keep list of affected users in UpdateUserDataInterceptor as it is not stored in distributed memory won't work unless it is a single instance application)
2. Now based on my understanding of your question, I am making the following answers to the three factors in play.
current session next request
reduced cost (no distributed memory)
performance hit with database calls
( I will later update my thoughts on other possible paths and possible implementations for those paths)
3. Implementation options for the selected path - next-request-with-db-calls-and-no-distributed-memory
Any component that is part of request filter chain with the ability to call the database can achieve this by updating the SecurityContext. If you do this in the SecurityContextRepository, you are doing it at the earliest opportunity and you may even have the opportunity to restore the SecurityContext with updated principle instead of updating the already created SecurityContext. But any other filter or Interceptor can achieve this too by updating the SecurityContext.
4. Detailed look into each Implementation
SecurityContextRepository Option :
Looking at the HttpSessionSecurityContextRepository, it seems straight forward to extend it.
public class HttpSessionSecurityContextRepository
implements SecurityContextRepository {
.....
public SecurityContext loadContext(HttpRequestResponseHolder reqRespHolder) {
HttpServletRequest request = reqRespHolder.getRequest();
HttpServletResponse response = reqRespHolder.getResponse();
HttpSession httpSession = request.getSession(false);
SecurityContext context = readSecurityContextFromSession(httpSession);
........
//retrieve the user details from db
//and update the principal.
.......
return context;
}
}
SecurityContextHolderStrategy Option
Looking at the ThreadLocalSecurityContextHolderStrategy, it also looks straightforward
final class ThreadLocalSecurityContextHolderStrategy
implements SecurityContextHolderStrategy {
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();
....
public void setContext(SecurityContext context) {
// you can intercept this call here, manipulate the SecurityContext and set it
Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
contextHolder.set(context);
}
.....
}
Another filter or HandlerInterceptor //TODO WILL UPDATE
Note:
You mentioned principal is final in authentication object and you want to replace it. You can achieve this by creating a mutable wrapper of UserDetails, extending your current UserDetailsService and returning that wrapper. Then you can update the principal,
YourWrapper principalWrapper =(YourWrapper) securityContext
.getAuthentication().getPrincipal();
principalWrapper.setPrincipal(updated);

Springboot allow access to endpoint if userId matches

I am following up from this question:
How to configure Spring Boot Security so that a user is only allowed to update their own profile
Imagine I had an end-point /user/edit/{id}, I want this to be accessible if the user either tries to edit themslves (eg: a user with ID 1 accessing /user/edit/1 but not being able to access user/edit/2) or, if they are an admin, to be able to edit any user.
Is there any way I can achieve this in the security configuration?
.antMatchers("/user/edit/**").hasRole("ADMIN")
Would restrict this to admin users, I want either admin or the id matching the user's id.
The only thing I can think of is inside the controller having something like
#GetMapping("/edit/{id}")
public void edit(#PathVariable("id") int id, Principal principal) {
User u = (User) userDetailsService.loadUserByUsername(principal.getName());
if(u.getId() == id || u.getRoles().contains("ADMIN")) {
//accept uer
}
}
But I was under the impression we shouldn't encode access logic in our controller?
It is possible to use Spring Security's Method Security Expressions to do this. Example copied from the docs:
#PreAuthorize("#c.name == authentication.name")
public void doSomething(#P("c") Contact contact);
Read the sections preceding, as there is some configuration needed. Also note that if an expression is used repeatedly you can define your own security annotations.
I was under the impression we shouldn't encode access logic in our
controller?
"Should" is maybe too strong a word, IMHO. Security expressions are powerful, and in theory would allow you to keep all security checks separate from the controller logic. Easier to spot when a check is wrong, or missing. Easier to compare with the Swagger annotations too, if you are using those to document your endpoints.
But it can get trickier when you have to do something like filter rows returned so that the user only sees some of the results. Spring Security can do that using #PostFilter. But sometimes it isn't optimal. For example, if you know that certain rows aren't going to be returned you may be able to run a faster query, rather than filter out rows after the fact.
My first Spring Security project had queries like that, so ever since I have tended to use controller logic instead of security annotations. But that's not a good reason to never use annotations! So by all means use security expressions when you can, but if you have trouble with them or other considerations arise, integrating security with your controller logic isn't so bad IMHO.
To control role access in your controller you can use annotations like #Secured or #PreAuthorize.
To use the #Secured, put in you security config class:
#EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
// ...
}
And now you can use it in your controller:
#Secured("ROLE_ADMIN")
#PostMapping
public Account post(Account account, double amount){
// ...
}
To use the #PreAuthorize, put in you security config class:
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
// ...
}
And now you can use it in your controller:
#PreAuthorize("hasAuthority('ROLE_ADMIN')")
#PostMapping
public Account post(Account account, double amount){
// ...
}
For more information you can check here the spring docs.

Does Spring Security's RunAsManagerImpl work?

Is this a bug in Spring Security's RunAsManagerImpl, or are my expectations wrong?
My understanding of the (limited) documentation, is that with a RunAsManagerImpl defined in my config if I call doFoo() in the following:
#Secured({"ROLE_FOO", "RUN_AS_BAR"})
public void doFoo() {
doBar();
}
#Secured("ROLE_BAR")
public void doBar() {
// ...
}
then, provided the current Authentication has the role "FOO", doBar() will execute successfully.
But it doesn't, Spring throws an AccessDeniedException. However, changing doBar()'s annotation to:
#Secured("ROLE_RUN_AS_BAR")
works successfully.
Upon examination of the source code, the reason is fairly clear - if it encounters an attribute that starts with "RUN_AS_", it creates:
GrantedAuthority extraAuthority = new SimpleGrantedAuthority(getRolePrefix() + attribute.getAttribute());
where, by default:
private String rolePrefix = "ROLE_";
So the authority that is applied is "ROLE_RUN_AS_BAR", which doesn't seem right at all. Is this a bug that I should raise, or have I misunderstood the intended use of this functionality?
It's the expected behavior, as described in the documentation:
The created GrantedAuthorityImpls will be prefixed with a special
prefix indicating that it is a role (default prefix value is ROLE_),
and then the remainder of the RUN_AS_ keyword. For example, RUN_AS_FOO
will result in the creation of a granted authority of ROLE_RUN_AS_FOO.
The purpose of such basic implementation is not to impersonate a user, but to acquire a "technical role". For example, some part of your code should require a technical role of "database manager". No user has this role but I can be acquired programmatically.
Of course, you can bypass this code by just updating the Authentication in SecurityContextHolder, but having a central implementation point to "upgrade" an Authentication object can be more secure when used by a jvm securitymanager.
However, the RunAsManager is a really simple interface, in order to be easily reimplemented: If the default behavior doesn't match what you need, you only have one method to reimplement.

Spring security with Hibernate, store encrypted passwords

I'm sure this has been asked before, but I can't find anything that answers this problem.
With Spring-security, I'm using a password encoder.
<beans:bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder"/>
<authentication-manager>
<authentication-provider user-service-ref='CustomUserDetailsService'>
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
Within my UserDAOImpl I have the following code when adding a user...
#Override
public void addUser(final User user) {
user.setPassword(passwordEncoder.encodePassword(user.getPassword(), "salt"));
sessionFactory.getCurrentSession().save(user);
}
My password gets encoded correctly, but always gets read as invalid, which sort of makes sense as I don't know how Spring would know my salt was "salt" - how do you tell spring security as well as Hibernate to use the same salt? Am I missing something about how spring security manages passwords?
The recommended way is to use a standard password encoder, that will use a random salt, ans store this salt with the digested password. This way, you don't need to provide any salt. If you want to provide your own salt, then you need to inject a SaltSource into the DAO authenticator, as explained by the documentation (and of course use the same source when you encode the password to create a new user):
The StandardPasswordEncoder in the crypto package uses a random 8-byte
salt, which is stored in the same field as the password.
Note
The legacy approach to handling salt was to inject a SaltSource into
the DaoAuthenticationProvider, which would obtain a salt value for a
particular user and pass it to the PasswordEncoder. Using a random
salt and combining it with the password data field means you don't
have to worry about the details of salt handling (such as where the
the value is stored), as it is all done internally. So we'd strongly
recommend you use this approach unless you already have a system in
place which stores the salt separately.
In your case, the SaltSource would always return the "salt". Note that this way of salting is insecure, because all the users sharing a common password (yes, it happens) end up with the same hashed password. This means that an attacker finding the password of one user also finds the password of all the users sharing the same password.

Implementing remember me without a key

i found some samples that implements remember me functionality by just
<remember-me/>
and other samples implement it as:
<remember-me key="_spring_security_remember_me"/>
and i want to know what is the difference between the two declarations, and is the _spring_security_remember_me is a predefined key?
thanks.
The default key can be found in AuthenticationConfigBuilder.createRememberMeFilter()
final String DEF_KEY = "SpringSecured";
That is the value that is used if you don't specify one in <remember-me>
From the documentation, the key attribute is used in hashing the value stored in the cookie. It prevents a malicious user from trying to decode the cookie, because they can't do that (well it s a lot harder) without the key.
For anyone looking for the rememberme().key() feature in the future, it seems that as of Spring Boot 2.2.6 there is SecureRandom generator to generate the key if it is not provided. Here is the implementation found in org.springframework.security.config.http.AuthenticationConfigBuilder.createRememberMeFilter
private String createKey() {
SecureRandom random = new SecureRandom();
return Long.toString(random.nextLong());
}

Resources