Skip to content
This repository has been archived by the owner on Feb 27, 2021. It is now read-only.

Commit

Permalink
Merge pull request #883 from dissemin/shibboleth
Browse files Browse the repository at this point in the history
Shibboleth
  • Loading branch information
wetneb committed Jan 13, 2021
2 parents e7f96e6 + c12322e commit 28300e5
Show file tree
Hide file tree
Showing 56 changed files with 4,642 additions and 167 deletions.
44 changes: 36 additions & 8 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@
from papers.models import Researcher
from publishers.models import Journal
from publishers.models import Publisher
from upload.models import UploadedPDF


@pytest.fixture
def shib_meta():
SHIB_META = {
'username' : 'https://idp.dissem.in/!https://sp.dissem.in!dmltZXNzQGRpc2N3b3JsZC5lZHU=',
'first_name' : 'Samuel',
'last_name' : 'Vimes',
'orcid' : '0000-0001-8187-9704',
'email' : 'vimess@discworld.edu',
}
return SHIB_META


@pytest.fixture
Expand Down Expand Up @@ -212,6 +225,19 @@ def dummy_repository(repository):
"""
return repository.dummy_repository()


@pytest.fixture
def uploaded_pdf(user_leibniz):
"""
A simple uploaded pdf of user leibniz. The file does not exist.
"""
pdf = UploadedPDF.objects.create(
user=user_leibniz,
file='uploaded_pdf.pdf',
)
return pdf


@pytest.fixture
def requests_mocker():
with responses.RequestsMock() as rsps:
Expand All @@ -232,6 +258,7 @@ def request_callback(request):
return (200, headers, body)
except FileNotFoundError:
print('File not found: {} - Returning 404'.format(f_path))
print("curl -LH \"Accept: application/citeproc+json\" \"{}\" > {}".format(request.url, f_path))
return (404, {}, None)

requests_mocker.add_callback(
Expand Down Expand Up @@ -280,7 +307,6 @@ def mock_pub_orcid(requests_mocker):
def request_callback(request):
# Remove leading /v2.1/ and trailing /
f_name = '{}.json'.format(request.path_url[6:-1])
print(f_name)
f_path = os.path.join(settings.BASE_DIR, 'test_data', 'orcid', f_name)
headers = {
'Content-Type' : 'application/citeproc+json'
Expand All @@ -290,12 +316,12 @@ def request_callback(request):
body = f.read()
return (200, headers, body)
except FileNotFoundError:
print('File not found: {} - Returning 404'.format(f_path))
print("curl -H \"Accept: application/orcid+json\" \"{}\" > {}".format(request.url, f_path))
return (404, {}, None)

requests_mocker.add_callback(
requests_mocker.GET,
re.compile(r'https://pub.orcid.org/v2.1'),
re.compile(r'https://pub.{}/v2.1'.format(settings.ORCID_BASE_DOMAIN)),
callback=request_callback
)

Expand Down Expand Up @@ -721,13 +747,16 @@ def base_oaisource():


# Fixtures and Functions for load_test_data, which should prefereably not be used as it loads a lot of things
def get_researcher_by_name(first, last):
n = Name.lookup_name((first, last))
return Researcher.objects.get(name=n)
@pytest.fixture(scope="class")
def get_researcher_by_name():
def func(first, last):
n = Name.lookup_name((first, last))
return Researcher.objects.get(name=n)
return func


@pytest.fixture
def load_test_data(request, db):
def load_test_data(request, db, get_researcher_by_name):
call_command('loaddata', 'test_dump.json')
self = request.cls
self.i = Institution.objects.get(name='ENS')
Expand All @@ -744,7 +773,6 @@ def load_test_data(request, db):
self.lncs = Journal.objects.get(issn='0302-9743')
self.acm = Journal.objects.get(issn='1529-3785').publisher


@pytest.fixture
def rebuild_index(request):
rebuild_index = (
Expand Down
1 change: 1 addition & 0 deletions deposit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def depositing_user(db, request, user_leibniz):
"""
Depositing user with Researcher profile with and without ORCID
"""
user_leibniz.shib = dict()
Researcher.create_by_name(
user=user_leibniz,
first=user_leibniz.first_name,
Expand Down
13 changes: 13 additions & 0 deletions deposit/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from functools import wraps

def shib_meta_to_user(view_func):
"""
Decorator that adds shib_meta dict from request.session to request.user
This could also be done in the middleware, but just sometimes need to access the attributes; and request.session is usually the better place
We use this, so we do not need to pass around a request to all the backend deposit functions that only care about the user
"""
@wraps(view_func)
def inner(request, *args, **kwargs):
request.user.shib = request.session.get('shib', {})
return view_func(request, *args, **kwargs)
return inner
38 changes: 20 additions & 18 deletions deposit/sword/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,26 @@
from lxml import etree
from zipfile import ZipFile

from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import MultipleObjectsReturned
from django.utils.functional import cached_property
from django.utils.translation import ugettext as _

from deposit.models import DepositRecord
from deposit.models import UserPreferences
from deposit.protocol import DepositError
from deposit.protocol import DepositResult
from deposit.protocol import RepositoryProtocol
from deposit.registry import protocol_registry
from deposit.sword.forms import SWORDMETSForm
from deposit.utils import MetadataConverter
from deposit.utils import get_email

from papers.models import Institution
from papers.models import OaiRecord
from papers.models import Researcher
from papers.utils import kill_html

from website.utils import get_users_idp


logger = logging.getLogger('dissemin.' + __name__)


Expand Down Expand Up @@ -201,8 +203,11 @@ def _get_xml_dissemin_metadata(self, form):
ds_depositor = etree.SubElement(ds, DS + 'depositor')

ds_authentication = etree.SubElement(ds_depositor, DS + 'authentication')
# hard-coded since there is currently only one authentication method
ds_authentication.text = 'orcid'
# We have currently two uthentication methods
if self.user.shib.get('username'):
ds_authentication.text = 'shibboleth'
else:
ds_authentication.text = 'orcid'

ds_first_name = etree.SubElement(ds_depositor, DS + 'firstName')
ds_first_name.text = self.user.first_name
Expand All @@ -224,6 +229,15 @@ def _get_xml_dissemin_metadata(self, form):
else:
ds_is_contributor.text = 'false'

# If the user is authenticated via shibboleth, we can find out if the user is a member of the repository's institution
ds_identical_institution = etree.SubElement(ds_depositor, DS + 'identicalInstitution')
idp_identifier = get_users_idp(self.user)
if Institution.objects.get_repository_by_identifier(idp_identifier) == self.repository:
ds_identical_institution.text = 'true'
else:
ds_identical_institution.text = 'false'


# Information about the publication

ds_publication = etree.SubElement(ds, DS + 'publication')
Expand Down Expand Up @@ -272,19 +286,7 @@ def get_form_initial_data(self, **kwargs):
self.paper.consolidate_metadata(wait=False)

# We try to find an email, if we do not succed, that's ok
up = UserPreferences.get_by_user(user=self.user)
if up.email:
data['email'] = up.email
else:
try:
r = Researcher.objects.get(user=self.user)
except ObjectDoesNotExist:
pass
except MultipleObjectsReturned:
logger.warning("User with id {} has multiple researcher objects assigned".format(self.user.id))
else:
if r.email:
data['email'] = r.email
data['email'] = get_email(self.user)

return data

Expand Down
7 changes: 3 additions & 4 deletions deposit/sword/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,16 +218,15 @@ def test_get_bound_form(self, book_god_of_the_labyrinth, empty_user_preferences,


@pytest.mark.parametrize('email', ['isaac.newton@dissem.in', None])
def test_get_form_initial_data(self, book_god_of_the_labyrinth, empty_user_preferences, email):
def test_get_form_initial_data(self, book_god_of_the_labyrinth, user_leibniz, email):
"""
Check the initial data
TODO: Licenses
"""
self.protocol.paper = book_god_of_the_labyrinth

self.protocol.user = empty_user_preferences.user
empty_user_preferences.email = email
empty_user_preferences.save()
self.protocol.user = user_leibniz
user_leibniz.email = email

initial = self.protocol.get_form_initial_data()

Expand Down
12 changes: 0 additions & 12 deletions deposit/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,8 @@
from deposit.models import DepositRecord
from deposit.models import LetterOfDeclaration
from papers.models import Researcher
from upload.models import UploadedPDF


@pytest.fixture
def uploaded_pdf(user_leibniz):
"""
A simple uploaded pdf of user leibniz. The file does not exist.
"""
pdf = UploadedPDF.objects.create(
user=user_leibniz,
file='uploaded_pdf.pdf',
)
return pdf

@pytest.fixture
def lod_env(request, db, book_god_of_the_labyrinth, authenticated_client, dummy_repository, uploaded_pdf):
"""
Expand Down
38 changes: 38 additions & 0 deletions deposit/tests/test_decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django.contrib.auth.middleware import AuthenticationMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.http import HttpResponse

