Spring Security 5 programatically validate a username and password - spring-boot

I have a grails 5 Spring Security app (that i've recently migrated from grails 3). Spring Security 4+ uses a different password scheme where it includes the algorithm, salt and hashed password all in the password field delimited like so: "{algorithm}{salt}{hash}"
This all works fine. I've appended "{SHA-256}" to the start of existing passwords, and authentication is working for the web app.
The problem is that I have an API section of my app that uses basic auth which I manually authenticate in my controllers (not using spring security). This is simple and stateless and works well for my purposes. Problem is, I can no longer validate usernames and passwords when I create new users which Spring Security adds a salt for.
Old code that worked before adding salt to new users was effectively:
String sha256hex = DigestUtils.sha256Hex(password);
String dbHashedPw = "{SHA-256}${sha256hex}"
user = User.findByUsernameAndPassword(email, dbHashedPw)
This doesn't handle salt, or iterations, so does not work on passwords generated for new users.
I've tried enabling grails.plugin.springsecurity.useBasicAuth: true (in application.yml) but this perhaps was misconfigured since it seemed to have no effect.
I've also tried improving my code above to work with the salt and iterating in the same manner as Spring Security does, but it becomes complicated and doesn't seem like the best way to do it.
What I want is an interface like:
boolean springSecurityService.validatePassword(UserDetails userDetails, String password)
Where Spring Security would grab the password from the database and use the markup describing the algorithm and the salt, and do the appropriate hashing on password and compare the two, returning a boolean if the password matches.
It seems like this should be simple, but I've now spent over a full day hacking around it with no success. Any help would be appreciated!

Answering my own question with a workaround I've found. I couldn't find the springSecurityService interface that I wanted, but I did find I could emulate the old grails 3 password encoding by not calling spring security in User.groovy, and instead doing the following:
import org.apache.commons.codec.digest.DigestUtils
...
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = "{SHA-256}" + DigestUtils.sha256Hex(password)
}
Note I'm relying on apache library: 'commons-codec:commons-codec:1.11' to do the hash.
Of course, it should be mentioned that SHA-256 is not considered secure any more and this is only for backwards compatibility before a migration is possible.

Related

Impossible to my mind not to see the password as plaintext sent to server via Swagger

The task that one asks to me seems to me really impossible.
We use Spring, and Swagger UI to test the Back-End Spring.
We have a Rest controller with a method for the login presenting 2 parameters annotated #RequestParameter (one for the login, and the second one for the password).
#PostMapping("/login")
public JSONObject login(#RequestParam(name = "username")String username, #RequestParam(name = "password")String password ){
return null;
// controller for Swagger-UI
// managed by Spring security
}
Necessarily, we send to the server an HTTP request with the password as plaintext :
https://myserveraddress:8443/MyApplication/login?password=mySecretPassword&username=myLogin
One asks me to "hide" in the URL the password, to hide the value of the parameter called password sent to the Backend server, without changing the signature of this method.
I need an advice.
It seems to me impossible.
I have no idea.
Even by replacing #RequestParameter by #RequestHeader, the value of the password will be sent to the server (hopefully) and see.
I am within inches of saying it's not possible.
Thanks a lot for your help to confirm or infirm by giving me a miraculous solution.

Set and update Keycloak/OpenId-Connect Claims in Client application

I'd like to know if and how it is possible to set and update Keycloak (OpenID-Connect) AccessToken or IdToken attributes (so called Claims) by a client web application, after successful authentication.
The use case is to add specific user-attributes (e.g. number of pets, hair color, favorite car, etc.) to the Access- or Id-Token, while the user is logged in to our web application based on a Vue.js Frontend and a SpringBoot Backend, mainly exposing REST Services to the Frontend.
A second web-application, also using the Keycloak Token for user authentication/authorization (Single-Sign-On feature) should be able to read the user-attributes added by the first web-application to the Token.
Even I'm afraid that adding and changing of Token payload is not allowed by architectural design of OpenId-Connect, I nevertheless hope it will be possible anyhow.
Token-attributes are implemented as 'Claims' in OpenId-Connect. And Keycloak supports 'Claim' mappings during the authentication process (set by static mappings on Keycloak server as well as by code that runs on the Keycloak server).
The appropriate methods to set and get Claim key-value pairs are mentioned by the following articles:
How to create a Script Mapper in Keycloak?:
token.getOtherClaims().put("myClaimName", "claim value");
Include user locale to the Keycloak ID token:
Map<String, Object> otherClaims = token.getOtherClaims();
if (otherClaims.containsKey("myClaimName")) {
String claimValue = String.valueOf(otherClaims.get("myClaimName"));
}
For the case changing of Token payload by Keycloak clients is not allowed by architectural design, I appreciate any suggestion on best practices to hand over dynamically added user-attributes from one webapp to another webapp, having the same Keycloak Access- and/or Id-Token in common.
Yes, changing of token payload by user application is not allowed/possible by architectural design. App doesn't own private key, which is required to create proper token signature, when you change payload.

