Exemplo n.º 1
0
def launch_lti(request):
    """
    Receives a request from consumer and authenticates user (or create it)
    """

    # print out log if LTI_DEBUG=True in settings
    if settings.LTI_DEBUG:
        for item in request.POST:
            print >> sys.stderr, ('%s: %s \r' % (item, request.POST[item]))

    if 'oauth_consumer_key' not in request.POST:
        raise PermissionDenied()

    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)

    try:  # attempt to validate request, if fails raises 403 Forbidden
        if tool_provider.valid_request(request) == False:
            raise PermissionDenied()
    except:
        print "LTI Exception: Not a valid request."
        raise PermissionDenied()

    return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
Exemplo n.º 2
0
def add_problem(request):
    session = request.session
    if session['LTI_POST']:
        try:
            request_post = pickle.loads(session['LTI_POST'])

            request_post['lis_outcome_service_url'] = fix_url(request_post['lis_outcome_service_url'])
            consumer_key = settings.CONSUMER_KEY
            secret = settings.LTI_SECRET
            tool = DjangoToolProvider(consumer_key, secret, request_post)

            result = float(request.POST.get('result'))
            if result == 5:
                score = '1.00'
            else:
                score = '0.00'
            post_result = tool.post_replace_result(score,{'message_identifier':'edX_fix'})
            print post_result.is_success()
            d = dict()
            d['score'] = score
            d['success'] = post_result.is_success()
            d['result'] = result
            d['show'] = True
            return render_to_response("ims_lti_py_sample/index.html", d,  RequestContext(request))
        except KeyError,e:
            return render_to_response("ims_lti_py_sample/error.html",  RequestContext(request))
Exemplo n.º 3
0
def launch_lti(request):
    """
    Receives a request from consumer and authenticates user (or create it)
    """

    # print out log if LTI_DEBUG=True in settings
    if settings.LTI_DEBUG:
        for item in request.POST:
            print >> sys.stderr, ('%s: %s \r' % (item, request.POST[item]))
    
    if 'oauth_consumer_key' not in request.POST:
        raise PermissionDenied()
        
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)
    
    try: # attempt to validate request, if fails raises 403 Forbidden
        if tool_provider.valid_request(request) == False:
            raise PermissionDenied()
    except:
        print "LTI Exception: Not a valid request."
        raise PermissionDenied()
    
    return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
Exemplo n.º 4
0
def add_problem(request):
    session = request.session
    if session['LTI_POST']:
        try:
            request_post = pickle.loads(session['LTI_POST'])

            request_post['lis_outcome_service_url'] = fix_url(
                request_post['lis_outcome_service_url'])
            consumer_key = settings.CONSUMER_KEY
            secret = settings.LTI_SECRET
            tool = DjangoToolProvider(consumer_key, secret, request_post)

            result = float(request.POST.get('result'))
            if result == 5:
                score = '1.00'
            else:
                score = '0.00'
            post_result = tool.post_replace_result(
                score, {'message_identifier': 'edX_fix'})
            print post_result.is_success()
            d = dict()
            d['score'] = score
            d['success'] = post_result.is_success()
            d['result'] = result
            d['show'] = True
            return render_to_response("ims_lti_py_sample/index.html", d,
                                      RequestContext(request))
        except KeyError, e:
            return render_to_response("ims_lti_py_sample/error.html",
                                      RequestContext(request))
Exemplo n.º 5
0
def initialize_lti_tool_provider(req):
    """
    Starts the provider given the consumer_key and secret.
    """
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET_DICT[req.POST.get('context_id')]

    # use the function from ims_lti_py app to verify and initialize tool
    provider = DjangoToolProvider(consumer_key, secret, req.POST)

    # NOTE: before validating the request, temporarily remove the
    # QUERY_STRING to work around an issue with how Canvas signs requests
    # that contain GET parameters. Before Canvas launches the tool, it duplicates the GET
    # parameters as POST parameters, and signs the POST parameters (*not* the GET parameters).
    # However, the oauth2 library that validates the request generates
    # the oauth signature based on the combination of POST+GET parameters together,
    # resulting in a signature mismatch. By removing the QUERY_STRING before
    # validating the request, the library will generate the signature based only on
    # the POST parameters like Canvas.
    qs = req.META.pop('QUERY_STRING', '')

    # now validate the tool via the valid_request function
    # this means that request was well formed but invalid
    if provider.valid_request(req) == False:
        debug_printer("DEBUG - LTI Exception: Not a valid request.")
        raise PermissionDenied()
    else:
        debug_printer('DEBUG - LTI Tool Provider was valid.')

    req.META['QUERY_STRING'] = qs  # restore the query string

    return provider
Exemplo n.º 6
0
def lti(request, gid):
    graph = get_object_or_404(Graphs, pk=gid)

    if request.method != 'POST' or 'oauth_consumer_key' not in request.POST:
        return HttpResponse("Improper LTI request method", status=405)

    # confirm oauth credentials with ims_lti tool
    tool_provider = DjangoToolProvider(graph.lti_key, graph.lti_secret,
                                       request.POST)
    try:
        if tool_provider.valid_request(request) is False:
            raise PermissionDenied()
    except:
        raise PermissionDenied()

    # build username from userid
    userid = getattr(tool_provider, "user_id", None)
    if userid is None: raise PermissionDenied()

    username = "******" % (userid)

    # try to get the user
    user = authenticate(username=username)
    if user is None:
        u = User.objects.create_user(username=username)
        u.set_unusable_password()
        u.save()
        user = authenticate(username=username)

    # have the user ready to go, login
    login(request, user)

    # LTI user logged in, forward to map
    return HttpResponseRedirect(reverse("maps:display", kwargs={"gid": gid}))
Exemplo n.º 7
0
def lti(request, gid):
    graph = get_object_or_404(Graphs, pk=gid)

    if request.method != 'POST' or 'oauth_consumer_key' not in request.POST:
        return HttpResponse("Improper LTI request method", status=405)

    # confirm oauth credentials with ims_lti tool
    tool_provider = DjangoToolProvider(graph.lti_key, graph.lti_secret, request.POST)
    try:
        if tool_provider.valid_request(request) is False:
            raise PermissionDenied()
    except:
        raise PermissionDenied()

    # build username from userid
    userid = getattr(tool_provider, "user_id", None)
    if userid is None: raise PermissionDenied()

    username = "******" % (userid)

    # try to get the user
    user = authenticate(username=username)
    if user is None:
        u = User.objects.create_user(username=username)
        u.set_unusable_password()
        u.save()
        user = authenticate(username=username)

    # have the user ready to go, login
    login(request, user)

    # LTI user logged in, forward to map
    return HttpResponseRedirect(reverse("maps:display", kwargs={"gid":gid}))
    def send_lti_grade(self, grade):
        """ Instantiates DjangoToolProvider using stored lti parameters and sends grade """
        self._validate_lti_grade_request(grade)
        provider = DjangoToolProvider(settings.LTI_CLIENT_KEY, settings.LTI_CLIENT_SECRET, self.edx_lti_parameters)
        outcome = provider.post_replace_result(grade)

        _logger.info(u"LTI grade request was {successful}. Description is {description}".format(
            successful="successful" if outcome.is_success() else "unsuccessful", description=outcome.description
        ))

        return outcome
Exemplo n.º 9
0
    def _get_tool_provider(self):
        try:
            lti_secret = settings.LTI_SECRET_DICT[self.request.LTI.get(
                'hx_context_id')]
        except KeyError:
            lti_secret = settings.LTI_SECRET

        if 'launch_params' in self.request.LTI:
            params = self.request.LTI['launch_params']
            return DjangoToolProvider(CONSUMER_KEY, lti_secret, params)
        return DjangoToolProvider(CONSUMER_KEY, lti_secret)
