Repository: oppia/oppia

Issue:
Oppia local server stops working after going back from enter username page to enter email id page during new sign-in.
<!--
  - Thanks for taking the time to report a bug in the Oppia project.
  - Before filing a new issue, please do a quick search to check that it hasn't
  - already been filed on the [issue tracker](https://github.com/oppia/oppia/issues)._
  -->

**Describe the bug**
While doing the new sign-in, if I go back after entering the email id from enter the username page, the local server stops working and I am not able to open home page even after re-entering URL in new tab.

**To Reproduce**
Steps to reproduce the behavior:
 1. Start Oppia server locally.
 2. Click on sign-in button and after entering email id, move forward.
 3. When enter the username page appears, try to go back to the home page by clicking back button.
 4. Try re-entering the URL.

**Observed behavior**
Described above and proof video attached below.

**Expected behavior**
Should be able to go back from enter the username page.

**Screenshots**

https://user-images.githubusercontent.com/56637531/130371419-303ff69d-a5db-44f5-9cca-5495dcf91e8e.mov


**Desktop (please complete the following information; delete this section if the issue does not arise on desktop):**
 - OS: Mac
 - Browser Chrome
 - Browser-version 92


Oppia local server stops working after going back from enter username page to enter email id page during new sign-in.
<!--
  - Thanks for taking the time to report a bug in the Oppia project.
  - Before filing a new issue, please do a quick search to check that it hasn't
  - already been filed on the [issue tracker](https://github.com/oppia/oppia/issues)._
  -->

**Describe the bug**
While doing the new sign-in, if I go back after entering the email id from enter the username page, the local server stops working and I am not able to open home page even after re-entering URL in new tab.

**To Reproduce**
Steps to reproduce the behavior:
 1. Start Oppia server locally.
 2. Click on sign-in button and after entering email id, move forward.
 3. When enter the username page appears, try to go back to the home page by clicking back button.
 4. Try re-entering the URL.

**Observed behavior**
Described above and proof video attached below.

**Expected behavior**
Should be able to go back from enter the username page.

**Screenshots**

https://user-images.githubusercontent.com/56637531/130371419-303ff69d-a5db-44f5-9cca-5495dcf91e8e.mov


**Desktop (please complete the following information; delete this section if the issue does not arise on desktop):**
 - OS: Mac
 - Browser Chrome
 - Browser-version 92




Discussion:
This is happening on the Oppia test server too. I tried this once and now I am not able to access the test server on my browser.
Not sure whom to assign these types of issues, that's why assigning to release coordinators. @U8NWXD @kevintab95 

Edit: Clearing cookies worked.
I was able to reproduce this locally on the release branch. The issue seems to be that when going back, the URL becomes:

```
http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
...
```

(I added line breaks to make the repetition clear)
@brianrodri could you take a look at this since it appears to be related to the firebase login flow you worked on?
I was unable to reproduce this on the `release-3.1.3` branch, so I think we should consider it a regression. 

Note that on branch `release-3.1.3` there was a console error: 
```
Http failure during parsing for http://localhost:8181/logout?redirect_url=http://localhost:8181/userinfohandler
```
This is happening on the Oppia test server too. I tried this once and now I am not able to access the test server on my browser.
Not sure whom to assign these types of issues, that's why assigning to release coordinators. @U8NWXD @kevintab95 

Edit: Clearing cookies worked.
I was able to reproduce this locally on the release branch. The issue seems to be that when going back, the URL becomes:

```
http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
redirect_url=http://localhost:8181/logout?
...
```

(I added line breaks to make the repetition clear)
@brianrodri could you take a look at this since it appears to be related to the firebase login flow you worked on?
I was unable to reproduce this on the `release-3.1.3` branch, so I think we should consider it a regression. 

Note that on branch `release-3.1.3` there was a console error: 
```
Http failure during parsing for http://localhost:8181/logout?redirect_url=http://localhost:8181/userinfohandler
```

Resolving patch:
diff --git a/core/controllers/base.py b/core/controllers/base.py
--- a/core/controllers/base.py
+++ b/core/controllers/base.py
@@ -251,9 +251,10 @@ def dispatch(self):
             Exception. The CSRF token is missing.
             UnauthorizedUserException. The CSRF token is invalid.
         """
+        request_split = python_utils.url_split(self.request.uri)
         # If the request is to the old demo server, redirect it permanently to
         # the new demo server.
-        if self.request.uri.startswith('https://oppiaserver.appspot.com'):
+        if request_split.netloc == 'oppiaserver.appspot.com':
             self.redirect('https://oppiatestserver.appspot.com', permanent=True)
             return
 
@@ -267,7 +268,7 @@ def dispatch(self):
                 '/logout?redirect_url=%s' % feconf.PENDING_ACCOUNT_DELETION_URL)
             return
 
-        if self.partially_logged_in:
+        if self.partially_logged_in and request_split.path != '/logout':
             self.redirect('/logout?redirect_url=%s' % self.request.uri)
             return
 


Test patch:
diff --git a/core/controllers/base_test.py b/core/controllers/base_test.py
--- a/core/controllers/base_test.py
+++ b/core/controllers/base_test.py
@@ -99,6 +99,7 @@ class BaseHandlerTests(test_utils.GenericTestBase):
     TEST_EDITOR_USERNAME = 'testeditoruser'
     DELETED_USER_EMAIL = 'deleted.user@example.com'
     DELETED_USER_USERNAME = 'deleteduser'
+    PARTIALLY_LOGGED_IN_USER_EMAIL = 'partial@example.com'
 
     class MockHandlerWithInvalidReturnType(base.BaseHandler):
         GET_HANDLER_ERROR_RETURN_TYPE = 'invalid_type'
@@ -162,6 +163,11 @@ def setUp(self):
         deleted_user_model.update_timestamps()
         deleted_user_model.put()
 
+        # Create a new user but do not submit their registration form.
+        user_services.create_new_user(
+            self.get_auth_id_from_email(self.PARTIALLY_LOGGED_IN_USER_EMAIL),
+            self.PARTIALLY_LOGGED_IN_USER_EMAIL)
+
     def test_that_no_get_results_in_500_error(self):
         """Test that no GET request results in a 500 error."""
 
@@ -344,6 +350,25 @@ def test_splash_redirect(self):
         response = self.get_html_response('/splash', expected_status_int=302)
         self.assertEqual('http://localhost/', response.headers['location'])
 
+    def test_partially_logged_in_redirect(self):
+        login_context = self.login_context(
+            self.PARTIALLY_LOGGED_IN_USER_EMAIL)
+
+        with login_context:
+            response = self.get_html_response(
+                '/splash', expected_status_int=302)
+            self.assertEqual(
+                response.location,
+                'http://localhost/logout?redirect_url=http://localhost/splash')
+
+    def test_no_partially_logged_in_redirect_from_logout(self):
+        login_context = self.login_context(
+            self.PARTIALLY_LOGGED_IN_USER_EMAIL)
+
+        with login_context:
+            response = self.get_html_response(
+                '/logout', expected_status_int=200)
+
     def test_unauthorized_user_exception_raised_when_session_is_stale(self):
         with python_utils.ExitStack() as exit_stack:
             call_counter = exit_stack.enter_context(self.swap_with_call_counter(