voteamerica / backend

MIT License
7 stars 17 forks source link

Back-end support for secure operator page #204

Closed jkbits1 closed 5 years ago

jkbits1 commented 5 years ago

This PR is one part of two PRs, where the other is for the front-end. The code for the front-end PR exists and that PR will be raised when this PR is approved.

Together, the two PRs create an operator page secured with a login (based on JWT tokens). This new code provides a setup/platform where multiple volunteers can contribute to individual parts of the operator page (both front-end and back-end), as specified in the github issues. It makes it possible to build the front-end code using current, efficient, technologies that are widely known. This supports assistance by a wider range of volunteers.

The operator page, pending approval of the two PRs, now exists and shows limited secure information from the db. The existing examples provide a guide for new volunteers to extend the page.

IMPORTANT: these changes are not meant necessarily to be the final version of this setup (more details below). We may fine-tune things or add/swap-in various technologies later (both front-end and back-end).

Quick review notes: Although many files appear changed, that’s mostly formatting. The key changes to the Node app are:

1) An authentication/authorisation pattern (defined in index.ts, login.ts, token.ts and hapi-auth-jwt-local.ts) to secure specific routes for logging in and viewing db information.

2) New routes to support querying and updating operator information.

The db has a new operator table and associated function.

Technologies added:

1) JWT tokens – a current and mainstream way to provide both authentication and authorisation.

In response to a valid login, a JWT token is sent from the web server to the client. The token contains both the username and a true/false value for admin rights. The token’s expiration time is set to 1 hour.

NOTE: JWT tokens, by design, are not encrypted. The information contained is visible to anyone. So they should be sent over HTTPS (and with a specified expiration time).

My view is that some version of this solution should exist in any final setup.

2) General authentication pattern/mechanism - this is a very standard pattern which, among many other places, is defined here: https://auth0.com/blog/hapijs-authentication-secure-your-api-with-json-web-tokens

The use of JWT tokens ensures that this mechanism maybe be altered without change to the front-end.

NOTE: the above link is specified to make it clear that this authentication mechanism forms an initial solution, in part to get development activity under way quickly and effectively. This pattern does not prevent debate or later changes. The linked page is provided by Auth0 who provide a free platform (for our level of use) for external authentication/authorisation as additional/alternative mechanisms.

This pattern uses Bcrypt as a secure way to store salted hashes of passwords locally.

Later, we may find benefit to using either the Auth0 or some other provider’s platform to enable logins based on external accounts such as Google or Facebook. However, Facebook authentication requires some registering of the web app with them, and occasionally there are glitches in their code changes. It also would need a review as to whether all operators have a Google mail account. All benefits require testing.

My view is that some version of this mechanism should exist in any final setup as well as any alternative methods.

3) Secured and related routes – currently secured routes are drivers/list and users/list (to provide information to the operator page) plus createuser. The route users/authenticate exists to return a JWT token in response to valid login details.

4) Default user – on deployment, we need to add an initial user to the db. This can be done when the JWT secret (next item) is agreed and shared privately.

5) Environment variable: JWT_SECRET – this must be defined for the JWT authorisation to operate. If not provided, none of the secure routes are added to the server and all authorisation calls fail.

NOTE: adjustments have been made to the working folder and paths for .travis.yml and associated machine creation script so that ./common-sudo-fix.sh is located correctly during the Travis build. Currently, this does not cause any problems for the travis tests, but seems useful to this fix now in case of future changes to that script that are necessary.

dmilet commented 5 years ago

@jkbits1 Lots of changes in there. Maybe I should merge and try it out locally ? Do you want me to create the new objects in the postgres DB in DO?

jkbits1 commented 5 years ago

@dmilet thanks, this sounds like a good plan.

I’ll amend the PR now so that createuser isn’t a secure route, which will make for easier testing (otherwise it's harder to create the initial user), and change it back when testing is complete.

Both createuser and authenticate routes return a token if successful (createuser only on the first successful attempt). By design, if the calls fail, they return minimal information except that they failed. This token is then used for the xxx/list calls as follows:

    Header key: "Authorization"
    Header value: "Bearer " + token (there is a space required after Bearer)

Secure routes and login routes:

POST localhost:8000/createuser?email=eee&username=dm&password=abc&admin=true
GET  localhost:8000/users/authenticate?username=dm2&password=abc
GET  localhost:8000/users/list
Authorization header: "Bearer " + token  

GET  localhost:8000/drivers/list
Authorization header: "Bearer " + token  

Yes, please, can you create the database parts on DO? I’m very keen to become familiar with the new deployment methods, following your explanations, but have been focused on getting this area ready up to now.

The environment variable JWT_TOKEN is required for any of the secure routes to operate. Without that, the createuser and authenticate routes will return a failure, while the xxx/list routes will not exist.

This RFC recommends a key for the JWT HS256 algorithm of 256 bits or above: https://tools.ietf.org/html/rfc7518#section-3.2

As you plan to merge, I’ll raise a PR for the front-end. That works fine without the back-end changes and will be ready use for quicker for testing from that side.