How can i restrict client access to only one group of users in keycloak?

后端 未结 8 614
一生所求
一生所求 2020-12-24 15:08

I have a client in keycloak for my awx(ansible tower) webpage. I need only the users from one specific keycloak group to be able to log in through

相关标签:
8条回答
  • 2020-12-24 15:16

    I solved it like this:

    1. Create a new role in Keycloak.
    2. Assign this role to the group.
    3. Create a new authentication script in Kycloak. Configure which role is allowed upon login (e.g. user.hasRole(realm.getRole("yourRoleName"))).
    4. In the client's settings, under "Authentication Flow Overrides", choose the authentication script that was just created.
    0 讨论(0)
  • 2020-12-24 15:18

    Follow-up to Allan's answer: His approach is working (for me ;-) ), though I had some struggle on how to deploy it. This is how I did it:

    • Bundle script in a JAR file as documented here, deploy it by copying to standalone/deployments/ (see manual link)
    • Enable scripts: Start Keycloak with -Dkeycloak.profile.feature.scripts=enabled
    • In your realm, create a new flow. Duplicate the Browser flow in a required subflow, and add the script authenticator as final (required) element:
    • Now add to all clients which should be restricted a client role feature:authenticate. Users which don't bear that role won't get access to the application.
    0 讨论(0)
  • 2020-12-24 15:19

    according docu https://www.keycloak.org/docs/6.0/server_admin/#executions u have to active that feature to add some custom scripts with "add execution".

    bin/standalone.sh|bat -Dkeycloak.profile.feature.scripts=enabled
    

    @Allan solution with feature:authenticate looks good to me

    0 讨论(0)
  • 2020-12-24 15:22

    On Keycloak admin console, go to Clients menu, select your client. On the client configuration page, set Authorization Enabled: On, click Save. A new Authorization tab should appear, go to it, then to the Policies tab underneath, click Create Policy and select Group-based policy. There, you can restrict access to specific groups, assuming you have defined your groups via the Groups menu already.

    --EDIT 2019-11-08--

    As mentioned in comments, Client Protocol must be set to openid-connect and Access Type must be set to confidential, in order to make the Authorization Enabled option visible.

    0 讨论(0)
  • 2020-12-24 15:24

    I tried Allan's solution and it is working fine using Keycloak 11.0.3 but it has some cons mentioned below. Here is my solution for the authenticator script which does not grant access for users if they are not member at least one of the given groups. In such case a unique error message is shown.

    AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
    
     function authenticate(context) {
        var allowed_groups = ['foo', 'bar'];
        var username = user ? user.username : "anonymous";
        var groups = user.getGroups();
        var group_array = groups.toArray();
        
        for (var i in group_array) {
            var gn = group_array[i].getName();
            if (allowed_groups.indexOf(gn) >= 0) {
                LOG.info("Access granted for user '" + username + "' for being member of LDAP group '" + gn + "'");
                return context.success();
            }    
        }
    
        LOG.info("Access denied for user '" + username + ". for not being member of any of the following LDAP groups: " + allowed_groups);
        context.failure(AuthenticationFlowError.IDENTITY_PROVIDER_DISABLED, context.form().setError(
            "User doesn't have the required LDAP group membership to view this page", null).createForm("error.ftl"));
        return;
     }
    

    There are two minor user experience related cons with this solution worth mentioning:

    • When a not logged in user tries to connect to a client which access gets denied by the authenticator script the whole authentication flow is considered failure. This means the user doesn't get logged in into Keycloak despite the fact they provided the correct credentials
    • When a logged in user tries to connect to a client which access gets denied by the authenticator script the Keycloak login page is displayed (without showing any error message) which is deceptive as the user can have the false feeling they are not logged in

    In addition if you maintain multiple clients and you need to have different groups (or roles) checked per client then you have to implement as many new authentication flows as many different checks you need. In short the solution works, but it has some disadvantages. I believe a simple feature such as restricting the access based on groups or roles is essential for an identity and access management system and should be supported natively!

    0 讨论(0)
  • 2020-12-24 15:35

    If it can help, here is a script which helps implementing this behaviour for any client: if the client contains a given role (here it is called feature:authenticate), then the script checks whether the user has the role and shows an error page (a new template that needs to be deployed in the theme) if not.

    AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
    
     function authenticate(context) {
        var MANDATORY_ROLE = 'feature:authenticate';
        var username = user ? user.username : "anonymous";
    
        var client = session.getContext().getClient();
    
        LOG.debug("Checking access to authentication for client '" + client.getName() + "' through mandatory role '" + MANDATORY_ROLE + "' for user '" + username + "'");
    
        var mandatoryRole = client.getRole(MANDATORY_ROLE);
    
        if (mandatoryRole === null) {
            LOG.debug("No mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
            return context.success();
        }
    
        if (user.hasRole(mandatoryRole)) {
            LOG.info("Successful authentication for user '" + username + "' with mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
            return context.success();
        }
    
        LOG.info("Denied authentication for user '" + username + "' without mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
        return denyAccess(context, mandatoryRole);
     }
    
     function denyAccess(context, mandatoryRole) {
        var formBuilder = context.form();
        var client = session.getContext().getClient();
        var description = !mandatoryRole.getAttribute('deniedMessage').isEmpty() ? mandatoryRole.getAttribute('deniedMessage') : [''];
        var form = formBuilder
            .setAttribute('clientUrl', client.getRootUrl())
            .setAttribute('clientName', client.getName())
            .setAttribute('description', description[0])
            .createForm('denied-auth.ftl');
        return context.failure(AuthenticationFlowError.INVALID_USER, form);
     }
    
    0 讨论(0)
提交回复
热议问题