示例#1
0
    def verify(self, tenant: AnyStr, password: AnyStr) -> bool:
        """
        Verify a user using LDAP schema.

        :tenant (AnyStr) the user username
        :password (AnyStr) the user password

        Return a boolean describing the success of the user authentication.
        """
        result = None
        try:
            if tenant == envvar('ADMIN_ACCOUNT'):
                if password == envvar('GRAFANA_ADMIN_PASSWORD'):
                    result = True
                else:
                    result = False
            else:
                result = self.client.compare_s(
                    'cn={},{}'.format(tenant, self.l_schema), 'userPassword',
                    password)
                if result and envvar('GRAFANA') == 'true':
                    user_grafana = grafana.get_grafana_user(tenant)
                    if not user_grafana:
                        grafana.create_grafana_user(tenant, password)
                    if self.verify_group_admin():
                        grafana.update_grafana_role(user_grafana, 'Editor')
        except ldap.NO_SUCH_OBJECT:
            logging.error(f'User does not exist {tenant}')
        finally:
            return result
示例#2
0
def update_frontend_rating_config() -> Response:
    """Edit a configuration, from the frontend."""
    received = load_from_form(request.form)
    try:
        schema.validate_request_content(received)
    except schema.ValidationError as exc:
        abort(make_response(jsonify(message=exc.message), 400))

    try:
        api = client.CustomObjectsApi(get_client())
        cr = api.get_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrules',
                'namespace': envvar('RATING_NAMESPACE'),
                'name': received['name']
            })

        cr['spec'] = {
            'metrics': received.get('metrics', cr['spec']['metrics']),
            'rules': received.get('rules', cr['spec']['rules'])
        }
        api.patch_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrules',
                'namespace': envvar('RATING_NAMESPACE'),
                'name': received['name'],
                'body': cr
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return make_response(f'RatingRule {received["name"]} edited', 200)
示例#3
0
def new_frontend_rating_config() -> Response:
    """Add a new configuration, from the frontend."""
    received = load_from_form(request.form)
    try:
        schema.validate_request_content(received)
    except schema.ValidationError as exc:
        abort(make_response(jsonify(message=exc.message), 400))
    body = {
        'apiVersion': 'rating.alterway.fr/v1',
        'kind': 'RatingRule',
        'metadata': {
            'name': received['name'],
            'namespace': envvar('RATING_NAMESPACE')
        },
        'spec': {
            'metrics': received['metrics'],
            'rules': received['rules']
        }
    }

    try:
        api = client.CustomObjectsApi(get_client())
        api.create_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'namespace': envvar('RATING_NAMESPACE'),
                'plural': 'ratingrules',
                'body': body
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return make_response(f'RatingRule {received["body"]["name"]} created', 200)
示例#4
0
def models_rule_edit() -> Response:
    """Edit a RatingRuleModels."""
    config = request.form or request.get_json()
    api = client.CustomObjectsApi(get_client())
    try:
        cr = api.get_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrulemodels',
                'namespace': envvar('RATING_NAMESPACE'),
                'name': config['name']
            })

        cr['spec'] = {
            'metric': config.get('metric', cr['spec']['metric']),
            'timeframe': config.get('timeframe', cr['spec']['timeframe']),
            'name': config.get('metric_name', cr['spec']['name'])
        }
        api.patch_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrulemodels',
                'namespace': envvar('RATING_NAMESPACE'),
                'name': config['name'],
                'body': cr
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return make_response(f'RatingRuleModels {config["name"]} edited', 200)
示例#5
0
def change_password(tenant: AnyStr) -> Response:
    """
    Change the password of the user.

    :tenant (AnyStr) A string representing the tenant.

    Return a response object.
    """
    old, new = request.form['old'], request.form['new']
    if tenant == '' or old == new:
        return make_response(
            render_template('password.html',
                            message='New and old password are similar'))
    elif auth.verify(tenant, old):
        if envvar('GRAFANA') == 'true':
            grafana.update_grafana_password(grafana.get_grafana_user(tenant),
                                            password)
        query.update_tenant(tenant, encrypt_password(new))
        return make_response(
            render_template('password.html',
                            message='Your password has been updated'))
    else:
        return make_response(
            render_template('password.html',
                            message='unrecognized user / password'))
