Tuesday, January 22, 2019

8. That little matter of creating a user

Now that our simplified authentication system is in place, we are faced with the little matter of how to create a new user. Since we don't have a username, password, or token we can't really create a new user.
To accomplish that, we need to make some modifications to our AuthenticationFilter.  In the doFilter method, we add a special if block to take care of user creation.
            if (httpRequest.getRequestURI().toString().equals("/user") && httpRequest.getMethod().equals("POST")) {

                Optional username = getOptionalHeader(httpRequest,"username");
                UsernamePasswordPrincipal usernamePasswordPrincipal = new UsernamePasswordPrincipal(username, username, true);
                processUsernameAuthentication(usernamePasswordPrincipal);
            }
            else if (httpRequest.getRequestURI().toString().equals("/authenticate") && httpRequest.getMethod().equals("POST")) {

                Optional username = getOptionalHeader(httpRequest,"username");
                Optional password = getOptionalHeader(httpRequest,"password");
                UsernamePasswordPrincipal usernamePasswordPrincipal = new UsernamePasswordPrincipal(username, password);
                processUsernameAuthentication(usernamePasswordPrincipal);
            }

As we can see the code fragment, if the call is made to /user endpoint with POST method, we look for a username header and trigger spring authentication. We also need to make a change in the UsernamePasswordPrincipal to take a flag that would tell us if the user is a new user or existing user.
Now that we have modified the principal and filter, we need to handle this in the provider. The provider that gets invoked for username and password authentication is UsernamePasswordAuthenticationProvider.
As we can see in the provider's authenticate method, we have added an if block that checks if this is a new user. In case it is a new user, we authenticate this user with a role NEWUSER. The create user endpoint is only allowed to be called for a role NEWUSER.
Now that we have stitched the path for authentication of a new user to create user endpoint, we can see the endpoint itself.
    @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    @PreAuthorize(MyConstants.ANNOTATION_ROLE_NEWUSER)
    public Optional createUser(@RequestHeader(value="username") String username, @RequestBody User user) {
        user.setMask(Role.USER.ordinal());
        User storedUser = userRepository.save(user);
        storedUser.setPassword(null);
        return Optional.of(storedUser);
    }
As we can see, we have a @PreAuthorize added with NEWUSER role. We also set the role of the user to the USER. Before returning the response, we set the password to null.
This fixes our service to allow the creation of a new user. The complete code is available tagged as v1.1 for this and previous posts.

No comments:

Post a Comment