from deposit.decorators import shib_meta_to_user
from website.middleware import ShibbolethRemoteUserMiddleware

class TestShibMetaToUser:

def test_with_values(self, db, monkeypatch, rf, shib_meta):
monkeypatch.setattr(ShibbolethRemoteUserMiddleware, 'parse_attributes', lambda x, y: (shib_meta, None))
request = rf.get('/', REMOTE_USER=shib_meta.get('username'))
SessionMiddleware().process_request(request)
AuthenticationMiddleware().process_request(request)
ShibbolethRemoteUserMiddleware().process_request(request)

# Let's test the decorator
@shib_meta_to_user
def sample_view(request):
# Let's check the attribute
assert request.user.shib == shib_meta
return HttpResponse()
response = sample_view(request)
assert response.status_code == 200

def test_without_values(self, rf):
request = rf.get('/')
SessionMiddleware().process_request(request)
AuthenticationMiddleware().process_request(request)

# Let's test the decorator
@shib_meta_to_user
def sample_view(request):
# Let's check the attribute
assert request.user.shib =={}
return HttpResponse()
response = sample_view(request)
assert response.status_code == 200
71 changes: 70 additions & 1 deletion deposit/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import pytest

from deposit.models import UserPreferences
from deposit.utils import MetadataConverter

