Exemple #1
0
class UserDetailResource(Resource):
    """Details of the currently logged in user."""

    def __init__(self):
        self.response_handler = ResponseBody()
        self.user_schema = UserSchema()

    @require_oauth()
    def get(self):
        try:
            token = request.headers.get('authorization').split(' ')[1]
        except Exception:
            token = None

        if token:
            try:
                token_details = OAuth2Token.query.filter_by(
                    access_token=token).first()
                if token_details:
                    user_id = token_details.user_id
                    if not user_id:
                        if 'id' in session:
                            user_id = session['id']
                    user = User.query.filter_by(id=user_id).first()
                    user_obj = self.user_schema.dump(user)
                    user_obj.pop('role_id', None)
                    if not user_obj['can_login']:
                        user_obj['can_login'] = False
                    return self.response_handler.get_one_response(user_obj)
            except Exception:
                return self.response_handler.custom_response(messages=[{'error': 'Cannot get an ID for current user.'}])
Exemple #2
0
class ValidateOAuth2TokenResource(Resource):
    """
    This resource determines the validity of an OAuth2Token.
    """
    def __init__(self):
        self.response_handler = ResponseBody()

    def post(self):
        req_json = request.get_json(force=True)
        access_token = req_json["token"]
        access_token_in_db = OAuth2Token.query.filter_by(
            access_token=access_token).first()

        try:
            is_expired = access_token_in_db.is_access_token_expired()
        except AttributeError:
            # Token is not valid, if it does not exist.
            is_valid = False
        else:
            # Token is not valid, if the token is expired (and vice versa).
            is_valid = not is_expired

        return self.response_handler.custom_response(
            status="OK", code=200, messages={"valid": is_valid})
Exemple #3
0
 def handle_errors(e):
     logging.info(f"""{e}, app.py, line 83""")
     response_body = ResponseBody()
     if isinstance(e, ValidationError):
         return response_body.custom_response(status="Error",
                                              messages=[e.messages])
     elif isinstance(e, RecordNotFoundError):
         return response_body.not_found_response(e.record_id)
     else:
         try:
             error_code = str(e).split(':')[0][:3].strip()
             error_text = str(e).split(':')[0][3:].strip()
             if isinstance(error_code, int):
                 return response_body.custom_response(
                     code=error_code, messages={'error': error_text})
             else:
                 raise Exception
         except Exception as e:
             return response_body.exception_response(str(e))
Exemple #4
0
 def __init__(self):
     self.client_schema = OAuth2ClientSchema()
     self.clients_schema = OAuth2ClientSchema(many=True)
     self.response_handler = ResponseBody()
