Exemple #1
0
def _authenticate_user(req):
    session = req.env['beaker.session']
    try:
        req.context['user'] = session['user']

        connection = db.connect()
        cursor = connection.cursor()

        cursor.execute('SELECT `csrf_token` FROM `session` WHERE `id` = %s', session['_id'])
        if cursor.rowcount != 1:
            cursor.close()
            connection.close()
            raise HTTPUnauthorized('Invalid Session', 'CSRF token missing', '')

        token = cursor.fetchone()[0]
        if req.get_header('X-CSRF-TOKEN') != token:
            cursor.close()
            connection.close()
            raise HTTPUnauthorized('Invalid Session', 'CSRF validation failed', '')

        cursor.close()
        connection.close()
    except KeyError:
        raise HTTPUnauthorized('Unauthorized', 'User must be logged in', '')
Exemple #2
0
    def on_get(self, req: Request, res: Response):
        if req.auth is None:
            raise HTTPNotImplemented('Not Implemented',
                                     'Use Basic Auth method!')

        auth_type, token = req.auth.split(' ')
        if auth_type.lower() != 'bearer':
            raise HTTPUnauthorized("Unauthorized")

        jwt_payload = self.__validate_token(token)

        user = self.__get_user(jwt_payload["user"])

        res.status = HTTP_200
        res.body = json.dumps(user)
Exemple #3
0
    def __handle__(*args, **kwargs):
        """

        :param args:
        :param kwargs:
                        service_name: the name of the service that is using the requester
        :return: the response object if no error detected
        :raises:
                requests.exceptions.Timeout: when the timeout is reached
                requests.exceptions.ConnectionError: When no connection is available
        """
        service = kwargs.get('service_name', 'Service')
        if 'ignore_exception' in kwargs:
            r = function(*args, **kwargs)
            return r
        try:
            r = function(*args, **kwargs)
            if r.status_code == 401:
                raise HTTPUnauthorized(
                    title='You are not authorized',
                    description='Please validate your authentication')
            if r.status_code == 404:
                raise HTTPNotFound()
            if r.status_code == 500:
                logger.error('Internal server error, message {}'.format(
                    r.text))
                raise HTTPInternalServerError(
                    'Failed to process request on {}'.format(service),
                    code='102')
            if r.status_code > 299:
                logger.error('Failed to process request, message {}'.format(
                    r.text))
                raise HTTPError(str(r.status_code),
                                description=r.text,
                                code='103')
            return r
        except requests.exceptions.Timeout:
            logger.error('{} Timeout'.format(service))
            raise HTTPError(
                HTTP_REQUEST_TIMEOUT,
                title='{} Timeout'.format(service),
                description='{} connection timeout'.format(service),
                code='100')
        except requests.exceptions.ConnectionError:
            raise HTTPError(HTTP_INTERNAL_SERVER_ERROR,
                            title='{} Connection Error'.format(service),
                            description='{} connection error'.format(service),
                            code='101')
Exemple #4
0
    def delete_subchapter_mutate(cls, info, model=None, **kwargs):
        if info.context['auth']['data']:
            if not info.context['auth']['data']['admin']: raise CodeduExceptionHandler(HTTPUnauthorized(description="PERMISSION DENIED"))
            query = model.get_query(info)
            model = model._meta.model
            data = kwargs.get('data', None)
            if data:
                instance = get_instance_by_pk(query, model, data)

                tmp_instance = instance.one()
                instance.delete()
                if tmp_instance.token:
                    shutil.rmtree(f"{root_path}/images/subchapter/{tmp_instance.token}")
                return cls(**{model.__tablename__:tmp_instance})
        else:
            raise CodeduExceptionHandler(HTTPUnauthorized(description=info.context['auth']['description']))
Exemple #5
0
 def on_delete(self, req: Request, resp: Response, id: int):
     token = req.get_param('token', required=True)
     user_data = get_user_data(token)
     if not is_site_admin(user_data, self.uowm):
         raise HTTPUnauthorized(
             f'Not authorized to make this request',
             f'You are not authorized to make this request')
     with self.uowm.start() as uow:
         template = uow.config_message_template.get_by_id(id)
         if not template:
             raise HTTPNotFound(
                 title=f'Message template {id} not found',
                 description=f'Unable to find message template with ID {id}'
             )
         uow.config_message_template.remove(template)
         uow.commit()
 def process_resource(self, request, response, resource, params):
     # Check the authorization credentials.
     authorized = False
     if request.auth is not None and request.auth.startswith('Basic '):
         # b64decode() returns bytes, but we require a str.
         credentials = b64decode(request.auth[6:]).decode('utf-8')
         username, password = credentials.split(':', 1)
         if (username == config.webservice.admin_user
                 and password == config.webservice.admin_pass):
             authorized = True
     if not authorized:
         # Not authorized.
         realm = 'Basic realm="{}",charset="{}"'.format(REALM, UTF8)
         raise HTTPUnauthorized('401 Unauthorized',
                                'REST API authorization failed',
                                challenges=[realm])