from deposit.utils import get_email
from deposit.utils import get_preselected_repository
from papers.models import Institution
from papers.models import OaiSource
from papers.models import OaiRecord
from papers.models import Researcher
from publishers.models import Journal
from publishers.models import Publisher

Expand Down Expand Up @@ -71,6 +75,71 @@ def alternative_record(db, book_god_of_the_labyrinth, dummy_oaisource):
return o


class TestGetEmail:
"""
Test about getting the email of a user
"""
email = 'test@dissem.in'

@pytest.fixture(autouse=True)
def setup(self, django_user_model):
self.user = django_user_model.objects.create(username='test')

def test_mail_from_shib(self):
self.user.shib = {'email' : self.email}
email = get_email(self.user)
assert email == self.email

def test_mail_from_preferences(self):
UserPreferences.objects.create(user=self.user, email=self.email)
email = get_email(self.user)
assert email == self.email

def test_mail_from_researcher(self):
Researcher.create_by_name('a', 'b', user=self.user, email=self.email)
email = get_email(self.user)
assert email == self.email

def test_mail_from_user(self):
self.user.email = self.email
email = get_email(self.user)
assert email == self.email

def test_no_email(self):
email = get_email(self.user)
assert email is None

class TestGetPreselectedRepository:

@pytest.fixture(autouse=True)
def setup(self, django_user_model, dummy_repository):
self.user = django_user_model.objects.create(username='test')
self.repository = dummy_repository
self.repositories = [dummy_repository]

def test_preferred_repository(self):
UserPreferences.objects.create(user=self.user, preferred_repository=self.repository)
assert get_preselected_repository(self.user, self.repositories) == self.repository

def test_from_shibboleth(self, shib_meta):
self.user.shib = shib_meta
Institution.objects.create(
name='Insitute',
identifiers=['shib:{}'.format(shib_meta.get('username').split('!')[0])],
repository=self.repository
)
assert get_preselected_repository(self.user, self.repositories) == self.repository

def test_last(self):
UserPreferences.objects.create(user=self.user, last_repository=self.repository)
assert get_preselected_repository(self.user, self.repositories) == self.repository

def test_none(self):
assert get_preselected_repository(self.user, self.repositories) is None




class TestMetadataConverter():

oairecord_keys = ['doi', 'essn', 'issn', 'issue', 'journal', 'pages', 'publisher', 'romeo_id', 'volume']
Expand Down
Loading

0 comments on commit 28300e5

Please sign in to comment.