示例#6
0
    def verify(self, tenant: AnyStr, password: AnyStr) -> bool:
        """
        Verify if a user token is not empty.

        :tenant (AnyStr) the user username
        :password (AnyStr) the user password

        Return a boolean describing the success of the user verification in keycloak.
        """
        if tenant == envvar('ADMIN_ACCOUNT'):
            if password == envvar('GRAFANA_ADMIN_PASSWORD'):
                return True
            else:
                return False
        else:
            return self.get_token(tenant, password)
示例#7
0
def models_rule_new() -> Response:
    """Create a RatingRuleModels."""
    config = request.form or request.get_json()
    body = {
        'apiVersion': 'rating.alterway.fr/v1',
        'kind': 'RatingRuleModels',
        'metadata': {
            'name': config['name']
        },
        'spec': {
            'timeframe': config['timeframe'],
            'metric': config['metric'],
            'name': config['metric_name']
        }
    }
    api = client.CustomObjectsApi(get_client())
    try:
        api.create_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'namespace': envvar('RATING_NAMESPACE'),
                'plural': 'ratingrulemodels',
                'body': body
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return make_response(f'RatingRuleModels {config["name"]} created', 200)
示例#8
0
def update_postgres_schema():
    """Verify and update the postgreSQL schema."""
    postgres_database_uri = config.envvar('POSTGRES_DATABASE_URI')
    engine = create_engine(postgres_database_uri)
    global db_updated
    if not db_updated:
        db_update(engine)
        db_updated = True
示例#9
0
 def initialize_ldap_connection(self) -> Dict:
     """Initialize the ldap connection."""
     l_con = None
     try:
         l_con = ldap.initialize(envvar('LDAP_URL'))
     except ldap.LDAPError:
         logging.error('Wrong LDAP URL')
     finally:
         return l_con
示例#10
0
def presto_engine():
    """
    Initialize the Presto database engine.

    Returns the created engine
    """
    sqlalchemy.dialects.presto = sqlalchemy_presto
    presto_database_uri = config.envvar('PRESTO_DATABASE_URI')
    return create_engine(presto_database_uri)
示例#11
0
def signup_user() -> Response:
    """Create a user and the associated namespaces."""
    tenant = request.form.get('tenant')
    password = request.form.get('password')
    admin_user = request.form.get('admin')
    namespaces = request.form.get('namespaces')
    if new_user(tenant, password) and envvar('ADMIN_ACCOUNT') != tenant:
        if admin_user == 'on':
            query.insert_group_tenant(tenant, 'admin')
        else:
            query.insert_group_tenant(tenant, 'user')
        add_user(tenant, password)
        update_tenant_namespaces(tenant, namespaces)
        if envvar('GRAFANA') == 'true':
            grafana.create_grafana_user(tenant, password)
            if admin_user == 'on':
                grafana.update_grafana_role(grafana.get_grafana_user(tenant),
                                            'Editor')
        return render_template('signup.html', message='User created')
    return render_template('signup.html', message='User already exists')
示例#12
0
def format_grafana_frontend_request(url: AnyStr) -> AnyStr:
    """
    Format the URL for a frontend request toward Grafana.

    :url (AnyStr) A string representing the destination of the request.

    Return the formatted url.
    """
    protocol = 'https' if os.environ.get('AUTH', 'false') == 'true' else 'http'
    grafana_frontend_url = envvar('FRONTEND_URL')
    return f'{protocol}://{grafana_frontend_url}{url}'
