[keycloak-user] Restrict access to a client to a subset of Keycloak users

Thomas Darimont thomas.darimont at googlemail.com
Fri Feb 24 08:23:58 EST 2017


PR sent: https://issues.jboss.org/browse/KEYCLOAK-4505

With that PR applied I can do the following:

/*
 * Template for JavaScript based authenticator's.
 * See
org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory
 */

// import enum for error lookup
AuthenticationFlowError =
Java.type("org.keycloak.authentication.AuthenticationFlowError");
OAuth2ErrorRepresentation =
Java.type("org.keycloak.representations.idm.OAuth2ErrorRepresentation");
Response = Java.type("javax.ws.rs.core.Response");
MediaType = Java.type("javax.ws.rs.core.MediaType");

/**
 * An example authenticate function.
 *
 * The following variables are available for convenience:
 * user - current user {@see org.keycloak.models.UserModel}
 * realm - current realm {@see org.keycloak.models.RealmModel}
 * session - current KeycloakSession {@see
org.keycloak.models.KeycloakSession}
 * clientSession - current client session {@see
org.keycloak.models.ClientSessionModel}
 * httpRequest - current HttpRequest {@see
org.jboss.resteasy.spi.HttpRequest}
 * script - current script {@see org.keycloak.models.ScriptModel}
 * LOG - current logger {@see org.jboss.logging.Logger}
  * You one can extract current http request headers via:
 * httpRequest.getHttpHeaders().getHeaderString("Forwarded")
 *
 * @param context {@see
org.keycloak.authentication.AuthenticationFlowContext}
 */
function authenticate(context) {

    var username = user ? user.username : "anonymous";
    LOG.info(script.name + " trace auth for: " + username);
    LOG.info(script.name + " client session for client: " +
clientSession.client.clientId);

    var groups = user.getGroups();
    var group_array = groups.toArray();

    var authShouldFail = true;
    for (var i in group_array) {
      var gn = group_array[i].getName();
      LOG.info(script.name + " group name: " + gn);
      if (gn === "account-access") {
        authShouldFail = false;
        break;
      }
    }

    if (authShouldFail
     //&& clientSession.client.clientId === "dummy-account"
     ) {

        var errorRep = new
OAuth2ErrorRepresentation("invalid_grant","invalid_user_credentials");
        var response =
Response.status(401).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();

        LOG.info(script.name + " failed auth for: " + username);
        context.failure(AuthenticationFlowError.INVALID_USER, response);
        return;
    }

    context.success();
}



2017-02-24 12:19 GMT+01:00 Thomas Darimont <thomas.darimont at googlemail.com>:

> FYI I just gave this a spin...
>
> It seems that the ScriptAuthenticator currently has no binding for
> clientSession in order to access the client id for authentication,
> e.g. this is missing in ScriptBasedAuthenticator
>             bindings.put("clientSession", context.getClientSession());
>
> I'll send a PR which adds that binding. This will then enable to provide
> client specific authentication behaviour.
>
> Chreers,
> Thomas
>
> 2017-02-24 11:33 GMT+01:00 Shane Boulden <shane.boulden at gmail.com>:
>
>> I got this working today with a custom auth flow, thanks heaps!
>>
>> Just one thing - I've copied the 'Direct Grant Flow', and added a JS
>> script at the end to only allow certain groups to authenticate using the
>> OpenShift 'oc login' command from a prompt.
>>
>> This works allowing/denying access based on a group, however when a user
>> does not belong to the correct group, the oc login prompt displays the
>> following error:
>>
>> "Error from server: Internal error: unexpected error: 500"
>>
>> Here's the code I used for my JS script:
>>
>> function authenticate(context){
>>   var groups = user.getGroups();
>>   var group_array = groups.toArray();
>>
>>   for (var i in group_array) {
>>     var gn = group_array[i].getName();
>>
>>     if (gn === "openshift-access") {
>>       context.success();
>>       return;
>>     }
>>   }
>>   context.failure(authenticationflowerror.INVALID_USER)
>>   return;
>> }
>>
>> I thought this may be because the OpenShift CLI tool can't interpret the
>> error message back from Keycloak. I've also tried the following, but I get
>> a "ClassNotFound" exception when I try to import the OAuth2 error
>> representation:
>>
>> Authenticationflowerror = Java.type("org.keycloak.authen
>> tication.AuthenticationFlowError");
>> // Throws 'ClassNotFoundException
>> Oauth2 = Java.type("org.keycloak.representations.idm.OAuth2ErrorRepre
>> sentation");
>> Response = Java.type("javax.ws.rs.core.Response");
>> MediaType = Java.Type("javax.ws.rs.core.MediaType");
>>
>> function authenticate(context) {
>>   var groups = user.getGroups();
>>   var group_array = groups.toArray();
>>
>>   for (var i in group_array) {
>>     var gn = group_array[i].getName();
>>
>>     if (gn === "openshift-access") {
>>       context.success();
>>       return;
>>     }
>>   }
>>   var errorRep = new Oauth2("invalid_grant","invalid_user_credentials");
>>   response = Response.status(401).type(MediaType.APPLICATION_JSON_TYPE).b
>> uild();
>>
>>   context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, response);
>>   return;
>> }
>>
>> Any ideas or assistance is appreciated.
>>
>> Shane
>>
>> On Fri, Feb 24, 2017 at 5:16 AM, Shane Boulden <shane.boulden at gmail.com>
>> wrote:
>>
>>> Thanks very much Marek and Thomas for taking the time to get back to me.
>>>
>>> I've found an example of a JS authenticator here:
>>>  http://www.lookatsrc.com/source/scripts/authenticator-templ
>>> ate.js?a=org.keycloak:keycloak-services
>>>
>>> Is this how I would build the custom authenticator, and extend it to
>>> check the user roles and clientID?
>>>
>>> Thanks
>>>
>>> Shane
>>>
>>> On 24 Feb. 2017 01:25, "Thomas Darimont" <thomas.darimont at googlemail.com>
>>> wrote:
>>>
>>>> Hello Shane,
>>>>
>>>> you could try to do that with the Javascript based Authenticator.
>>>>
>>>> Cheers,
>>>> Thomas
>>>>
>>>> 2017-02-23 14:07 GMT+01:00 Marek Posolda <mposolda at redhat.com>:
>>>>
>>>>> I can think of some workarounds. Like for example, create an
>>>>> Authenticator, which will be added to the bottom of the authentication
>>>>> flow. Authenticator will throw an exception in case that unpermitted
>>>>> user is trying to authenticate to the client corresponding to your
>>>>> openshift application. You have the user available (he is already
>>>>> authenticated) and you have also the client (can be determined based on
>>>>> clientId).
>>>>>
>>>>> Maybe even easier is to do that in custom RequiredActionProvider and do
>>>>> this check in "evaluateTriggers".
>>>>>
>>>>> This is workaround as it mixes authentication and authorization (among
>>>>> other issues). But hopefully it can suit your needs.
>>>>>
>>>>> Marek
>>>>>
>>>>> On 23/02/17 07:19, Shane Boulden wrote:
>>>>> > Hi everyone,
>>>>> >
>>>>> > I'm trying to figure out a fairly straight-forward problem set -
>>>>> >
>>>>> >     - I have a number of users in a Keycloak database, federated
>>>>> from an
>>>>> >     LDAP provider with a READ_ONLY policy (ie; I can't "disable" the
>>>>> users)
>>>>> >     - I want to limit access to a client to only certain Keycloak
>>>>> users
>>>>> >
>>>>> > I thought this would be possible with a role that is shared by the
>>>>> client
>>>>> > and the user. However, it looks like Keycloak lets the application
>>>>> itself
>>>>> > determine access via a role: http://lists.jboss.org/
>>>>> > pipermail/keycloak-user/2014-November/001205.html
>>>>> >
>>>>> > But what if I can't update the application's behaviour? Eg; if I
>>>>> want to
>>>>> > integrate Keycloak with OpenShift, and OpenShift doesn't consume any
>>>>> > information from the OIDC provider?
>>>>> >
>>>>> > In this particular example, I don't want to limit the users in the
>>>>> Keycloak
>>>>> > database - I want to sync all users from LDAP, but limit application
>>>>> access
>>>>> > to only a subset.
>>>>> >
>>>>> > Any assistance is greatly appreciated.
>>>>> >
>>>>> > Shane
>>>>> > _______________________________________________
>>>>> > keycloak-user mailing list
>>>>> > keycloak-user at lists.jboss.org
>>>>> > https://lists.jboss.org/mailman/listinfo/keycloak-user
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> keycloak-user mailing list
>>>>> keycloak-user at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/keycloak-user
>>>>>
>>>>
>>>>
>>
>


More information about the keycloak-user mailing list