Exemple #7
0
def simple_create_mutate(cls, info, model=None, **kwargs):
    if info.context['auth']['data']:
        model = model._meta.model
        data = kwargs.get('data', None)
        image_info = info.context.get('image_info', None)
        if data:
            data['user_id'] = info.context['auth']['data']['user_id']
            db_session = info.context.get('session', None)
            if db_session:
                instance = model(**data)
                db_session.add(instance)
                db_session_flush(db_session)

            return cls(**{model.__tablename__:instance})
    else:
        raise CodeduExceptionHandler(HTTPUnauthorized(description=info.context['auth']['description']))
Exemple #8
0
 def update_subchapter_mutate(cls, info, model=None, **kwargs):
     if info.context['auth']['data']:
         if not info.context['auth']['data']['admin']: raise CodeduExceptionHandler(HTTPUnauthorized(description="PERMISSION DENIED"))
         query = model.get_query(info)
         model = model._meta.model
         data = kwargs.get('data', None)
         image_info = info.context.get('image_info', None)
         if data:
             instance = get_instance_by_pk(query, model, data)
             
             instance.update(data)
             if image_info:
                 image_handle('subchapter', instance.one(), image_info)
             return cls(**{model.__tablename__:instance.one()})
     else:
         raise CodeduExceptionHandler(HTTPUnauthorized(description=info.context['auth']['description']))
Exemple #9
0
    def get_profile(self, account_id):
        sm = Session_Maker(self.Api_Session)
        with sm as session:
            profile = session.query(Profile).filter(
                Profile.account_id == account_id).first()
            if profile is None:
                msg = "Uknown account_id passed."
                raise HTTPUnauthorized("Bad account_id", msg)

            profile_dict = {
                'gradYear': str(profile.gradYear),
                'firstName': profile.firstName,
                'lasName': profile.lastName,
                'major': profile.major
            }

            return profile_dict
 def on_post_potential(self, req: Request, resp: Response):
     token = req.get_param('token', required=True)
     post_id = req.get_param('post_id', required=True)
     user_data = get_user_data(token)
     if not user_data:
         raise HTTPUnauthorized('Invalid user token provided',
                                'Invalid user token provided')
     with self.uowm.start() as uow:
         template = MemeTemplatePotential(post_id=post_id,
                                          submitted_by=user_data['name'],
                                          vote_total=1)
         template.votes.append(
             MemeTemplatePotentialVote(post_id=template.post_id,
                                       user=user_data['name'],
                                       vote=1))
         uow.meme_template_potential.add(template)
         uow.commit()
Exemple #11
0
 def on_delete(self, req: Request, resp: Response):
     token = req.get_param('token', required=True)
     watch_id = req.get_param_as_int('watch_id', required=True)
     user_data = get_user_data(token)
     with self.uowm.start() as uow:
         watch = uow.repostwatch.get_by_id(watch_id)
         if not watch:
             raise HTTPNotFound(
                 title='No watch found',
                 description=f'Failed to find watch with ID {watch_id}')
         if watch.user.lower() != user_data['name'].lower():
             if not is_sleuth_admin(token, user_data):
                 raise HTTPUnauthorized(
                     title='You are not authorized to delete this watch',
                     description=
                     'You are not authorized to delete this post watch')
         uow.repostwatch.remove(watch)
         uow.commit()
Exemple #12
0
                def wrapper(request, *args, **kw):

                    user = request.context['user']

                    # this is authentication part
                    if not user.id:
                        raise HTTPUnauthorized('Invalid or expired session')

                    # this is authorization part
                    groups = set(user.groups)

                    if groups_required and not groups.intersection(groups_required):
                        raise HTTPForbidden('Unauthorized access')

                    if groups_forbidden and groups.intersection(groups_forbidden):
                        raise HTTPForbidden('Unauthorized access')

                    return f(*args, **kw)
