I have setup jBPM by using the following docker image: jboss/jbpm-server-full:latest
After following the steps mentioned in https://blog.kie.org/2021/02/migrating-jbpm-images-secured-by-ldap-to-elytron.html (incl. modifying the kie-server.war file with the two ldap user property files).
I finally got the authentication so far, that I replaced the old OTHER authentication mechanism by the new KieLdap and when I login with a correct LDAP username (ie. "ldapuser") as well as correct password, I am presented with a different error view as when I am login with an inexistent user or with an incorrect password:
Login failed: Not Authorized
Login as another User
This means for me: Login is theoretically working!
On the LDAP server (FreeIPA), I see the request by jBPM for BINDing to the user as well as getting all the groups which the user is a member of.
Performing the user auth:
[15/Jan/2024:10:41:01.226351348 +0100] conn=19193 op=0 BIND dn="uid=tech_jbpm,cn=users,cn=accounts,dc=example,dc=ch" method=128 version=3
[15/Jan/2024:10:41:01.229601791 +0100] conn=19193 op=0 RESULT err=0 tag=97 nentries=0 wtime=0.000385959 optime=0.003256677 etime=0.003636806 dn="uid=tech_jbpm,cn=users,cn=accounts,dc=example,dc=ch"
[15/Jan/2024:10:41:01.230835297 +0100] conn=19193 op=1 SRCH base="cn=users,cn=accounts,dc=example,dc=ch" scope=1 filter="(uid=ldapuser)" attrs="1.1"
[15/Jan/2024:10:41:01.231469269 +0100] conn=19193 op=1 RESULT err=0 tag=101 nentries=1 wtime=0.000181602 optime=0.000634202 etime=0.000810154
[15/Jan/2024:10:41:01.232423161 +0100] conn=19193 op=2 UNBIND
Getting the groups of the user:
[15/Jan/2024:10:41:01.235885094 +0100] conn=19194 op=0 BIND dn="uid=tech_jbpm,cn=users,cn=accounts,dc=example,dc=ch" method=128 version=3
[15/Jan/2024:10:41:01.239461648 +0100] conn=19194 op=0 RESULT err=0 tag=97 nentries=0 wtime=0.000513500 optime=0.003582121 etime=0.004090225 dn="uid=tech_jbpm,cn=users,cn=accounts,dc=example,dc=ch"
[15/Jan/2024:10:41:01.240776989 +0100] conn=19194 op=1 SRCH base="cn=users,cn=accounts,dc=example,dc=ch" scope=1 filter="(uid=ldapuser)" attrs="1.1"
[15/Jan/2024:10:41:01.242193465 +0100] conn=19194 op=1 RESULT err=0 tag=101 nentries=1 wtime=0.000520836 optime=0.001418289 etime=0.001932418
[15/Jan/2024:10:41:01.242759072 +0100] conn=19194 op=2 SRCH base="cn=groups,cn=accounts,dc=example,dc=ch" scope=2 filter="(member=uid=ldapuser,cn=users,cn=accounts,dc=example,dc=ch)" attrs=" cn"
[15/Jan/2024:10:41:01.253362800 +0100] conn=19194 op=2 RESULT err=0 tag=101 nentries=26 wtime=0.000225495 optime=0.010595889 etime=0.010815564
[15/Jan/2024:10:41:01.256216795 +0100] conn=19194 op=3 UNBIND
I tried to enable debugging of the Elytron Security module by adding the following logger to the standalone.xml file:
<logger category="org.wildfly.security">
<level name="DEBUG"/>
<handlers>
<handler name="CONSOLE"/>
</handlers>
</logger>
But no output is generated on authenticating a user.
There are some errors, which were inexistent prior to the configuration of the LDAP:
jbpm | 10:08:35,421 INFO [org.kie.server.controller.websocket.client.WebSocketKieServerControllerImpl] (KieServer-ControllerConnect) Kie Server points to non Web Socket controller 'http://localhost:8080/business-central/rest/controller', using default REST mechanism
jbpm | 10:08:35,666 WARN [org.kie.server.services.impl.controller.DefaultRestControllerImpl] (KieServer-ControllerConnect) Exception encountered while syncing with controller at http://localhost:8080/business-central/rest/controller/server/sample-server error Error while sending PUT request to http://localhost:8080/business-central/rest/controller/server/sample-server response code 405
How can I further debug this problem, without any working log output of the authentication?
All performed LDAP setup steps are documented below:
# Blogs: https://blog.kie.org/2021/02/migrating-jbpm-images-secured-by-ldap-to-elytron.html, https://www.mastertheboss.com/jbossas/jboss-security/configuring-ldap-based-authentication-with-elytron-on-wildfly/
FULL MIGRATION
In the case of kie-server-showcase image, only the kie-server.war is present (no KieLoginModule dependencies) and therefore, it’s possible to make a full migration to Elytron.
Elytron is based on a security-domain concept, in other words, on the representation of a security policy. It is backed by security-realm/s, and resources to make transformations (role-decoder, permission-mapper and others).
In this practical example, we are going to use Elytron LDAP Security Realm to access LDAP backend and verify credentials as well as obtain attributes associated with an identity.
More complex scenarios would allow having several security realms, and by means of a security-mapper, determine which attributes would be retrieved from each security realm.
0. Modify the kie-server.war file.
docker cp jbpm:/opt/jboss/wildfly/standalone/deployments/kie-server.war ./
Unpack the war on an ubuntu machine.
scp root@jbpm.example.ch:/opt/jbpm/kie-server.war ./
Then add these two files:
nano kie-server/WEB-INF/classes/jbpm.user.info.properties
ldap.user.ctx=cn\=users,cn\=accounts,dc\=example,dc\=ch
ldap.role.ctx=cn\=groups,cn\=accounts,dc\=example,dc\=ch
ldap.user.filter=(uid\={0})
ldap.role.filter=(cn\={0})
nano kie-server/WEB-INF/classes/jbpm.usergroup.callback.properties
ldap.user.ctx=cn\=users,cn\=accounts,dc\=example,dc\=ch
ldap.role.ctx=cn\=groups,cn\=accounts,dc\=example,dc\=ch
ldap.user.roles.ctx=cn\=groups,cn\=accounts,dc\=example,dc\=ch
ldap.user.filter=(uid\={0})
ldap.role.filter=(cn\={0})
ldap.user.roles.filter=(member\={0})
ldap.bind.user=uid\=tech_jbpm,cn\=users,cn\=accounts,dc\=example,dc\=ch
ldap.bind.pwd=9sdvYxGksGRX7stug7
java.naming.provider.url=ldap://10.1.20.10:389
Repack the kie-server.war and upload & mount it on the server:
jar -cvf kie-server.war *
scp ./kie-server.war root@jbpm.example.ch:/opt/jbpm/kie-server.war
1.- First, let’s remove the security-domain called other at legacy security subsystem, as it will be no longer used:
[root@c01-lxc-jbpm-001 jbpm]# docker exec -it jbpm bash
[jboss@5a3ffa8318d2 bin]$ bash jboss-cli.sh
[standalone@localhost:9990 /] connect
[standalone@localhost:9990 /] /subsystem=undertow/application-security-domain=other:remove
[standalone@localhost:9990 /] /subsystem=ejb3/application-security-domain=other:remove
Then reload Kie Server:
[standalone@localhost:9990 /] reload
And connect again:
[standalone@localhost:9990 /] connect
3.- Define the directory context to connect with LDAP and the LDAP Realm into Elytron:
[standalone@localhost:9990 /] /subsystem=elytron/dir-context=ldap-connection:add(url=ldap://10.10.0.10:389, principal="uid=tech_jbpm,cn=users,cn=accounts,dc=example,dc=ch", credential-reference={clear-text="secret"})
[standalone@localhost:9990 /] /subsystem=elytron/ldap-realm="KieLdap":add(dir-context=ldap-connection, \
direct-verification=true, \
identity-mapping={search-base-dn="cn=users,cn=accounts,dc=example,dc=ch", \
rdn-identifier="uid", \
attribute-mapping=[{filter-base-dn="cn=groups,cn=accounts,dc=example,dc=ch",filter="(member=uid={0},cn=users,cn=accounts,dc=example,dc=ch)",from="cn",to="Roles"}]})
Notice that the LDAP connection needs the principal (bindDN) and its password as the used LDAP server doesn’t allow anonymous binding.
Retrieved roles are mapped from “cn” to “Roles”, where the RoleDecoder will take them.
This RoleDecoder component (as its name indicates) is in charge of decoding user’s roles.
Our simple-role-decoder (from-roles-attribute) is pretty straightforward: roles are obtained directly from the attribute “Roles”.
<simple-role-decoder name="from-roles-attribute" attribute="Roles"/>
4.- Create the security domain in Elytron, named KIEDomain, (any name is valid, as we will map it later to the one defined at application level) and add it the previous LDAP realm, and the default-permission-mapper:
[standalone@localhost:9990 /] /subsystem=elytron/security-domain=KIEDomain:add(realms=[{realm=KieLdap,role-decoder=from-roles-attribute}], default-realm="KieLdap", permission-mapper=default-permission-mapper)
5.- Next, we need to define the HTTP authentication factory: for kie-server, it’s needed to link the mechanisms for BASIC and FORM authentications:
[standalone@localhost:9990 /] /subsystem=elytron/http-authentication-factory=ldap-http-auth:add(http-server-mechanism-factory=global,security-domain=KIEDomain,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=KieLdap}]}, {mechanism-name=FORM}])
6.- Map the application security domain (other, as it is the one specified at jboss-web.xml) to our Elytron security domain (KIEDomain) for the undertow and ejb3 subsystems:
[standalone@localhost:9990 /] /subsystem=undertow/application-security-domain=other:add(security-domain=KIEDomain)
[standalone@localhost:9990 /] /subsystem=ejb3/application-security-domain=other:add(security-domain=KIEDomain)
7.- Update the messaging-activemq (JMS) to point to our Elytron security domain (KIEDomain) and undefine (remove) the default security domain given by WildFly:
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:write-attribute(name=elytron-domain, value=KIEDomain)
[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default:undefine-attribute(name=security-domain)
8.- Disable JACC from legacy security subsystem and enable it at elytron by adding the default policy:
Does not work: [standalone@localhost:9990 /] /subsystem=security:write-attribute(name=initialize-jacc, value=false)
[standalone@localhost:9990 /] /subsystem=elytron/policy=jacc:add(jacc-policy={})
[standalone@localhost:9990 /] reload
[standalone@localhost:9990 /] connect
Update 17.01.2024
After enabling debugging by using the configuration from the first answer, I get the following log output in server.log. There are only authentication successes in the log, even though the login to the kie-server still does not work.
2024-01-17 18:51:38,571 DEBUG [org.wildfly.security] (default task-1) Context [javax.naming.ldap.InitialLdapContext@1576a899] was closed. Connection closed or just returned to the pool.
2024-01-17 18:51:38,571 TRACE [org.wildfly.security] (default task-1) Role mapping: principal [ldapuser] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
2024-01-17 18:51:38,573 TRACE [org.wildfly.security] (default task-1) Authorizing principal ldapuser.
2024-01-17 18:51:38,574 TRACE [org.wildfly.security] (default task-1) Authorizing against the following attributes: [Roles] => [ipausers, employees, teamleads, vpn, app_kimai_teamlead, app_grafana_editor, team_mgmt, app_swissd_user, team_office_lead, team_cybsec_lead, team_devops_lead, team_sysops_lead, app_cockpit_admin, ma_bills, ma_tech, role_cyb, role_hr, role_sys, role_soc, role_dev, role_mgt, role_sales, role_mktg, user, admin, kie-server]
2024-01-17 18:51:38,575 TRACE [org.wildfly.security] (default task-1) Authorizing against the following runtime attributes: [] => []
2024-01-17 18:51:38,575 TRACE [org.wildfly.security] (default task-1) Permission mapping: identity [ldapuser] with roles [] implies ("org.wildfly.security.auth.permission.LoginPermission" "") = true
2024-01-17 18:51:38,575 TRACE [org.wildfly.security] (default task-1) Authorization succeed
2024-01-17 18:51:38,576 TRACE [org.wildfly.security] (default task-1) Handling CachedIdentityAuthorizeCallback: principal = ldapuser authorizedIdentity = SecurityIdentity{principal=ldapuser, securityDomain=org.wildfly.security.auth.server.SecurityDomain@e3b9f68, authorizationIdentity=EMPTY, realmInfo=RealmInfo{name='KieLdap', securityRealm=org.wildfly.security.auth.realm.ldap.LdapSecurityRealm@1fa010d8}, creationTime=2024-01-17T18:51:38.571413Z}
2024-01-17 18:51:38,577 DEBUG [org.wildfly.security.http.form] (default task-1) User [ldapuser] authenticated successfully
2024-01-17 18:51:38,577 TRACE [org.wildfly.security] (default task-1) Handling AuthenticationCompleteCallback: succeed
2024-01-17 18:51:38,577 TRACE [org.wildfly.security] (default task-1) Handling SecurityIdentityCallback: identity = SecurityIdentity{principal=ldapuser, securityDomain=org.wildfly.security.auth.server.SecurityDomain@e3b9f68, authorizationIdentity=EMPTY, realmInfo=RealmInfo{name='KieLdap', securityRealm=org.wildfly.security.auth.realm.ldap.LdapSecurityRealm@1fa010d8}, creationTime=2024-01-17T18:51:38.571413Z}
2024-01-17 18:51:38,577 TRACE [org.wildfly.security.http.form] (default task-1) User redirected to original path [http://jbpm.example.ch/business-central/kie-wb.jsp]
2024-01-17 18:51:38,578 TRACE [org.wildfly.security] (default task-1) Role mapping: principal [ldapuser] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
2024-01-17 18:51:38,638 TRACE [org.wildfly.security.http.servlet] (default task-1) Created ServletSecurityContextImpl enableJapi=true, integratedJaspi=true, applicationContext=default-host /business-central
2024-01-17 18:51:38,638 TRACE [org.wildfly.security.http.servlet] (default task-1) No AuthConfigProvider for layer=HttpServlet, appContext=default-host /business-central
2024-01-17 18:51:38,638 TRACE [org.wildfly.security.http.servlet] (default task-1) JASPIC Unavailable, using HTTP authentication.
2024-01-17 18:51:38,638 TRACE [org.wildfly.security] (default task-1) No CachedIdentity to restore.
2024-01-17 18:51:38,638 TRACE [org.wildfly.security] (default task-1) Created HttpServerAuthenticationMechanism [org.wildfly.security.auth.server.SecurityIdentityServerMechanismFactory$1@51543146] for mechanism [BASIC]
2024-01-17 18:51:38,639 TRACE [org.wildfly.security] (default task-1) Created HttpServerAuthenticationMechanism [org.wildfly.security.auth.server.SecurityIdentityServerMechanismFactory$1@4e1a1cab] for mechanism [FORM]
2024-01-17 18:51:38,639 TRACE [org.wildfly.security] (default task-1) Handling AvailableRealmsCallback: realms = []
2024-01-17 18:51:38,639 TRACE [org.wildfly.security.http.form] (default task-1) Trying to re-authenticate session PUpj1tWHGVItrh2pGn--S_v4-Xted7GauMr2MQmX. Request URI: [http://jbpm.example.ch/business-central/kie-wb.jsp], Context path: [/business-central]
2024-01-17 18:51:38,639 TRACE [org.wildfly.security] (default task-1) Handling CachedIdentityAuthorizeCallback: principal = null authorizedIdentity = SecurityIdentity{principal=ldapuser, securityDomain=org.wildfly.security.auth.server.SecurityDomain@e3b9f68, authorizationIdentity=EMPTY, realmInfo=RealmInfo{name='KieLdap', securityRealm=org.wildfly.security.auth.realm.ldap.LdapSecurityRealm@1fa010d8}, creationTime=2024-01-17T18:51:38.571413Z}
2024-01-17 18:51:38,639 TRACE [org.wildfly.security] (default task-1) Handling AuthenticationCompleteCallback: succeed
2024-01-17 18:51:38,639 TRACE [org.wildfly.security] (default task-1) Handling SecurityIdentityCallback: identity = SecurityIdentity{principal=ldapuser, securityDomain=org.wildfly.security.auth.server.SecurityDomain@e3b9f68, authorizationIdentity=EMPTY, realmInfo=RealmInfo{name='KieLdap', securityRealm=org.wildfly.security.auth.realm.ldap.LdapSecurityRealm@1fa010d8}, creationTime=2024-01-17T18:51:38.571413Z}
2024-01-17 18:51:38,640 TRACE [org.wildfly.security] (default task-1) Role mapping: principal [ldapuser] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
2024-01-17 18:51:38,640 TRACE [org.wildfly.security] (default task-1) Role mapping: principal [ldapuser] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
2024-01-17 18:51:38,640 TRACE [org.wildfly.security] (default task-1) Permission mapping: identity [ldapuser] with roles [] implies ("javax.security.jacc.WebResourcePermission" "/kie-wb.jsp" "GET") = false
I finally found the answer:
I used the default:
<simple-role-decoder name="from-roles-attribute" attribute="roles"/>
But my commands to connect LDAP parsed the CN attribute of the LDAP groups into "Roles". Since the default role-decoder uses "roles" as an attribute and the label is case sensitive, it did not find anything to parse.
Solution was to change the above line to:
<simple-role-decoder name="from-roles-attribute" attribute="Roles"/>