Decode the Bcrypt encoded password in Spring Security to deactivate user account - bcrypt

I am working on web application project in Spring Hibernate MVC. I am storing encoded passwords in a database using Bcrypt algorithm in Spring security.
Now I want to get that encoded password to be decoded to deactivate a use account where in I am giving user email and password to verify before user deactivate the account. I have a problem in getting the decoded password.
Can anyone help me to get out of it or any alternate solution for my requirement?

The problem is solved by using below code:
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
encoder.matches(password, user.getPassword());
password - from form(JSP)
user.getPassword() - from database
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
if(email.equalsIgnoreCase(user.getEmail()) && encoder.matches(password, user.getPassword())) {
userService.deactivateUserByID(user.getId());
redirectAttributes.addFlashAttribute("successmsg", "Your account has been deactivated successfully.");
model.setViewName("redirect:/logout");
}else{
redirectAttributes.addFlashAttribute("errormsg", "Email or Password is incorrect");
model.setViewName("redirect:/app/profile/deactivate");
}

BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
boolean isPasswordMatches = bcrypt.matches(userenteredpasswordWithotEncryoted, encryptedPasswordFromDb);
Example:
boolean isPasswordMatches = bcrypt.matches(
"Truck123",
"$2a$10$kcVH3Uy86nJgQtYqAFffZORT9wbNMuNtqytcUZQRX51dx6IfSFEd."
);
if (isPasswordMatches) { // correct password
...
} else { // Wrong Password
...
}

Related

Retrieve plain password from database from Spring security without decrypting

I have a requirement where I need to store plain text password from a application I downloaded a project
from git hub https://github.com/bezkoder/spring-boot-spring-security-jwt-authentication .It is getting
stored in the database as plain text which is what I want as per my tweak where I remove encoding(My
requirement).The problem occurs when I signin using the username and password.I am not able to find where
password is getting decrypted and checked.The login fails with a message Login failed:
Error: Unauthorized.
In the logs I see:
Unauthorized error: Bad credentials
o.s.s.c.bcrypt.BCryptPasswordEncoder : Encoded password does not look like BCrypt
I know where it is throwing exception
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
How to read plain text password from database using the above code.
It' in the class WebSecurityConfig on line 50 to 52:
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
If you really need plain text password then you can use
#Bean
public PasswordEncoder passwordEncoder() {
return new NoOpPasswordEncoder();
}
But this will be highly unsave.

Decode a password before login Spring Boot

I have a login form with spring security jdbc authentication, it works well with normal form submission.
Now i've encrypted the user password on client side with javascript, i use cryptoJs and the encrypted password is submitted to the server, the problem is that i have to decode the password before let spring check the password hash in the database and i can't figure how to do that, i've tried with a custom filter
public class LoginFilter extends UsernamePasswordAuthenticationFilter{
public LoginFilter(AuthenticationManager auth){
super.setAuthenticationManager(auth);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException{
//Decode password
return super.attemptAuthentication(request, response);
}
}
it intercept the request, i can get the password and decode it but i can't pass to the UsernamePasswordAuthenticationFilter, how can i pass to spring the decoded password instead of the encoded submitted by the user?
P.S. I'm not using Https and i know that javascript encryption is probably useless
Yep, ideologically it's really understandable - if you receive an encrypted password, so you can get and store a password hash, and later check it (I think no one framework stores and compares real passwords, just their hashes). But this is your own problem and you will solve it from your side ...
Really, you cannot set request parameters anywhere, but you can set a new request attribute and anywhere to get it from request: request.setAttribute("<string key>", <object value>); and var value = (String) request.getAttribute("<string key>");
I've found a solution, not sure if it is the best possible but it works, Spring uses a PasswordEncoder object to check that the password typed by the user match the stored (and hashed) password.
I was using a BCryptPasswordEncoder which uses the method matches(rawPass,encodedPass) to check the password, so i've created my own PasswordEncoder in this way
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.usersByUsernameQuery(USER_QUERY)
.authoritiesByUsernameQuery(ROLE_QUERY)
.dataSource(dataSource)
.passwordEncoder(new PasswordEncoder(){
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
// Decoding stuff on the encrypted password sended by the client (rawPassword)
return encoder.matches(decryptedPassword, encodedPassword);
}
#Override
public String encode(CharSequence rawPassword) {
//Same crypto operation to get the plain password
return encoder.encode(decryptedPassword);
}
});
}
so the client send the encrypted password to the server, the custom PasswordEncoder decrypt it to get back the plain password then pass it to the BCryptPasswordEncoder, Spring security will handle the rest of the authentication process

Extending a Jhipster JWT (Spring) monolith application to support impersonation