Exemple #13
0
    def on_patch(self, req: Request, resp: Response, subreddit: Text):
        token = req.get_param('token', required=True)
        user_data = get_user_data(token)
        if not is_sub_mod_token(token, subreddit,
                                self.config.reddit_useragent):
            raise HTTPUnauthorized(
                f'Not authorized to make changes to {subreddit}',
                f'You\'re not a moderator on {subreddit}')
        with self.uowm.start() as uow:
            monitored_sub = uow.monitored_sub.get_by_sub(subreddit)
            if not monitored_sub:
                raise HTTPNotFound(
                    title=f'Subreddit {subreddit} Not Found',
                    description=f'Subreddit {subreddit} Not Found')
            raw = json.load(req.bounded_stream)
            for k, v in raw.items():
                if k not in self.config.sub_monitor_exposed_config_options:
                    continue
                if hasattr(monitored_sub, k):
                    if getattr(monitored_sub, k) != v:
                        log.debug('Update %s config | %s: %s => %s', subreddit,
                                  k, getattr(monitored_sub, k), v)
                        uow.monitored_sub_config_change.add(
                            MonitoredSubConfigChange(
                                source='site',
                                subreddit=subreddit,
                                config_key=k,
                                old_value=str(getattr(monitored_sub, k)),
                                new_value=str(v),
                                updated_by=user_data['name']))
                        setattr(monitored_sub, k, v)
            try:
                uow.commit()
            except Exception as e:
                log.exception('Problem saving config', exc_info=True)
                raise HTTPInternalServerError(
                    title='Problem Saving Config',
                    description='Something went t**s up when saving the config'
                )

        celery.send_task(
            'redditrepostsleuth.core.celery.admin_tasks.update_subreddit_config_from_database',
            args=[monitored_sub, user_data],
            queue='monitored_sub_config_update')
Exemple #14
0
 def on_patch(self, req: Request, resp: Response):
     token = req.get_param('token', required=True)
     user_data = get_user_data(token)
     data = json.load(req.bounded_stream)
     with self.uowm.start() as uow:
         watch = uow.repostwatch.get_by_id(data['id'])
         if not watch:
             raise HTTPNotFound(
                 title=f'Post Watch Not Found',
                 description=
                 f'Unable to find post watch with ID {data["id"]}')
         if watch.user.lower() != user_data['name'].lower():
             if not is_sleuth_admin(token, user_data):
                 raise HTTPUnauthorized(
                     title='You are not authorized to make this change',
                     description=
                     'You are not authorized to modify this post watch')
         watch.enabled = data['enabled']
         uow.commit()
Exemple #15
0
    def create_subchapter_mutate(cls, info, model=None, **kwargs):
        if info.context['auth']['data']:
            if not info.context['auth']['data']['admin']: raise CodeduExceptionHandler(HTTPUnauthorized(description="PERMISSION DENIED"))
            model = model._meta.model
            data = kwargs.get('data', None)
            image_info = info.context.get('image_info', None)
            if data:
                db_session = info.context.get('session', None)
                if db_session:
                    instance = model(**data)
                    db_session.add(instance)
                    db_session_flush(db_session)

                    if image_info:
                        image_handle('subchapter', instance, image_info)

                return cls(**{model.__tablename__:instance})
        else:
            raise CodeduExceptionHandler(HTTPUnauthorized(description=info.context['auth']['description']))
Exemple #16
0
 def on_patch(self, req: Request, resp: Response, id: int):
     token = req.get_param('token', required=True)
     user_data = get_user_data(token)
     if not is_site_admin(user_data, self.uowm):
         raise HTTPUnauthorized(
             f'Not authorized to make this request',
             f'You are not authorized to make this request')
     with self.uowm.start() as uow:
         template = uow.config_message_template.get_by_id(id)
         if not template:
             raise HTTPNotFound(
                 title=f'Message template {id} not found',
                 description=f'Unable to find message template with ID {id}'
             )
         raw = json.load(req.bounded_stream)
         template.template_name = raw['template_name']
         template.template = raw['template']
         resp.body = json.dumps(template.to_dict())
         uow.commit()
