Ejemplo n.º 1
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)
Ejemplo n.º 2
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)
Ejemplo n.º 3
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
Ejemplo n.º 4
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
Ejemplo n.º 5
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)
Ejemplo n.º 6
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
Ejemplo n.º 7
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
Ejemplo n.º 8
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
Ejemplo n.º 9
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
Ejemplo n.º 10
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
Ejemplo n.º 11
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)