コード例 #1
0
    def setUp(self):
        """
        user_a -> admin
        user_b -> user2

        user_a uploads shared file.

        We authenticate to the API with user_b.

        user_b subscribes to user_a's shake.]
        """
        super(APIResourceRequests, self).setUp()
        self.user_a = User(
                name='admin',
                email='*****@*****.**',
                email_confirmed=1,
                is_paid=1,
                about="admin",
                website='https://mltshp.com')
        self.user_a.set_password('asdfasdf')
        self.user_a.save()
        self.sid = self.sign_in('admin', 'asdfasdf')
        self.xsrf = self.get_xsrf()

        self.test_file1_path = os.path.abspath("test/files/1.png")
        self.test_file1_sha1 = Sourcefile.get_sha1_file_key(self.test_file1_path)
        self.test_file1_content_type = "image/png"
        response = self.upload_file(file_path=self.test_file1_path, sha1=self.test_file1_sha1,
            content_type=self.test_file1_content_type, user_id=self.user_a.id, sid=self.sid, xsrf=self.xsrf)

        self.user_b = User(name='user2', email='*****@*****.**', email_confirmed=1, is_paid=1)
        self.user_b.set_password('asdfasdf')
        self.user_b.save()

        self.group_shake = self.user_b.create_group_shake(title='Group Shake', name='groupshake', description='This is a group shake.')
        self.group_shake_2 = self.user_a.create_group_shake(title='Another Group', name='anothergroup')
        # Add user_b to user_a's group shake, so we get it in user_b's /shakes endpoint.
        shake_manager = ShakeManager(user_id=self.user_b.id, shake_id=self.group_shake_2.id)
        shake_manager.save()

        self.app = App(user_id=self.user_a.id, title='An App', description='Nothing yet.', redirect_url='http://client.example.com/return')
        self.app.save()

        self.authorization = Authorizationcode.generate(self.app.id, self.app.redirect_url, self.user_b.id)
        self.access_token = Accesstoken.generate(self.authorization.id)

        extra_authorization = Authorizationcode.generate(self.app.id, self.app.redirect_url, self.user_b.id)
        self.ratelimited_access_token = Accesstoken.generate(extra_authorization.id)
        now_hour = datetime.utcnow().strftime('%Y-%m-%d %H:00:00')
        ratelimit = Apihit(accesstoken_id=self.ratelimited_access_token.id, hits=options.api_hits_per_hour - 2, hour_start=now_hour)
        ratelimit.save()

        #subscription
        self.user_b.subscribe(self.user_a.shake())
コード例 #2
0
    def test_sending_valid_request_returns_access_token(self):
        message = "grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s" % (self.app.key(), self.app.secret, 'admin', 'asdfasdf')
        response = api_request(self, self.get_url('/api/token'), method='POST', body=message, unsigned=True)
        access_token = Accesstoken.all()
        self.assertEqual(len(access_token), 1)
        self.assertTrue(access_token[0])

        # Now clean up so the invalid test will work out of order.
        for token in access_token:
            token.delete()
コード例 #3
0
    def test_access_token_is_not_deleted_when_new_one_is_requested(self):
        # First request one.
        message = "grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s&client_secret=%s" % (self.authorization.code, self.app.redirect_url, self.app.key(), self.app.secret)

        response = api_request(self, self.get_url('/api/token'), method='POST', body=message, unsigned=True)

        #one access token should have been created:
        access_token = Accesstoken.get('id=1')
        self.assertTrue(access_token)
        self.assertFalse(access_token.deleted)
        access_tokens = Accesstoken.all()
        self.assertEqual(len(access_tokens), 1)

        j_response = json_decode(response.body)
        self.assertEqual(j_response['token_type'], 'mac')
        self.assertEqual(j_response['access_token'], access_token.consumer_key)
        self.assertEqual(j_response['secret'], access_token.consumer_secret)
        self.assertEqual(j_response['algorithm'], 'hmac-sha-1')

        # Now request another.
        other_authorization = Authorizationcode.generate(self.app.id, self.app.redirect_url, self.user_b.id)
        message = "grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s&client_secret=%s" % (other_authorization.code, self.app.redirect_url, self.app.key(), self.app.secret)

        response = api_request(self, self.get_url('/api/token'), method='POST', body=message, unsigned=True)

        # A second access token should have been created, but the
        # first one should be gone.
        access_token = Accesstoken.get('id=1')
        self.assertFalse(access_token.deleted)
        access_token = Accesstoken.get('id=2')
        self.assertFalse(access_token.deleted)
        access_tokens = Accesstoken.all()
        self.assertEqual(len(access_tokens), 2)

        j_response = json_decode(response.body)
        self.assertEqual(j_response['token_type'], 'mac')
        self.assertEqual(j_response['access_token'], access_token.consumer_key)
        self.assertEqual(j_response['secret'], access_token.consumer_secret)
        self.assertEqual(j_response['algorithm'], 'hmac-sha-1')