Exemple #5
0
class ClientResource(Resource):
    """Client Resource

    This resource represents an OAuth 2.0 client that is associated with a user.

    """
    def __init__(self):
        self.client_schema = OAuth2ClientSchema()
        self.clients_schema = OAuth2ClientSchema(many=True)
        self.response_handler = ResponseBody()

    @require_oauth()
    def get(self, id: str = None):
        if not id:
            clients = OAuth2Client.query.all()
            clients_obj = self.clients_schema.dump(clients)
            return self.response_handler.get_all_response(clients_obj)
        else:
            client = OAuth2Client.query.filter_by(id=id).first()
            if client:
                client_obj = self.client_schema.dump(client)
                return self.response_handler.get_one_response(
                    client_obj, request={'id': id})
            else:
                return self.response_handler.not_found_response(id)

    @require_oauth()
    def post(self, id: str = None):
        '''
        The POST method mainly enables the following:
        (1) creation of a new Client.
        (2) deletion or rotatation of the secret of an existing client – accomplished by POSTing with 
        query params (?action=delete_secret, or ?action=rotate_secret).
        '''

        # Check for data, since all POST requests need it.
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        if not request_data:
            return self.response_handler.empty_request_body_response()

        # Check for query params
        action = request.args.get("action")
        if action:
            try:
                client_id = request_data['id']
            except KeyError as e:
                return self.response_handler.custom_response(
                    code=422, messages='Please provide the ID of the client.')

            if action == 'delete_secret':
                return self._delete_secret(client_id)
            elif action == 'rotate_secret':
                return self._rotate_secret(client_id)
            else:
                return self.response_handler.custom_response(
                    code=422,
                    messages=
                    "Invalid query param! 'action' must be either 'delete_secret' or 'rotate_secret'."
                )

        # Assume that the request intends to create a new user: an ID should not be in the request data.
        if id is not None:
            return self.response_handler.method_not_allowed_response()

        errors = self.client_schema.validate(request_data)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)

        try:
            client = OAuth2Client()
            client.id = str(uuid4()).replace('-', '')
            client.user_id = request_data['user_id']
            client.client_id = gen_salt(24)
            client.client_secret = gen_salt(48)
            client_metadata = {'scope': ''}
            for k, v in request_data.items():
                if hasattr(client, k):
                    if k == 'roles':
                        try:
                            for role_id in request_data[k]:
                                role = Role.query.filter_by(id=role_id).first()
                                if role:
                                    client.roles.append(role)
                                else:
                                    return self.response_handler.custom_response(
                                        code=400,
                                        messages={
                                            'roles': [
                                                'Error assigning role to client.'
                                            ]
                                        })
                        except Exception as e:
                            return self.response_handler.custom_response(
                                code=400,
                                messages={
                                    'roles':
                                    ['Error assigning role to client.']
                                })
                    else:
                        try:
                            setattr(client, k, v)
                        except Exception as e:
                            client_metadata[k] = v
            client.set_client_metadata(client_metadata)
            client.client_id_issued_at = int(time.time())

            db.session.add(client)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)
        return self.response_handler.successful_creation_response(
            'Client', client.id, request_data)

    @require_oauth()
    def put(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()

        return self.update(id, False)

    @require_oauth()
    def patch(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        return self.update(id)

    @require_oauth()
    def delete(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        try:
            client = OAuth2Client.query.filter_by(id=id).first()
            if client:
                client_obj = self.client_schema.dump(client)
                db.session.delete(client)
                db.session.commit()
                return self.response_handler.successful_delete_response(
                    'Client', id, client_obj)
            else:
                return self.response_handler.not_found_response(id)
        except Exception:
            return self.response_handler.not_found_response(id)

    def update(self, id: str, partial=True):
        """General update function for PUT and PATCH.

        Using Marshmallow, the logic for PUT and PATCH differ by a single parameter. This method abstracts that logic
        and allows for switching the Marshmallow validation to partial for PATCH and complete for PUT.
        """
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        client = OAuth2Client.query.filter_by(id=id).first()
        if not client:
            return self.response_handler.not_found_response(id)
        if not request_data:
            return self.response_handler.empty_request_body_response()
        errors = self.client_schema.validate(request_data, partial=partial)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)

        for k, v in request_data.items():
            if hasattr(client, k):
                if k == 'roles':
                    try:
                        if len(request_data[k]
                               ) == 0:  # allow removal of all roles
                            client.roles = []
                        else:
                            current_roles = client.roles.copy()
                            new_roles = []
                            for role_id in request_data[k]:
                                role = Role.query.filter_by(id=role_id).first()
                                if role:
                                    new_roles.append(role)
                                    if role not in client.roles:  # only append roles that aren't already there
                                        client.roles.append(role)
                                else:
                                    return self.response_handler.custom_response(
                                        code=400,
                                        messages={
                                            'roles': [
                                                'Error assigning role to client.'
                                            ]
                                        })
                            for role in current_roles:
                                if role not in new_roles:
                                    client.roles.remove(role)
                    except Exception as e:
                        return self.response_handler.custom_response(
                            code=400,
                            messages={
                                'roles': ['Error assigning role to client.']
                            })
                elif k == 'client_secret':
                    return self.response_handler.custom_response(
                        code=422,
                        messages={
                            'client_secret':
                            ['The client_secret cannot be updated.']
                        })
                else:
                    setattr(client, k, v)
        try:
            db.session.commit()
            return self.response_handler.successful_update_response(
                'Client', id, request_data)
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)

    def _update_secret(self, client_id: str, new_secret):
        """Helper function for updating the client_secret.

        This function serves the delete and rotate actions, available in the POST method.

        """
        client = OAuth2Client.query.filter_by(id=client_id).first()
        if not client:
            return self.response_handler.not_found_response(client_id)

        client.client_secret = new_secret

        try:
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name)
        return self.response_handler.custom_response(
            code=200, status='OK', messages={'client_secret': new_secret})

    def _delete_secret(self, client_id):
        new_secret = None
        return self._update_secret(client_id, new_secret)

    def _rotate_secret(self, client_id):
        new_secret = gen_salt(48)
        return self._update_secret(client_id, new_secret)
 def __init__(self):
     self.data_trust_schema = DataTrustSchema()
     self.data_trusts_schema = DataTrustSchema(many=True)
     self.response_handler = ResponseBody()