示例#13
0
def check_admin(tenant: AnyStr) -> bool:
    """
    Check if a user is admin.

    tenant: (AnyStr) the username

    Return a boolean to express if a user is admin or no.
    """
    if tenant == envvar('ADMIN_ACCOUNT'):
        return True
    else:
        return auth.verify_group_admin(tenant=tenant)
示例#14
0
    def client(self, **kwargs: Dict) -> KeycloakOpenID:
        """
        Create an authenticated keycloak client.

        :kwargs (Dict) A directory contaning
        the keycloak client authentication credentials

        Return the KeycloakOpenID object.
        """
        config = {}
        if kwargs:
            config.update(kwargs)
        else:
            config.update({
                'server_url': envvar('KEYCLOAK_URL'),
                'client_id': envvar('KEYCLOAK_CLIENT_ID'),
                'realm_name': envvar('KEYCLOAK_REALM'),
                'client_secret_key': envvar('KEYCLOAK_SECRET_KEY')
            })
        self.client = KeycloakOpenID(**config)
        return self.client
示例#15
0
    def verify(self, tenant: AnyStr, password: AnyStr) -> bool:
        """
        Verify a user in local database.

        :tenant (AnyStr) the user username
        :password (AnyStr) the user password

        Return a boolean describing the success of the user authentication.
        """
        if tenant == envvar('ADMIN_ACCOUNT'):
            if password == envvar('GRAFANA_ADMIN_PASSWORD'):
                return True
            else:
                return False
        else:
            results = query.get_tenant_id(tenant)
            if not results or \
               not check_encrypted_password(password, results[0]['password']):
                return False
            else:
                return True
示例#16
0
def login_user():
    """
    Login the user into rating operator.

    Return the user session if the credentials are valid or an error message if not.
    """
    tenant = request.form.get('tenant')
    password = request.form.get('password')
    verified = auth.verify(tenant, password)

    if verified:
        logging.info('User logged')
        session.update({
            'tenant': tenant,
            'timestamp': time.time(),
        })
        cookie_settings = {}
        if tenant != envvar_string('ADMIN_ACCOUNT') and hasattr(
                auth, 'instance'):
            namespaces = auth.get_namespace()
            update_tenant_namespaces(tenant, namespaces)
            if isinstance(auth.instance, Keycloak):
                session.update({'token': verified})
                cookie_settings.update({
                    'httponly':
                    envvar_string('COOKIE_HTTPONLY'),
                    'secure':
                    envvar_string('COOKIE_SECURE'),
                    'samesite':
                    envvar_string('COOKIE_SAMESITE')
                })
                if os.environ.get('AUTH') == 'true':
                    cookie_settings.update(
                        {'domain': os.environ.get('DOMAIN')})
        response = make_response(redirect('/home'))
        # protocol = 'https' if os.environ.get('AUTH', 'false') == 'true' else 'http'
        # params = {
        #     '_scheme': protocol,
        #     '_external': protocol == 'https'
        # }
        # to = url_for('.dashboards', **params)
        # response = make_response(redirect(to))

        if envvar('GRAFANA') == 'true':
            grafana_session = grafana.login_grafana_user(tenant, password)
            if grafana_session:
                response.set_cookie('grafana_session', grafana_session,
                                    **cookie_settings)
        return response
    else:
        message = 'Invalid credentials/Authentication server unreachable'
        return render_template('login.html', message=message)
示例#17
0
    def wrapper(**kwargs: dict) -> Callable:
        """
        Execute the verification of the admin token.

        :kwargs (dict) A dictionary containing all the function parameters

        Return the decorated function
        """
        token = get_token_from_request(request)
        admin_api_key = envvar('RATING_ADMIN_API_KEY')
        if token == admin_api_key:
            return func(**kwargs)
        raise InvalidToken('Internal token unrecognized')
