def __init__(self, *args, **kwargs): self.oauth_server = DataStoreServer(data_store=MockDataStore()) self.oauth_server.add_signature_method( oauth2.SignatureMethod_PLAINTEXT()) self.oauth_server.add_signature_method( oauth2.SignatureMethod_HMAC_SHA1()) BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
def __init__(self, consumer_key=None, consumer_secret=None, access_token_key=None, access_token_secret=None, cache=DEFAULT_CACHE, cache_timeout=DEFAULT_CACHE_TIMEOUT ): self.consumer_key = consumer_key self.consumer_secret = consumer_secret self.access_token_key = access_token_key self.access_token_secret = access_token_secret self.host = "api.yelp.com" self.SetCache(cache) self.SetCacheTimeout(cache_timeout) if consumer_key is not None \ and consumer_secret is not None \ and access_token_key is not None \ and access_token_secret is not None: self._signature_method_plaintext = oauth.SignatureMethod_PLAINTEXT() self._signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1() self._oauth_token = oauth.Token(key=access_token_key, secret=access_token_secret) self._oauth_consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
def __init__(self, api_key, shared_secret, httplib2_inst=None): """Override init to ensure required args""" super(TwoLegged, self).__init__(api_key, shared_secret, httplib2_inst) self.endpoint = PRIVATE_ENDPOINT self.scheme = HTTPS_SCHEME self.hmac_sha1_signature = oauth.SignatureMethod_HMAC_SHA1() self.plaintext_signature = oauth.SignatureMethod_PLAINTEXT()
def verify_oauth_request(request, oauth_request, consumer, token=None): """ Helper function to verify requests. """ from treeio.core.api.auth.store import store # Check nonce if not store.check_nonce(request, oauth_request, oauth_request['oauth_nonce']): return False # Verify request try: oauth_server = oauth.Server() oauth_server.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) oauth_server.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) # Ensure the passed keys and secrets are ascii, or HMAC will complain. consumer = oauth.Consumer(consumer.key.encode('ascii', 'ignore'), consumer.secret.encode('ascii', 'ignore')) if token is not None: token = oauth.Token(token.key.encode('ascii', 'ignore'), token.secret.encode('ascii', 'ignore')) oauth_server.verify_request(oauth_request, consumer, token) except oauth.Error: return False return True
def test_sign_request(self): url = "http://sp.example.com/" params = { 'oauth_version': "1.0", 'oauth_nonce': "4572616e48616d6d65724c61686176", 'oauth_timestamp': "137131200" } tok = oauth.Token(key="tok-test-key", secret="tok-test-secret") con = oauth.Consumer(key="con-test-key", secret="con-test-secret") params['oauth_token'] = tok.key params['oauth_consumer_key'] = con.key req = oauth.Request(method="GET", url=url, parameters=params) methods = { 'TQ6vGQ5A6IZn8dmeGB4+/Jl3EMI=': oauth.SignatureMethod_HMAC_SHA1(), 'con-test-secret&tok-test-secret': oauth.SignatureMethod_PLAINTEXT() } for exp, method in methods.items(): req.sign_request(method, con, tok) self.assertEquals(req['oauth_signature_method'], method.name) self.assertEquals(req['oauth_signature'], exp)
def new_client(token=None): """Generate a new ningapi.Client instance""" consumer = oauth.Consumer(key=CONSUMER_KEY, secret=CONSUMER_SECRET) client = ningapi.Client(NING_API_URL, NETWORK_SUBDOMAIN, consumer, token) client.method = oauth.SignatureMethod_PLAINTEXT() return client
def verify_oauth_request(request, oauth_request, consumer, token=None): """ Helper function to verify requests. """ from store import store # Check nonce if not store.check_nonce(request, oauth_request, oauth_request['oauth_nonce']): return False # Verify request try: oauth_server = oauth.Server() oauth_server.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) oauth_server.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) # Ensure the passed keys and secrets are ascii, or HMAC will complain. consumer = oauth.Consumer(consumer.key.encode('ascii', 'ignore'), consumer.secret.encode('ascii', 'ignore')) if token is not None: token = oauth.Token(token.key.encode('ascii', 'ignore'), token.secret.encode('ascii', 'ignore')) oauth_server.verify_request(oauth_request, consumer, token) except oauth.Error, err: logger.error('OAuth-request verification error', extra={'data': { 'error': err.message }}) return False
def initialize_server_request(request): """Shortcut for initialization.""" # Django converts Authorization header in HTTP_AUTHORIZATION # Warning: it doesn't happen in tests but it's useful, do not remove! auth_header = {} if 'Authorization' in request.META: auth_header = {'Authorization': request.META['Authorization']} elif 'HTTP_AUTHORIZATION' in request.META: auth_header = {'Authorization': request.META['HTTP_AUTHORIZATION']} # Don't include extra parameters when request.method is POST and # request.MIME['CONTENT_TYPE'] is "application/x-www-form-urlencoded" # (See http://oauth.net/core/1.0a/#consumer_req_param). # But there is an issue with Django's test Client and custom content types # so an ugly test is made here, if you find a better solution... parameters = {} if request.method == "POST" and \ (request.META.get('CONTENT_TYPE') == "application/x-www-form-urlencoded" \ or request.META.get('SERVER_NAME') == 'testserver'): parameters = dict((k, v.encode('utf-8')) for (k, v) in request.REQUEST.iteritems()) oauth_request = oauth.Request.from_request(request.method, request.build_absolute_uri(request.path), headers=auth_header, parameters=parameters, query_string=request.META.get('QUERY_STRING', '')) if oauth_request: oauth_server = oauth.Server() if 'plaintext' in OAUTH_SIGNATURE_METHODS: oauth_server.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) if 'hmac-sha1' in OAUTH_SIGNATURE_METHODS: oauth_server.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) else: oauth_server = None return oauth_server, oauth_request
def getInstance(cls): if cls._instance == None: cls._instance = oauth.Server() cls._instance.add_signature_method( oauth.SignatureMethod_PLAINTEXT()) cls._instance.add_signature_method( oauth.SignatureMethod_HMAC_SHA1()) return cls._instance
def oauth_signed_request(self, req): """Signs any request using OAuth. Mandatory before any request of access upon OAuth-protected data""" oauth_request = oauth2.Request.from_consumer_and_token( self.consumer, self.token, req.method, req.url) oauth_request.sign_request(oauth2.SignatureMethod_PLAINTEXT(), self.consumer, self.token) for header, value in oauth_request.to_header().items(): req.headers[header] = value rep = self.session.send(req.prepare()) rep.raise_for_status() return rep
def __init__(self, num=0): if (TOKEN_KEY[num] and TOKEN_SECRET[num]): self._signature_method_plaintext = oauth.SignatureMethod_PLAINTEXT( ) self._signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1( ) self._oauth_token = oauth.Token(key=TOKEN_KEY[num], secret=TOKEN_SECRET[num]) self._oauth_consumer = oauth.Consumer(key=CONSUMER_KEY, secret=CONSUMER_SECRET) else: exit()
def initialize_server_request(request): """Shortcut for initialization.""" oauth_request = get_oauth_request(request) if oauth_request: oauth_server = oauth.Server() if 'plaintext' in OAUTH_SIGNATURE_METHODS: oauth_server.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) if 'hmac-sha1' in OAUTH_SIGNATURE_METHODS: oauth_server.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) else: oauth_server = None return oauth_server, oauth_request
def _get_request(self, method='GET', parameters=None, use_token=True): consumer = oauth.Consumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET) if use_token: token = oauth.Token(OAUTH_TOKEN_KEY, OAUTH_TOKEN_SECRET) else: token = None request = oauth.Request.from_consumer_and_token(consumer, token, http_method=method, parameters=parameters) request.sign_request(oauth.SignatureMethod_PLAINTEXT(), consumer, token) return request
def test_add_signature_method(self): server = oauth.Server() res = server.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) self.assertTrue(len(res) == 1) self.assertTrue('HMAC-SHA1' in res) self.assertTrue( isinstance(res['HMAC-SHA1'], oauth.SignatureMethod_HMAC_SHA1)) res = server.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) self.assertTrue(len(res) == 2) self.assertTrue('PLAINTEXT' in res) self.assertTrue( isinstance(res['PLAINTEXT'], oauth.SignatureMethod_PLAINTEXT))
def __init__(self, subdomain): self.request_token_url = 'http://%s.%s%s' % ( subdomain, config.LOGGLY_DOMAIN, config.OAUTH_REQUEST_TOKEN_PATH) self.access_token_url = 'http://%s.%s%s' % ( subdomain, config.LOGGLY_DOMAIN, config.OAUTH_ACCESS_TOKEN_PATH) self.authorize_url = 'http://%s.%s%s' % ( subdomain, config.LOGGLY_DOMAIN, config.OAUTH_AUTHORIZE_PATH) self.callback_url = config.OAUTH_CALLBACK_URL self.consumer = oauth.Consumer(config.OAUTH_CONSUMER_KEY, config.OAUTH_CONSUMER_SECRET) self.signature_method_plaintext = oauth.SignatureMethod_PLAINTEXT() self.signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1() self.connection = httplib.HTTPConnection(config.AB_DOMAIN)
def GetRequestToken(self): connection = httplib.HTTPSConnection(FitBit.config.SERVER) consumer = oauth.Consumer(FitBit.config.CONSUMER_KEY, FitBit.config.CONSUMER_SECRET) signature_method = oauth.SignatureMethod_PLAINTEXT() oauth_request = oauth.Request.from_consumer_and_token( consumer, http_url=FitBit.config.REQUEST_TOKEN_URL) oauth_request.sign_request(signature_method, consumer, None) resp = self.FetchResponse(oauth_request, connection, FitBit.config.REQUEST_TOKEN_URL) auth_token = oauth.Token.from_string(resp) auth_url = "%s?oauth_token=%s" % (FitBit.config.AUTHORIZATION_URL, auth_token.key) return auth_url, auth_token
def GetRequestToken(self): connection = httplib.HTTPSConnection(self.SERVER) consumer = oauth.Consumer(self.CONSUMER_KEY, self.CONSUMER_SECRET) signature_method = oauth.SignatureMethod_PLAINTEXT() oauth_request = oauth.Request.from_consumer_and_token( consumer, http_url=self.REQUEST_TOKEN_URL) oauth_request.sign_request(signature_method, consumer, None) resp = self.FetchResponse( oauth_request, connection, self.REQUEST_TOKEN_URL) #passing in explicit url print resp auth_token = oauth.Token.from_string(resp) auth_url = "%s?oauth_token=%s" % ( self.AUTHORIZATION_URL, auth_token.key) #build the URL return auth_url, auth_token
def __init__(self, consumer_key=None, consumer_secret=None, access_token_key=None, access_token_secret=None): self._consumer_key = consumer_key self._consumer_secret = consumer_secret self._access_token_key = access_token_key self._access_token_secret = access_token_secret self._signature_method_plaintext = oauth.SignatureMethod_PLAINTEXT() self._signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1() self._oauth_token = oauth.Token(key=access_token_key, secret=access_token_secret) self._oauth_consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
def ApiCall(self, access_token, apiCall): signature_method = oauth.SignatureMethod_PLAINTEXT() connection = httplib.HTTPSConnection(FitBit.config.SERVER) #build the access token from a string access_token = oauth.Token.from_string(access_token) consumer = oauth.Consumer(FitBit.config.CONSUMER_KEY, FitBit.config.CONSUMER_SECRET) final_url = 'https://' + FitBit.config.SERVER + apiCall oauth_request = oauth.Request.from_consumer_and_token( consumer, token=access_token, http_url=final_url) oauth_request.sign_request(signature_method, consumer, access_token) headers = oauth_request.to_header(realm='api.fitbit.com') connection.request('GET', apiCall, headers=headers) resp = connection.getresponse() response = resp.read() return response
def _create_authorization_url_parameters(self): params = { 'oauth_version': "1.0", 'oauth_nonce': oauth.generate_nonce(), 'oauth_timestamp': int(time.time()), 'oauth_token': self.token.key, 'oauth_consumer_key': self.consumer.key } req = oauth.Request(method="GET", url="http://example.com", parameters=params) signature_method = oauth.SignatureMethod_PLAINTEXT() req.sign_request(signature_method, self.consumer, self.token) return dict(req)
def request(self, api_call, extra_params=None): self.parameters = { 'oauth_signature_method': oauth2.SignatureMethod_PLAINTEXT.name, 'oauth_timestamp': oauth2.generate_timestamp(), 'oauth_nonce': oauth2.generate_nonce(), 'oauth_version': '1.0', } if type(extra_params) is dict: self.parameters.update(extra_params) self.req = oauth2.Request(url=api_call, parameters=self.parameters) self.req.sign_request( signature_method=oauth2.SignatureMethod_PLAINTEXT(), token=self.user_token, consumer=self.cons_token) return self.req
def create_headers(self) -> dict: (consumer_key, key, secret) = self.maas_api_key.split(':') resource_token_string = "oauth_token_secret={}&oauth_token={}".format(secret, key) resource_token = oauth.Token.from_string(resource_token_string) consumer_token = oauth.Consumer(consumer_key, "") oauth_request = oauth.Request.from_consumer_and_token( consumer_token, token=resource_token, http_url=self.maas_api_url, parameters={'auth_nonce': uuid.uuid4().hex}) oauth_request.sign_request(oauth.SignatureMethod_PLAINTEXT(), consumer_token, resource_token) headers = oauth_request.to_header() headers['Accept'] = 'application/json' return headers
def _logglyAuth(request): ''' Perform an authorization request to Loggly.com for accessing a user's account. Keyword arguments: request -- the request object. Return: Redirect the user to Loggly.com's for giving access to AfterGlow. ''' # Construct a consumer object. consumer = oauth.Consumer(key=settings.LOGGLY_OAUTH_CONSUMER_KEY, secret=settings.LOGGLY_OAUTH_CONSUMER_SECRET) request_token_url = "http://%s.loggly.com/api/oauth/request_token/" % ( request.POST['logglySubdomain']) authorize_url = "http://%s.loggly.com/api/oauth/authorize/" % ( request.POST['logglySubdomain']) client = oauth.Client(consumer) # Change the signature method to PLAINTEXT. method = oauth.SignatureMethod_PLAINTEXT() client.set_signature_method(method) # Request a token. resp, content = client.request(request_token_url, method="POST", body=urllib.urlencode({ 'oauth_callback': settings.LOGGLY_OAUTH_CALLBACK })) request_token = dict(urlparse.parse_qsl(content)) # Store the subdomain and token secret in the session. request.session["logglyTokenSecret"] = request_token['oauth_token_secret'] request.session["logglySubdomain"] = request.POST['logglySubdomain'] # Redirect the user to Loggly's webpage for granting/denying access. return redirect("%s?oauth_token=%s" % (authorize_url, request_token['oauth_token']))
def GetAccessToken(self, access_code, auth_token): oauth_verifier = access_code connection = httplib.HTTPSConnection(FitBit.config.SERVER) consumer = oauth.Consumer(FitBit.config.CONSUMER_KEY, FitBit.config.CONSUMER_SECRET) signature_method = oauth.SignatureMethod_PLAINTEXT() oauth_request = oauth.Request.from_consumer_and_token( consumer, token=auth_token, http_url=FitBit.config.ACCESS_TOKEN_URL, parameters={'oauth_verifier': oauth_verifier}) oauth_request.sign_request(signature_method, consumer, auth_token) # now the token we get back is an access token access_token = oauth.Token.from_string( self.FetchResponse(oauth_request, connection, FitBit.config.ACCESS_TOKEN_URL)) # store the access token when returning it access_token = access_token.to_string() return access_token
def GetAccessToken(self, access_code, auth_token, oauth_verifier): auth_token = oauth.Token.from_string(auth_token) oauth_verifier = oauth_verifier connection = httplib.HTTPSConnection(self.SERVER) consumer = oauth.Consumer(self.CONSUMER_KEY, self.CONSUMER_SECRET) signature_method = oauth.SignatureMethod_PLAINTEXT() oauth_request = oauth.Request.from_consumer_and_token( consumer, token=auth_token, http_url=self.ACCESS_TOKEN_URL, parameters={'oauth_verifier': oauth_verifier}) oauth_request.sign_request(signature_method, consumer, auth_token) # now the token we get back is an access token resp = self.FetchResponse(oauth_request, connection, self.ACCESS_TOKEN_URL) access_token = oauth.Token.from_string( resp ) # parse the response into an OAuthToken object / passingin explicit url # store the access token when returning it # access_token = access_token.to_string() return access_token
def ApiCall(self, access_token, apiCall='/1/user/-/activities/log/steps/date/today/1d.json'): #other API Calls possible, or read the FitBit documentation for the full list. #apiCall = '/1/user/-/devices.json' #apiCall = '/1/user/-/profile.json' #apiCall = '/1/user/-/activities/date/2011-06-17.json' signature_method = oauth.SignatureMethod_PLAINTEXT() connection = httplib.HTTPSConnection(self.SERVER) #build the access token from a string access_token = oauth.Token.from_string(access_token) consumer = oauth.Consumer(self.CONSUMER_KEY, self.CONSUMER_SECRET) final_url = 'http://' + self.SERVER + apiCall oauth_request = oauth.Request.from_consumer_and_token( consumer, token=access_token, http_url=final_url) oauth_request.sign_request(signature_method, consumer, access_token) headers = oauth_request.to_header(realm='api.fitbit.com') connection.request('GET', apiCall, headers=headers) resp = connection.getresponse() response = resp.read() return response
def verify_oauth_request(request, oauth_request, consumer, token=None): """ Helper function to verify requests. """ from store import store # Check nonce #print 'Nonce: %s' % store.check_nonce(request, oauth_request, oauth_request['oauth_nonce'], oauth_request['oauth_timestamp']) if not store.check_nonce(request, oauth_request, oauth_request['oauth_nonce'], oauth_request['oauth_timestamp']): #print 'nonce check fail' return False print 'Nonce: true' # Verify request try: oauth_server = oauth.Server() oauth_server.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) oauth_server.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) oauth_server.add_signature_method(SignatureMethod_RSA_SHA1()) # Ensure the passed keys and secrets are ascii, or HMAC will complain. consumer = oauth.Consumer(consumer.key.encode('ascii', 'ignore'), consumer.secret.encode('ascii', 'ignore')) if token is not None: token = oauth.Token(token.key.encode('ascii', 'ignore'), token.secret.encode('ascii', 'ignore')) print 'normalized parameters: %s' % oauth_request.get_normalized_parameters( ) oauth_server.verify_request(oauth_request, consumer, token) except oauth.Error as o: print o.message return False return True
def index(): # Basic processing of the LTI request starts here # this first block is about getting the user information provided by the LMS myrecord = None consumer = None masterapp = None userinfo = None user_id = request.vars.get("user_id", None) last_name = request.vars.get("lis_person_name_family", None) first_name = request.vars.get("lis_person_name_given", None) full_name = request.vars.get("lis_person_name_full", None) message_type = request.vars.get("lti_message_type") course_id = _param_converter(request.vars.get("custom_course_id", None)) if course_id: # Allow the course_id to be either a number or the name of the course, as a string. try: course_id = int(course_id) except ValueError: course_id = (db(db.courses.course_name == course_id).select( **SELECT_CACHE).first()) course_id = course_id.id if full_name and not last_name: names = full_name.strip().split() last_name = names[-1] first_name = " ".join(names[:-1]) email = request.vars.get("lis_person_contact_email_primary", None) instructor = ("Instructor" in request.vars.get( "roles", [])) or ("TeachingAssistant" in request.vars.get("roles", [])) result_source_did = request.vars.get("lis_result_sourcedid", None) outcome_url = request.vars.get("lis_outcome_service_url", None) # Deprecated: the use of the non-LTI-compliant name ``assignment_id``. The parameter should be ``custom_assignment_id``. assignment_id = _param_converter( request.vars.get("custom_assignment_id", request.vars.get("assignment_id", None))) practice = request.vars.get("practice", None) if user_id is None: return dict( logged_in=False, lti_errors=[ "user_id is required for this tool to function", request.vars ], masterapp=masterapp, ) elif first_name is None: return dict( logged_in=False, lti_errors=[ "First Name is required for this tool to function", request.vars, ], masterapp=masterapp, ) elif last_name is None: return dict( logged_in=False, lti_errors=[ "Last Name is required for this tool to function", request.vars, ], masterapp=masterapp, ) elif email is None: return dict( logged_in=False, lti_errors=[ "Email is required for this tool to function", request.vars ], masterapp=masterapp, ) else: userinfo = dict() userinfo["first_name"] = first_name userinfo["last_name"] = last_name # In the `Canvas Student View <https://community.canvaslms.com/docs/DOC-13122-415261153>`_ as of 7-Jan-2019, the ``lis_person_contact_email_primary`` is an empty string. In this case, use the userid instead. email = email or (user_id + "@junk.com") userinfo["email"] = email # Now we need to get some security info # oauth_consumer_key key = request.vars.get("oauth_consumer_key", None) if key is not None: myrecord = db(db.lti_keys.consumer == key).select().first() if myrecord is None: return dict( logged_in=False, lti_errors=["Could not find oauth_consumer_key", request.vars], masterapp=masterapp, ) else: session.oauth_consumer_key = key if myrecord is not None: masterapp = myrecord.application if len(masterapp) < 1: masterapp = "welcome" session.connect(request, response, masterapp=masterapp, db=db) oauth_server = oauth2.Server() oauth_server.add_signature_method(oauth2.SignatureMethod_PLAINTEXT()) oauth_server.add_signature_method(oauth2.SignatureMethod_HMAC_SHA1()) # Use ``setting.lti_uri`` if it's defined; otherwise, use the current URI (which must be built from its components). Don't include query parameters, which causes a failure in OAuth security validation. full_uri = settings.get( "lti_uri", "{}://{}{}".format(request.env.wsgi_url_scheme, request.env.http_host, request.url), ) oauth_request = oauth2.Request.from_request( "POST", full_uri, None, dict(request.vars), query_string=request.env.query_string, ) # Fix encoding -- the signed keys are in bytes, but the oauth2 Request constructor translates everything to a string. Therefore, they never compare as equal. ??? if isinstance(oauth_request.get("oauth_signature"), str): oauth_request["oauth_signature"] = oauth_request[ "oauth_signature"].encode("utf-8") consumer = oauth2.Consumer(myrecord.consumer, myrecord.secret) try: oauth_server.verify_request(oauth_request, consumer, None) except oauth2.Error as err: return dict( logged_in=False, lti_errors=[ "OAuth Security Validation failed:" + err.message, request.vars, ], masterapp=masterapp, ) consumer = None ############################################################################### # I think everything from the beginning to here could/should be refactored into # a validate function. Or make use of the lti package # Time to create / update / login the user if userinfo and (consumer is not None): userinfo["username"] = email # Only assign a password if we're creating the user. The # ``get_or_create_user`` method checks for an existing user using both # the username and the email. update_fields = ["email", "first_name", "last_name"] if (not db((db.auth_user.username == userinfo["username"]) | (db.auth_user.email == userinfo["email"])).select( db.auth_user.id).first()): pw = db.auth_user.password.validate(str(uuid.uuid4()))[0] userinfo["password"] = pw update_fields.append("password") user = auth.get_or_create_user(userinfo, update_fields=update_fields) if user is None: return dict( logged_in=False, lti_errors=["Unable to create user record", request.vars], masterapp=masterapp, ) # user exists; make sure course name and id are set based on custom parameters passed, if this is for runestone. As noted for ``assignment_id``, parameters are passed as a two-element list. # course_id = _param_converter(request.vars.get("custom_course_id", None)) # if the instructor uses their course name instead of its id number then get the number. if course_id: user["course_id"] = course_id user["course_name"] = getCourseNameFromId( course_id ) # need to set course_name because calls to verifyInstructor use it user.update_record() # Update instructor status. # TODO: this block should be removed. The only way to become an instructor # is through Runestone if instructor: # Give the instructor free access to the book. db.user_courses.update_or_insert(user_id=user.id, course_id=course_id) db.course_instructor.update_or_insert(instructor=user.id, course=course_id) else: # Make sure previous instructors are removed from the instructor list. db((db.course_instructor.instructor == user.id) & (db.course_instructor.course == course_id)).delete() # Before creating a new user_courses record: if (not db((db.user_courses.user_id == user.id) & (db.user_courses.course_id == course_id)).select(). first()): # In academy mode, present payment or donation options, per the discussion at https://github.com/RunestoneInteractive/RunestoneServer/pull/1322. if settings.academy_mode: # To do so, store the current URL, so this request can be completed after creating the user. # TODO: this doesn't work, since the ``course_id``` and ``assignment_id`` aren't saved in this redirect. Therefore, these should be stored (perhaps in ``session``) then used after a user pays / donates. session.lti_url_next = full_uri auth.login_user(user) redirect(URL(c="default")) else: # Otherwise, simply create the user. db.user_courses.update_or_insert(user_id=user.id, course_id=course_id) auth.login_user(user) if message_type == "ContentItemSelectionRequest": return _provide_assignment_list(course_id, consumer) elif assignment_id: # If the assignment is released, but this is the first time a student has visited the assignment, auto-upload the grade. _launch_assignment(assignment_id, user, result_source_did, outcome_url) # If we got here, the assignment wasn't launched. return dict( logged_in=False, lti_errors=[ f"Invalid assignment id {assignment_id}; please contact your instructor.", request.vars, ], masterapp=masterapp, ) elif practice: _launch_practice(outcome_url, result_source_did, user, course_id) # else just redirect to the book index redirect(get_course_url("index.html"))
def server(self): result = oauth.Server() result.add_signature_method(oauth.SignatureMethod_PLAINTEXT()) result.add_signature_method(oauth.SignatureMethod_HMAC_SHA1()) return result
def index(): myrecord = None consumer = None masterapp = None userinfo = None user_id = request.vars.get('user_id', None) last_name = request.vars.get('lis_person_name_family', None) first_name = request.vars.get('lis_person_name_given', None) full_name = request.vars.get('lis_person_name_full', None) if full_name and not last_name: names = full_name.strip().split() last_name = names[-1] first_name = ' '.join(names[:-1]) email = request.vars.get('lis_person_contact_email_primary', None) instructor = ("Instructor" in request.vars.get('roles', [])) or \ ("TeachingAssistant" in request.vars.get('roles', [])) result_source_did=request.vars.get('lis_result_sourcedid', None) outcome_url=request.vars.get('lis_outcome_service_url', None) assignment_id = _param_converter(request.vars.get('assignment_id', None)) practice = request.vars.get('practice', None) if user_id is None : return dict(logged_in=False, lti_errors=["user_id is required for this tool to function", request.vars], masterapp=masterapp) elif first_name is None : return dict(logged_in=False, lti_errors=["First Name is required for this tool to function", request.vars], masterapp=masterapp) elif last_name is None : return dict(logged_in=False, lti_errors=["Last Name is required for this tool to function", request.vars], masterapp=masterapp) elif email is None : return dict(logged_in=False, lti_errors=["Email is required for this tool to function", request.vars], masterapp=masterapp) else : userinfo = dict() userinfo['first_name'] = first_name userinfo['last_name'] = last_name # In the `Canvas Student View <https://community.canvaslms.com/docs/DOC-13122-415261153>`_ as of 7-Jan-2019, the ``lis_person_contact_email_primary`` is an empty string. In this case, use the userid instead. email = email or (user_id + '@junk.com') userinfo['email'] = email key = request.vars.get('oauth_consumer_key', None) if key is not None: myrecord = db(db.lti_keys.consumer==key).select().first() if myrecord is None : return dict(logged_in=False, lti_errors=["Could not find oauth_consumer_key", request.vars], masterapp=masterapp) else: session.oauth_consumer_key = key if myrecord is not None : masterapp = myrecord.application if len(masterapp) < 1 : masterapp = 'welcome' session.connect(request, response, masterapp=masterapp, db=db) oauth_server = oauth2.Server() oauth_server.add_signature_method(oauth2.SignatureMethod_PLAINTEXT()) oauth_server.add_signature_method(oauth2.SignatureMethod_HMAC_SHA1()) # Use ``setting.lti_uri`` if it's defined; otherwise, use the current URI (which must be built from its components). Don't include query parameters, which causes a failure in OAuth security validation. full_uri = settings.get('lti_uri', '{}://{}{}'.format( request.env.wsgi_url_scheme, request.env.http_host, request.url )) oauth_request = oauth2.Request.from_request( 'POST', full_uri, None, dict(request.vars), query_string=request.env.query_string ) # Fix encoding -- the signed keys are in bytes, but the oauth2 Request constructor translates everything to a string. Therefore, they never compare as equal. ??? if isinstance(oauth_request.get('oauth_signature'), six.string_types): oauth_request['oauth_signature'] = oauth_request['oauth_signature'].encode('utf-8') consumer = oauth2.Consumer(myrecord.consumer, myrecord.secret) try: oauth_server.verify_request(oauth_request, consumer, None) except oauth2.Error as err: return dict(logged_in=False, lti_errors=["OAuth Security Validation failed:"+err.message, request.vars], masterapp=masterapp) consumer = None # Time to create / update / login the user if userinfo and (consumer is not None): userinfo['username'] = email # Only assign a password if we're creating the user. The # ``get_or_create_user`` method checks for an existing user using both # the username and the email. update_fields = ['email', 'first_name', 'last_name'] if not db( (db.auth_user.username == userinfo['username']) | (db.auth_user.email == userinfo['email']) ).select(db.auth_user.id).first(): pw = db.auth_user.password.validate(str(uuid.uuid4()))[0] userinfo['password'] = pw update_fields.append('password') user = auth.get_or_create_user(userinfo, update_fields=update_fields) if user is None: return dict(logged_in=False, lti_errors=["Unable to create user record", request.vars], masterapp=masterapp) # user exists; make sure course name and id are set based on custom parameters passed, if this is for runestone. As noted for ``assignment_id``, parameters are passed as a two-element list. course_id = _param_converter(request.vars.get('custom_course_id', None)) section_id = _param_converter(request.vars.get('custom_section_id', None)) if course_id: user['course_id'] = course_id user['course_name'] = getCourseNameFromId(course_id) # need to set course_name because calls to verifyInstructor use it user['section'] = section_id user.update_record() # Update instructor status. if instructor: # Give the instructor free access to the book. db.user_courses.update_or_insert(user_id=user.id, course_id=course_id) db.course_instructor.update_or_insert(instructor=user.id, course=course_id) else: db((db.course_instructor.instructor == user.id) & (db.course_instructor.course == course_id)).delete() # Before creating a new user_courses record, present payment or donation options. if not db((db.user_courses.user_id==user.id) & (db.user_courses.course_id==course_id)).select().first(): # Store the current URL, so this request can be completed after creating the user. session.lti_url_next = full_uri auth.login_user(user) redirect(URL(c='default')) if section_id: # set the section in the section_users table # test this db.section_users.update_or_insert(db.section_users.auth_user == user['id'], auth_user=user['id'], section = section_id) auth.login_user(user) if assignment_id: # If the assignment is released, but this is the first time a student has visited the assignment, auto-upload the grade. assignment = db(db.assignments.id == assignment_id).select( db.assignments.released).first() grade = db( (db.grades.auth_user == user.id) & (db.grades.assignment == assignment_id) ).select(db.grades.lis_result_sourcedid, db.grades.lis_outcome_url).first() send_grade = (assignment and assignment.released and grade and not grade.lis_result_sourcedid and not grade.lis_outcome_url) # save the guid and url for reporting back the grade db.grades.update_or_insert((db.grades.auth_user == user.id) & (db.grades.assignment == assignment_id), auth_user=user.id, assignment=assignment_id, lis_result_sourcedid=result_source_did, lis_outcome_url=outcome_url) if send_grade: _try_to_send_lti_grade(user.id, assignment_id) redirect(URL('assignments', 'doAssignment', vars={'assignment_id':assignment_id})) elif practice: if outcome_url and result_source_did: db.practice_grades.update_or_insert((db.practice_grades.auth_user == user.id), auth_user=user.id, lis_result_sourcedid=result_source_did, lis_outcome_url=outcome_url, course_name=getCourseNameFromId(course_id)) else: # don't overwrite outcome_url and result_source_did db.practice_grades.update_or_insert((db.practice_grades.auth_user == user.id), auth_user=user.id, course_name=getCourseNameFromId(course_id)) redirect(URL('assignments', 'settz_then_practice', vars={'course_name':user['course_name']})) redirect(get_course_url('index.html'))