Exemple #1
0
def create_service_account(namespace: str) -> object:
    enforce_authorization(namespace)

    f = open("templates/keycloak/client.json", "r")
    j = json.loads(f.read())

    cid = "sa-%s-%s" % (namespace, get_random_string(10))

    j['clientId'] = cid
    j['protocolMappers'][0]['config']['claim.value'] = namespace

    keycloak_admin = admin_api()

    try:
        response = keycloak_admin.create_client(j)
        cuuid = keycloak_admin.get_client_id(cid)
        r = keycloak_admin.generate_client_secrets(cuuid)
        return ({'client_id': cid, 'client_secret': r['value']}, 201)
    except KeycloakGetError as err:
        if err.response_code == 409:
            abort(
                make_response(
                    jsonify(
                        error=
                        "Service Account for this namespace is already created."
                    ), 400))
        else:
            log.error(err)
            abort(
                make_response(jsonify(error="Failed to add service account"),
                              400))
Exemple #2
0
def update_service_account_credentials(namespace: str,
                                       client_id: str) -> object:
    enforce_authorization(namespace)

    cid = "sa-%s-" % namespace

    if not client_id.startswith(cid):
        abort(make_response(jsonify(error="Invalid client ID"), 400))

    keycloak_admin = admin_api()

    try:
        cuuid = keycloak_admin.get_client_id(client_id)
        r = keycloak_admin.generate_client_secrets(cuuid)
        return ({'client_id': client_id, 'client_secret': r['value']}, 201)
    except KeycloakGetError as err:
        if err.response_code == 409:
            abort(
                make_response(
                    jsonify(
                        error=
                        "Service Account for this namespace is already created."
                    ), 400))
        else:
            log.error(err)
            abort(
                make_response(jsonify(error="Failed to add service account"),
                              400))
Exemple #3
0
def membership_sync(namespace, role_name, desired_membership_list):
    log = app.logger

    desired_membership = []
    for user in desired_membership_list:
        if role_name in user['roles']:
            desired_membership.append(user['username'])

    keycloak_admin = admin_api()

    base_group_path = get_base_group_path(role_name)

    group = keycloak_admin.get_group_by_path("%s/%s" %
                                             (base_group_path, namespace),
                                             search_in_subgroups=True)

    if group is None:
        log.warn("[%s] Group %s/%s Missing!" %
                 (namespace, base_group_path, namespace))
        create_group(namespace, base_group_path, role_name)
        group = keycloak_admin.get_group_by_path("%s/%s" %
                                                 (base_group_path, namespace),
                                                 search_in_subgroups=True)

    group = keycloak_admin.get_group(group['id'])

    membership = keycloak_admin.get_group_members(group['id'])

    counts_removed = 0
    counts_added = 0
    counts_missing = 0
    # Remove users that are not part of the provided membership
    for member in membership:
        if member['username'] not in desired_membership:
            log.debug("[%s] REMOVE user %s from %s", namespace,
                      member['username'], base_group_path)
            keycloak_admin.group_user_remove(member['id'], group['id'])
            counts_removed = counts_removed + 1
        else:
            desired_membership.remove(member['username'])

    # Add missing users to the membership
    unregistered_users = []
    for username in desired_membership:
        user_id = keycloak_admin.get_user_id(username)
        if user_id is None:
            log.debug("[%s] UNREGISTERED user %s FROM %s", namespace, username,
                      base_group_path)
            counts_missing = counts_missing + 1
            unregistered_users.append(username)
        else:
            log.debug("[%s] ADDING user %s TO %s", namespace, username,
                      base_group_path)
            keycloak_admin.group_user_add(user_id, group['id'])
            counts_added = counts_added + 1

    # Update the pending attribute with users that are not registered yet
    update_pending_registrations(group, unregistered_users)

    return counts_added, counts_removed, counts_missing
Exemple #4
0
def create_namespace() -> object:
    log = app.logger
    enforce_role_authorization('aps.ns:manage')

    keycloak_admin = admin_api()

    namespace = request.get_json(force=True)['name']

    if not namespace_valid(namespace):
        log.error("Namespace validation failed %s" % namespace)
        abort(
            make_response(
                jsonify(
                    error=
                    "Namespace name validation failed.  Reference regular expression '%s'."
                    % namespace_validation_rule), 400))

    payload = {"name": namespace}

    try:
        for role_name in ['viewer', 'admin']:

            group_base_path = get_base_group_path(role_name)
            parent_group = keycloak_admin.get_group_by_path(group_base_path)
            if parent_group is None:
                keycloak_admin.create_group(
                    {"name": get_base_group_name(role_name)})
                parent_group = keycloak_admin.get_group_by_path(
                    group_base_path)

            response = keycloak_admin.create_group(payload,
                                                   parent=parent_group['id'])
            log.debug("[%s] Group %s/%s created!" %
                      (namespace, group_base_path, namespace))

            new_users_group_id = response['id']

            if 'preferred_username' in g.principal:
                username = g.principal['preferred_username']
                user_id = keycloak_admin.get_user_id(username)
                log.debug("[%s] ADDING user %s TO %s" %
                          (namespace, username, group_base_path))
                keycloak_admin.group_user_add(user_id, new_users_group_id)

    except KeycloakGetError as err:
        if err.response_code == 409:
            log.error("Namespace %s already created." % namespace)
            log.error(err)
            abort(
                make_response(jsonify(error="Namespace is already created."),
                              400))
        else:
            log.error("Failed to create namespace %s" % namespace)
            log.error(err)
            abort(make_response(jsonify(error="Failed to add namespace"), 400))

    return ('', 201)