Exemple #17
0
    def on_post(self, req, resp):
        """Create a new session based on provided login information"""

        json = req.json

        #FIXME: implement timing-invariance to fix timing attacks
        try:
            user = User.objects.get(email=json.get("email"))
            if password_ctx.verify(json.get("password"), user.auth):
                session = Session()
                session.user = user
                session.save()
                resp.session = session

                resp.json = {'sid': session.sid,
                             'uid':str(user.id),
                             'email': user.email}
            else:
                raise AuthenticationError()
        except (DoesNotExist, AuthenticationError) as err:
            raise HTTPUnauthorized("AuthenticationError", "No such user or wrong password", "")
Exemple #18
0
 def process_resource(self, request, response, resource, params):
     # Set this attribute on the resource right before it is dispatched to.
     # This can be used by the resource to provide different responses
     # based on the API version, and for path_to() to provide an API
     # version-specific path.
     resource.api = params.pop('api')
     # Check the authorization credentials.
     authorized = False
     if request.auth is not None and request.auth.startswith('Basic '):
         # b64decode() returns bytes, but we require a str.
         credentials = b64decode(request.auth[6:]).decode('utf-8')
         username, password = credentials.split(':', 1)
         if (username == config.webservice.admin_user and
                 password == config.webservice.admin_pass):
             authorized = True
     if not authorized:
         # Not authorized.
         raise HTTPUnauthorized(
             '401 Unauthorized',
             'REST API authorization failed',
             challenges=['Basic realm=Mailman3'])
Exemple #19
0
 def on_post(self, req: Request, resp: Response):
     token = req.get_param('token', required=True)
     user_data = get_user_data(token)
     raw = json.load(req.bounded_stream)
     if not is_site_admin(user_data, self.uowm):
         raise HTTPUnauthorized(
             f'Not authorized to make this request',
             f'You are not authorized to make this request')
     with self.uowm.start() as uow:
         new_template = ConfigMessageTemplate(
             template_name=raw['template_name'],
             template=raw['template'],
             template_slug=raw['template_slug'])
         uow.config_message_template.add(new_template)
         try:
             resp.body = json.dumps(new_template.to_dict())
             uow.commit()
         except IntegrityError as e:
             raise HTTPInternalServerError(
                 title='Failed to save message template',
                 description=str(e))
Exemple #20
0
 def on_get_user(self, req: Request, resp: Response, user: Text):
     results = []
     token = req.get_param('token', required=True)
     user_data = get_user_data(token)
     if user.lower() != user_data['name'].lower():
         if not is_sleuth_admin(token, user_data):
             raise HTTPUnauthorized(
                 title='You are not authorized to views these watches',
                 description=
                 f'You are not authorized to view watches for {user}')
     with self.uowm.start() as uow:
         watches = uow.repostwatch.get_all_by_user(user_data['name'])
         for watch in watches:
             post = uow.posts.get_by_post_id(watch.post_id)
             if not post:
                 continue
             results.append({
                 'watch': watch.to_dict(),
                 'post': post.to_dict()
             })
     resp.body = json.dumps(results)
Exemple #21
0
                def wrapper(request, *args, **kw):

                    user = request.context['user']

                    # this is authentication part
                    if not user.id:
                        raise HTTPUnauthorized('Invalid or expired session')

                    # this is authorization part
                    groups = set(user.groups)
                    if self.site_identifier in kw:
                        site_id = int(kw[self.site_identifier])
                        groups = groups.union(user.site_groups.get(site_id, []))

                    if groups_required and not groups.intersection(groups_required):
                        raise HTTPForbidden('Unauthorized access')

                    if groups_forbidden and groups.intersection(groups_forbidden):
                        raise HTTPForbidden('Unauthorized access')

                    return f(*args, **kw)
Exemple #22
0
    def set_context(token):

        uid, groups, name, email, mobile, site_groups = None, [], '', None, None, {}

        if token:
            try:
                session = sessions.get(
                    token,
                    ['uid', 'name', 'groups', 'email', 'mobile', 'site_groups']
                )
                uid, name, groups, email, mobile, site_groups = (
                    session['uid'], session['name'], session['groups'],
                    session['email'], session['mobile'], session['site_groups']
                )
            except InvalidSessionError:
                raise HTTPUnauthorized('Invalid or expired session')

        return User(
            sid=token, id=uid, name=name, groups=groups,
            email=email, mobile=mobile, site_groups=site_groups
        )