示例#18
0
def format_grafana_admin_request(url: AnyStr) -> AnyStr:
    """
    Format the URL for an administrator request toward Grafana.

    :url (AnyStr) A string representing the destination of the request.

    Return the formatted URL.
    """
    admin_password = envvar('GRAFANA_ADMIN_PASSWORD')
    admin_name = os.environ.get('ADMIN_ACCOUNT', 'admin')
    protocol = 'https' if os.environ.get('AUTH', 'false') == 'true' else 'http'
    grafana_backend_url = get_backend_url()
    return f'{protocol}://{admin_name}:{admin_password}@{grafana_backend_url}{url}'
示例#19
0
    def wrapper(**kwargs: Dict) -> Callable:
        """
        Verify if super-admin and return the tenant session.

        :kwargs (Dict) A dictionary containing all the function parameters

        Return the decorated function.
        """
        tenant = session.get('tenant')
        if tenant == envvar('ADMIN_ACCOUNT'):
            response = func(**kwargs)
        else:
            response = make_response(redirect('/login'))
        return response
示例#20
0
def delete_frontend_rating_config() -> Response:
    """Delete a configuration, from the frontend."""
    try:
        api = client.CustomObjectsApi(get_client())
        api.delete_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'namespace': envvar('RATING_NAMESPACE'),
                'plural': 'ratingrules',
                'name': request.form['name']
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return make_response(f'RatingRule {request.form["name"]} deleted', 200)
示例#21
0
def format_url(path: AnyStr) -> AnyStr:
    """
    Format the url according to environment variables and path.

    :path (AnyStr) A string representing the path to construct.

    Returns the formatted url.
    """
    if os.environ.get('AUTH') == 'true' and 'http' not in path:
        api_url = envvar('RATING_API_URL')
        domain = os.environ.get('DOMAIN', 'svc.cluster.local')
        protocol = 'https' if os.environ.get('AUTH',
                                             'false') == 'true' else 'http'
        return f'{protocol}://{api_url}.{domain}{path}'
    return path
示例#22
0
def register_admin_key():
    """Register the administrator key from the environment."""
    config.load_incluster_config()
    api = client.CoreV1Api(get_client())
    namespace = envvar('RATING_NAMESPACE')
    secret_name = f'{namespace}-admin'
    try:
        secret_encoded_bytes = api.read_namespaced_secret(
            secret_name, namespace).data
    except ApiException as exc:
        raise exc
    rating_admin_api_key = list(secret_encoded_bytes.keys())[0]
    os.environ[rating_admin_api_key] = b64decode(
        secret_encoded_bytes[rating_admin_api_key]).decode('utf-8')
    return os.environ[rating_admin_api_key]
示例#23
0
def models_rule_get() -> Response:
    """Get a RatingRuleModels."""
    api = client.CustomObjectsApi(get_client())
    try:
        response = api.get_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrulemodels',
                'namespace': envvar('RATING_NAMESPACE'),
                'name': request.args.to_dict()['name']
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return {'results': response, 'total': 1}
示例#24
0
def models_rule_delete() -> Response:
    """Delete a RatingRuleModels."""
    config = request.form or request.get_json()
    api = client.CustomObjectsApi(get_client())
    try:
        api.delete_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'namespace': envvar('RATING_NAMESPACE'),
                'plural': 'ratingrulemodels',
                'name': config['name']
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return make_response(f'RatingRuleModels {config["name"]} deleted', 200)
示例#25
0
def logout_user() -> Response:
    """Disconnect a user by closing the session."""
    if 'tenant' not in session:
        abort(400)
    resp = make_response(redirect('/login'))
    if envvar('GRAFANA') == 'true':
        grafana.logout_grafana_user(session['tenant'])
        if os.environ.get('AUTH') == 'true':
            resp.delete_cookie('grafana_session',
                               domain=os.environ.get('DOMAIN'))
        else:
            resp.delete_cookie('grafana_session')
    if session.get('token') is not None:
        auth.client().logout(session['token']['refresh_token'])
    session.clear()
    return resp