Exemple #5
0
def update_pending_registrations(group, unregistered_users):
    if 'attributes' in group:
        attrs = group['attributes']
    else:
        attrs = group['attributes'] = {}

    attrs['pending'] = unregistered_users

    keycloak_admin = admin_api()
    keycloak_admin.update_group(group['id'], group)
Exemple #6
0
def create_group(namespace, group_base_path, role_name):
    log = app.logger
    keycloak_admin = admin_api()

    parent_group = keycloak_admin.get_group_by_path(group_base_path)
    if parent_group is None:
        keycloak_admin.create_group({"name": get_base_group_name(role_name)})
        parent_group = keycloak_admin.get_group_by_path(group_base_path)

    keycloak_admin.create_group({"name": namespace}, parent=parent_group['id'])
    log.debug("[%s] Group %s/%s created!", namespace, group_base_path,
              namespace)
Exemple #7
0
def delete_namespace(namespace: str) -> object:
    log = app.logger
    enforce_authorization(namespace)
    enforce_role_authorization('aps.ns:manage')

    keycloak_admin = admin_api()

    try:
        for role_name in ['viewer', 'admin']:
            group = keycloak_admin.get_group_by_path(
                "%s/%s" % (get_base_group_path(role_name), namespace),
                search_in_subgroups=True)
            if group is not None:
                keycloak_admin.delete_group(group['id'])
    except KeycloakGetError as err:
        log.error(err)
        abort(make_response(jsonify(error="Failed to delete namespace"), 400))

    return ('', 204)
Exemple #8
0
def list_service_accounts(namespace: str) -> object:
    enforce_authorization(namespace)

    keycloak_admin = admin_api()

    try:
        params_path = {"realm-name": keycloak_admin.realm_name}
        data_raw = keycloak_admin.raw_get(
            URL_ADMIN_CLIENTS.format(**params_path),
            clientId='sa-%s-' % namespace,
            search=True)
        response = raise_error_from_response(data_raw, KeycloakGetError)
        result = []
        for r in response:
            result.append(r['clientId'])
        return (json.dumps(result), 200)
    except KeycloakGetError as err:
        log.error(err)
        abort(
            make_response(jsonify(error="Failed to read service accounts"),
                          400))
Exemple #9
0
def export_details() -> object:
    log = app.logger
    try:
        keycloak_admin = admin_api()

        response = []
        all_plugins = get_plugins()
        acl_namespaces = get_acl_namespaces(keycloak_admin)
        namespaces = get_namespaces(keycloak_admin)
        for namespace in namespaces:
            ns_name = namespace['name']
            ns_id = namespace['id']
            ns = {
                "namespace": ns_name,
                "attributes": {},
                "view_membership": [],
                "admin_membership": [],
                "service_accounts": [],
                "acl_protected": []
            }
            for acln in acl_namespaces:
                if acln['name'] == ns_name:
                    ns['admin_membership'] = get_group_membership(
                        keycloak_admin, acln['id'])
                    break

            ns['view_membership'] = get_group_membership(keycloak_admin, ns_id)
            ns['attributes'] = get_group_attributes(keycloak_admin, ns_id)
            ns['service_accounts'] = get_service_accounts(
                keycloak_admin, ns_name)
            ns['acl_protected'] = get_acl_protected_services_by_ns(
                ns_name, all_plugins)
            response.append(ns)

        return make_response(jsonify(response))
    except:
        traceback.print_exc()
        log.error("Error generating report. %s" % sys.exc_info()[0])
        abort(make_response(jsonify(error="Failed to generate report"), 400))
Exemple #10
0
def delete_service_account(namespace: str, client_id: str) -> object:
    log = app.logger
    enforce_authorization(namespace)

    if client_id_valid(namespace, client_id) == False:
        abort(make_response(jsonify(error="Invalid client ID"), 400))

    keycloak_admin = admin_api()

    try:
        cuuid = keycloak_admin.get_client_id(client_id)
        if cuuid is None:
            abort(
                make_response(jsonify(error="Service Account does not exist"),
                              400))
        else:
            keycloak_admin.delete_client(cuuid)
            return ({}, 204)
    except KeycloakGetError as err:
        log.error(err)
        abort(
            make_response(jsonify(error="Failed to delete service account"),
                          400))
Exemple #11
0
 def __init__ (self):
     self.keycloak_admin = admin_api()