Exemplo n.º 10
0
def assessment(request):
	if request.session['launch_params']:
		key = request.session['launch_params']['oauth_consumer_key']
	else:
		key_error_temp = get_template("error.html")
		key_error_html = key_error_temp.render(Context({'message': 'The tool never launched'}))
		return HttpResponse(key_error_html)

	tp = DjangoToolProvider(key, oauth_creds[key], request.session['launch_params'])

	score = request.POST['score']
	tp.post_replace_result(score)
	temp = get_template('assessment_finished.html')
	html = temp.render(Context({'score': score}))
	return HttpResponse(html)
Exemplo n.º 11
0
    def send_lti_grade(self, grade):
        """ Instantiates DjangoToolProvider using stored lti parameters and sends grade """
        self._validate_lti_grade_request(grade)
        provider = DjangoToolProvider(settings.LTI_CLIENT_KEY,
                                      settings.LTI_CLIENT_SECRET,
                                      self.edx_lti_parameters)
        outcome = provider.post_replace_result(grade)

        _logger.info(
            u"LTI grade request was %(successful)s. Description is %(description)s",
            dict(successful="successful"
                 if outcome.is_success() else "unsuccessful",
                 description=outcome.description))

        return outcome
Exemplo n.º 12
0
def lti_init(request, course_id=None, unit_id=None):
    """LTI init view

    Analyze LTI POST request to start LTI session.

    :param course_id: course id from launch url
    :param unit_id: unit id from lunch url
    """
    if settings.LTI_DEBUG:
        LOGGER.info(request.META)
        LOGGER.info(request.POST)
    session = request.session
    # Code from ims_lti_py_django example
    session.clear()
    try:
        consumer_key = settings.CONSUMER_KEY
        secret = settings.LTI_SECRET

        tool = DjangoToolProvider(consumer_key, secret, request.POST)
        is_valid = tool.is_valid_request(request)
        session['target'] = '_blank'
    except (oauth2.MissingSignature,
            oauth2.Error,
            KeyError,
            AttributeError) as err:
        is_valid = False
        session['message'] = "{}".format(err)

    session['is_valid'] = is_valid
    session['LTI_POST'] = {k: v for (k, v) in request.POST.iteritems()}

    if settings.LTI_DEBUG:
        msg = 'session: is_valid = {}'.format(session.get('is_valid'))
        LOGGER.info(msg)
        if session.get('message'):
            msg = 'session: message = {}'.format(session.get('message'))
            LOGGER.info(msg)
    if not is_valid:
        return render_to_response(
            'lti/error.html',
            {'message': 'LTI request is not valid'},
            RequestContext(request)
        )

    return lti_redirect(request, course_id, unit_id)
Exemplo n.º 13
0
def index(request):
    if settings.LTI_DEBUG:
        print "META"
        print request.META
        print "PARAMS"
        print request.POST
    session = request.session
    session.clear()
    try:
        consumer_key = settings.CONSUMER_KEY
        secret = settings.LTI_SECRET

        tool = DjangoToolProvider(consumer_key, secret, request.POST)
        is_valid = tool.is_valid_request(request)
        session['message'] = "We are cool!"
    except oauth2.MissingSignature, e:
        is_valid = False
        session['message'] = "{}".format(e)
        pass
Exemplo n.º 14
0
def index(request):
    if settings.LTI_DEBUG:
        print "META"
        print request.META
        print "PARAMS"
        print request.POST
    session = request.session
    session.clear()
    try:
        consumer_key = settings.CONSUMER_KEY
        secret = settings.LTI_SECRET

        tool = DjangoToolProvider(consumer_key, secret, request.POST)
        is_valid = tool.is_valid_request(request)
        session['message'] = "We are cool!"
    except oauth2.MissingSignature,e:
        is_valid = False
        session['message'] = "{}".format(e)
        pass
Exemplo n.º 15
0
def initialize_lti_tool_provider(req):
    """
    Starts the provider given the consumer_key and secret.
    """
    # get the consumer key and secret from settings (__init__.py file)
    # will be used to compare against request to validate the tool init
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET

    # use the function from ims_lti_py app to verify and initialize tool
    provider = DjangoToolProvider(consumer_key, secret, req.POST)

    # now validate the tool via the valid_request function
    # this means that request was well formed but invalid
    if provider.valid_request(req) == False:
        debug_printer("DEBUG - LTI Exception: Not a valid request.")
        raise PermissionDenied()
    else:
        debug_printer("DEBUG - LTI Tool Provider was valid.")
    return provider
Exemplo n.º 16
0
def lti_init(request, course_id=None, unit_id=None):
    """LTI init view

    Analyze LTI POST request to start LTI session.

    :param course_id: course id from launch url
    :param unit_id: unit id from lunch url
    """
    if settings.LTI_DEBUG:
        LOGGER.info(request.META)
        LOGGER.info(request.POST)
    session = request.session
    # Code from ims_lti_py_django example
    session.clear()
    try:
        consumer_key = settings.CONSUMER_KEY
        secret = settings.LTI_SECRET

        tool = DjangoToolProvider(consumer_key, secret, request.POST)
        is_valid = tool.is_valid_request(request)
        session['target'] = '_blank'
    except (oauth2.MissingSignature, oauth2.Error, KeyError,
            AttributeError) as err:
        is_valid = False
        session['message'] = "{}".format(err)

    session['is_valid'] = is_valid
    session['LTI_POST'] = {k: v for (k, v) in request.POST.iteritems()}

    if settings.LTI_DEBUG:
        msg = 'session: is_valid = {}'.format(session.get('is_valid'))
        LOGGER.info(msg)
        if session.get('message'):
            msg = 'session: message = {}'.format(session.get('message'))
            LOGGER.info(msg)
    if not is_valid:
        return render_to_response('lti/error.html',
                                  {'message': 'LTI request is not valid'},
                                  RequestContext(request))

    return lti_redirect(request, course_id, unit_id)
Exemplo n.º 17
0
def lti_tool(request):
	key = request.POST['oauth_consumer_key']
	if key:
		secret = oauth_creds[key]
		if secret:
			tp = DjangoToolProvider(key, secret, request.POST)
		else:
			tp = DjangoToolProvider(None, None, request.POST)
			tp.lti_msg = "Your consumer didn't used a recognized key"
			tp.lti_errorlog = "You did it wrong!"
			error_temp = get_template("error.html")
			context_data = Context({'message': 'Consumer key not recognized', 
				'params': request.POST})
			error_html = error_temp.render(context_data)
			return HttpResponse(error_html)	

	else:
		key_error_temp = get_template("error.html")
		key_error_html = key_error_temp.render(Context({'message': 'Consumer key not recognized'}))
		return HttpResponse(key_error_html)

	if not tp.is_valid_request(request):
		sigerror_temp = get_template("error.html")
		context_data = Context({'message': 'The OAuth signature is invalid', 
				'params': request.POST})
		sigerror_html = sigerror_temp.render(context_data)		
		return HttpResponse(sigerror_html)


	request.session['launch_params'] = tp.to_params()
	userid = request.POST['user_id']
	temp = get_template('assessment.html')
	html = temp.render(Context({'userid': userid}))
	return HttpResponse(html)
Exemplo n.º 18
0
def ltilaunch(request):
    consumer_key = request.POST.get('oauth_consumer_key')

    if consumer_key:
        consumer = LTIConsumer.objects.get(consumer_key=consumer_key)
    else:
        return HttpResponse('oauth_consumer_key must be supplied', status=403)

    tool_provider = DjangoToolProvider(consumer_key, consumer.secret, request.POST)

    if not tool_provider.is_launch_request():
        return HttpResponse('Not a launch request', status=403)

    lti_params = tool_provider.to_params()

    # Set the session stuff in here.
    request.session['user_id'] = lti_params['user_id']
    course_id = str(lti_params['context_id'])
    request.session['course_id'] = course_id

    request.session['course_title'] = lti_params['context_title']

    return_url = lti_params.get('launch_presentation_return_url')

    # This is FutureLearn specific
    if return_url and 'www.futurelearn.com' in return_url:
        parts = urlparse(lti_params['launch_presentation_return_url']).path.split('/')
        if len(parts) >= 4:
            chosen_topic = parts[2]
            request.session['chosen_topic'] = 'Ebola' if 'sandpit' in course_id else chosen_topic
            request.session['course_run'] = int(parts[3])
    else:
        # Test data.
        request.session['chosen_topic'] = 'dyslexia'
        request.session['course_run'] = 1

    _log_launch(lti_params['user_id'],lti_params['context_id'], lti_params.get('launch_presentation_return_url'))

    return results(request)
