Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Is91/server-side implementation of 2FA (⚠️ devops) #3257

Merged
merged 183 commits into from
Aug 15, 2022

Conversation

pcrespov
Copy link
Member

@pcrespov pcrespov commented Aug 12, 2022

What do these changes do?

Implements server-side of a first implementation of 2FA (two-factor-authentication)

The workflows with 2FA are the following

  1. Registration
    a. submit user email and password for registration (confirmation email sent)
    b. user email confirmed by clicking confirmation email link
    c. submit phone number for registration (confirmation SMS sent)
    d. user phone confirmed by adding 2FA code received
  2. Login
    a. submit user email and password (2FA SMS sent)
    b. submit 2FA code
    c. user successfully logs in

NOTE: this PR introduces server-side of 2FA functionality (still not front-end) and by default IS DISABLED.

Highlights of implementation

  • implemented in the webserver's login plugin
    • adds dependency to redis plugin to store 2fa codes for confirmation
  • SMS uses https://www.twilio.com/ service

⚠️ devops

Example of env-vars needed to enable 2FA


WEBSERVER_LOGIN_REGISTRATION_CONFIRMATION_REQUIRED=1
WEBSERVER_LOGIN_2FA_REQUIRED=1

TWILIO_ACCOUNT_SID=REPLACE_ME_with_valid_account_sid
TWILIO_AUTH_TOKEN=REPLACE_ME_with_valid_auth_token
TWILIO_MESSAGING_SID=REPLACE_ME_with_37_chars_SID___

VERY IMPORTANT:

  • Cherry-Pick Redis-Commander changes from d67532c
  • Take redis and redis commander down (scale to zero), remove redis docker volume, assert change took place

Devops should also consider:

  1. New db in redis. Might require modifying redis-commander service in ops-stack. This service must append to environment REDIS_HOSTS: ,validation_codes:${REDIS_HOST}:${REDIS_PORT}:2
  2. New variables for twilio. Check with @odeimaiz how to create account and add credentials in env-vars where 2FA is activated.

Related issue/s

How to test

  • acceptance test in
$ cd services/web/server
$ make install-dev
$ pytest -vv tests/unit/with_dbs/03/test_login_2fa.py

Checklist

  • add test with workflow services/web/server/tests/unit/with_dbs/03/test_login_2fa.py
  • review settings
  • review plugin dependencies ( redis required by login if 2FA is active!)
  • review routes:
    • paths
    • returned body for data when return code is 202 (Accepted)
  • tests w/ and w/o 2FA required
  • revert front-end before review!
  • Openapi changes? make openapi-specs, git commit ... and then make version-*)
  • Database migration script? cd packages/postgres-database, make setup-commit, sc-pg review -m "my changes"
  • Unit tests for the changes exist
  • Runs in the swarm
  • Documentation reflects the changes
  • New module? Add your github username to .github/CODEOWNERS

@pcrespov pcrespov marked this pull request as ready for review August 15, 2022 13:31
@pcrespov pcrespov requested a review from odeimaiz August 15, 2022 13:31
@pcrespov pcrespov requested a review from odeimaiz August 15, 2022 14:09
Copy link
Contributor

@GitHK GitHK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Nice, please check my comments below. I think as a first iteration this looks good enough.

@@ -21,6 +21,48 @@ paths:
default:
$ref: "#/components/responses/DefaultErrorResponse"

/auth/verify-phone-number:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maybe consider to rate limit this route? I think a rate limit by IP should be sufficient.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but I would like to do it with traefik
I wait to next iteration where we add the front-end. There we might have to change the paths again



def _generage_2fa_code() -> str:
return f"{1000 + secrets.randbelow(8999)}" # code between [1000, 9999)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not include some chars as well? Also when using numbers people usually go for XXX-XXX they display the code split in two groups of 3 which are simpler to memorise. I'd stick to these formats which are known to the users.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@odeimaiz created it with numbers. I guess is twilio reqs? for a tmp code i do no see it makes a huge difference

Comment on lines +136 to +141
async def register_phone(request: web.Request):
"""
Submits phone registration
- sends a code
- registration is completed requesting to 'phone_confirmation' route with the code received
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I get it correctly, this is used when a new account is created?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

)
return response

assert user["phone"] # nosec
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this can be None, could you check and raise an error here in that case.
Ideally there should be a validator for the phone number as well. But just a the above check is already better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should NOT be None in this context. That is why i added assertion, to make sure the external context respects this

Copy link
Member

@sanderegg sanderegg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very good! maybe only question that might be also more devops... is there any limitation on the number of SMS that can be sent?


assert user["phone"] # nosec
try:
code = await set_2fa_code(request.app, user["email"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there some way of preventing me from calling xXXXXX times this entrypoint?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep ... @GitHK also mentioned it. I think it is a good idea and i will add this in next iteration (remember that the config by default disables 2FA)

Do you have any input about how to do this in traeffik? i.e. selectively rate limit some entrypoints?

"TWILIO_AUTH_TOKEN": "fake-token",
"TWILIO_MESSAGING_SID": "x" * 34,
}
# NOTE: apparently some session-based fixtures is settings these envs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm.. apparently?

Copy link
Member Author

@pcrespov pcrespov Aug 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is that these variables are somehow already defined at the start of the test (even if no fixture was added) ... for that reason i have to explicitly delenv them!

I say "apparently" because my guess is that monkeypatch_session and monkeypatch_module are somehow introducing these variables as a side-effect. Those are very dangerous and marked for deprecation ... so I am slowly removing them

@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

No Coverage information No Coverage information
0.0% 0.0% Duplication

@pcrespov pcrespov merged commit e7cfd69 into ITISFoundation:master Aug 15, 2022
@pcrespov pcrespov deleted the is91/server-2FA branch August 15, 2022 22:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:webserver issue related to the webserver service
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants