Password in database different from password obtained with spring security - spring

I am using Spring Security to read user password from MySql database. The issue is, that it seems the password obtained from database is not the same as the password stored in the database, so I'm getting authentication error.
What makes it even stranger is that it seems after application restart I keep getting different passwords. Since I can't really find a similar topic I'm sure I have overlooked some basic stuff but I just can't see where. Here is my configure:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(new PasswordAuthentication())
.usersByUsernameQuery("SELECT user_name, user_password, verified "
+ "FROM user_details "
+ "WHERE user_email = ?")
.authoritiesByUsernameQuery("SELECT user_name, user_role_desc "
+ "FROM user_details "
+ "WHERE user_email = ?");
}
PasswordEncoder is custom but as I understand Security should just call the matches method:
public boolean matches(CharSequence password, String token)
{
System.out.println(password);
System.out.println(token);
And this is where I see that token is different from the one stored in the database even though the pattern is the same.
I have a UsernamePasswordAuthenticationFilter but no other custom implementation. Does anything else in the chain modify the password obtained from the database?
EDIT:
The password in the database is:
$22$17$9GD7-A8_W4h9q4_uJ-fFSMhJjKMIbKNJng-G6IfzNCQ
While if I print out the - supposedly same - password returned by jdbcAuthentication then I see:
Password 1:
$22$17$c-gMYpcX5d0YOgf6HBs19MuImTq7wb41tBeKSTw1mMw
This remains the same in the log as long as I don't restart the application. If I restart, then it will be different, eg:
$22$17$zG0Ph1AM9_xAADIR8l01JVkCNzNwk_s0Z4VJt49NSiU
Then third time:
$22$17$B4y1Yr8Mt0QuuMg-AK6x02RyAZlQVnbo9A6KKEYitlE
etc. But as long as I don't restart the app the password returned by jdbcAuthentication remains the same - just not the one that is in the database.

I think I got it. The fault was, that I thought that both usersByUsernameQuery and authoritiesByUsernameQuery are by default prepared with the value extracted from the request.
This is not the case. The authoritiesByUsernameQuery is prepared with the result of the first column returned by the usersByUsernameQuery. This broke the process as I have used the email address in the validation but in the first query I still selected user_name to be returned, therefore the authorities query failed.

Related

How can I get the ID attribute of a logged in User and set it as a foreign key in the database

So here is the thing. I have 2 tables in the database: User and Client.
A user can add one or many clients in the database. So what I want is when a user will add a client - the function will retrieve the id of the logged in User and add it as a foreign key in the client table.
I have already done the OneToMany Mapping.
Here is my controller:
#RequestMapping(value = "/postficheclient", method = RequestMethod.POST)
public ResponseEntity<?> createClient(#RequestBody Client newClient) {
// newClient.setUser(user);
return new ResponseEntity<Client>(clientservices.save(newClient), HttpStatus.CREATED);
}
With that function, it adds a null value in the Client table.
Can someone help me, please?
PS: I use the spring security system.
With Spring Security, you can get the logged client through SecurityContextHolder.getContext().getAuthentication()
and you can get various details from:
getPrincipal() - usually the user identifier
getAuthorities() - the authorities
getDetails() - additional user details
The infos put in the various fields depends how spring security handle your authentication mecanism, but I guess you can find what you need for in principal.

Spring security grails plugin

I'm using Spring security grails plugin v2.0.0 RC5 in my grails application , but i noticed something , that while login to the application the username is not case sensitive for instance if you wrote user or USER both will login successfully. What i need to do is to make the username case sensitive.
i found the that isLoggedIn action in springSecurityService handling the login but i can't see anything in it any checking of the provided username or password.
here is the isLoggedIn code :
boolean isLoggedIn() {
def authentication = SCH.context.authentication
authentication && !authenticationTrustResolver.isAnonymous(authentication)
}
Am i searching the the right place ?
There is a configuration property for that. https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#domainClassProperties
userLookup.usernameIgnoreCase
In my Grails app I'm using the Spring Security plugin and have defined a custom userDetailsService Spring bean in order to control how user and role data is retrieved, e.g.
class MyUserDetailsService implements GrailsUserDetailsService {
/**
* Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least one role, so
* we give a user with no granted roles this one which gets past that restriction but
* doesn't grant anything.
*/
static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]
UserDetails loadUserByUsername(String username, boolean loadRoles) {
return loadUserByUsername(username)
}
UserDetails loadUserByUsername(String username) {
User.withTransaction { status ->
User user = User.findByUsername(username)
if (!user && user.username.equal(username)) {
throw new UsernameNotFoundException('User not found', username)
}
def authorities = user.authorities.collect {new GrantedAuthorityImpl(it.authority)}
return new CustomUserDetails(
user.username,
user.password,
user.enabled,
!user.accountExpired,
!user.passwordExpired,
!user.accountLocked,
authorities ?: NO_ROLES,
user.id,
user.name)
}
}
}
Now you will see
**if (!user && user.username.equal(username)) {**
this will solve your problem.
But here is another problem, your implementation also depends on your database because like MySQL is case insensitive, so if you search a user with name Joy then it will return all the user doesn't wich have name joy doesn't matter it is in capital letter or small letter.
So you need check in database value before persisting new user.
also, another problem is, if you will check the user domain
username blank: false, unique: true, email: true
username is unique, means you can't insert username joy again if Joy exists in db, so you need to change it and write your own custom logic to handle this problem.

security to url for a user

For a url like
#RequestMapping(value = "/users/{userId}/update/password", method = RequestMethod.PUT)
how to be sure the connected user can modify only its password and not the one of other user...
actually, i have protection on url... but it's not enough to prevent this case
http.authorizeRequests().antMatchers("/rest/users/**").hasRole("USER");
Assuming that you have a Spring bean with a public method with username as one of the arguments (it can be in controller, security layer, service layer or DAO), you can add a #PreAuthorize annotation:
#PreAuthorize("#username == authentication.name")
public void updateUserPassword(String username, String newPassword);
You must enable pre- and post-annotations in your security config if not already done so.
I soppuse you have a authentication over /rest/users/**. You can get current user with the following code.
YourUserPrincipalDto dto = (YourUserPrincipalDto) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Long userId = dto.getUserId();
YourUserPrincipalDto should implements UserDetails.
Add the Principal object (like here) to your method's argument list to confirm that the authenticated user is the same user as the userId in the API URL (do whatever background DAO queries are necessary to map between the userId and the authenticated user). Return a 403 or 404 if it is not, otherwise update the password. Whether you return 403 or 404, best to be consistent and return the same number for both unauthorized and user-not-found situations in order to not provide unwanted information to hackers.

How can I modify a password within form login before using it for authentication in spring security?

I registered a jdbcAuthentication(). How can I replace the password that is pushed in the SELECT statement?
A PasswordEncoder is not sufficient as I want to concatenate the username and password of an incoming login request then hash this string and using the outcoming hash as the password to authenticate with JDBC.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(datasource)
.usersByUsernameQuery("SELECT username, password, true as enabled "
+ "FROM users WHERE username = ?")
.authoritiesByUsernameQuery("SELECT username, role as authority "
+ "FROM users, roles "
+ "WHERE username = ?");
}
}
I added a custom UsernamePasswordAuthenticationFilter but its attemptAuthentication() method doesn't get called within a login attempt.
http.addFilterBefore(new CustomUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
If I understand this correctly, your password field in the database is actually the hash of the username and password?
The way Spring Security works is it first loads the UserDetails object from the database based on username alone. It then compares the password (after any necessary encoding -- e.g. salt, etc) with the password that was supplied (also after any necessary encoding).
In order to accomplish what you want to, I believe you'd need to provide a custom 'AuthenticationProviderobject that would perform your method of authentication (because it's different than what the built in provider expects. The docs for [AuthenticationProvider are here][1]. You'll also need to modify either your XML or#Configuration` class to use the custom provider.

Spring social oauth how to get sign in provider in SocialUserDetailsService?

In my Spring Social app, I'm trying to integrate certain Social Login functionalities. After being redirected from, for example Twitter, Spring calls the following to look up the user.
public class SimpleSocialUserDetailsService implements SocialUserDetailsService {
#Override
public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException, DataAccessException {
/*
Commented
*/
}
However, since I will have multiple social login providers, the userId alone is not enough for me to look up the user in my database. I need at least the sign in provider or access token.
Is there anyway to get the sign in provider, or more information, in SocialUserDetailsService? Any other way to solve my problem would be great!
Spring Social is rather Agnostic to the Sign in Providers when properly implemented. I believe you are confused on the flow of Spring Social. At the point you describe spring social has already looked up the connections table and presumably found a record, so it looks up your user table for the user matching with userId (as referenced in the connections table) This is usually associated with the username.
This connection <-> User matching is done in the SocialAuthenticationProvider before calling the SocialUserDetails loadUserByUserId method.
So the SocialAuthenticationProvider already does what you ask for by querying the usersConnectionRepository and comparing the provider connection to find the appropriate user.
Now for your case you would can go ahead and override the user service that you have setup. As long as the userId used on the doPostSignUp call matches the one you look up in the loadUserByUserId, the proper user will be retrieved.
This is a sample:
Wherever your signup logic is executed, you call the doPostSignup and pass the desired user id (Username or another uniquely identifiable String)
ProviderSignInUtils.doPostSignUp(variableForNewUserObject.getId().toString(), request);
Now you Override the loadUserByUserId in SimpleSocialUserDetailsService
#Autowired
private UserDetailsService userDetailsService;
#Override
public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
return (SocialUserDetails) userDetails;
}

Resources