Exemplo n.º 19
0
def initialize_lti_tool_provider(req):
    """
    """
    # get the consumer key and secret from settings (__init__.py file)
    # will be used to compare against request to validate the tool init
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET

    # use the function from ims_lti_py app to verify and initialize tool
    provider = DjangoToolProvider(consumer_key, secret, req.POST)

    # now validate the tool via the valid_request function
    try:
        # this means that request was well formed but invalid
        if provider.valid_request(req) == False:
            debug_printer("DEBUG - LTI Exception: Not a valid request.")
            raise PermissionDenied()
        else:
            debug_printer('DEBUG - LTI Tool Provider was valid.')
    except:
        raise PermissionDenied()
    return provider
Exemplo n.º 20
0
 def setUp(self):
     """
     This is very simple, imitate the paramaters passed in via a request
     and create a tool provider from ims_lti_py.
     """
     tool_provider_parameters = {
         "lti_message_type": "basic-lti-launch-request",
         "lti_version": "LTI-1p0",
         "resource_link_id": "c28ddcf1b2b13c52757aed1fe9b2eb0a4e2710a3",
         "lis_result_sourcedid": "261-154-728-17-784",
         "lis_outcome_service_url": "http://localhost/lis_grade_passback",
         "launch_presentation_return_url": "http://example.com/lti_return",
         "custom_param1": "custom1",
         "custom_param2": "custom2",
         "ext_lti_message_type": "extension-lti-launch",
         "roles": "Learner,Instructor,Observer"
     }
     self.tp = DjangoToolProvider('hi', 'oi', tool_provider_parameters)
Exemplo n.º 21
0
def launch_lti(request):
    """ Receives a request from the lti consumer and creates/authenticates user in django """

    """ See post items in log by setting LTI_DEBUG=True in settings """    
    if settings.LTI_DEBUG:
        for item in request.POST:
            print ('%s: %s \r' % (item, request.POST[item]))

    if 'oauth_consumer_key' not in request.POST:
        logging.error('oauth_consumer_key missing from request')
        raise PermissionDenied()  
    
    """ key/secret from settings """
    consumer_key = settings.CONSUMER_KEY 
    secret = settings.LTI_SECRET    
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)

    """ Decode parameters - UOC LTI uses a custom param to indicate the encoding: utf-8, iso-latin, base64 """
    encoding = None
    utf8 = get_lti_value('custom_lti_message_encoded_utf8', tool_provider)         
    iso = get_lti_value('custom_lti_message_encoded_iso', tool_provider)       
    b64 = get_lti_value('custom_lti_message_encoded_base64', tool_provider)  

    if iso and int(iso) == 1: encoding = 'iso'
    if utf8 and int(utf8) == 1: encoding = 'utf8'
    if b64 and int(b64) == 1: encoding = 'base64'
    
    try: # attempt to validate request, if fails raises 403 Forbidden
        tool_provider.valid_request(request)
    except:
        logging.error('Invalid LTI request')
        print "LTI Exception:  Not a valid request."
        raise PermissionDenied() 

    email = get_lti_value(settings.LTI_EMAIL, tool_provider, encoding=encoding)
    roles = get_lti_value(settings.LTI_ROLES, tool_provider, encoding=encoding)
    #user_id = get_lti_value('user_id', tool_provider, encoding=encoding)
    lms_context= get_lti_value('context_id', tool_provider, encoding=encoding)
    course_name = get_lti_value('context_title', tool_provider, encoding=encoding)
    assignment = get_lti_value('resource_link_title', tool_provider, encoding=encoding)
    outcome_url = get_lti_value(settings.LTI_OUTCOME, tool_provider, encoding=encoding)

    if not email:
        if settings.LTI_DEBUG: print "Email wasn't found in post"
        raise PermissionDenied()
    
    """ GET OR CREATE NEW USER """
    lti_username = email #create username with email and user_id
    try:
        """ Check if user already exists using email, if not create new """    
        user = User.objects.get(username=lti_username)
    except User.DoesNotExist:
        """ first time entry, create new user """
        user = User.objects.create_user(lti_username, email)
        user.set_unusable_password()
        user.save()
    except User.MultipleObjectsReturned:
        logging.error("Multiple user objects returned on LTI login")
        return HttpResponse("Error with database")

    #If person has an instructor role, let's make he/she an admin
    if 'Instructor' in roles and user.is_superuser == False:
        user.is_superuser = True
        user.is_staff = True
        user.save()
    
    """ Log in user and redirect to LOGIN_REDIRECT_URL defined in settings (default: accounts/profile) """
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request, user)
    request.session['course_name'] = course_name
    request.session['assignment_name'] = assignment
    request.session['lms_context'] = lms_context
    request.session['outcome_url'] = outcome_url
    request.session['return_url'] = request.META['HTTP_REFERER']
    return HttpResponseRedirect('/grader/code/')
Exemplo n.º 22
0
 def _get_lti_parameters_from_request(cls, request):
     provider = DjangoToolProvider(settings.LTI_CLIENT_KEY, settings.LTI_CLIENT_SECRET, request.POST)
     provider.valid_request(request)
     return provider.to_params()
Exemplo n.º 23
0
def lti_init(request, course_id=None, unit_id=None):
    """LTI init view

    Analyze LTI POST request to start LTI session.

    :param course_id: course id from launch url
    :param unit_id: unit id from lunch url
    """
    if settings.LTI_DEBUG:
        LOGGER.debug(request.META)
        LOGGER.debug(request.POST)
    session = request.session
    # Code from ims_lti_py_django example
    session.clear()

    short_term_lti = request.POST.get('custom_short_term')
    instance_guid = request.POST.get('tool_consumer_instance_guid')
    consumer_key = request.POST.get('oauth_consumer_key')

    if short_term_lti:
        lti_consumer = LtiConsumer.objects.filter(
            consumer_key=consumer_key).first()
    else:
        lti_consumer = LtiConsumer.get_or_combine(instance_guid, consumer_key)

    if not lti_consumer:
        LOGGER.error(
            'Consumer with key {} was not found.'.format(consumer_key))
        return render(request, 'lti/error.html',
                      {'message': 'LTI request is not valid'})

    try:
        if lti_consumer.expiration_date and lti_consumer.expiration_date < date.today(
        ):
            raise oauth2.Error('Consumer Key has expired.')
        if lti_consumer.consumer_key != consumer_key:
            raise oauth2.Error('Wrong Consumer Key: {}'.format(consumer_key))
        consumer_key = lti_consumer.consumer_key
        secret = lti_consumer.consumer_secret
        tool = DjangoToolProvider(consumer_key, secret, request.POST)
        is_valid = tool.is_valid_request(request)
        session['target'] = '_blank'
    except (oauth2.MissingSignature, oauth2.Error, KeyError,
            AttributeError) as err:
        is_valid = False
        session['message'] = "{}".format(err)
        LOGGER.error("Error during processing LTI request: {}".format(
            err.__str__()))

    session['is_valid'] = is_valid
    session['LTI_POST'] = {k: v for (k, v) in list(request.POST.items())}

    if settings.LTI_DEBUG:
        msg = 'session: is_valid = {}'.format(session.get('is_valid'))
        LOGGER.debug(msg)
        if session.get('message'):
            msg = 'session: message = {}'.format(session.get('message'))
            LOGGER.debug(msg)
    if not is_valid:
        return render(request, 'lti/error.html',
                      {'message': 'LTI request is not valid'})

    return lti_redirect(request, lti_consumer, course_id, unit_id)