Exemple #23
0
    def _decode_jwt_token(self, token):
        options = dict(
            ('verify_' + claim, True) for claim in self.verify_claims)

        options.update(
            dict(('require_' + claim, True) for claim in self.required_claims))

        try:
            payload = jwt.decode(jwt=token,
                                 key=self.secret_key,
                                 options=options,
                                 algorithms=[self.algorithm],
                                 issuer=self.issuer,
                                 audience=self.audience,
                                 leeway=self.leeway)
        except InvalidTokenError as ex:
            raise HTTPUnauthorized(title='401 Unauthorized',
                                   description=str(ex),
                                   challenges=None)

        return payload
    def process_resource(self, req, resp, resource, params):
        """If this is not an exempt route, verify that a valid, signed
        jwt is present.

        """

        if req.path in self.exempt_routes:
            return

        token = req.headers.get('AUTHORIZATION', '').partition('Bearer ')[2]

        try:
            claims = jwt.decode(token,
                                key=self.secret,
                                audience=self.audience,
                                leeway=self.leeway)
            params['jwt_claims'] = {}
            for claim in claims:
                params['jwt_claims'][claim] = claims[claim]
        except jwt.InvalidTokenError as err:
            raise HTTPUnauthorized('Authentication Required',
                                   'Please provide a valid auth token.', None)
Exemple #25
0
def authentication_required(req, resp, resource, uri_kwargs):
    """Ensure that user is authenticated otherwise return ``401 Unauthorized``.

    If request fails to authenticate this authorization hook will also
    include list of ``WWW-Athenticate`` challenges.

    Args:
        req (falcon.Request): the request object.
        resp (falcon.Response): the response object.
        resource (object): the resource object.
        uri_kwargs (dict): keyword arguments from the URI template.

    .. versionadded:: 0.4.0
    """
    if 'user' not in req.context:
        args = ["Unauthorized", "This resource requires authentication"]

        # compat: falcon >= 1.0.0 requires the list of challenges
        if FALCON_VERSION >= (1, 0, 0):
            args.append(req.context.get('challenges', []))

        raise HTTPUnauthorized(*args)
Exemple #26
0
def on_post(req, resp):
    login_info = uri.parse_query_string(req.context['body'])

    user = login_info.get('username')
    password = login_info.get('password')
    if user is None or password is None:
        raise HTTPBadRequest('Invalid login attempt', 'Missing user/password')

    if not auth_manager.authenticate(user, password):
        raise HTTPUnauthorized('Authentication failure',
                               'bad login credentials', '')

    connection = db.connect()
    cursor = connection.cursor(db.DictCursor)
    data = get_user_data(None, {'name': user}, dbinfo=(connection, cursor))
    if not data:
        cursor.close()
        connection.close()
        raise HTTPNotFound()

    session = req.env['beaker.session']
    session['user'] = user
    session.save()
    csrf_token = '%x' % SystemRandom().getrandbits(128)
    try:
        cursor.execute(
            'INSERT INTO `session` (`id`, `csrf_token`) VALUES (%s, %s)',
            (req.env['beaker.session']['_id'], csrf_token))
    except db.IntegrityError:
        raise HTTPBadRequest('Invalid login attempt', 'User already logged in')
    connection.commit()
    cursor.close()
    connection.close()

    # TODO: purge out of date csrf token
    data[0]['csrf_token'] = csrf_token
    resp.body = dumps(data[0])
    def on_patch_potential(self, req: Request, resp: Response, id: int):
        token = req.get_param('token', required=True)
        vote = req.get_param_as_int('vote',
                                    required=True,
                                    min_value=-1,
                                    max_value=1)
        user_data = get_user_data(token)
        if not user_data:
            raise HTTPUnauthorized('Invalid user token provided',
                                   'Invalid user token provided')
        with self.uowm.start() as uow:
            template = uow.meme_template_potential.get_by_id(id)
            if not template:
                raise HTTPNotFound(
                    title=f'Unable to find template with ID {id}',
                    description=f'Unable to find template with ID {id}')

            existing_vote = next(
                (x for x in template.votes if x.user == user_data['name']),
                None)
            if existing_vote and existing_vote.vote == vote:
                raise HTTPBadRequest(
                    title='Invalid vote',
                    description='You have already cast a vote for this template'
                )
            elif existing_vote:
                template.vote_total += vote
                existing_vote.vote = vote
            else:
                template.vote_total += vote
                template.votes.append(
                    MemeTemplatePotentialVote(
                        post_id=template.post_id,
                        user=user_data['name'],
                        vote=vote,
                        meme_template_potential_id=template.id))
            uow.commit()