コード例 #4
0
    def test_access_token_returned_for_valid_authorization_code_and_credentials(self):
        message="grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s&client_secret=%s" % (self.authorization.code, self.app.redirect_url, self.app.key(), self.app.secret)

        response = api_request(self, self.get_url('/api/token'), method='POST', body=message, unsigned=True)

        #one access token should have been created:
        access_token = Accesstoken.get('id=1')

        j_response = json_decode(response.body)
        self.assertEqual(j_response['token_type'], 'mac')
        self.assertEqual(j_response['access_token'], access_token.consumer_key)
        self.assertEqual(j_response['secret'], access_token.consumer_secret)
        self.assertEqual(j_response['algorithm'], 'hmac-sha-1')
コード例 #5
0
 def test_sending_invalid_password_returns_error(self):
     message = "grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s" % (self.app.key(), self.app.secret, 'admin', 'qwerqwer')
     response = api_request(self, self.get_url('/api/token'), method='POST', body=message, unsigned=True)
     access_token = Accesstoken.all()
     self.assertEqual(len(access_token), 0)
コード例 #6
0
    def test_disconnecting_connection(self):
        """
        Sending a post request to /settings/connections/{{app_id}}/disconnect should mark
        an access token as deleted.
        """
        # app created by Torrez.
        app = App(user_id=self.user.id,title='Title')
        app.save()

        # another user.
        new_user = User(name='newuser', email='*****@*****.**', email_confirmed=1, is_paid=1)
        new_user.set_password('asdfasdf')
        new_user.save()

        #connect another user and app
        token = Accesstoken(user_id=new_user.id, app_id=app.id, deleted=0)
        token.save()

        # If torrez hits URL, which he should never be able to find, nothing happens
        # to token.
        self.post_url("/account/settings/connections/%s/disconnect" % app.id)
        token_reloaded = Accesstoken.get('id = %s', token.id)
        self.assertEqual(0, token_reloaded.deleted)

        # but if the user it's about hits it, the token deletes.
        self.sign_in('newuser', 'asdfasdf')
        self.post_url("/account/settings/connections/%s/disconnect" % app.id)
        token_reloaded = Accesstoken.get('id = %s', token.id)
        self.assertEqual(1, token_reloaded.deleted)

        # Even if there are several undeleted access tokens, they all end up deleted.
        token_two = Accesstoken(user_id=new_user.id, app_id=app.id, deleted=0)
        token_two.save()
        token_three = Accesstoken(user_id=new_user.id, app_id=app.id, deleted=0)
        token_three.save()

        self.post_url("/account/settings/connections/%s/disconnect" % app.id)
        token_reloaded = Accesstoken.get('id = %s', token.id)
        token_two_reloaded = Accesstoken.get('id = %s', token_two.id)
        token_three_reloaded = Accesstoken.get('id = %s', token_three.id)
        self.assertEqual(1, token_reloaded.deleted)  # still
        self.assertEqual(1, token_two_reloaded.deleted)
        self.assertEqual(1, token_three_reloaded.deleted)
コード例 #7
0
    def post(self):
        grant_type = self.get_argument('grant_type', None)
        code = self.get_argument('code', None)
        redirect_url = self.get_argument('redirect_uri', None)
        client_secret = self.get_argument('client_secret', None)
        client_id = self.get_argument('client_id', None)
        username = self.get_argument('username', None)
        password = self.get_argument('password', None)

        if not grant_type or not client_id or not client_secret:
            self.set_status(400)
            return self.write({
                'error':
                'invalid_request',
                'error_description':
                "The grant_type, client_id, and client_secret parameters are required."
            })

        if grant_type == 'password':
            pass
        elif grant_type == 'authorization_code':
            if not code or not redirect_url:
                self.set_status(400)
                return self.write({
                    'error':
                    'invalid_request',
                    'error_description':
                    "The code and redirect_url parameters are required."
                })
        else:
            self.set_status(401)
            return self.write({'error': 'invalid_grant'})

        app = App.by_key(client_id)
        if not app:
            self.set_status(401)
            return self.write({'error': 'invalid_client'})

        if app.secret != client_secret:
            self.set_status(401)
            return self.write({'error': 'access_denied'})

        auth_code = None
        if grant_type == 'password':
            #generating one in one fell swoop.
            #if user password match then make an auth_code
            check_user = User.authenticate(username, password)
            if check_user:
                auth_code = Authorizationcode.generate(
                    app_id=app.id,
                    redirect_url=app.redirect_url,
                    user_id=check_user.id)
            else:
                self.set_status(401)
                return self.write({'error': 'invalid_request'})
        else:
            auth_code = Authorizationcode.get(
                "code = %s and redirect_url = %s  and expires_at > %s", code,
                redirect_url, datetime.utcnow())

        if auth_code:
            self.set_header("Cache-Control", "no-store")
            access_token = Accesstoken.generate(auth_code.id)
            if access_token:
                response = {
                    "access_token": access_token.consumer_key,
                    "secret": access_token.consumer_secret,
                    "token_type": "mac",
                    "algorithm": "hmac-sha-1"
                }
                return self.write(response)
            else:
                self.set_status(401)
                return self.write({'error': 'invalid_grant'})
        else:
            self.set_status(401)
            return self.write({'error': 'invalid_grant'})