Exemplo n.º 24
0
    def authenticate(self, request):

        logger.info("about to begin authentication process")

        request_key = request.POST.get('oauth_consumer_key', None)

        if request_key is None:
            logger.error("Request doesn't contain an oauth_consumer_key; can't continue.")
            return None

        secret = oauth_creds.get(request_key, None)

        if secret is None:
            logger.error("Could not get a secret for key %s" % request_key)
            raise PermissionDenied

        logger.debug('using key/secret %s/%s' % (request_key, secret))
        tool_provider = DjangoToolProvider(request_key, secret, request.POST.dict())

        postparams = request.POST.dict()

        logger.debug('request is secure: %s' % request.is_secure())
        for key in postparams:
            logger.debug('POST %s: %s' % (key, postparams.get(key)))

        logger.debug('request abs url is %s' % request.build_absolute_uri())

        for key in request.META:
            logger.debug('META %s: %s' % (key, request.META.get(key)))

        logger.info("about to check the signature")

        if not tool_provider.is_valid_request(request):
            logger.error("Invalid request: signature check failed.")
            raise PermissionDenied

        logger.info("done checking the signature")

        print tool_provider.oauth_timestamp

        logger.info("about to check the timestamp: %d" % int(tool_provider.oauth_timestamp))
        if time() - int(tool_provider.oauth_timestamp) > 60 * 60:
            logger.error("OAuth timestamp is too old.")
            #raise PermissionDenied
        else:
            logger.info("timestamp looks good")

        logger.info("done checking the timestamp")

        # (this is where we should check the nonce)

        # if we got this far, the user is good

        user = None

        if request.POST.get('lis_person_sourcedid'):
            username = self.clean_username(request.POST.get('lis_person_sourcedid'))
        elif request.POST.get('custom_canvas_user_login_id'):
            username = self.clean_username(request.POST.get('custom_canvas_user_login_id'))
        else:
            username = self.clean_username(request.POST.get('user_id'))

        email = request.POST.get('lis_person_contact_email_primary')
        first_name = request.POST.get('lis_person_name_given')
        last_name = request.POST.get('lis_person_name_family')

        logger.info("We have a valid username: %s" % username)

        UserModel = get_user_model()

        # Note that this could be accomplished in one try-except clause, but
        # instead we use get_or_create when creating unknown users since it has
        # built-in safeguards for multiple threads.
        if self.create_unknown_user:
            user, created = UserModel.objects.get_or_create(**{
                UserModel.USERNAME_FIELD: username,
            })

            if created:
                logger.debug('authenticate created a new user for %s' % username)
            else:
                logger.debug('authenticate found an existing user for %s' % username)

        else:
            logger.debug('automatic new user creation is turned OFF! just try to find and existing record')
            try:
                user = UserModel.objects.get_by_natural_key(username)
            except UserModel.DoesNotExist:
                logger.debug('authenticate could not find user %s' % username)
                # should return some kind of error here?
                pass

        # update the user
        if email:
            user.email = email
        if first_name:
            user.first_name = first_name
        if last_name:
            user.last_name = last_name
        user.save()
        logger.debug("updated the user record in the database")

        return user
Exemplo n.º 25
0
def launch_lti(request):
    """ Receives a request from the lti consumer and creates/authenticates user in django """

    """ See post items in log by setting LTI_DEBUG=True in settings """    
    if settings.LTI_DEBUG:
        for item in request.POST:
            print ('%s: %s \r' % (item, request.POST[item]))

    if 'oauth_consumer_key' not in request.POST:
        raise PermissionDenied()  
    
    """ key/secret from settings """
    consumer_key = settings.CONSUMER_KEY 
    secret = settings.LTI_SECRET
    
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)
    print "ROLES:  %s " % tool_provider.roles
    
    try: # attempt to validate request, if fails raises 403 Forbidden
        if tool_provider.valid_request(request) == False:
            raise PermissionDenied()
    except:
        raise PermissionDenied() 
    
    """ RETRIEVE username, names, email and roles.  These may be specific to the consumer, 
    in order to change them from the default values:  see README.txt """
    first_name = get_lti_value(settings.LTI_FIRST_NAME, tool_provider)
    last_name = get_lti_value(settings.LTI_LAST_NAME, tool_provider)
    email = get_lti_value(settings.LTI_EMAIL, tool_provider)
#    avatar = tool_provider.custom_params['custom_photo'] 
    roles = get_lti_value(settings.LTI_ROLES, tool_provider)
    user_id = get_lti_value('user_id', tool_provider)
    
    if not email or not user_id:
        print "Email and/or user_id wasn't found in post, return Permission Denied"
        raise PermissionDenied()    
    
    """ CHECK IF USER'S ROLES ALLOW ENTRY, IF RESTRICTION SET BY VELVET_ROLES SETTING """
    if settings.VELVET_ROLES:
        """ Roles allowed for entry into the application.  If these are not set in settings then we allow all roles to enter """
        if not roles:
            """ if roles is None, then setting for LTI_ROLES may be wrong, return 403 for user and print error to log """
            print "VELVET_ROLES is set but the roles for the user were not found.  Check that the setting for LTI_ROLES is correct."
            raise PermissionDenied()
        if not isinstance(roles, list): roles = (roles,) # In the case we are using a custom field for roles, may be a string and needs to be converted to a list
        is_role_allowed = [m for velvet_role in settings.VELVET_ROLES for m in roles if velvet_role.lower()==m.lower()]
        if not is_role_allowed:
            print "User does not have accepted role for entry, roles: %s" % roles
            raise PermissionDenied() 
    
    """ GET OR CREATE NEW USER AND LTI_PROFILE """
    lti_username = '******' % (request.POST['oauth_consumer_key'], user_id) #create username with consumer_key and user_id
    try:
        """ Check if user already exists using email, if not create new """    
        user = User.objects.get(email=email)
        if user.username != lti_username:
            """ If the username is not in the format user_id, change it and save.  This could happen
            if there was a previously populated User table. """
            user.username = lti_username
            user.save()
    except User.DoesNotExist:
        """ first time entry, create new user """
        user = User.objects.create_user(lti_username, email)
        user.set_unusable_password()
        if first_name: user.first_name = first_name
        if last_name: user.last_name = last_name
        user.save()
    except User.MultipleObjectsReturned:
        """ If the application is not requiring unique emails, multiple users may be returned if there was an existing
        User table before implementing this app with multiple users for the same email address.  Could add code to merge them, but for now we return 404 if 
        the user with the lti_username does not exist """    
        user = get_object_or_404(User, username=lti_username)
            
    """ CHECK IF ANY OF USER'S ROLES ARE IN THE VELVET_ADMIN_ROLES SETTING, IF SO MAKE SUPERUSER IF IS NOT ALREADY """
    if not user.is_superuser and settings.VELVET_ADMIN_ROLES:
        if [m for l in settings.VELVET_ADMIN_ROLES for m in roles if l.lower() in m.lower()]:
            user.is_superuser = True
            user.is_staff = True
            user.save()
    
    """ Save extra info to custom profile model (add/remove fields in models.py)""" 
    lti_userprofile = user.get_profile()
    lti_userprofile.roles = roles
#    lti_userprofile.avatar = avatar  #TO BE ADDED:  function to grab user profile image if exists
    lti_userprofile.save()
    
    """ Log in user and redirect to LOGIN_REDIRECT_URL defined in settings (default: accounts/profile) """
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request, user)

    return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL) 
    