class DataTrustResource(Resource):
    """A Data Trust Resource."""
    def __init__(self):
        self.data_trust_schema = DataTrustSchema()
        self.data_trusts_schema = DataTrustSchema(many=True)
        self.response_handler = ResponseBody()

    @require_oauth()
    def get(self, id: str = None):
        if not id:
            data_trusts = DataTrust.query.all()
            data_trusts_obj = self.data_trusts_schema.dump(data_trusts).data
            return self.response_handler.get_all_response(data_trusts_obj)
        else:
            data_trust = DataTrust.query.filter_by(id=id).first()
            if data_trust:
                data_trusts_obj = self.data_trust_schema.dump(data_trust).data
                return self.response_handler.get_one_response(
                    data_trusts_obj, request={'id': id})
            else:
                return self.response_handler.not_found_response(id)

    @require_oauth()
    def post(self, id=None):
        if id is not None:
            return self.response_handler.method_not_allowed_response()
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        if not request_data:
            return self.response_handler.empty_request_body_response()
        data, errors = self.data_trust_schema.load(request_data)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)
        try:
            data_trust = DataTrust(request_data['data_trust_name'])
            db.session.add(data_trust)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)
        return self.response_handler.successful_creation_response(
            'Data Trust', data_trust.id, request_data)

    @require_oauth()
    def put(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()

        return self.update(id, False)

    @require_oauth()
    def patch(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        return self.update(id)

    @require_oauth()
    def delete(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        try:
            data_trust = DataTrust.query.filter_by(id=id).first()
            if data_trust:
                data_trust_obj = self.data_trust_schema.dump(data_trust).data
                db.session.delete(data_trust)
                db.session.commit()
                return self.response_handler.successful_delete_response(
                    'Data Trust', id, data_trust_obj)
            else:
                return self.response_handler.not_found_response(id)
        except Exception:
            return self.response_handler.not_found_response(id)

    def update(self, id: str, partial=True):
        """General update function for PUT and PATCH.

        Using Marshmallow, the logic for PUT and PATCH differ by a single parameter. This method abstracts that logic
        and allows for switching the Marshmallow validation to partial for PATCH and complete for PUT.

        """
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        data_trust = DataTrust.query.filter_by(id=id).first()
        if not data_trust:
            return self.response_handler.not_found_response(id)
        if not request_data:
            return self.response_handler.empty_request_body_response()
        data, errors = self.data_trust_schema.load(request_data,
                                                   partial=partial)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)

        for k, v in request_data.items():
            if hasattr(data_trust, k):
                setattr(data_trust, k, v)
        try:
            data_trust.date_last_updated = datetime.utcnow()
            db.session.commit()
            return self.response_handler.successful_update_response(
                'Data Trust', id, request_data)
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)
Exemple #8
0
 def __init__(self):
     self.role_schema = RoleSchema()
     self.roles_schema = RoleSchema(many=True)
     self.response_handler = ResponseBody()
Exemple #9
0
class RoleResource(Resource):
    """Role Resource

    This resource represents a role associated with a client.

    """
    def __init__(self):
        self.role_schema = RoleSchema()
        self.roles_schema = RoleSchema(many=True)
        self.response_handler = ResponseBody()

    @require_oauth()
    def get(self, id: str = None):
        if not id:
            roles = Role.query.all()
            roles_obj = self.roles_schema.dump(roles).data
            return self.response_handler.get_all_response(roles_obj)
        else:
            role = Role.query.filter_by(id=id).first()
            if role:
                role_obj = self.role_schema.dump(role).data
                return self.response_handler.get_one_response(
                    role_obj, request={'id': id})
            else:
                return self.response_handler.not_found_response(id)

    @require_oauth()
    def post(self, id: str = None):
        if id is not None:
            return self.response_handler.method_not_allowed_response()
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        if not request_data:
            return self.response_handler.empty_request_body_response()
        data, errors = self.role_schema.load(request_data)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)

        try:
            role = Role(role=request_data['role'],
                        description=request_data['description'])
            if 'rules' in request_data.keys():
                role.rules = request_data['rules']
            db.session.add(role)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)
        return self.response_handler.successful_creation_response(
            'Role', role.id, request_data)

    @require_oauth()
    def put(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()

        return self.update(id, False)

    @require_oauth()
    def patch(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        return self.update(id)

    @require_oauth()
    def delete(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        try:
            role = Role.query.filter_by(id=id).first()
            if role:
                role_obj = self.role_schema.dump(role).data
                db.session.delete(role)
                db.session.commit()
                return self.response_handler.successful_delete_response(
                    'Role', id, role_obj)
            else:
                return self.response_handler.not_found_response(id)
        except Exception:
            return self.response_handler.not_found_response(id)

    def update(self, id: str, partial=True):
        """General update function for PUT and PATCH.

        Using Marshmallow, the logic for PUT and PATCH differ by a single parameter. This method abstracts that logic
        and allows for switching the Marshmallow validation to partial for PATCH and complete for PUT.

        """
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        role = Role.query.filter_by(id=id).first()
        if not role:
            return self.response_handler.not_found_response(id)
        if not request_data:
            return self.response_handler.empty_request_body_response()
        data, errors = self.role_schema.load(request_data, partial=partial)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)

        for k, v in request_data.items():
            if hasattr(role, k):
                setattr(role, k, v)
        try:
            db.session.commit()
            return self.response_handler.successful_update_response(
                'Role', id, request_data)
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)
Exemple #10
0
class UserResource(Resource):
    """A User Resource.

    This resource defines an Auth Service user who may have zero or more OAuth 2.0 clients
    associated with their accounts.

    """

    def __init__(self):
        self.data_trust_schema = DataTrustSchema()
        self.data_trusts_schema = DataTrustSchema(many=True)
        self.user_schema = UserSchema()
        self.users_schema = UserSchema(many=True)
        self.response_handler = ResponseBody()

    @require_oauth()
    def get(self, id: str = None):
        if not id:
            users = User.query.all()
            users_obj = self.users_schema.dump(users).data
            return self.response_handler.get_all_response(users_obj)
        else:
            user = User.query.filter_by(id=id).first()
            if user:
                user_obj = self.user_schema.dump(user).data
                return self.response_handler.get_one_response(user_obj, request={'id': id})
            else:
                return self.response_handler.not_found_response(id)

    @require_oauth()
    @use_args(POST_ARGS)
    def post(self, action, id: str = None):
        # Check for data, since all POST requests need it.
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        if not request_data:
            return self.response_handler.empty_request_body_response()

        if id is not None:
            return self.response_handler.method_not_allowed_response()

        # Check for query params/webargs (i.e., action).
        if action:
            try:
                user_id = request_data['id']
            except KeyError as e:
                return self.response_handler.custom_response(code=422, messages='Please provide the ID of the user.')
            else:
                return self._deactivate(user_id)

        data, errors = self.user_schema.load(request_data)
        if errors:
            return self.response_handler.custom_response(code=422, messages=errors)
        try:
            user = User(request_data['username'], request_data['password'], firstname=request_data['firstname'], lastname=request_data['lastname'],
                        organization=request_data['organization'], email_address=request_data['email_address'],
                        data_trust_id=request_data['data_trust_id'])
            if 'telephone' in request_data.keys():
                user.telephone = request_data['telephone']
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name, request=request_data)
        return self.response_handler.successful_creation_response('User', user.id, request_data)

    @require_oauth()
    def put(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()

        return self._update(id, False)

    @require_oauth()
    def patch(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        return self._update(id)

    @require_oauth()
    def delete(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        try:
            user = User.query.filter_by(id=id).first()
            if user:
                user_obj = self.user_schema.dump(user).data
                db.session.delete(user)
                db.session.commit()
                return self.response_handler.successful_delete_response('User', id, user_obj)
            else:
                return self.response_handler.not_found_response(id)
        except Exception:
            return self.response_handler.not_found_response(id)

    def _update(self, id: str, partial=True):
        """General update function for PUT and PATCH.

        Using Marshmallow, the logic for PUT and PATCH differ by a single parameter. This method abstracts that logic
        and allows for switching the Marshmallow validation to partial for PATCH and complete for PUT.

        """
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        user = User.query.filter_by(id=id).first()
        if not user:
            return self.response_handler.not_found_response(id)
        if not request_data:
            return self.response_handler.empty_request_body_response()
        data, errors = self.user_schema.load(request_data, partial=partial)
        if errors:
            return self.response_handler.custom_response(code=422, messages=errors)

        for k, v in request_data.items():
            if hasattr(user, k) and k != 'password_hash':
                setattr(user, k, v)
            if k == 'password':
                user.password = v
        try:
            user.date_last_updated = datetime.utcnow()
            db.session.commit()
            return self.response_handler.successful_update_response('User', id, request_data)
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name, request=request_data)

    def _deactivate(self, user_id: str):
        user = User.query.filter_by(id=user_id).first()
        if not user:
            return self.response_handler.not_found_response(user_id)

        user.active = False
        self._db_commit()

        clients = OAuth2Client.query.filter_by(user_id=user_id).all()
        for client in clients:
            client.client_secret = None
            self._db_commit()

        return self.response_handler.successful_update_response('User', user_id)

    def _db_commit(self):
        try:
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name)
Exemple #11
0
 def __init__(self):
     self.scope_schema = ScopeSchema()
     self.scopes_schema = ScopeSchema(many=True)
     self.response_handler = ResponseBody()
Exemple #12
0
 def __init__(self):
     self.response_handler = ResponseBody()
Exemple #13
0
 def __init__(self):
     self.user_schema = UserSchema()
     self.users_schema = UserSchema(many=True)
     self.response_handler = ResponseBody()
Exemple #14
0
class UserResource(Resource):
    """A User Resource.

    This resource defines an Auth Service user who may have zero or more OAuth 2.0 clients
    associated with their accounts.

    """

    def __init__(self):
        self.user_schema = UserSchema()
        self.users_schema = UserSchema(many=True)
        self.response_handler = ResponseBody()

    @require_oauth()
    def get(self, id: str = None):
        if not id:
            users = User.query.all()
            users_obj = self.users_schema.dump(users)
            users_obj_clean = [{k: v for k, v in user.items() if k != 'role_id'}
                               for user in users_obj]
            return self.response_handler.get_all_response(users_obj_clean)
        else:
            user = User.query.filter_by(id=id).first()
            if user:
                user_obj = self.user_schema.dump(user)
                user_obj.pop('role_id')
                return self.response_handler.get_one_response(user_obj, request={'id': id})
            else:
                return self.response_handler.not_found_response(id)

    @require_oauth()
    def post(self, id: str = None):
        # Check for data, since all POST requests need it.
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        if not request_data:
            return self.response_handler.empty_request_body_response()

        if id is not None:
            return self.response_handler.method_not_allowed_response()

        # Check for query params
        action = request.args.get("action")
        if action:
            try:
                user_id = request_data['id']
            except KeyError as e:
                return self.response_handler.custom_response(code=422, messages='Please provide the ID of the user.')
            else:
                if action == "deactivate":
                    return self._deactivate(user_id)
                elif action == "activate":
                    return self._activate(user_id)
                else:
                    return self.response_handler.custom_response(code=422, messages="Invalid query param! 'action' can only be 'deactivate'.")

        errors = self.user_schema.validate(request_data)
        if errors:
            return self.response_handler.custom_response(code=422, messages=errors)
        try:
            user = User(
                request_data['username'], request_data['password'],
                role_id=request_data['role_id'] if 'role_id' in request_data.keys(
                ) else None,
                person_id=request_data['person_id'] if 'person_id' in request_data.keys(
                ) else None,
                can_login=request_data['can_login'] if 'can_login' in request_data.keys(
                ) else False,
                active=request_data['active'] if 'active' in request_data.keys() else False)
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name, request=request_data)
        return self.response_handler.successful_creation_response('User', user.id, request_data)

    @require_oauth()
    def put(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()

        return self._update(id, False)

    @require_oauth()
    def patch(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        return self._update(id)

    @require_oauth()
    def delete(self, id: str = None):
        if id is None:
            return self.response_handler.method_not_allowed_response()
        user = User.query.filter_by(id=id).first()
        if user:
            user_obj = self.user_schema.dump(user)
            db.session.delete(user)
            db.session.commit()
            return self.response_handler.successful_delete_response('User', id, user_obj)
        else:
            return self.response_handler.not_found_response(id)

    def _update(self, id: str, partial=True):
        """General update function for PUT and PATCH.

        Using Marshmallow, the logic for PUT and PATCH differ by a single parameter. This method abstracts that logic
        and allows for switching the Marshmallow validation to partial for PATCH and complete for PUT.

        """
        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        user = User.query.filter_by(id=id).first()
        if not user:
            return self.response_handler.not_found_response(id)
        if not request_data:
            return self.response_handler.empty_request_body_response()
        errors = self.user_schema.validate(request_data, partial=partial)
        if errors:
            return self.response_handler.custom_response(code=422, messages=errors)

        for k, v in request_data.items():
            if hasattr(user, k) and k != 'password_hash':
                setattr(user, k, v)
            if k == 'password':
                user.password = v
        try:
            user.date_last_updated = datetime.utcnow()
            db.session.commit()
            return self.response_handler.successful_update_response('User', id, request_data)
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name, request=request_data)

    def _deactivate(self, user_id: str):
        user = User.query.filter_by(id=user_id).first()
        if not user:
            return self.response_handler.not_found_response(user_id)

        user.active = False
        user.can_login = False
        user.date_last_updated = datetime.utcnow()

        tokens = OAuth2Token.query.filter_by(user_id=user.id).all()
        for token in tokens:
            token.revoked = True
            token.expires_in = 0

        clients = OAuth2Client.query.filter_by(user_id=user_id).all()
        for client in clients:
            client.client_secret = None

        self._db_commit()

        return self.response_handler.successful_update_response('User', user_id)

    def _activate(self, user_id: str):
        user = User.query.filter_by(id=user_id).first()
        if not user:
            raise RecordNotFoundError(record_id=user_id)

        user.active = True
        user.can_login = True
        user.date_last_updated = datetime.utcnow()

        clients = OAuth2Client.query.filter_by(user_id=user_id).all()
        for client in clients:
            client.client_secret = gen_salt(48)

        self._db_commit()

        return self.response_handler.successful_update_response('User', user_id)

    def _db_commit(self):
        try:
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(exception_name)
Exemple #15
0
    def __init__(self):
        self.authorized_scope_schema = AuthorizedScopeSchema()
        self.authorized_scopes_schema = AuthorizedScopeSchema(many=True)

        self.response_handler = ResponseBody()
Exemple #16
0
class AuthorizedScopeResource(Resource):
    """Authorized scope resource for linking roles to scopes.

    This resource enables the notion of an OAuth2 scope to be shared between user roles and
    OAuth2 clients. This way, the capabilities of specific clients can be restricted to the
    scopes associated with a user's role.

    """
    def __init__(self):
        self.authorized_scope_schema = AuthorizedScopeSchema()
        self.authorized_scopes_schema = AuthorizedScopeSchema(many=True)

        self.response_handler = ResponseBody()

    @require_oauth()
    def get(self, id: str = None, sid: str = None):
        if sid is None:
            try:
                authorized_scopes = AuthorizedScope.query.all()
                scopes_obj = self.authorized_scopes_schema.dump(
                    authorized_scopes)
                scopes_obj_clean = [{
                    k: v
                    for k, v in authorized_scope.items()
                    if k != 'scope_id' and k != 'role_id' and k != 'role'
                } for authorized_scope in scopes_obj]
                return self.response_handler.get_all_response(scopes_obj_clean)
            except Exception:
                return self.response_handler.exception_response('Unknown')
        else:
            try:
                authorized_scope = AuthorizedScope.query.filter(
                    AuthorizedScope.role_id == id,
                    AuthorizedScope.scope_id == sid).first()
                scope_obj = self.authorized_scope_schema.dump(authorized_scope)
                if scope_obj:
                    scope_obj.pop('role_id', None)
                    scope_obj.pop('scope_id', None)
                    return self.response_handler.get_one_response(scope_obj)
                else:
                    return self.response_handler.not_found_response(id=sid)
            except Exception:
                return self.response_handler.exception_response('Unkown')

    @require_oauth()
    def post(self, id: str = None, sid: str = None):
        if sid is not None:
            return self.response_handler.method_not_allowed_response()

        try:
            request_data = request.get_json(force=True)
        except Exception as e:
            return self.response_handler.empty_request_body_response()
        if not request_data:
            return self.response_handler.empty_request_body_response()
        errors = self.authorized_scope_schema.validate(request_data)
        if errors:
            return self.response_handler.custom_response(code=422,
                                                         messages=errors)

        try:
            authorized_scope = AuthorizedScope(
                role_id=id, scope_id=request_data['scope_id'])
            db.session.add(authorized_scope)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            exception_name = type(e).__name__
            return self.response_handler.exception_response(
                exception_name, request=request_data)
        return self.response_handler.successful_creation_response(
            'AuthorizedScope', authorized_scope.role_id, request_data)

    @require_oauth()
    def put(self, id: str = None, sid: str = None):
        return self.response_handler.method_not_allowed_response()

    @require_oauth()
    def patch(self, id: str = None, sid: str = None):
        return self.response_handler.method_not_allowed_response()

    @require_oauth()
    def delete(self, id: str, sid: str = None):
        if sid is None:
            return self.response_handler.method_not_allowed_response()
        try:
            authorized_scope = AuthorizedScope.query.filter(
                AuthorizedScope.role_id == id,
                AuthorizedScope.scope_id == sid).first()
            if authorized_scope:
                authorized_scope_obj = self.authorized_scope_schema.dump(
                    authorized_scope)
                db.session.delete(authorized_scope)
                db.session.commit()
                return self.response_handler.successful_delete_response(
                    'Role', id, authorized_scope_obj)
            else:
                return self.response_handler.not_found_response(sid)
        except Exception:
            return self.response_handler.not_found_response(sid)