コード例 #8
0
    def wrapper(self, *args, **kwargs):
        #break up header and get access token, timestamp, nonce
        auth_items = {}
        if self.request.headers.get('Authorization'):
            try:
                h = self.request.headers.get('Authorization').replace(
                    'MAC ', '')
                auth_items = dict(
                    item.split('=', 1)
                    for item in h.replace('"', '').split(', '))
            except:
                self.set_status(401)
                self.set_header(
                    'WWW-Authenticate',
                    'MAC realm="mltshp" error="invalid_token", error_description="Cannot parse token."'
                )
                self.finish()
                return

            try:
                access_token_str = auth_items['token']
            except KeyError:
                self.set_status(401)
                self.set_header(
                    'WWW-Authenticate',
                    'MAC realm="mltshp" error="invalid_token", error_description="Missing token."'
                )
                self.finish()
                return
            access_token = Accesstoken.get('consumer_key = %s and deleted=0',
                                           access_token_str)

            if not access_token:
                self.set_status(401)
                self.set_header(
                    'WWW-Authenticate',
                    'MAC realm="mltshp" error="invalid_token", error_description="Invalid access token."'
                )
                self.finish()
                return

            api_log = Apilog.get('accesstoken_id=%s and nonce=%s',
                                 access_token.id, auth_items['nonce'])
            if api_log:
                self.set_status(401)
                self.set_header(
                    'WWW-Authenticate',
                    'MAC realm="mltshp" error="invalid_token", error_description="Duplicate nonce."'
                )
                self.finish()
                return
            else:
                api_log = Apilog(accesstoken_id=access_token.id,
                                 nonce=auth_items['nonce'])
                api_log.save()

            timestamp = int(auth_items['timestamp'])
            nowstamp = int(time.mktime(datetime.utcnow().timetuple()))
            if (nowstamp - timestamp) > 30:
                self.set_status(401)
                self.set_header(
                    'WWW-Authenticate',
                    'MAC realm="mltshp" error="invalid_token", error_description="Token is expired."'
                )
                self.finish()
                return

            hits_per_hour = options.api_hits_per_hour
            if hits_per_hour is not None:
                hits = Apihit.hit(access_token.id)
                #raise ValueError("YESSSS %d HITS PER HOUR AND %d HITS WHAT" % (hits_per_hour, hits))
                self.set_header('X-RateLimit-Limit', str(hits_per_hour))
                self.set_header('X-RateLimit-Reset',
                                str(nowstamp % 3600 + 3600))
                if hits >= hits_per_hour:
                    self.set_status(400)
                    self.set_header('X-RateLimit-Remaining', '0')
                    self.finish()
                    return
                self.set_header('X-RateLimit-Remaining', hits_per_hour - hits)

            parsed_url = urlparse(self.request.full_url())
            query_array = []
            if parsed_url.query:
                query_array += parsed_url.query.split('&')
            for i in range(len(query_array)):
                if query_array[i].find('=') == -1:
                    query_array[i] += '='
            query_array.sort()
            port = 80
            if not parsed_url.port:
                if parsed_url.scheme == 'https':
                    port = 443
            elif parsed_url.port:
                port = parsed_url.port

            normalized_string = normalize_string(auth_items['token'],
                                                 auth_items['timestamp'],
                                                 auth_items['nonce'],
                                                 self.request.method,
                                                 parsed_url.hostname, port,
                                                 parsed_url.path, query_array)

            digest = hmac.new(access_token.consumer_secret.encode('ascii'),
                              normalized_string, sha1).digest()
            signature = base64.encodestring(digest).strip()

            if signature == auth_items['signature']:
                self.oauth2_user_id = access_token.user_id
                return method(self, *args, **kwargs)
            else:
                self.set_status(401)
                self.set_header(
                    'WWW-Authenticate',
                    'MAC realm="mltshp" error="invalid_token", error_description="Signature doesn\'t match."'
                )
                self.write("NORMALIZED STRING: \n")
                self.write(normalized_string)
                self.write('-----\n')
                self.write('MY SIGNATURE\n')
                self.write(signature)
                self.write('\nYOUR SIGNATURE\n')
                self.write(auth_items['signature'])
                self.finish()
                return
        else:
            self.set_status(401)
            self.set_header('WWW-Authenticate', 'Basic realm="mltshp"')
            self.finish()