Exemplo n.º 26
0
    def _validate_request(self, request):
        '''
        Validates an LTI launch request.
        '''
        consumer_key = getattr(settings, 'CONSUMER_KEY', None)
        try:
            secret = settings.LTI_SECRET_DICT[request.POST.get('context_id')]
        except:
            secret = settings.LTI_SECRET

        if consumer_key is None or secret is None:
            self.logger.error("missing consumer key/secret: %s/%s" % (consumer_key, secret))
            raise ImproperlyConfigured("Unable to validate LTI launch. Missing setting: CONSUMER_KEY or LTI_SECRET")

        request_key = request.POST.get('oauth_consumer_key', None)
        if request_key is None:
            self.logger.error("request doesn't contain an oauth_consumer_key; can't continue.")
            raise LTILaunchError

        if request_key != consumer_key:
            self.logger.error("could not get a secret for requested key: %s" % request_key)
            raise LTILaunchError

        self.logger.debug('using key/secret %s/%s' % (request_key, secret))
        tool_provider = DjangoToolProvider(request_key, secret, request.POST)

        postparams = request.POST.dict()
        self.logger.debug('request is secure: %s' % request.is_secure())
        for key in postparams:
            self.logger.debug('POST %s: %s' % (key, postparams.get(key)))
        self.logger.debug('request abs url is %s' % request.build_absolute_uri())
        for key in request.META:
            self.logger.debug('META %s: %s' % (key, request.META.get(key)))

        self.logger.debug("about to check the signature")
        try:
            # NOTE: before validating the request, temporarily remove the
            # QUERY_STRING to work around an issue with how Canvas signs requests
            # that contain GET parameters. Before Canvas launches the tool, it duplicates the GET
            # parameters as POST parameters, and signs the POST parameters (*not* the GET parameters).
            # However, the oauth2 library that validates the request generates
            # the oauth signature based on the combination of POST+GET parameters together,
            # resulting in a signature mismatch. By removing the QUERY_STRING before
            # validating the request, the library will generate the signature based only on
            # the POST parameters like Canvas.
            qs = request.META.pop('QUERY_STRING', '')
            self.logger.debug('removed query string temporarily: %s' % qs)
            request_is_valid = tool_provider.is_valid_request(request, parameters={}, handle_error=False)
            request.META['QUERY_STRING'] = qs  # restore the query string
            self.logger.debug('restored query string: %s' % request.META['QUERY_STRING'])
        except oauth2.Error as e:
            self.logger.error("signature check failed")
            self.logger.exception(e)
            raise LTILaunchError

        self.logger.info("signature verified")

        self.logger.debug("about to check the timestamp: %d" % int(tool_provider.oauth_timestamp))
        if time.time() - int(tool_provider.oauth_timestamp) > 60 * 60:
            self.logger.warning("OAuth timestamp is too old.")
            # raise PermissionDenied
        else:
            self.logger.info("OAuth timestamp looks good")

        for required_param in ('resource_link_id', 'context_id', 'user_id'):
            if required_param not in request.POST:
                self.logger.error("Required LTI param '%s' was not present in request" % required_param)
                raise LTILaunchError

        if ('lis_person_sourcedid' not in request.POST and 'lis_person_name_full' not in request.POST and request.POST['user_id'] != "student"):
            self.logger.error('person identifier (i.e. username) or full name was not present in request')
            raise LTILaunchError
Exemplo n.º 27
0
    def authenticate(self, request):

        logger.info("about to begin authentication process")

        request_key = request.POST.get('oauth_consumer_key', None)

        if request_key is None:
            logger.error(
                "Request doesn't contain an oauth_consumer_key; can't continue."
            )
            return None

        if not settings.LTI_OAUTH_CREDENTIALS:
            logger.error("Missing LTI_OAUTH_CREDENTIALS in settings")
            raise PermissionDenied

        secret = settings.LTI_OAUTH_CREDENTIALS.get(request_key)

        if secret is None:
            logger.error("Could not get a secret for key %s" % request_key)
            raise PermissionDenied

        logger.debug('using key/secret %s/%s' % (request_key, secret))
        tool_provider = DjangoToolProvider(request_key, secret,
                                           request.POST.dict())

        postparams = request.POST.dict()

        logger.debug('request is secure: %s' % request.is_secure())
        for key in postparams:
            logger.debug('POST %s: %s' % (key, postparams.get(key)))

        logger.debug('request abs url is %s' % request.build_absolute_uri())

        for key in request.META:
            logger.debug('META %s: %s' % (key, request.META.get(key)))

        logger.info("about to check the signature")

        try:
            request_is_valid = tool_provider.is_valid_request(request)
        except oauth2.Error:
            logger.exception(u'error attempting to validate LTI launch %s',
                             postparams)
            request_is_valid = False

        if not request_is_valid:
            logger.error("Invalid request: signature check failed.")
            raise PermissionDenied

        logger.info("done checking the signature")

        logger.info("about to check the timestamp: %d" %
                    int(tool_provider.oauth_timestamp))
        if time() - int(tool_provider.oauth_timestamp) > 60 * 60:
            logger.error("OAuth timestamp is too old.")
            #raise PermissionDenied
        else:
            logger.info("timestamp looks good")

        logger.info("done checking the timestamp")

        # (this is where we should check the nonce)

        # if we got this far, the user is good

        user = None

        # Retrieve username from LTI parameter or default to an overridable function return value
        username = tool_provider.lis_person_sourcedid or self.get_default_username(
            tool_provider, prefix=self.unknown_user_prefix)
        username = self.clean_username(username)  # Clean it

        email = tool_provider.lis_person_contact_email_primary
        first_name = tool_provider.lis_person_name_given
        last_name = tool_provider.lis_person_name_family

        # Check that we have an email field at least
        if not email:
            logger.error("Invalid request: Invalid email.")
            raise PermissionDenied

        logger.info("We have a valid username: %s" % username)

        UserModel = get_user_model()

        # Note that this could be accomplished in one try-except clause, but
        # instead we use get_or_create when creating unknown users since it has
        # built-in safeguards for multiple threads.
        if self.create_unknown_user:
            user, created = UserModel.objects.get_or_create(**{
                # UserModel.USERNAME_FIELD: username,
                'email': email,
            })

            if created:
                logger.debug('authenticate created a new user for %s' %
                             username)
            else:
                logger.debug('authenticate found an existing user for %s' %
                             username)

        else:
            logger.debug(
                'automatic new user creation is turned OFF! just try to find and existing record'
            )
            try:
                user = UserModel.objects.get_by_natural_key(username)
            except UserModel.DoesNotExist:
                logger.debug('authenticate could not find user %s' % username)
                # should return some kind of error here?
                pass

        # update the user
        if email:
            user.email = email
        if username:
            user.name = username
        if first_name:
            user.first_name = first_name
        if last_name:
            user.last_name = last_name
        user.save()
        logger.debug("updated the user record in the database")

        return user
