Passed
Push — master ( b8e570...5310e7 )
by Peter
01:38
created

LtiRequestValidator   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 33
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 6
c 2
b 0
f 0
dl 0
loc 33
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A validate_timestamp_and_nonce() 0 6 1
A get_client_secret() 0 11 2
A enforce_ssl() 0 7 2
A validate_client_key() 0 2 1
1
from django.shortcuts import redirect
2
from django.http import HttpResponse
3
from django.core.exceptions import PermissionDenied
4
from django.core.urlresolvers import reverse
5
from oauthlib.oauth1 import RequestValidator
6
from lti.contrib.django import DjangoToolProvider
7
from lti import ToolConfig
8
9
from opensubmit.models import Course
10
from opensubmit.social import passthrough
11
from opensubmit import settings
12
13
import logging
14
logger = logging.getLogger('OpenSubmit')
15
16
17
class LtiRequestValidator(RequestValidator):
18
    dummy_client = 'NiemandWuerdeEinenDeutschenLtiKeyAnlegenDerSoLangIstAlsoEinGuterDummy'
19
    client_key_length = (1, 100)   # relax default restrictions
20
21
    def get_client_secret(self, client_key, request):
22
        '''
23
        Return secret for client key.
24
25
        Dummy client handling as described in
26
        http://oauthlib.readthedocs.io/en/latest/_modules/oauthlib/oauth1/rfc5849/request_validator.html
27
        '''
28
        if client_key == self.dummy_client:
29
            return self.dummy_client + 'MitSecret'
30
        else:
31
            return Course.objects.get(lti_key=client_key).lti_secret
32
33
    @property
34
    def enforce_ssl(self):
35
        if settings.DEBUG:
36
            # for test suite runs
37
            return False
38
        else:
39
            return True
40
41
    def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, request, request_token=None, access_token=None):
42
        '''
43
        Allow replay attacks.
44
        Ok, seriousely: TODO for storing nonce in database.
45
        '''
46
        return True
47
48
    def validate_client_key(self, client_key, request):
49
        return Course.objects.filter(lti_key=client_key).exists()
50
51
52
def login(request):
53
    '''View to check the provided LTI credentials.
54
55
    Getting in with a faked LTI consumer basically demands a
56
    staff email adress and a valid LTI key / secret pair.
57
    Which makes the latter really security sensitive.
58
    '''
59
    post_params = request.POST
60
    tool_provider = DjangoToolProvider.from_django_request(request=request)
61
    validator = LtiRequestValidator()
62
    if tool_provider.is_valid_request(validator):
63
        data = {}
64
        data['ltikey'] = post_params.get('oauth_consumer_key')
65
        # None of them is mandatory
66
        data['id'] = post_params.get('user_id', None)
67
        data['username'] = post_params.get('custom_username', None)
68
        data['last_name'] = post_params.get('lis_person_name_family', None)
69
        data['email'] = post_params.get('lis_person_contact_email_primary', None)
70
        data['first_name'] = post_params.get('lis_person_name_given', None)
71
        request.session[passthrough.SESSION_VAR] = data
72
        return redirect(reverse('social:begin', args=['lti']))
73
    else:
74
        raise PermissionDenied
75
76
77
def config(request):
78
    launch_url = request.build_absolute_uri(reverse('lti'))
79
80
    lti_tool_config = ToolConfig(
81
        title='OpenSubmit',
82
        description='Assignment Management and Submission System',
83
        launch_url=launch_url,
84
        secure_launch_url=launch_url)
85
86
    return HttpResponse(lti_tool_config.to_xml(), content_type='text/xml')
87