diff --git a/api/users/views.py b/api/users/views.py index b920798be86..b887ee7bdd6 100644 --- a/api/users/views.py +++ b/api/users/views.py @@ -755,7 +755,11 @@ def post(self, request, *args, **kwargs): # 1. update user oauth, with pending status external_identity[external_id_provider][external_id] = 'LINK' if external_id_provider in user.external_identity: - user.external_identity[external_id_provider].update(external_identity[external_id_provider]) + # v1 looks to be used because of /confirm/external/ usage for auth but add orcid external identity rewrite updates for v2 as well + if external_id_provider == settings.EXTERNAL_IDENTITY_PROFILE.get('OrcidProfile'): + user.external_identity[external_id_provider] = external_identity[external_id_provider] + else: + user.external_identity[external_id_provider].update(external_identity[external_id_provider]) else: user.external_identity.update(external_identity) if not user.accepted_terms_of_service and accepted_terms_of_service: @@ -1153,7 +1157,6 @@ class ConfirmEmailView(generics.CreateAPIView): def _process_external_identity(self, user, external_identity, service_url): """Handle all external_identity logic, including task enqueueing and url updates.""" - provider = next(iter(external_identity)) if provider not in user.external_identity: raise ValidationError('External-ID provider mismatch.') diff --git a/api_tests/users/views/test_user_external_login.py b/api_tests/users/views/test_user_external_login.py index 6f436f5d422..fca05aadbc8 100644 --- a/api_tests/users/views/test_user_external_login.py +++ b/api_tests/users/views/test_user_external_login.py @@ -48,7 +48,7 @@ def csrf_token(self): @pytest.fixture() def session_data(self): session = SessionStore() - session['auth_user_external_id_provider'] = 'orcid' + session['auth_user_external_id_provider'] = 'ORCID' session['auth_user_external_id'] = '1234-1234-1234-1234' session['auth_user_fullname'] = 'external login' session['auth_user_external_first_login'] = True @@ -62,7 +62,7 @@ def test_external_login(self, app, payload, url, session_data, csrf_token): with capture_notifications(): res = app.post_json_api(url, payload, headers={'X-CSRFToken': csrf_token}) assert res.status_code == 200 - assert res.json == {'external_id_provider': 'orcid', 'auth_user_fullname': 'external login'} + assert res.json == {'external_id_provider': 'ORCID', 'auth_user_fullname': 'external login'} assert not OSFUser.objects.get(username='freddie@mercury.com').is_confirmed def test_invalid_payload(self, app, url, session_data, csrf_token): @@ -84,6 +84,24 @@ def test_existing_user(self, app, payload, url, user_one, session_data, csrf_tok with capture_notifications(): res = app.post_json_api(url, payload, headers={'X-CSRFToken': csrf_token}) assert res.status_code == 200 - assert res.json == {'external_id_provider': 'orcid', 'auth_user_fullname': 'external login'} + assert res.json == {'external_id_provider': 'ORCID', 'auth_user_fullname': 'external login'} user_one.reload() assert user_one.username in user_one.unconfirmed_emails + + def test_existing_user_orcid_overwrites(self, app, payload, url, user_one, session_data, csrf_token): + user_one.external_identity = { + 'ORCID': { + '0000-0000-0000-0000': 'LINK', + } + } + user_one.save() + app.set_cookie(CSRF_COOKIE_NAME, csrf_token) + app.set_cookie(settings.COOKIE_NAME, str(session_data)) + assert user_one.external_identity['ORCID'] == {'0000-0000-0000-0000': 'LINK'} + assert '0000-0000-0000-0000' in user_one.external_identity['ORCID'] + payload['data']['attributes']['email'] = user_one.username + with capture_notifications(): + res = app.post_json_api(url, payload, headers={'X-CSRFToken': csrf_token}) + assert res.status_code == 200 + user_one.reload() + assert user_one.external_identity['ORCID'] == {'1234-1234-1234-1234': 'LINK'} diff --git a/framework/auth/views.py b/framework/auth/views.py index aefb1b4f0e8..c40605ca512 100644 --- a/framework/auth/views.py +++ b/framework/auth/views.py @@ -1097,7 +1097,11 @@ def external_login_email_post(): # 1. update user oauth, with pending status external_identity[external_id_provider][external_id] = 'LINK' if external_id_provider in user.external_identity: - user.external_identity[external_id_provider].update(external_identity[external_id_provider]) + # v1 looks to be used because of /confirm/external/ usage for auth but add orcid external identity rewrite updates for v2 as well + if external_id_provider == settings.EXTERNAL_IDENTITY_PROFILE.get('OrcidProfile'): + user.external_identity[external_id_provider] = external_identity[external_id_provider] + else: + user.external_identity[external_id_provider].update(external_identity[external_id_provider]) else: user.external_identity.update(external_identity) if not user.accepted_terms_of_service and form.accepted_terms_of_service.data: