Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 this client.

How can I forbid all other users(except from one particular group) from using this keycloak client?

like image 646
lukasell Avatar asked Jan 22 '19 10:01

lukasell


3 Answers

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.

like image 68
cdan Avatar answered Oct 17 '22 18:10

cdan


I found a solution which does not require the scripts extension or any changes on the flow.

The key for this solution are the Client Scopes. An application which wants to to authorize a user needs a scope like email or uid, right? What if you only pass them to an application if a user is in a specific group?

In the following, my client application name is App1.

Solution:

  1. Go to your client roles (realm -> Clients -> click App1 -> Roles)
  2. Click 'Add Role' -> enter Name (e.g. 'access') -> click 'Save'
  3. Go to Client Scopes (realm -> Client Scopes)
  4. Click on the scope which is needed by your client application (e.g. 'email')
  5. Assign Client Role 'access' in 'Scope' Tab by choosing client application 'App1' in Drop Down 'Client Roles'

Now, you won't be able to log into your client application App1 anymore, as the role 'access' is not assigned to any user or group. You can try.

Let's create a new group and assign the role and a user to it.

  1. Create Group (realm -> Groups -> Click 'New' -> enter Name 'App1 Users' -> Click Save)
  2. In the Group, choose 'Role Mappings', choose 'App1' in Client Roles drop down, and assign the role 'access'
  3. Assign User to 'App1 Users' (realm -> Users -> Click on User -> Groups -> Select 'App1 Users -> Click Join)

Voila, the chosen user can log into App1.

like image 38
Michael Jobst Avatar answered Oct 17 '22 18:10

Michael Jobst


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);
 }
like image 8
Allan Avatar answered Oct 17 '22 18:10

Allan