Spring Boot Facebook Starter how to login several users? how to obtain accessToken or providerId

I've followed several tutorials and got really close to nowhere understanding spring integration with facebook API, having strong knowledge in other spring modules I found myself surprised...
Every tutorial uses:
public <A> Connection<A> findPrimaryConnection(Class<A> apiType) {
String providerId = getProviderId(apiType);
if (connections.containsKey(providerId)) {
return (Connection<A>) connections.get(providerId).get(0);
}
return null;
}
As this returns me first connection every time?
I've tried connecting to my app from two different machines and both requests return same facebook profile..
So as usual I went to investigate api what is required to obtain user-specific-connection when stumbled upon method which does what I want:
public <A> Connection<A> getConnection(Class<A> apiType, String providerUserId) {
return (Connection<A>) getConnection(new ConnectionKey(getProviderId(apiType), providerUserId));
}
Ok, so I went trying to figure out how to obtain providerId... I fail, many questions such as:
How to get providerUserId by providerId, accessToken and secret? (Spring Social)
don't make it clearer.
It seems I am not the first to fail understand philosophy of Spring integration with facebook. As to many of us it is obvious that we want to use advanced features where every user needs to have it's own connection to facebook with its own data returned and possibility to login via facebook.
Could you kindly please explain how to get connection/facebook object per user as I am very disoriented by the implementation of this spring module.
Does Spring Social Facebook even support concurrent users logged in to Facebook? It all feels to me like building beautiful Eiffel tower without any doors.
I didn't use Spring Security integration as I felt ConnectController approach will provide more control, but apparently it does not and has biased assumptions. Now looking at Spring Security integration.
I tried thi myself some month ago and found it also very confusing.
For me it looked like as if all this spring-social stuff is trying to identify a user of your web-app interactively using OAuth.
What I was looking for was connecting my spring application to facebook to e.g. post something there.
For this purpose you can use the FacebookTemplate and forget about the provider etc. :
public String postOnFacebook(Machine machine, String url) {
Facebook facebook = new FacebookTemplate(accessToken);
FacebookLink link = createLink(machine, url);
// the first parm is the title on top of the message
String message = facebook.feedOperations().postLink("message", link);
return message;
}
You need an accessToken for the facebook account, which is a different story. Finally this helped :
http://www.slickremix.com/facebook-60-day-user-access-token-generator/

Getting username in PasswordEncoder

I created my own authentication provider for my spring application, on which I specified the org.springframework.security.crypto.password.PasswordEncoder. I have my users stored in the database with their encrypted passwords (after a database algorithm). For being able to make the authentication, I would need to have access from the org.springframework.security.crypto.password.PasswordEncoder class to the username that is sent for authentication. Can anyone guide me how can I do this? Or is there any other approach?
N.B. I'm using SpringSecurity 3.2.
I don't even care if it's an old question, I've just spent 9 hours trying to figure this out. Might as well leave it here in case someone else stumbles upon this again.
String username = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest().getParameter("username");
Using the code above I was able to extract the username from current request.
ATTENTION: You must use the following class org.springframework.web.context.request.RequestContextHolder
There was a similar one that was doing me wrong.
Assuming that User Entered UserName,UserPassword is User,Pwd.
In order to Authenticate, you can perform the following.
Get User Entered Username and Password(User,Pwd).
Encode the Pwd using
String encodedPassword=passwordEncoder.encode(pwd);
Compare if UserEnteredUserName=DBUserNAme and UserEnteredEncodedPassword==EncodedPasswordInDB, based on match values, you can authenticate the User.

Unable to decrypt password in Jhipster

I have working on jhipster.but i am unable to decrypt password in jhipster and Spring.PasswordEncoderClass only provide encode and Match password function.can you help to decrypt password in jhipster.
Thanks in advance
We are using Spring Security's StandardPasswordEncoder, I do hope you can't decrypt it :-)
We are indeed storing hashed passwords: as you say, you can encode a password, and validate (match) if a specific String is the correct password, but you can't decrypt it. This means that if your database is stolen by a hacker, he would have a very hard time to figure out your users' passwords.
So this is a very good idea if you want to keep your users' password secure.
If, however, you want to have your passwords in plain text, you can change the encoder in your SecurityConfiguration class: you need to change the "passwordEncoder" bean, and probably use Spring Security's "NoOpPasswordEncoder" class. Of course, I have never done it, as I care about my users' data :-)

Resources