Exemplo n.º 28
0
Arquivo: views.py Projeto: trcm/kassdt
def launch_lti(request):
    """Process launch (start cprs) request from a leaning management system.
    This was modified from the original source.

    The method extracts the user's details such as name, ID, email, course
    and role (e.g., teacher, student) from the request and checks whether the
    user has permission to enter the system (see Raises section for details).
    If the user has permission, then the corresponding CPRS user is retrieved
    or created. The user's enrolments in the CPRS are updated with the course
    information in the request. The user is then redirected to his/her home page
    in the CPRS.

    Arguments:
        request (HttpRequest) -- the Http request sent by the LMS.

    Returns:
        HttpResponseRedirect which redirects the user to their home page
        in the CPRS if they have permission to access the system, or an error page
        if their role is not allowed.

    Raises:
        PermissionDenied -- if the user does not have permission to access the system.
                            this happens if:
                                - the request does not contain an email or user id
                                - the role sent in the request is None
                                - the authentication key is missing
                                - the request is not valid.
    """

    print "LAUNCH LTI HAS BEEN CALLED!!!"
    """ Receives a request from the lti consumer and creates/authenticates user in django """
    """ See post items in log by setting LTI_DEBUG=True in settings """
    if settings.LTI_DEBUG:
        for item in request.POST:
            print ('%s: %s \r' % (item, request.POST[item]))

    if 'oauth_consumer_key' not in request.POST:
        raise PermissionDenied()

    """ key/secret from settings """
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)

    """ Decode parameters - UOC LTI uses a custom param to indicate the encoding: utf-8, iso-latin, base64 """
    encoding = None
    utf8 = get_lti_value('custom_lti_message_encoded_utf8', tool_provider)
    iso = get_lti_value('custom_lti_message_encoded_iso', tool_provider)
    b64 = get_lti_value('custom_lti_message_encoded_base64', tool_provider)

    if iso and int(iso) == 1: encoding = 'iso'
    if utf8 and int(utf8) == 1: encoding = 'utf8'
    if b64 and int(b64) == 1: encoding = 'base64'

    try: # attempt to validate request, if fails raises 403 Forbidden
        if tool_provider.valid_request(request) == False:
            raise PermissionDenied()
    except:
        print "LTI Exception:  Not a valid request."
        raise PermissionDenied()

    """ RETRIEVE username, names, email and roles.  These may be specific to the consumer,
    in order to change them from the default values:  see README.txt """
    # username = get_lti_value('username', tool_provider, encoding=encoding)
    # username = username().lower()
    first_name = get_lti_value(settings.LTI_FIRST_NAME, tool_provider, encoding=encoding)
    last_name = get_lti_value(settings.LTI_LAST_NAME, tool_provider, encoding=encoding)
    email = get_lti_value(settings.LTI_EMAIL, tool_provider, encoding=encoding)
    course = request.POST['context_label']
    print course
    # for s in dir(settings):
    #     print s, ':', getattr(settings, s)

#    avatar = tool_provider.custom_params['custom_photo']
    roles = get_lti_value(settings.LTI_ROLES, tool_provider, encoding=encoding)
    print roles[0]
    # uoc_roles = get_lti_value(settings.LTI_CUSTOM_UOC_ROLES, tool_provider, encoding=encoding)
    user_id = get_lti_value('user_id', tool_provider, encoding=encoding)
    test = get_lti_value('context_title', tool_provider, encoding=encoding)

    if not email or not user_id:
        if settings.LTI_DEBUG: print "Email and/or user_id wasn't found in post, return Permission Denied"
        raise PermissionDenied()

    """ CHECK IF USER'S ROLES ALLOW ENTRY, IF RESTRICTION SET BY VELVET_ROLES SETTING """
    if settings.VELVET_ROLES:
        """ Roles allowed for entry into the application.  If these are not set in settings then we allow all roles to enter """
        if not roles and not uoc_roles:
            """ if roles is None, then setting for LTI_ROLES may be wrong, return 403 for user and print error to log """
            if settings.LTI_DEBUG: print "VELVET_ROLES is set but the roles for the user were not found.  Check that the setting for LTI_ROLES is correct."
            raise PermissionDenied()

        all_user_roles = []
        if roles:
            if not isinstance(roles, list): roles = (roles,)
            all_user_roles += roles
        if uoc_roles:
            if not isinstance(uoc_roles, list): uoc_roles = (uoc_roles,)
        all_user_roles += uoc_roles

        is_role_allowed = [m for velvet_role in settings.VELVET_ROLES for m in all_user_roles if velvet_role.lower()==m.lower()]

        if not is_role_allowed:
            if settings.LTI_DEBUG: print "User does not have accepted role for entry, roles: %s" % roles
            ctx = {'roles':roles, 'first_name':first_name, 'last_name':last_name, 'email':email, 'user_id':user_id}
            return render_to_response('lti_role_denied.html', ctx, context_instance=RequestContext(request))
        else:
            if settings.LTI_DEBUG: print "User has accepted role for entry, roles: %s" % roles

    """ GET OR CREATE NEW USER AND LTI_PROFILE """
    lti_username = '******' % (request.POST['oauth_consumer_key'], user_id) #create username with consumer_key and user_id
    try:
        """ Check if user already exists using email, if not create new """
        user = User.objects.get(email=email)
        if user.username != lti_username:
            """ If the username is not in the format user_id, change it and save.  This could happen
            if there was a previously populated User table. """
            user.username = lti_username
            user.save()
        try:
            print "adding course"
            print('course is ' + course)
            print(type(course))
            c = Course.objects.get(course_code=course)
            if c not in user.reviewuser.courses.all():
                user.reviewuser.courses.add(c)
                user.save()
        except Course.DoesNotExist:
            # Make course and enrol user in it.
            c = Course.objects.create(course_code=course)
            user.reviewuser.courses.add(c)
            user.save()
            print("New course created in CPRS")
        """ Detect if incoming user is a Instructor """
        if roles[0].__eq__("Instructor"):
            # user.isStaff = True
            user.is_staff = True
            c = Course.objects.get(course_code=course)
            createTutor(user.reviewuser, c)
            user.save()
            print "User is Staff Member"
        else:
            # user.reviewuser.isStaff = False
            user.is_staff = False
            user.save()
            print "User is Student"

    except User.DoesNotExist:
        """ first time entry, create new user """
        print lti_username, email
        # user = User.objects.create_user(newusername, email)
        user = User.objects.create_user(lti_username, email)
        p = first_name + last_name
        print p
        user.set_password(p)
        # user.set_unusable_password()
        if first_name: user.first_name = first_name
        if last_name: user.last_name = last_name
        user.save()
        ru = ReviewUser.objects.create(djangoUser=user)

        try:
            print "adding course"
            c = Course.objects.get(course_code=course)
            ru.courses.add(c)
            ru.save()
        except Course.DoesNotExist:
            # Make course and enrol user in it.
            c = Course.objects.create(course_code=course)
            ru.courses.add(c)
            ru.save()
            print "New course created in CPRS"
        """ Detect if incoming user is a Instructor """
        if roles[0].__eq__("Instructor"):
            # user.reviewuser.isStaff = True
            user.is_staff = True
            c = Course.objects.get(course_code=course)
            createTutor(user.reviewuser, c)
            user.save()
            print  "User is Staff Member"
        else:
            # user.reviewuser.isStaff = False
            user.is_staff = False
            user.save()
            print "User is Student"

    except User.MultipleObjectsReturned:
        """ If the application is not requiring unique emails, multiple users may be returned if there was an existing
        User table before implementing this app with multiple users for the same email address.  Could add code to merge them, but for now we return 404 if
        the user with the lti_username does not exist """
        user = get_object_or_404(User, username=lti_username)

    """ CHECK IF ANY OF USER'S ROLES ARE IN THE VELVET_ADMIN_ROLES SETTING, IF SO MAKE SUPERUSER IF IS NOT ALREADY """
    if not user.is_superuser and settings.VELVET_ADMIN_ROLES:
        if [m for l in settings.VELVET_ADMIN_ROLES for m in roles if l.lower() in m.lower()]:
            user.is_superuser = True
            user.is_staff = True
            user.save()

    """ Save extra info to custom profile model (add/remove fields in models.py)"""
    print "lti_userprofile"
    # lti_userpro = LTIProfile.objects.create(user=user)
    # lti_userpro.save()
    # lti_userprofile = LTIProfile.objects.get_or_create(user=user)
    # lti_userprofile.roles = (",").join(all_user_roles)
#    lti_userprofile.avatar = avatar  #TO BE ADDED:  function to grab user profile image if exists
    # lti_userprofile.save()

    """ Log in user and redirect to LOGIN_REDIRECT_URL defined in settings (default: accounts/profile) """
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request, user)

    # return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
    return HttpResponseRedirect('/review/')
