Keycloak with OpenID Connect restrict access

Hi, i’m using Keycloak 12.0.3 with OpenID Connect to authenticate our users against some clients (nextcloud, drupal, moodle …).

My goal is to allow only certain groups of users to have access to moodle or nextcloud. For example, students should not have access to nextcloud, but employees should.

I tried to configure keycloak with Authorization policies, but these are effectless. All users within keycloak can authenticate against all clients.

How can I configure keycloak so that only certain groups have access to the respective clients.

Best regards.

Hi,

I had the same problem with local gitlab and BBB setups. I solved it with Javascript based authenticators, as documented here:

https://www.keycloak.org/docs/latest/server_development/index.html#_script_providers

Within the script, you can access all user, realm, client and session properties to decide wether authenticate a user or not. The script must be added to the authentication chain after an authenticator which really authenticates the user (User+PW, cookie…).
(If you use an IdP-redirect, it is necessary to add the script to an authentication flow which is configured to be executed as post-idp-flow.)

Instead of stopping the authentication with a standard keycloak error page (as shown in the documentation), it is also possible to trigger a redirect back to the client with a standardised error message code appended to the original redirect_uri query string [1]. Then the “you are not allowed to use this” page is shown by the nextcloud etc, instead of keycloak. But this depends on the capabilities of the client software.

regards,
Matthias

[1] Final: OpenID Connect Core 1.0 incorporating errata set 1

Hi,

that sounds good. I managed to enable keycloak with Javascript based authenticators and sucessfully deployed the jar file with these example js files.

Maybe u can help me with the scrip, what should the script look like?

The easiest way for me would be to evaluate the roles in keycloak. For example bbb role, moodle role, nextcloud role etc.

Best regards
Daniel

Hi,

In my case, I checked the values of a user attribute called “memberOf”, which contains AD/LDAP group memberships. The allowed attribute values are configured with regular expressions. Here is the .js code:

AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
Status =  Java.type("javax.ws.rs.core.Response.Status");
URI = Java.type("java.net.URI");
Response = Java.type("javax.ws.rs.core.Response");

function authenticate(context) {
	
	//configuration: example clients with example regexps for matching group attributes
	var conf = {
		"bbb-client-id": {rx: /^bbb-group-.+$/i, doRedirect: true},
		"moodle-client-id": {rx: /^moodle-allowed-group$/i, doRedirect: true},
		"nextcloud-client-id": {rx: /^(nextcloud-.+|.+-nextcloud)$/i, doRedirect: false}
	};
	
	var client = session.getContext().getClient();
	
	//default: at least one character, ignore case  => all groups
	var clientId = client.getClientId();
	var rx = /^.+$/i;
	var doRedirect = false;
	if (conf.hasOwnProperty(clientId)) {
		rx = conf[clientId].rx;
		doRedirect = conf[clientId].doRedirect;
	} else {
		context.success();
		return;
	}

	//first matching group found, success
	for each (var item in user.attributes.memberOf) {
		if (rx.test(item)) {
			context.success();
			return;
		}
	}
	
	//log events for keycloak admin console
	var logevent = context.getEvent()
		.user(user)
		.detail("username", user.username)
		.detail("rx", rx)
		.detail("doRedirect", doRedirect);
	
	//depending on the clients capabilities: redirect with standardized oidc method or fail with keycloak error page
	if (doRedirect) {
		state = authenticationSession.getClientNotes().get("state");
		redirect_uri = authenticationSession.getClientNotes().get("redirect_uri");
		query = URI.create(redirect_uri).getQuery();
		if (query === undefined || query === null || query.trim() === ""){
			redirect_uri = redirect_uri + "?"; 
		} else {
			redirect_uri = redirect_uri + "&";
		}
		redirect_uri = redirect_uri + "error=access_denied";
		if (state !== undefined && state !== null && state.trim() !== "") {
			redirect_uri = redirect_uri + "&state=" + state;
		}
		//german error text for german browsers
		if (user.attributes.locale !== undefined && user.attributes.locale !== null && user.attributes.locale.length > 0 && user.attributes.locale[0].toLowerCase() === "de") {
			redirect_uri = redirect_uri + "&error_description="  + encodeURI("Zugriff verweigert für " + user.username);
		} else {
			redirect_uri = redirect_uri + "&error_description="  + encodeURI("Access denied for " + user.username);
		}
		logevent.detail("redirect_uri", redirect_uri).error("memberOf_authorization_failed");
		context.challenge(Response.seeOther(URI.create(redirect_uri)).build());
	} else {
		logevent.error("memberOf_authorization_failed");
		var formBuilder = context.form();
		var form = formBuilder
			.setAttribute('client', client)
			.setStatus(Status.FORBIDDEN)
			.createForm('forbidden.ftl');  //customized error page, standard error.ftl or similar will also work
		context.failure(AuthenticationFlowError.INVALID_USER, form);
	}
	
	return;	
}

I have no idea how to check users realm oder client roles, you will have to read the keycloak javadoc
https://www.keycloak.org/docs-api/12.0/javadocs/index.html
(Search for UserModel, RoleMapperModel, …)

regards,
Matthias

Thank you for the script. I try to get through :slight_smile:

And i found another good documentation with JavaScript Auth.

Danke und Gruß
Daniel