I have generated a jhipster angular/java application that is using JWT authentication.
I now want to extend the application to support impersonation.
I am interested in achieving the following:
Impersonation by admin: Allowing the admin user to login as any other user
Impersonation granted to user: Allowing another user that has been granted the right to impersonate a user (granted by the user itself) to login as that other user.
Audit - recording changes (audit function) - the audit trail must be able to distinguish between the actual user and an impersonated user and record this in the audit trail.
I see that Spring supports impersonation but it is unclear to me how I can implement it properly in my Jhipster application given that JWT is used. I am not sure if the Spring route is appropriate for JHipster-JWT-Monolith application - I am of the opinion that it not the right approach.
While there are some incomplete information on various other posts, after an extensive search I have been unable to find a post that can provide clear step by step guide on this. If somebody can do that for me it would be greatly appreciated. I expect others would also find such an answer very useful.
Thanks in advance.
Fergal
You just need to add below method in UserJwtController.java
#PostMapping("/authenticate-externalnodes")
public ResponseEntity<JWTToken> authenticateExternalnodes(#Valid #RequestBody LoginVM loginVM) {
// Get Roles for user via username
Set<Authority> authorities = userService.getUserWithAuthoritiesByLogin(loginVM.getUsername()).get()
.getAuthorities();
// Create Granted Authority Rules
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Authority authority : authorities) {
grantedAuthorities.add(new SimpleGrantedAuthority(authority.getName()));
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
loginVM.getUsername(), "", grantedAuthorities);
Authentication authentication = authenticationToken;
SecurityContextHolder.getContext().setAuthentication(authentication);
boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
String jwt = tokenProvider.createToken(authentication, rememberMe);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK);
}

Detected a Non-hex character at 1 or 2 position

I am using spring boot 2.0.5 and used following code for password encoding.
#Bean
public PasswordEncoder delegatingPasswordEncoder() {
PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
DelegatingPasswordEncoder passworEncoder = new DelegatingPasswordEncoder(
"bcrypt", encoders);
passworEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder);
return passworEncoder;
}
By the way,i generated encoded password using the above code from another project. Because in my current project i did not generate encoded password and i just copied that encoded password in my current projects database. The encoded password looks as below.
{bcrypt}$2a$10$DPOPug/9As2jwQzW3Ezr1u3LE31kFaMR/z/8bMpQYHQUJ0b6NyZri
The problem is when i use the password to login from the project where i generated the encoded string it works well. But when i use the same password to login from my current project it does not work. Please tell me the reason.
Replace your method with the below method.
#Bean
public PasswordEncoder delegatingPasswordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
Reference : https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#constructing-delegatingpasswordencoder

UserDetails getPassword returns null in spring security 3.1. How to get password of currently logged in user?

I have implemented change password functionality using spring security but ((UserDetails) principal).getPassword()) is returning null for logged in user.
If I remember correctly, this used to work earlier in 3.0. Was this changed in 3.1 so that the current password of the logged in user cannot be retrieved?
In the below code I am checking the current password typed in user password from the web page. I am then checking if the logged in user's password matches the typed in password. If it does then I want to set oldPasswordMatchNewPassword = true.
How do I implement this functionality?
#RequestMapping(value = "/account/changePassword.do", method = RequestMethod.POST)
public String submitChangePasswordPage(
#RequestParam("oldpassword") String oldPassword,
#RequestParam("password") String newPassword) {
Object principal = SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
String username = principal.toString();
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
System.out.println("username: " + username);
System.out.println("password: "
+ ((UserDetails) principal).getPassword());
if (((UserDetails) principal).getPassword() != null) {
if (((UserDetails) principal).getPassword().equals(oldPassword)) {
oldPasswordMatchNewPassword = true;
}
}
}
if (oldPasswordMatchNewPassword == true) {
logger.info("Old password matches new password. Password will be updated.");
changePasswordDao.changePassword(username, newPassword);
SecurityContextHolder.clearContext();
return "redirect:home.do";
} else {
logger.info("Old password did not match new password. Password will be not be updated.");
return null;
}
}
I put a couple of sysout()s so that I can see the values returned.
For ((UserDetails) principal).getUsername() I can see the correct logged in user.
((UserDetails) principal).getPassword() it is returning null.
How do I get ((UserDetails) principal).getPassword() this value?
Thanks in advance!
I used this block of code (erase-credentials="false") to fix this. I do not know if this is an elegant solution but it fixed my problem:
<authentication-manager alias="authenticationManager" erase-credentials="false">
<!-- authentication-provider user-service-ref="userService" -->
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" />
</authentication-provider>
</authentication-manager>
Yes, this has changed in version 3.1. Credentials are cleared after a successfull authentication by default. You can set eraseCredentialsAfterAuthentication to false on the ProviderManager to prevent this.
See details here: http://static.springsource.org/spring-security/site/docs/3.2.x/reference/core-services.html#core-services-erasing-credentials
Since the password isn't retained in memory after the user has been authenticated (generally a good thing), you would need to explicitly reload it in order to use it. An alternative and more flexible strategy is to inject an instance of the AuthenticationManager and use that directly:
String name = SecurityContextHolder.getContext().getAuthentication();
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(name, oldPassword));
// Update password here with your dao
} catch (AuthenticationException e) {
// Old password was wrong
}
that way you don't need to worry about things like password-encoding strategies. Note that you shouldn't be storing passwords in plain text. They should be hashed using bcrypt or something similar.

Resources