Exemplo n.º 29
0
    def _validate_request(self, request):
        '''
        Validates an LTI launch request.
        '''
        consumer_key = getattr(settings, 'CONSUMER_KEY', None)
        try:
            secret = settings.LTI_SECRET_DICT[request.POST.get('context_id')]
        except:
            secret = settings.LTI_SECRET

        if consumer_key is None or secret is None:
            self.logger.error("missing consumer key/secret: %s/%s" %
                              (consumer_key, secret))
            raise ImproperlyConfigured(
                "Unable to validate LTI launch. Missing setting: CONSUMER_KEY or LTI_SECRET"
            )

        request_key = request.POST.get('oauth_consumer_key', None)
        if request_key is None:
            self.logger.error(
                "request doesn't contain an oauth_consumer_key; can't continue."
            )
            raise LTILaunchError

        if request_key != consumer_key:
            self.logger.error("could not get a secret for requested key: %s" %
                              request_key)
            raise LTILaunchError

        self.logger.debug('using key/secret %s/%s' % (request_key, secret))
        tool_provider = DjangoToolProvider(request_key, secret, request.POST)

        postparams = request.POST.dict()
        self.logger.debug('request is secure: %s' % request.is_secure())
        for key in postparams:
            self.logger.debug('POST %s: %s' % (key, postparams.get(key)))
        self.logger.debug('request abs url is %s' %
                          request.build_absolute_uri())
        for key in request.META:
            self.logger.debug('META %s: %s' % (key, request.META.get(key)))

        self.logger.debug("about to check the signature")
        try:
            # NOTE: before validating the request, temporarily remove the
            # QUERY_STRING to work around an issue with how Canvas signs requests
            # that contain GET parameters. Before Canvas launches the tool, it duplicates the GET
            # parameters as POST parameters, and signs the POST parameters (*not* the GET parameters).
            # However, the oauth2 library that validates the request generates
            # the oauth signature based on the combination of POST+GET parameters together,
            # resulting in a signature mismatch. By removing the QUERY_STRING before
            # validating the request, the library will generate the signature based only on
            # the POST parameters like Canvas.
            qs = request.META.pop('QUERY_STRING', '')
            self.logger.debug('removed query string temporarily: %s' % qs)
            request_is_valid = tool_provider.is_valid_request(
                request, parameters={}, handle_error=False)
            request.META['QUERY_STRING'] = qs  # restore the query string
            self.logger.debug('restored query string: %s' %
                              request.META['QUERY_STRING'])
        except oauth2.Error as e:
            self.logger.error("signature check failed")
            self.logger.exception(e)
            raise LTILaunchError

        self.logger.info("signature verified")

        self.logger.debug("about to check the timestamp: %d" %
                          int(tool_provider.oauth_timestamp))
        if time.time() - int(tool_provider.oauth_timestamp) > 60 * 60:
            self.logger.warning("OAuth timestamp is too old.")
            # raise PermissionDenied
        else:
            self.logger.info("OAuth timestamp looks good")

        for required_param in ('resource_link_id', 'context_id', 'user_id'):
            if required_param not in request.POST:
                self.logger.error(
                    "Required LTI param '%s' was not present in request" %
                    required_param)
                raise LTILaunchError

        if ('lis_person_sourcedid' not in request.POST
                and 'lis_person_name_full' not in request.POST
                and request.POST['user_id'] != "student"):
            self.logger.error(
                'person identifier (i.e. username) or full name was not present in request'
            )
            raise LTILaunchError
Exemplo n.º 30
0
def launch_lti(request):
    """ Receives a request from the lti consumer and creates/authenticates user in django """
    """ See post items in log by setting LTI_DEBUG=True in settings """
    if settings.LTI_DEBUG:
        for item in request.POST:
            print('%s: %s \r' % (item, request.POST[item]))

    if 'oauth_consumer_key' not in request.POST:
        logging.error('oauth_consumer_key missing from request')
        raise PermissionDenied()
    """ key/secret from settings """
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)
    """ Decode parameters - UOC LTI uses a custom param to indicate the encoding: utf-8, iso-latin, base64 """
    encoding = None
    utf8 = get_lti_value('custom_lti_message_encoded_utf8', tool_provider)
    iso = get_lti_value('custom_lti_message_encoded_iso', tool_provider)
    b64 = get_lti_value('custom_lti_message_encoded_base64', tool_provider)

    if iso and int(iso) == 1: encoding = 'iso'
    if utf8 and int(utf8) == 1: encoding = 'utf8'
    if b64 and int(b64) == 1: encoding = 'base64'

    try:  # attempt to validate request, if fails raises 403 Forbidden
        tool_provider.valid_request(request)
    except:
        logging.error('Invalid LTI request')
        print "LTI Exception:  Not a valid request."
        raise PermissionDenied()

    email = get_lti_value(settings.LTI_EMAIL, tool_provider, encoding=encoding)
    roles = get_lti_value(settings.LTI_ROLES, tool_provider, encoding=encoding)
    #user_id = get_lti_value('user_id', tool_provider, encoding=encoding)
    lms_context = get_lti_value('context_id', tool_provider, encoding=encoding)
    course_name = get_lti_value('context_title',
                                tool_provider,
                                encoding=encoding)
    assignment = get_lti_value('resource_link_title',
                               tool_provider,
                               encoding=encoding)
    outcome_url = get_lti_value(settings.LTI_OUTCOME,
                                tool_provider,
                                encoding=encoding)

    if not email:
        if settings.LTI_DEBUG: print "Email wasn't found in post"
        raise PermissionDenied()
    """ GET OR CREATE NEW USER """
    lti_username = email  #create username with email and user_id
    try:
        """ Check if user already exists using email, if not create new """
        user = User.objects.get(username=lti_username)
    except User.DoesNotExist:
        """ first time entry, create new user """
        user = User.objects.create_user(lti_username, email)
        user.set_unusable_password()
        user.save()
    except User.MultipleObjectsReturned:
        logging.error("Multiple user objects returned on LTI login")
        return HttpResponse("Error with database")

    #If person has an instructor role, let's make he/she an admin
    if 'Instructor' in roles and user.is_superuser == False:
        user.is_superuser = True
        user.is_staff = True
        user.save()
    """ Log in user and redirect to LOGIN_REDIRECT_URL defined in settings (default: accounts/profile) """
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request, user)
    request.session['course_name'] = course_name
    request.session['assignment_name'] = assignment
    request.session['lms_context'] = lms_context
    request.session['outcome_url'] = outcome_url
    request.session['return_url'] = request.META['HTTP_REFERER']
    return HttpResponseRedirect('/grader/code/')
