Keycloak federation / external IAM in openDesk?
Problem: We want to connect an external keycloak which is not part of the project.
Solution: Keycloak-federation
ad-hoc Federation issues: An easy ad-hoc federation is not possible. We failed at the UDM-rest-API. The documentation for the ucs appliance is probably not tested in opendesk context.
First Issue - emailPrimaryAdress is necessary:
2024-01-18 08:46:08,994 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) Univention Authenticator, authenticate has been called. 2024-01-18 08:46:08,994 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) User:Sven 2024-01-18 08:46:08,994 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) lastname:Andersen 2024-01-18 08:46:08,994 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) username:external-kdo-keycloak-sven.andersen 2024-01-18 08:46:08,994 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) user: {emailVerified=[true], firstName=[Sven], lastName=[Andersen], univentionObjectIdentifier=[58134880-c1b6-43a9-a3db-2ceaff62a229], objectGUID=[YjY1MTFkNmUtOWFiYi00M2UzLWI5MzAtNmQwMzkxM2E4ZWI3], univentionSourceIAM=[kdo-keycloak], email=[sven.andersen@kdo.de], username=[external-kdo-keycloak-sven.andersen]} 2024-01-18 08:46:08,994 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) remSourceIden_key: univentionSourceIAM 2024-01-18 08:46:08,995 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) remObjIden_key: univentionObjectIdentifier 2024-01-18 08:46:08,996 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) univentionObjectIdentifier:YjY1MTFkNmUtOWFiYi00M2UzLWI5MzAtNmQwMzkxM2E4ZWI3 2024-01-18 08:46:08,997 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) univentionSourceIAM:kdo-keycloak 2024-01-18 08:46:08,997 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) targetFederationLink:null 2024-01-18 08:46:08,997 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) User attempted login. First name: Sven, Last name: Andersen, Username: external-kdo-keycloak-sven.andersen, E-Mail: sven.andersen@kdo.de 2024-01-18 08:46:09,423 ERROR [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2212) Failed to create user via UDM: org.openapitools.client.ApiException: {"error": {"code": 422, "title": "Unprocessable Entity", "message": "1 error(s) occurred:\nRequest argument \"mailPrimaryAddress\" The property \"mailPrimaryAddress\" is required.\n", "error": {"mailPrimaryAddress": "The property \"mailPrimaryAddress\" is required."}}
Solution:
The attribute mailPrimaryAddress is required, so we have to make sure, that the attribute is not forced anymore. We have to set this: directory/manager/web/modules/users/user/properties/mailPrimaryAddress/required: true
to false
. This is the exact code: ums-stack
Implementation:
- make custom settings possible
- helmfile/apps/univention-management-stack/helmfile.yaml
installed: {{ .Values.univentionManagementStack.enabled }}
timeout: 900
# TODO: interim solution to provide custom UCR settings until the Nubus umbrella chart is
# included in openDesk.
# See: https://github.com/univention/nubus-stack/blob/main/helm/ums/values.yaml#L103
- name: "kdo-custom"
chart: "./kdo-custom"
commonLabels:
deploy-stage: "component-1"
component: "univention-management-stack"
- deploy a ConfigMap for kdo-ucr-setting with
mailPrimaryAdress
set tofalse
- helmfile/apps/univention-management-stack/kdo-custom/configmap-ucr.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: kdo-ucr-settings
data:
base.conf: |
directory/manager/web/modules/users/user/properties/mailPrimaryAddress/required: false
-
configMapUcrForced
ontokdo-ucr-settings
- helmfile/apps/univention-management-stack/values-common.yaml.gotmpl
global:
configMapUcrDefaults: "ums-stack-data-ums-ucr"
configMapUcr: "ums-stack-data-swp-ucr"
# configMapUcrForced: null
configMapUcrForced: "kdo-ucr-settings"
With these changes we solved the first problem.
Second Issue - Illegal base64 character:
cutout from the log:
2024-01-19 13:00:08,622 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2754) univentionObjectIdentifier:6c3ffc0a-4ecf-4233-af6b-782d3157f4d0
2024-01-19 13:00:08,622 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2754) univentionSourceIAM:kdo-keycloak
2024-01-19 13:00:08,622 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2754) targetFederationLink:null
2024-01-19 13:00:08,622 INFO [de.univention.authenticator.UniventionAuthenticator] (executor-thread-2754) User attempted login. First name: Sven, Last name: Andersen, Username: kdo-keycloak-sven.andersen, E-Mail: sven.andersen@kdo.de
2024-01-19 13:00:08,622 WARN [org.keycloak.services] (executor-thread-2754) KC-SERVICES0013: Failed authentication: java.lang.IllegalArgumentException: Illegal base64 character 2d
at java.base/java.util.Base64$Decoder.decode0(Base64.java:848)
at java.base/java.util.Base64$Decoder.decode(Base64.java:566)
at de.univention.authenticator.UniventionAuthenticator.authenticate(UniventionAuthenticator.java:129)
So whats the problem? The GUID expect a base64 value, we deliver a unencoded SID. Why it has to be forced on base64? We took the code and changed following lines:
+ // TODO: (Assumption) The approach to handle this could be improved if
+ // the concern of handling the encoding/decoding is implemented as part
+ // of the attribute mapping. This code could then just use theattribute
+ // value without worrying about the encoding at all.
String decoded_remoteGUID;
try{
decoded_remoteGUID = LDAPUtil.decodeObjectGUID(Base64.getDecoder().decode(remIdGUID_value.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e){
decoded_remoteGUID = remIdGUID_value;
- //propagate the error
- context.failure(AuthenticationFlowError.INTERNAL_ERROR);
+ // propagate the error
+ // TODO: Interim commented out to allow to use a value which is not base64 encoded
+ // context.failure(AuthenticationFlowError.INTERNAL_ERROR);
+ logger.infof(remIdGUID_key + " was not base64 encoded. Using value without decoding it.");
}
+
// TODO: When the UDM allows it, avoid passing the password here
+ // TODO: The set of attributes is currently hardcoded.
+ // The UDM does allow many more attributes and a customization may make attributes
+ // required which are not provided here. An option might be to make this dynamic and
+ // try to use all configured attributes or filter the available attributes based on
+ // the generated API client.
Map<String, Object> userData = Map.of(
"firstname", firstname,
"lastname", lastname,
--
2.39.2
- String remIdGUID_key = System.getenv("KEYCLOAK_FEDERATION_REMOTE_IDENTIFIER");
- String remSourceID_key = System.getenv("KEYCLOAK_FEDERATION_SOURCE_IDENTIFIER");
+ String remIdGUID_key = Optional.ofNullable(System.getenv("KEYCLOAK_FEDERATION_REMOTE_IDENTIFIER")).orElse("univentionObjectIdentifier");
+ String remSourceID_key = Optional.ofNullable(System.getenv("KEYCLOAK_FEDERATION_SOURCE_IDENTIFIER")).orElse("univentionSourceIAM");
String decoded_remoteGUID;
try{
decoded_remoteGUID = LDAPUtil.decodeObjectGUID(Base64.getDecoder().decode(remIdGUID_value.getBytes("UTF-8")));
- } catch (UnsupportedEncodingException e){
+ } catch (IllegalArgumentException | UnsupportedEncodingException e){
decoded_remoteGUID = remIdGUID_value;
// propagate the error
// TODO: Interim commented out to allow to use a value which is not base64 encoded
- so we made sure a value which is not base64 encoded is allowed and deleted the UnsupportedEncodingException
What now?
- we made some keycloak experiments based on the ucs-appliance documentation - mapper, first broker login
- after all we had a functional keycloak federation with a test keycloak of the KDO
Whats next?
- the integration is by far not perfect and not reproducible for the community
- we dont get any permissions in opendesk, the default permissions are not working on external objects
what is the question?
- are there plans to make it easier to connect with an existent IAM to opendesk?
- did someone else tried to do a federation and want to connect?
Result
- we were able to login to opendesk with an external keycloak
- right now we try to reproduce it, and make it avaiable for the community, hopefully this issue will help.