示例#26
0
def models_rule_list() -> Response:
    """Get the RatingRuleModel."""
    try:
        api = client.CustomObjectsApi(get_client())
        response = api.list_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrulemodels',
                'namespace': envvar('RATING_NAMESPACE')
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return {
        'results': [item['metadata']['name'] for item in response['items']],
        'total': 1
    }
示例#27
0
def frontend_rating_config(config_name: AnyStr) -> Response:
    """
    Get the RatingRule for a given configuration name.

    :config_name (AnyStr) A string representing the configuration name.

    Return the configuration or abort.
    """
    try:
        api = client.CustomObjectsApi(get_client())
        response = api.get_namespaced_custom_object(
            **{
                'group': 'rating.alterway.fr',
                'version': 'v1',
                'plural': 'ratingrules',
                'namespace': envvar('RATING_NAMESPACE'),
                'name': config_name
            })
    except ApiException as exc:
        abort(make_response(str(exc), 400))
    return {'results': response, 'total': 1}
示例#28
0
def update_rated_metrics_object(metric: AnyStr, last_insert: AnyStr):
    """
    Update a RatedMetrics object.

    :metric (AnyStr) A name representing the metric to be updated
    :last_insert (AnyStr) The timestamp of the latest data frame rating
    """
    config.load_incluster_config()
    rated_metric = f'rated-{metric.replace("_", "-")}'
    rated_namespace = envvar('RATING_NAMESPACE')
    custom_api = client.CustomObjectsApi(get_client())
    body = {
        'apiVersion': 'rating.alterway.fr/v1',
        'kind': 'RatedMetric',
        'metadata': {
            'namespace': rated_namespace,
            'name': rated_metric,
        },
        'spec': {
            'metric': metric,
            'date': last_insert
        }
    }
    try:
        custom_api.create_namespaced_custom_object(group='rating.alterway.fr',
                                                   version='v1',
                                                   namespace=rated_namespace,
                                                   plural='ratedmetrics',
                                                   body=body)
    except ApiException as exc:
        if exc.status != 409:
            raise exc
        custom_api.patch_namespaced_custom_object(group='rating.alterway.fr',
                                                  version='v1',
                                                  namespace=rated_namespace,
                                                  plural='ratedmetrics',
                                                  name=rated_metric,
                                                  body=body)
示例#29
0
    def get_keycloak_user_token(self, tenant: AnyStr,
                                password: AnyStr) -> Dict:
        """
        Get the token of the user authentication in Keycloak.

        :tenant (AnyStr) the user username
        :password (AnyStr) the user password

        Return the keycloak user token if valid credentials.
        """
        keycloak_openid = self.client
        token = None
        try:
            token = keycloak_openid.token(tenant, password)
            if envvar('GRAFANA') == 'true':
                user_grafana = grafana.get_grafana_user(tenant)
                if not user_grafana:
                    grafana.create_grafana_user(tenant, password)
                if self.verify_group_admin():
                    grafana.update_grafana_role(user_grafana, 'Editor')
        except exceptions.KeycloakAuthenticationError or exceptions.KeycloakGetError:
            logging.error(f'Authentication error for user {tenant}')
        finally:
            return token
示例#30
0
        Verify if a user is admin.

        :kwargs (Dict) contains username

        Return a boolean describing if the user is in admin group.
        """
        if kwargs['tenant']:
            tenant = kwargs['tenant']
        res = query.get_group_tenant(tenant)
        if res[0]['user_group'] == 'admin':
            return True
        else:
            return False

    def __init__(self, method: AnyStr = None, **kwargs):
        try:
            instance = {'ldap': LDAP, 'keycloak': Keycloak}[method]()
        except KeyError:
            return

        self.instance = instance
        self.client = instance.client
        self.verify = instance.verify
        self.get_namespace = instance.get_namespace
        self.verify_group_admin = instance.verify_group_admin


# envvar('AUTH_METHOD'))
auth = Authenticator(method=envvar('AUTH_METHOD'))
auth.client()