Exemple #28
0
    def create_question_mutate(cls, info, model=None, **kwargs):
        if info.context['auth']['data']:
            model = model._meta.model
            data = kwargs.get('data', None)
            if data:
                tags = data.get('tags', None)
                if tags:
                    del data['tags']
                data['user_id'] = info.context['auth']['data']['user_id']
                db_session = info.context.get('session', None)
                if db_session:
                    instance = model(**data)
                    if tags:
                        tags = tags.split(" ")
                        exist_tags = {tag.name:tag for tag in gql_models['tag'].get_query(info).filter(gql_models['tag']._meta.model.name.in_(tags)).all()}
                        new_tags = [gql_models['tag']._meta.model(name=tag) for tag in tags if not tag in exist_tags.keys()]
                        db_session.add_all(new_tags)
                        instance.tags = list(exist_tags.values())+new_tags
                    db_session.add(instance)
                    db_session_flush(db_session)

                return cls(**{model.__tablename__:instance})
        else:
            raise CodeduExceptionHandler(HTTPUnauthorized(description=info.context['auth']['description']))
Exemple #29
0
    def update_post_like_mutate(cls, info, model=None, **kwargs):
        if info.context['auth']['data']:
            query = model.get_query(info)
            model = model._meta.model
            data = kwargs.get('data', None)
            image_info = info.context.get('image_info', None)
            if data:
                data['user_id'] = info.context['auth']['data']['user_id']
                db_session = info.context.get('session', None)
                if db_session:
                    instance = get_instance_by_pk(query, model, data)
                    if not instance.first():
                        tmp_instance = model(**data)
                        db_session.add(tmp_instance)
                        db_session_flush(db_session)
                    else:
                        tmp_instance = instance.one()
                        instance.delete()

                return cls(**{model.__tablename__: tmp_instance})
        else:
            raise CodeduExceptionHandler(
                HTTPUnauthorized(
                    description=info.context['auth']['description']))
Exemple #30
0
    def create(self, params, meta, **kwargs):
        validated = kwargs.get('validated')
        refresh_token = validated.get('refresh_token')
        new_refresh_token = generate_user_token()
        new_access_token = generate_user_token(lenght=128)

        # redis keys for tokens
        refresh_token_key = cache.hmget(CACHE_TOKENS_KEYS, refresh_token)[0]

        user_info_byte = cache.hgetall(refresh_token_key)
        if not user_info_byte:
            raise HTTPUnauthorized(title="Unauthorized",
                                   description="Invalid token")
        user_info = {}
        for k, v in user_info_byte.items():
            user_info[k.decode()] = v.decode()

        new_refresh_token_key = CACHE_REFRESH_TOKEN.format(
            project_id=user_info.get('project'),
            service=user_info.get('service'),
            token=new_refresh_token,
        )
        new_access_token_key = CACHE_ACCESS_TOKEN.format(
            project_id=user_info.get('project'),
            service=user_info.get('service'),
            token=new_access_token,
        )

        cache_service_tokens_key = CACHE_SERVICE_TOKEN_LIST.format(
            project_id=user_info.get('project'),
            service=user_info.get('service'))

        # old access token
        access_token = user_info.pop('access_token', None)
        access_token_key = cache.hmget(CACHE_TOKENS_KEYS, access_token)[0]

        # delete old access token from redis
        cache.delete(access_token_key)
        cache.hdel(CACHE_TOKENS_KEYS, access_token)

        # add the access and refresh token in service_tokens
        cache.sadd(cache_service_tokens_key, new_access_token)
        cache.sadd(cache_service_tokens_key, new_refresh_token)

        # set the new access token
        cache.hmset(new_access_token_key, user_info)
        cache.hset(CACHE_TOKENS_KEYS, new_access_token, new_access_token_key)

        # update user_info with access token which corresponds to new refresh token
        user_info['access_token'] = new_access_token

        # set the new refresh token with updated user_info
        cache.hmset(new_refresh_token_key, user_info)
        cache.hset(CACHE_TOKENS_KEYS, new_refresh_token, new_refresh_token_key)

        # remove the old refresh token from redis
        cache.delete(refresh_token_key)
        cache.hdel(CACHE_TOKENS_KEYS, refresh_token)

        # set expire time for the access token
        cache.expire(new_access_token_key, CACHE_ACCESS_TOKEN_EXPIRES_IN)
        return {
            "refresh_token": new_refresh_token,
            "access_token": new_access_token,
            "expires_in": CACHE_ACCESS_TOKEN_EXPIRES_IN
        }