Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication using cookies in spring boot

//Part of my Controller class

@RequestMapping("/login")
    public String login(HttpServletRequest request,HttpServletResponse response) {
        request.setAttribute("mode", "MODE_LOGIN");


        return "welcomepage";
    }

    @RequestMapping ("/login-user")
    public String loginUser(@ModelAttribute User user, HttpServletRequest request,HttpServletResponse response) {
        if((userService.findByUsernameAndPassword(user.getUsername(), user.getPassword())!=null)) {
            Cookie loginCookie=new Cookie("mouni","user.getUsername()");
            loginCookie.setMaxAge(30*5);
            response.addCookie(loginCookie);
        return "homepage";
        }
        else {
            request.setAttribute("error", "Invalid Username or Password");
            request.setAttribute("mode", "MODE_LOGIN");
            return "welcomepage";

        }

    }

I am doing a library management project on java spring boot. I have one problem, i would like to do authentication using cookies. In brief, Once after user logged in with his credentials, username should be saved as cookie value. Next time when user is going to login, he can just enter username and should be logged in successfully. Could someone please help me out

like image 644
mounika Avatar asked Sep 03 '18 06:09

mounika


2 Answers

Since security is a complex matter, I recommend using Spring Security, even though you're tasked to do it without. To illustrate the complexity about security, I can already tell you that your current code has a vulnerability, since you're trusting a plaintext username cookie as your sole authentication. Spring Security on the other hand uses a key to generate a remember me cookie so that it is much more difficult to impersonate someone (unless you know the key).

So, if you would be using Spring Security, the first thing you need to do is to create a UserDetailsService, which has a method called loadByUsername(). To implement this, you could use your UserService and use the User builder to construct a Spring Security user object:

public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if ("admin".equalsIgnoreCase(username)) {
        return User.builder()
            .username(username)
            // This should contain the hashed password for the requested user
            .password("$2a$10$T5viXrOTIkraRe2mZPyZH.MAqKaR6x38L.rbmRp53yQ8R/cFrJkda")
            // If you don't need roles, just provide a default one, eg. "USER"
            .roles("USER", "ADMIN")
            .build();
    } else {
        // Throw this exception if the user was not found
        throw new UsernameNotFoundException("User not found");
    }
}

Be aware, in contrary to your original UserService.findByUsernameAndPassword() you do not have to check the password by yourself, just retrieve the user object and pass the hashed password.

The next step is to provide a proper PasswordEncoder bean. In my example I'm using BCrypt with 10 rotations, so I created the following bean:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(10);
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new MyUserDetailsService();
    }
}

The next step is to configure Spring Security. For example:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .antMatcher("/**")
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login.html").permitAll()
            .loginProcessingUrl("/login-user").permitAll().usernameParameter("username").passwordParameter("password")
            .defaultSuccessUrl("/welcome.html")
            .and()
        .rememberMe()
            .alwaysRemember(true)
            .tokenValiditySeconds(30*5)
            .rememberMeCookieName("mouni")
            .key("somesecret")
            .and()
        .csrf().disable();
}

In this case, all endpoints (/**) will be secured, you'll have a login form at login.html containing two form fields (username and password). The destination of the form should be /login-user and when a user is successfully logged in, he will be redirected to /welcome.html.

Similar to what you wrote in your code, this will generate a cookie called mouni containing a value (no longer a plain username) and it will be valid for 150 seconds, just like in your example.

I'm disabling CSRF here because I'm using a simple HTML form, and otherwise I would have to add a templating engine to pass the CSRF key. Ideally, you should keep this enabled.

like image 69
g00glen00b Avatar answered Oct 25 '22 19:10

g00glen00b


You are using Spring framework which has the capability for the same which you are trying to achieve. so why to do it manually?

Have a look at spring security.

https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/

like image 43
Alien Avatar answered Oct 25 '22 20:10

Alien