Adding security to spring webservice for password - spring

i am new to spring. i need to make a user registration form where user will provide their basic details and password which i am directly saving to database.password is as string datatype in registration bean and varchar in database.
Now my approach is that i will do the service call from mobile or website to that web service and send password as plain text.
But i think this is not a good way as there is no security while sending data through webservice or in server code or in database, password is just a string with few validations.
Is there a good approach to do this task according to industry standards.
Thank you in advance.
Also i want that my password should not be intercepted by hackers or in server. The password should go in encrypted form from client and should save in database.Nobody managing server/DB should see that password.

Use BCryptPasswordEncoder provided by Spring Security to encrypt your user's password and store hashed password string to the database.
Example:
#Transactional
#Override
public User create(UserCreateForm form) {
User user = new User();
user.setEmail(form.getEmail());
user.setPasswordHash(new BCryptPasswordEncoder().encode(form.getPassword()));
user.setRole(form.getRole());
return userRepository.save(user);
}

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.

Update fields of the principal at the runtime

I use OAuth2 authentication with my own authorization and resource server in Spring Boot. I want to change some fields in my User implements UserDetails(it's my Principal) object at runtime on behalf of the same user or on behalf of another user(administrator/moderator). E.g. user1 with id=1 want to change his country, so he calls this method:
#PostMapping("/setMyCountry")
public void setMyCountry(#CurrentUser User user, #RequestParam String newCountry){
user.setCountry(newCountry);
userRepository.save(user);
}
But when I want to check his country using this:
#GetMapping("/getMyCountry")
public String getMyCountry(#CurrentUser User user){
return user.getCountry();
}
I get the same old country.
Similarly, with the changes as administrator:
#PostMapping("/setUserCountry")
public void setUserCountry(#CurrentUser Moderator moderator, #RequestParam String newCountry){
User user = userRepository.findById(1L).get();
user.setCountry(newCountry);
userRepository.save(user);
}
#GetMapping("/getUserCountry")
public String getUserCountry(#CurrentUser Moderator moderator){
User user = userRepository.findById(1L).get();
return user.getCountry();
}
It returns the same country. But, of course, the DB shows new value.
I already saw question about the similar issues, but if I use this in setMyCountry():
Authentication newAuth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(newAuth);
then this still doesn't work. Please note, that I use my custom tokens, token providers and token granters, but they all return UsernamePasswordAuthenticationToken at the end.
So, how can I change field of the User and update current principal without log out and log in?
Common practice when using oauth2 is that the Authentication server knows nothing about the users, more than user name, password, what roles, and an some sort of key so it can look up the user object. This can be a unique UUID, or the username (subject) as in an email address.
The resource server gets a token from a client, it takes this token and then calls the authorization server to verify the token, the authorization server verifies it and if verified then sends back information to the resource server so that the resource server can populate its UserDetails object.
If the resource server needs to know say what country this user lives in, it gets the id from the Principal/UserDetails object and then calls maybe a user service, or another database, or another table, or even back to the authorization server that maybe has a /user endpoint and presents the token to the authorization server (that in turn gets the principal info, gets the subject and then looks up in a database for the user info) and then send the user object back.
What my point is that you should always separate Authentication and Authorization (roles etc) information, from the actual User information.
What if you change from say using facebook authentication to github authentication. Do you need to redo all the users? no, because you have all user information separated from the authorization information.

JWT password validation best practice advice

I have an asp.net web API. I implemented a token authentication that I am trying to validate user name and password from the database. I am new to JWT so I need your advice.
Here are my questions;
Should I encrypt username and password in my database?
The client sends the username and password in the request body, Should the client send them in the header? And should they be encrypted?
Best Regards.
You should absolutely encrypt your password in the database. Even better if you hash it with "salt" (hashing will let you implement the log in logic, but the original password will be unrecoverable even if you know the hash).
Sending the password in the request body is fine if the connection is protected by TLS (HTTPS). There's no gain in putting it in the headers.
Usernames are often stored in plain text.
P.S. Your question has nothing specific to JWT, it is just general password management.

Why the session attribute is coming as null

A HTML5 UI is connected to the backend (REST Jersey to business logic to Hibernate and DB). I need to create and maintain a session for each user login until the user logs out.
I am clueless on how to approach this problem.
I followed this approach
Initially when the User is successfully logs in , i am setting attribute under session as shown below
HttpSession session = request.getSession(true);
session.setAttribute("islogged", "islogged");
String value = (String)session.getAttribute("islogged");
System.out.println("****************** The User Logge in Value"+value);
Later in a different page i am checking if the user is logged in or not this way
public String checkIfUserLoggedIn() throws JSONException,ClassNotFoundException, SQLException
{
HttpSession session = request.getSession();
String value = (String)session.getAttribute("islogged");
if(value==null)
{
// always its coming here only
}
}
I agree with francesco foresti, please do not rely on HTTP session without Auth. this is unsafe, and quite dangerous for your app.
Have you been implementing a specific session mecanism ?
If not, jersey as it is will not store session data as it. Every call that you will make will give you a session id that is different from yours.
You have to make authentication & use the auth token in order to identify you session.
use JAX-RS
Please do use an auth mecanism as defined : https://jersey.java.net/documentation/latest/security.html
#Path("authentication")
#Singleton
public static class MyResource {
// Jersey will inject proxy of Security Context
#Context
SecurityContext securityContext;
#GET
public String getUserPrincipal() {
return securityContext.getUserPrincipal().getName();
}
}
or use another framework : Spring, Shiro.... etc.
I really prefer that solution, since another framework will implement a lot of stuff for you. You gain a lot of time doing so.
Please take a look to official jersey doc: https://jersey.java.net/documentation/latest/index.html
I wouldn't rely on the http session. My approach would be to put an "Authorization" field in the header of the response that the server returns when the user logs in, and ask the user to put the very same header in each suqsequent call. In this header you put the informations that help the server find the identity of the user
(take a look at what twitter does as an example : https://dev.twitter.com/oauth/overview/authorizing-requests). The server could save the informations about the logged in user in the database, or You could create a Map in a Singleton that would serve as the "authorization gatekeeper" for your services.

Two factor authentication with Spring Security like Gmail

Here, my scenario is bit similar to two-factor authentication of Gmail. When a user logs in successfully(SMS code is send to user) then he is challenged with another page to enter the SMS code. If user gets the SMS code correctly he is shown the secured page(like Gmail Inbox).
I did this bit of research on this and suggestion is to rather than giving ROLE_USER upon login, gave him PRE_AUTH_USER and show the second page where he enters the SMS code; upon success give them ROLE_USER.
However, my question is Spring has InsufficientAuthenticationException and in this scenario we won't make use of it. Will there be other better ways of implementing two factor authentication in my scenario?
P.S. I have bit of customized spring security configuration. In my Login page apart from username and password I have Recaptcha validation as well, also my authenticationProviderm authenticationSuccessHandler, logoutSuccessHandler, accessDeniedHandler all are customized.
Upon SMS code validation success, you could grant ROLE_USER authority as follows.
private void grantAuthority() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(auth.getAuthorities());
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication newAuth =
new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(),
authorities);
SecurityContextHolder.getContext().setAuthentication(newAuth);
}
The code is from copied from a blog post ,and sample application which has implemented two-factor authentication. If I had found it bit earlier it would save a lot of time !!!
Try to throw InsufficientAuthenticationException if the first level of authentication passes, then catch it with ExceptionTranslationFilter and forward to the second level of authentication page.
The two factor authentication page can resubmit the user name and password in hidden fields, together with the two factor token. In this second time the custom authentication provider would be able to authenticate successfully the user.

Resources