Exemplo n.º 31
0
def launch_lti(request):
    """ Receives a request from the lti consumer and creates/authenticates user in django """
    """ See post items in log by setting LTI_DEBUG=True in settings """
    if settings.LTI_DEBUG:
        for item in request.POST:
            print('%s: %s \r' % (item, request.POST[item]))

    if 'oauth_consumer_key' not in request.POST:
        raise PermissionDenied()
    """ key/secret from settings """
    consumer_key = settings.CONSUMER_KEY
    secret = settings.LTI_SECRET
    tool_provider = DjangoToolProvider(consumer_key, secret, request.POST)
    """ Decode parameters - UOC LTI uses a custom param to indicate the encoding: utf-8, iso-latin, base64 """
    encoding = None
    utf8 = get_lti_value('custom_lti_message_encoded_utf8', tool_provider)
    iso = get_lti_value('custom_lti_message_encoded_iso', tool_provider)
    b64 = get_lti_value('custom_lti_message_encoded_base64', tool_provider)

    if iso and int(iso) == 1: encoding = 'iso'
    if utf8 and int(utf8) == 1: encoding = 'utf8'
    if b64 and int(b64) == 1: encoding = 'base64'

    try:  # attempt to validate request, if fails raises 403 Forbidden
        if tool_provider.valid_request(request) == False:
            raise PermissionDenied()
    except:
        print "LTI Exception:  Not a valid request."
        raise PermissionDenied()
    """ RETRIEVE username, names, email and roles.  These may be specific to the consumer, 
    in order to change them from the default values:  see README.txt """
    first_name = get_lti_value(settings.LTI_FIRST_NAME,
                               tool_provider,
                               encoding=encoding)
    last_name = get_lti_value(settings.LTI_LAST_NAME,
                              tool_provider,
                              encoding=encoding)
    email = get_lti_value(settings.LTI_EMAIL, tool_provider, encoding=encoding)
    #    avatar = tool_provider.custom_params['custom_photo']
    roles = get_lti_value(settings.LTI_ROLES, tool_provider, encoding=encoding)
    #    uoc_roles = get_lti_value(settings.LTI_CUSTOM_UOC_ROLES, tool_provider, encoding=encoding)
    user_id = get_lti_value('user_id', tool_provider, encoding=encoding)
    test = get_lti_value('context_title', tool_provider, encoding=encoding)

    if not email or not user_id:
        if settings.LTI_DEBUG:
            print "Email and/or user_id wasn't found in post, return Permission Denied"
        raise PermissionDenied()
    """ CHECK IF USER'S ROLES ALLOW ENTRY, IF RESTRICTION SET BY VELVET_ROLES SETTING """
    if settings.VELVET_ROLES:
        """ Roles allowed for entry into the application.  If these are not set in settings then we allow all roles to enter """
        if not roles and not uoc_roles:
            """ if roles is None, then setting for LTI_ROLES may be wrong, return 403 for user and print error to log """
            if settings.LTI_DEBUG:
                print "VELVET_ROLES is set but the roles for the user were not found.  Check that the setting for LTI_ROLES is correct."
            raise PermissionDenied()

        all_user_roles = []
        if roles:
            if not isinstance(roles, list): roles = (roles, )
            all_user_roles += roles
        if uoc_roles:
            if not isinstance(uoc_roles, list): uoc_roles = (uoc_roles, )
            all_user_roles += uoc_roles

        is_role_allowed = [
            m for velvet_role in settings.VELVET_ROLES for m in all_user_roles
            if velvet_role.lower() == m.lower()
        ]

        if not is_role_allowed:
            if settings.LTI_DEBUG:
                print "User does not have accepted role for entry, roles: %s" % roles
            ctx = {
                'roles': roles,
                'first_name': first_name,
                'last_name': last_name,
                'email': email,
                'user_id': user_id
            }
            return render_to_response('lti_role_denied.html',
                                      ctx,
                                      context_instance=RequestContext(request))
        else:
            if settings.LTI_DEBUG:
                print "User has accepted role for entry, roles: %s" % roles
    """ GET OR CREATE NEW USER AND LTI_PROFILE """
    lti_username = request.POST['lis_person_sourcedid']
    try:
        """ Check if user already exists using email, if not create new """
        user = User.objects.get(email=email)
        if user.username != lti_username:
            """ If the username is not in the format user_id, change it and save.  This could happen
            if there was a previously populated User table. """
            user.username = lti_username
            user.save()
    except User.DoesNotExist:
        """ first time entry, create new user """
        user = User.objects.create_user(lti_username, email)
        user.set_unusable_password()
        if first_name: user.first_name = first_name
        if last_name: user.last_name = last_name
        user.save()
    except User.MultipleObjectsReturned:
        """ If the application is not requiring unique emails, multiple users may be returned if there was an existing
        User table before implementing this app with multiple users for the same email address.  Could add code to merge them, but for now we return 404 if 
        the user with the lti_username does not exist """
        user = get_object_or_404(User, username=lti_username)
    """ CHECK IF ANY OF USER'S ROLES ARE IN THE VELVET_ADMIN_ROLES SETTING, IF SO MAKE SUPERUSER IF IS NOT ALREADY """
    if not user.is_superuser and settings.VELVET_ADMIN_ROLES:
        if [
                m for l in settings.VELVET_ADMIN_ROLES for m in roles
                if l.lower() in m.lower()
        ]:
            user.is_superuser = True
            user.is_staff = True
            user.save()

    all_user_roles = []
    """ Save extra info to custom profile model (add/remove fields in models.py)"""
    lti_userprofile = get_object_or_404(LTIProfile, user=user)
    lti_userprofile.roles = (",").join(all_user_roles)
    #    lti_userprofile.avatar = avatar  #TO BE ADDED:  function to grab user profile image if exists
    lti_userprofile.save()
    """ Log in user and redirect to LOGIN_REDIRECT_URL defined in settings (default: accounts/profile) """
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request, user)

    return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
Exemplo n.º 32
0
 def _get_lti_parameters_from_request(cls, request):
     provider = DjangoToolProvider(settings.LTI_CLIENT_KEY,
                                   settings.LTI_CLIENT_SECRET, request.POST)
     provider.valid_request(request)
     return provider.to_params()
Exemplo n.º 33
0
    def authenticate(self, request):

        logger.info("about to begin authentication process")

        request_key = request.POST.get('oauth_consumer_key', None)

        if request_key is None:
            logger.error("Request doesn't contain an oauth_consumer_key; can't continue.")
            return None

        oauth_credentials = getattr(settings, 'LTI_OAUTH_CREDENTIALS', {})
        cohorts = Cohort.objects.filter(oauth_key=request_key).all()
        cohort = None
        if cohorts:
            cohort = cohorts[0]

        # Let settings.LTI_OAUTH_CREDENTIALS secret override the database cohort secret
        secret = oauth_credentials.get(request_key)
        if secret is None and cohort:
            secret = cohort.oauth_secret

        if secret is None:
            logger.error("Could not get a secret for key %s" % request_key)
            raise PermissionDenied

        logger.debug('using key/secret %s/%s' % (request_key, secret))
        tool_provider = DjangoToolProvider(request_key, secret, request.POST.dict())

        postparams = request.POST.dict()

        logger.debug('request is secure: %s' % request.is_secure())
        for key in postparams:
            logger.debug('POST %s: %s' % (key, postparams.get(key)))

        logger.debug('request abs url is %s' % request.build_absolute_uri())

        for key in request.META:
            logger.debug('META %s: %s' % (key, request.META.get(key)))

        logger.info("about to check the signature")

        valid = False
        try:
            valid = tool_provider.is_valid_request(request)
        except:
            logger.error(str(sys.exc_info()[0]))
            valid = False
        finally:
            if not valid:
                logger.error("Invalid request: signature check failed.")
                raise PermissionDenied

        logger.info("done checking the signature")

        logger.info("about to check the timestamp: %d" % int(tool_provider.oauth_timestamp))
        if time() - int(tool_provider.oauth_timestamp) > 60 * 60:
            logger.error("OAuth timestamp is too old.")
            #raise PermissionDenied
        else:
            logger.info("timestamp looks good")

        logger.info("done checking the timestamp")

        # (this is where we should check the nonce)

        # if we got this far, the user is good

        user = None

        # Retrieve username from LTI parameter or default to an overridable function return value
        username = tool_provider.lis_person_sourcedid or self.get_default_username(
            tool_provider, prefix=self.unknown_user_prefix)
        username = self.clean_username(username)  # Clean it

        email = tool_provider.lis_person_contact_email_primary
        first_name = tool_provider.lis_person_name_given
        last_name = tool_provider.lis_person_name_family

        logger.info("We have a valid username: %s" % username)

        UserModel = get_user_model()

        # Note that this could be accomplished in one try-except clause, but
        # instead we use get_or_create when creating unknown users since it has
        # built-in safeguards for multiple threads.
        if self.create_unknown_user:
            user, created = UserModel.objects.get_or_create(**{
                UserModel.USERNAME_FIELD: username,
            })

            if created:
                logger.debug('authenticate created a new user for %s' % username)
            else:
                logger.debug('authenticate found an existing user for %s' % username)

        else:
            logger.debug(
                'automatic new user creation is turned OFF! just try to find and existing record')
            try:
                user = UserModel.objects.get_by_natural_key(username)
            except UserModel.DoesNotExist:
                logger.debug('authenticate could not find user %s' % username)
                # should return some kind of error here?
                pass

        # update the user
        if cohort:
            user.cohort = cohort
        if email:
            user.email = email
        # FIXME ADX-192: should really be using our own nickname field, instead
        # of requiring first_name to be unique.
        #if first_name:
        #    user.first_name = first_name
        if last_name:
            user.last_name = last_name
        user.save()
        logger.debug("updated the user record in the database")

        return user