hackforla / HomeUniteUs

We're working with community non-profits who have a Host Home or empty bedrooms initiative to develop a workflow management tool to make the process scalable (across all providers), reduce institutional bias, and effectively capture data.
https://homeunite.us/
GNU General Public License v2.0
35 stars 21 forks source link

Introduce AWS Cognito Authentication Mocking & Test Cognito User Pools #641

Closed Joshua-Douglas closed 3 months ago

Joshua-Douglas commented 4 months ago

This PR makes progress on issue #577. It builds off of the changes in #637.

What changes did you make?

This PR fixes the DevelopmentHUUConfig by introducing AWS Cognito authentication mocking. With these changes we can run the API without AWS Cognito credentials.

I've also introduced a AWSTemporaryUserpool which creates temporary, development-only AWS Cognito user pools in order to completely isolate development and test user data from production user data. With this change we can now write test cases that interact directly with AWS Cognito without worrying about potentially deleting or polluting real user data.

These changes were integrated into the existing runtime configuration system:

It is worth noting that authentication mocking and temporary user pools are implemented using the flask development WSGI server. These features are not supported when using a production grade server, like gunicorn. This is intentional since these are development-only features.

Testing done for these changes

The debug API test cases run with authentication mocking enabled, and the release API test cases run with authentication mocking disabled. Our github test action will run both test suites, to avoid mocking-related bugs.

Both test suites execute with temporary userpools, since we shouldn't ever test against real user data.

The TestsWithMockingDisabled was removed since we are now able to sign up and sign in users in our backend tests. Now all tests can now execute in both debug and release mode.

Other Changes

Test Project Refactor

Introducing mocking required a refactor of our pytest design. Before this refactor we were using a mix of unittest and pytest. Using both test frameworks made writing test infrastructure more challenging because unittest does not have direct access to pytest fixtures, which are great at providing context management. Since we use context managers to ensure our mocking and user pool environments are properly cleaned up, I decided to remove unittest altogether.

The test project now purely uses pytest. All the changes in test_host_controller.py and test_service_provider_controller.py are a part of this refactor.

Fix Confirm Endpoint

There were two issues with the confirm endpoint:

  1. There were duplicate implementations of confirm user
  2. The endpoint did not accept json data, but a user email and confirmation code is required.

Note: While authentication mocking is enabled, users can be confirmed using any code.

Rationale behind the changes?

Mocking and fake userpools allows us to more securely generate test users, and to more easily interact with the API during development.

We can now sign-up, confirm, and sign-in a temporary user from the swagger-ui using non-existent email addresses and fake confirmation codes. The user will be automatically deleted when the application stops, and there is no risk of leaking sensitive data when running in this mode.

Benefits of Mocking

Benefits of Temporary User Pool

JpadillaCoding commented 3 months ago

Hey Joshua, I was taking a look at the branch and testing out the application locally with development enabled. I tried login in with my usual login and it didn't work (to my understanding that's intended since we shouldn't be accessing user data), but I can't figure out how I would login. Could you clarify this for me? Thanks

Joshua-Douglas commented 3 months ago

Hey Joshua, I was taking a look at the branch and testing out the application locally with development enabled. I tried login in with my usual login and it didn't work (to my understanding that's intended since we shouldn't be accessing user data), but I can't figure out how I would login. Could you clarify this for me? Thanks

Hey @JpadillaCoding,

Can you try using the sign-up, confirm, and sign-in endpoints from the swagger-ui using non-existent email addresses and fake confirmation codes? The user will be automatically deleted when the application stops, and there is no risk of leaking sensitive data when running in this mode.

I can also add a script to add 1-2 test users each time the app starts up to save this inconvenient.

erikguntner commented 3 months ago

@Joshua-Douglas I'm trying this out as well, and going through the swagger ui worked! I think having a test user or 2 is a great idea. Otherwise it seems that you have to go through this process every time the server restarts?

Once I'm logged in I'm running into another issue. It seems the session isn't being preserved as I can't refresh the app or visit another page without having to sign back in.

https://github.com/hackforla/HomeUniteUs/assets/27253583/30a8ff21-b75d-48c7-8d8a-9ef18e04f624

I'm also getting this error in the console:

Screenshot 2024-01-30 at 10 26 47 AM

I don't remember this tokenPair property on the cookie before so I'm not sure if it's related to that or something else.

Joshua-Douglas commented 3 months ago

Hey @erikguntner and @JpadillaCoding,

Thank you so much for taking time to review the PR. I fixed the bug with the refresh endpoint, and I updated the mock configuration to automatically add test users. Try it out and let me know what you think! You should be able to log in using test@test.com with password Test!123 while using the development configuration.

Here is a more detailed log of my changes: