0

I am trying to implement a form based authentication. Authentication is based for the Users is based on Roles ADMIN and USER. When I run my custom login url .loginProcessingUrl("/admin/login") my authentication fails meaning

  1. I get a HttpStatus OK
  2. Anyone can sign in even if you are not register

but as soon as I comment out the .loginProcessingUrl("/admin/login") to use spring customs login page, it works.

I have looked at various examples but nothing to push me in the right direction. I don't know if it is because of I am not saving session ID in the User entity class (NOTE: I am not saving session ID yet cause I am trying to understand just the basic of form based authentication) or something is wrong with my JS.

NOTE: On start of this app, I am injecting dummy users with one having a Role ADMIN and the other two USERS

Here is my SecurityFilterChain in SecurityConfig Class

 @Bean
    public SecurityFilterChain filterChain1(HttpSecurity httpSecurity) throws Exception {

        return httpSecurity
                .cors() //
                .and() //
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((auth) -> auth
                        .antMatchers("/admin/**", "/secured/**")
                        .hasRole(ADMIN.name())
                )
                .formLogin() //
                .loginProcessingUrl("/admin/login")
                .and()
                // logout TODO
//                .logout()
//                .logoutUrl("/admin/logout")
//                .and()
                .build();
    }

Admin Login Controller api (not it has a global request mapping @RequestMapping("/admin"))

@PostMapping(path = "/login")
    public ResponseEntity<?> login(@Valid @RequestBody User user) {
        System.out.println("Status " + userDTOService.confirmUser(user));

        if (!userDTOService.confirmUser(user)) {
            return new ResponseEntity<>(!userDTOService.confirmUser(user), BAD_REQUEST);
        }

        return new ResponseEntity<>(userDTOService.confirmUser(user), FOUND);
    }

service class which confirms if the user exists

public Boolean confirmUser(User user) {
        /*
        * Check if username exist in the database
        * then check if the password provided equals password in database
        * Then check if user is an admin
        * */
        System.out.println(user);
        String userName = user.getUserName();
        String password = user.getPassword();
        Optional<User> findUser = userRepository.findUserByUserName(userName);

        return findUser
                .stream()
                .anyMatch(param ->
                        param.getPassword().equals(password)
                        && param.getRole().equals(ADMIN)
                );
    }

vanilla js sign in

const signIn = () => {
    formElement.addEventListener("submit", (event) => {
        event.preventDefault();

        const formD = new FormData(event.target);

        fetch(LOGIN, {
            method: "POST",
            body: formD
        }).then(async (response) => {
            if (response.ok) {
                // window.location.href = "../static/new.html";
                console.log("Success");
                return response.json();
            }
            const body = await response.json();
            throw new Error(body.message);
        })
        .catch((error) => {
            console.log(error);
        });

    })
}

Also for some weird reason, I get an this syntax error SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON coming from login the error console.log(error);

0

1 Answer 1

0

I figured the answer.

  1. Using .formLogin() and .loginProcessingUrl() is wrong when using REST APIs. This is because these methods are used for Springs inbuilt frontend ThymeLeaf.
  2. Using FormData is wrong because it is for uploading files so I instead created an object. Documentation for better explanation on FormData here.
  3. Since I am using basic authentication, I'll need to pass user credentials in the header.

Client side Logic

const signIn = (LOGIN) => {
    form.addEventListener("submit", (event) => {
        event.preventDefault();

        const formD = {
                        "username": name.value,
                        "password": password.value
                    }
        let authorizationData = 'Basic ' + btoa(name.value + ':' + password.value);

        fetch(LOGIN, {
            method: "POST",
            headers: {
                'Content-Type': 'application/json',
                "Authorization": authorizationData
            },
            body: JSON.stringify(formD)
        }).then(async (response) => {
            
            if (response.ok) {
                window.localStorage.setItem("Authorization", authorizationData)
                window.location.href = "../static/new.html";
                return response.json();
            }
            const body = await response.json();
            throw new Error(body.message);
        })
        .then ((data) => {
            console.log("Data " + data);
        })
        .catch((err) => {
            console.log("Error " + err.message);
        });

    })
}

Security filter

.cors() //
                    .and() //
                    .csrf(csrf -> csrf.ignoringAntMatchers("/h2-console/**").disable())
                    .authorizeHttpRequests((auth) -> auth
                            .antMatchers("/unsecured/**", "/admin/login", "/h2-console/**") //
                            .permitAll() //
                            .anyRequest().authenticated()
                    )
                    .sessionManagement(sessions -> sessions.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                    .headers(headers -> headers.frameOptions().sameOrigin())
                    .httpBasic()
                    .and()
                    .build();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.