Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
edx-platform-release
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
1
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Admin message
code.vt.edu will be down for maintenance from 0530-0630 EDT Wednesday, March 26th
Show more breadcrumbs
Hsin-Yu Chien
edx-platform-release
Commits
3505492f
Commit
3505492f
authored
5 years ago
by
Robert Raposa
Browse files
Options
Downloads
Patches
Plain Diff
require POST for login_user
ARCH-1253
parent
9f72c69e
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
common/djangoapps/third_party_auth/tests/specs/base.py
+91
-61
91 additions, 61 deletions
common/djangoapps/third_party_auth/tests/specs/base.py
openedx/core/djangoapps/user_authn/views/login.py
+1
-0
1 addition, 0 deletions
openedx/core/djangoapps/user_authn/views/login.py
with
92 additions
and
61 deletions
common/djangoapps/third_party_auth/tests/specs/base.py
+
91
−
61
View file @
3505492f
...
...
@@ -248,7 +248,7 @@ class HelperMixin(object):
return
defaults
def
get_request_and_strategy
(
self
,
auth_entry
=
None
,
redirect_uri
=
None
):
"""
Gets a fully-configured request and strategy.
"""
Gets a fully-configured
GET
request and strategy.
These two objects contain circular references, so we create them
together. The references themselves are a mixture of normal __init__
...
...
@@ -272,6 +272,21 @@ class HelperMixin(object):
return
request
,
strategy
def
_get_login_post_request
(
self
,
strategy
):
"""
Gets a fully-configured login POST request given a strategy and pipeline.
"""
request
=
self
.
request_factory
.
post
(
reverse
(
'
login_api
'
))
# Note: The shared GET request can't be used for login, which is now POST-only,
# so this POST request is given a copy of all configuration from the GET request
# with the active third-party auth pipeline and strategy.
request
.
site
=
strategy
.
request
.
site
request
.
social_strategy
=
strategy
request
.
user
=
strategy
.
request
.
user
request
.
session
=
strategy
.
request
.
session
request
.
backend
=
strategy
.
request
.
backend
return
request
@contextmanager
def
_patch_edxmako_current_request
(
self
,
request
):
"""
Make ``request`` be the current request for edxmako template rendering.
"""
...
...
@@ -534,12 +549,12 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
@mock.patch
(
'
third_party_auth.pipeline.segment.track
'
)
def
test_full_pipeline_succeeds_for_linking_account
(
self
,
_mock_segment_track
):
# First, create, the request and strategy that store pipeline state,
# First, create, the
GET
request and strategy that store pipeline state,
# configure the backend, and mock out wire traffic.
request
,
strategy
=
self
.
get_request_and_strategy
(
get_
request
,
strategy
=
self
.
get_request_and_strategy
(
auth_entry
=
pipeline
.
AUTH_ENTRY_LOGIN
,
redirect_uri
=
'
social:complete
'
)
request
.
backend
.
auth_complete
=
mock
.
MagicMock
(
return_value
=
self
.
fake_auth_complete
(
strategy
))
request
.
user
=
self
.
create_user_models_for_existing_account
(
get_
request
.
backend
.
auth_complete
=
mock
.
MagicMock
(
return_value
=
self
.
fake_auth_complete
(
strategy
))
get_
request
.
user
=
self
.
create_user_models_for_existing_account
(
strategy
,
'
user@example.com
'
,
'
password
'
,
self
.
get_username
(),
skip_social_auth
=
True
)
partial_pipeline_token
=
strategy
.
session_get
(
'
partial_pipeline_token
'
)
partial_data
=
strategy
.
storage
.
partial
.
load
(
partial_pipeline_token
)
...
...
@@ -548,75 +563,82 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
# expected state.
self
.
client
.
get
(
pipeline
.
get_login_url
(
self
.
provider
.
provider_id
,
pipeline
.
AUTH_ENTRY_LOGIN
))
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
request
)
actions
.
do_complete
(
get_
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
get_
request
)
login_user
(
strategy
.
request
)
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
request
)
post_request
=
self
.
_get_login_post_request
(
strategy
)
login_user
(
post_request
)
actions
.
do_complete
(
post_request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access, no-member
request
=
post_request
)
# First we expect that we're in the unlinked state, and that there
# really is no association in the backend.
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
request
),
linked
=
False
)
self
.
assert_social_auth_does_not_exist_for_user
(
request
.
user
,
strategy
)
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
get_
request
),
linked
=
False
)
self
.
assert_social_auth_does_not_exist_for_user
(
get_
request
.
user
,
strategy
)
# We should be redirected back to the complete page, setting
# the "logged in" cookie for the marketing site.
self
.
assert_logged_in_cookie_redirect
(
self
.
do_complete
(
strategy
,
request
,
partial_pipeline_token
,
partial_data
))
self
.
assert_logged_in_cookie_redirect
(
self
.
do_complete
(
strategy
,
get_request
,
partial_pipeline_token
,
partial_data
)
)
# Set the cookie and try again
self
.
set_logged_in_cookies
(
request
)
self
.
set_logged_in_cookies
(
get_
request
)
# Fire off the auth pipeline to link.
self
.
assert_redirect_after_pipeline_completes
(
self
.
do_complete
(
strategy
,
request
,
partial_pipeline_token
,
partial_data
)
self
.
do_complete
(
strategy
,
get_
request
,
partial_pipeline_token
,
partial_data
)
)
# Now we expect to be in the linked state, with a backend entry.
self
.
assert_social_auth_exists_for_user
(
request
.
user
,
strategy
)
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
request
),
linked
=
True
)
self
.
assert_social_auth_exists_for_user
(
get_
request
.
user
,
strategy
)
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
get_
request
),
linked
=
True
)
def
test_full_pipeline_succeeds_for_unlinking_account
(
self
):
# First, create, the request and strategy that store pipeline state,
# First, create, the
GET
request and strategy that store pipeline state,
# configure the backend, and mock out wire traffic.
request
,
strategy
=
self
.
get_request_and_strategy
(
get_
request
,
strategy
=
self
.
get_request_and_strategy
(
auth_entry
=
pipeline
.
AUTH_ENTRY_LOGIN
,
redirect_uri
=
'
social:complete
'
)
request
.
backend
.
auth_complete
=
mock
.
MagicMock
(
return_value
=
self
.
fake_auth_complete
(
strategy
))
get_
request
.
backend
.
auth_complete
=
mock
.
MagicMock
(
return_value
=
self
.
fake_auth_complete
(
strategy
))
user
=
self
.
create_user_models_for_existing_account
(
strategy
,
'
user@example.com
'
,
'
password
'
,
self
.
get_username
())
self
.
assert_social_auth_exists_for_user
(
user
,
strategy
)
# We're already logged in, so simulate that the cookie is set correctly
self
.
set_logged_in_cookies
(
request
)
self
.
set_logged_in_cookies
(
get_
request
)
# Instrument the pipeline to get to the dashboard with the full
# expected state.
self
.
client
.
get
(
pipeline
.
get_login_url
(
self
.
provider
.
provider_id
,
pipeline
.
AUTH_ENTRY_LOGIN
))
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
request
)
actions
.
do_complete
(
get_
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
get_
request
)
with
self
.
_patch_edxmako_current_request
(
strategy
.
request
):
login_user
(
strategy
.
request
)
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
user
=
user
,
# pylint: disable=protected-access
request
=
request
)
post_request
=
self
.
_get_login_post_request
(
strategy
)
with
self
.
_patch_edxmako_current_request
(
post_request
):
login_user
(
post_request
)
actions
.
do_complete
(
post_request
.
backend
,
social_views
.
_do_login
,
user
=
user
,
# pylint: disable=protected-access, no-member
request
=
post_request
)
# Copy the user that was set on the post_request object back to the original get_request object.
get_request
.
user
=
post_request
.
user
# First we expect that we're in the linked state, with a backend entry.
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
request
),
linked
=
True
)
self
.
assert_social_auth_exists_for_user
(
request
.
user
,
strategy
)
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
get_
request
),
linked
=
True
)
self
.
assert_social_auth_exists_for_user
(
get_
request
.
user
,
strategy
)
# Fire off the disconnect pipeline to unlink.
self
.
assert_redirect_after_pipeline_completes
(
actions
.
do_disconnect
(
request
.
backend
,
request
.
user
,
get_
request
.
backend
,
get_
request
.
user
,
None
,
redirect_field_name
=
auth
.
REDIRECT_FIELD_NAME
)
)
# Now we expect to be in the unlinked state, with no backend entry.
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
request
),
linked
=
False
)
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
get_
request
),
linked
=
False
)
self
.
assert_social_auth_does_not_exist_for_user
(
user
,
strategy
)
def
test_linking_already_associated_account_raises_auth_already_associated
(
self
):
...
...
@@ -650,7 +672,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
# unlinked, but getting that behavior is cumbersome here and already
# covered in other tests. Using linked=True does, however, let us test
# that the duplicate error has no effect on the state of the controls.
request
,
strategy
=
self
.
get_request_and_strategy
(
get_
request
,
strategy
=
self
.
get_request_and_strategy
(
auth_entry
=
pipeline
.
AUTH_ENTRY_LOGIN
,
redirect_uri
=
'
social:complete
'
)
strategy
.
request
.
backend
.
auth_complete
=
mock
.
MagicMock
(
return_value
=
self
.
fake_auth_complete
(
strategy
))
user
=
self
.
create_user_models_for_existing_account
(
...
...
@@ -659,28 +681,29 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
self
.
client
.
get
(
'
/login
'
)
self
.
client
.
get
(
pipeline
.
get_login_url
(
self
.
provider
.
provider_id
,
pipeline
.
AUTH_ENTRY_LOGIN
))
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
request
)
actions
.
do_complete
(
get_
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
request
=
get_
request
)
with
self
.
_patch_edxmako_current_request
(
strategy
.
request
):
login_user
(
strategy
.
request
)
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access
user
=
user
,
request
=
request
)
post_request
=
self
.
_get_login_post_request
(
strategy
)
with
self
.
_patch_edxmako_current_request
(
post_request
):
login_user
(
post_request
)
actions
.
do_complete
(
post_request
.
backend
,
social_views
.
_do_login
,
# pylint: disable=protected-access, no-member
user
=
user
,
request
=
post_request
)
# Monkey-patch storage for messaging; pylint: disable=protected-access
request
.
_messages
=
fallback
.
FallbackStorage
(
request
)
post_
request
.
_messages
=
fallback
.
FallbackStorage
(
post_
request
)
middleware
.
ExceptionMiddleware
().
process_exception
(
request
,
post_
request
,
exceptions
.
AuthAlreadyAssociated
(
self
.
provider
.
backend_name
,
'
account is already in use.
'
))
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
request
),
duplicate
=
True
,
linked
=
True
)
account_settings_context
(
post_
request
),
duplicate
=
True
,
linked
=
True
)
@mock.patch
(
'
third_party_auth.pipeline.segment.track
'
)
def
test_full_pipeline_succeeds_for_signing_in_to_existing_active_account
(
self
,
_mock_segment_track
):
# First, create, the request and strategy that store pipeline state,
# First, create, the
GET
request and strategy that store pipeline state,
# configure the backend, and mock out wire traffic.
request
,
strategy
=
self
.
get_request_and_strategy
(
get_
request
,
strategy
=
self
.
get_request_and_strategy
(
auth_entry
=
pipeline
.
AUTH_ENTRY_LOGIN
,
redirect_uri
=
'
social:complete
'
)
strategy
.
request
.
backend
.
auth_complete
=
mock
.
MagicMock
(
return_value
=
self
.
fake_auth_complete
(
strategy
))
user
=
self
.
create_user_models_for_existing_account
(
...
...
@@ -704,33 +727,37 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
# Next, the provider makes a request against /auth/complete/<provider>
# to resume the pipeline.
# pylint: disable=protected-access
self
.
assert_redirect_to_login_looks_correct
(
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
request
=
request
))
self
.
assert_redirect_to_login_looks_correct
(
actions
.
do_complete
(
get_
request
.
backend
,
social_views
.
_do_login
,
request
=
get_
request
))
# At this point we know the pipeline has resumed correctly. Next we
# fire off the view that displays the login form and posts it via JS.
with
self
.
_patch_edxmako_current_request
(
strategy
.
request
):
self
.
assert_login_response_in_pipeline_looks_correct
(
login_
user
(
strategy
.
request
))
self
.
assert_login_response_in_pipeline_looks_correct
(
login_
and_registration_form
(
strategy
.
request
))
# Next, we invoke the view that handles the POST, and expect it
# redirects to /auth/complete. In the browser ajax handlers will
# redirect the user to the dashboard; we invoke it manually here.
self
.
assert_json_success_response_looks_correct
(
login_user
(
strategy
.
request
),
verify_redirect_url
=
True
)
post_request
=
self
.
_get_login_post_request
(
strategy
)
self
.
assert_json_success_response_looks_correct
(
login_user
(
post_request
),
verify_redirect_url
=
True
)
# We should be redirected back to the complete page, setting
# the "logged in" cookie for the marketing site.
self
.
assert_logged_in_cookie_redirect
(
actions
.
do_complete
(
request
.
backend
,
social_views
.
_do_login
,
request
.
user
,
None
,
# pylint: disable=protected-access
redirect_field_name
=
auth
.
REDIRECT_FIELD_NAME
,
request
=
request
post_
request
.
backend
,
social_views
.
_do_login
,
post_
request
.
user
,
None
,
# pylint: disable=protected-access
, no-member
redirect_field_name
=
auth
.
REDIRECT_FIELD_NAME
,
request
=
post_
request
))
# Set the cookie and try again
self
.
set_logged_in_cookies
(
request
)
self
.
set_logged_in_cookies
(
get_request
)
# Copy the user that was set on the post_request object back to the original get_request object.
get_request
.
user
=
post_request
.
user
self
.
assert_redirect_after_pipeline_completes
(
self
.
do_complete
(
strategy
,
request
,
partial_pipeline_token
,
partial_data
,
user
)
self
.
do_complete
(
strategy
,
get_
request
,
partial_pipeline_token
,
partial_data
,
user
)
)
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
request
))
self
.
assert_account_settings_context_looks_correct
(
account_settings_context
(
get_
request
))
def
test_signin_fails_if_account_not_active
(
self
):
_
,
strategy
=
self
.
get_request_and_strategy
(
...
...
@@ -742,8 +769,9 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
user
.
is_active
=
False
user
.
save
()
with
self
.
_patch_edxmako_current_request
(
strategy
.
request
):
self
.
assert_json_failure_response_is_inactive_account
(
login_user
(
strategy
.
request
))
post_request
=
self
.
_get_login_post_request
(
strategy
)
with
self
.
_patch_edxmako_current_request
(
post_request
):
self
.
assert_json_failure_response_is_inactive_account
(
login_user
(
post_request
))
def
test_signin_fails_if_no_account_associated
(
self
):
_
,
strategy
=
self
.
get_request_and_strategy
(
...
...
@@ -752,7 +780,8 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
self
.
create_user_models_for_existing_account
(
strategy
,
'
user@example.com
'
,
'
password
'
,
self
.
get_username
(),
skip_social_auth
=
True
)
self
.
assert_json_failure_response_is_missing_social_auth
(
login_user
(
strategy
.
request
))
post_request
=
self
.
_get_login_post_request
(
strategy
)
self
.
assert_json_failure_response_is_missing_social_auth
(
login_user
(
post_request
))
def
test_first_party_auth_trumps_third_party_auth_but_is_invalid_when_only_email_in_request
(
self
):
self
.
assert_first_party_auth_trumps_third_party_auth
(
email
=
'
user@example.com
'
)
...
...
@@ -924,15 +953,16 @@ class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin):
self
.
create_user_models_for_existing_account
(
strategy
,
email
,
password
,
self
.
get_username
(),
skip_social_auth
=
True
)
strategy
.
request
.
POST
=
dict
(
strategy
.
request
.
POST
)
post_request
=
self
.
_get_login_post_request
(
strategy
)
post_request
.
POST
=
dict
(
post_request
.
POST
)
if
email
:
strategy
.
request
.
POST
[
'
email
'
]
=
email
post_
request
.
POST
[
'
email
'
]
=
email
if
password
:
strategy
.
request
.
POST
[
'
password
'
]
=
'
bad_
'
+
password
if
success
is
False
else
password
post_
request
.
POST
[
'
password
'
]
=
'
bad_
'
+
password
if
success
is
False
else
password
self
.
assert_pipeline_running
(
strategy
.
request
)
payload
=
json
.
loads
(
login_user
(
strategy
.
request
).
content
.
decode
(
'
utf-8
'
))
self
.
assert_pipeline_running
(
post_
request
)
payload
=
json
.
loads
(
login_user
(
post_
request
).
content
.
decode
(
'
utf-8
'
))
if
success
is
None
:
# Request malformed -- just one of email/password given.
...
...
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/user_authn/views/login.py
+
1
−
0
View file @
3505492f
...
...
@@ -333,6 +333,7 @@ def finish_auth(request): # pylint: disable=unused-argument
@ensure_csrf_cookie
@require_http_methods
([
'
POST
'
])
def
login_user
(
request
):
"""
AJAX request to log in the user.
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment