Hi all,
I am migrating an open source application from Wildfly 16 to
26. In the past, I used a JDBC login module with base64'ed SHA-256
hashes of passwords. The most relevant snippet looked like this:
<login-module code="Database" flag="required">
<module-option name="dsJndiName"
value="java:/jlawyerdb"/>
<module-option
name="principalsQuery" value="select password from
security_users where principalId=?"/>
<module-option name="rolesQuery"
value="select role, 'Roles' from security_roles where
principalId=?"/>
<module-option
name="unauthenticatedIdentity" value="anonymous"/>
<module-option
name="hashAlgorithm" value="SHA-256"/>
<module-option
name="hashEncoding" value="base64"/>
<module-option
name="hashUserPassword" value="true"/>
<module-option
name="hashStorePassword" value="false"/>
</login-module>
I am trying really hard for the last days to get an
equivalent configuration for Wildfly 26, to no avail. Here's
what I have:
(note that I have change the existing ApplicationRealm and
ApplicationDomain instead of adding new ones - i don't like it,
but it got me further than with new ones)
A JDBC realm:
<jdbc-realm name="ApplicationRealm">
<principal-query sql="select password
from security_users where principalId=?"
data-source="jlawyerdb">
<!-- clear-password-mapper
password-index="1"/ -->
<simple-digest-mapper
algorithm="simple-digest-sha-256" password-index="1"/>
</principal-query>
<principal-query sql="select role,
'Roles' from security_roles where principalId=?"
data-source="jlawyerdb">
<attribute-mapping>
<attribute to="Roles"
index="1"/>
</attribute-mapping>
</principal-query>
</jdbc-realm>
SASL Authentication Factory:
<sasl-authentication-factory
name="application-sasl-authentication"
sasl-server-factory="configured"
security-domain="ApplicationDomain">
<mechanism-configuration>
<!-- mechanism
mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/ -->
<mechanism
mechanism-name="DIGEST-SHA-256">
<mechanism-realm
realm-name="ApplicationRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
As I have a remote EJB client, I updated the remoting subsystem
to point to the factory:
<subsystem
xmlns="urn:jboss:domain:remoting:4.0">
<http-connector name="http-remoting-connector"
connector-ref="default" sasl-authentication-factory="application-sasl-authentication"/>
</subsystem>
The remote EJB client looks like this:
Properties
properties = new Properties();
properties.put("jboss.naming.client.ejb.context",
true);
// begin: for JMS only
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.wildfly.naming.client.WildFlyInitialContextFactory");
properties.put(Context.PROVIDER_URL,
"http-remoting://localhost:8080");
properties.put(Context.SECURITY_PRINCIPAL, "admin");
properties.put(Context.SECURITY_CREDENTIALS,
pwString);
properties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT",
"false");
properties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS",
"false");
properties.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_ENABLED",
"false");
properties.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS",
"false");
InitialContext ic = new InitialContext(properties);
SecurityServiceRemote remote =
(SecurityServiceRemote)
ic.lookup("ejb:j-lawyer-server/j-lawyer-server-ejb//SecurityService!com.jdimension.jlawyer.services.SecurityServiceRemote");
remote.login();
Only when passing in the base64'ed and hashed password, I
successfully gets a reference to the remote interface, but calling
any business logic yields:
2023-11-26 23:41:32,329
ERROR [org.jboss.as.ejb3.invocation] (default task-1)
WFLYEJB0034: Jakarta Enterprise Beans Invocation failed on
component SecurityService for method public abstract boolean
com.jdimension.jlawyer.services.SecurityServiceRemote.login(java.lang.String,java.lang.String):
javax.ejb.EJBAccessException: WFLYEJB0364: Invocation on method:
public abstract boolean
com.jdimension.jlawyer.services.SecurityServiceRemote.login(java.lang.String,java.lang.String)
of bean: SecurityService is not allowed
Logging tells me this:
2023-11-26 23:41:32,262
TRACE [org.wildfly.security] (default I/O-5) Handling
SocketAddressCallback
2023-11-26 23:41:32,263 TRACE [org.wildfly.security] (default
I/O-5) Handling SocketAddressCallback
2023-11-26 23:41:32,263 TRACE [org.wildfly.security] (default
I/O-5) Handling MechanismInformationCallback type='SASL'
name='JBOSS-LOCAL-USER' host-name='localhost' protocol='remote'
2023-11-26 23:41:32,263 TRACE [org.wildfly.security] (default
I/O-5) Handling MechanismInformationCallback type='SASL'
name='JBOSS-LOCAL-USER' host-name='localhost' protocol='remote'
2023-11-26 23:41:32,263 TRACE [org.wildfly.security] (default
I/O-5) Creating SaslServer
[org.wildfly.security.sasl.localuser.LocalUserServer@66e25eec]
for mechanism [JBOSS-LOCAL-USER] and protocol [remote]
2023-11-26 23:41:32,263 TRACE [org.wildfly.security] (default
I/O-5) Created SaslServer
[org.wildfly.security.sasl.util.SecurityIdentitySaslServerFactory$1@62ddd6e8->org.wildfly.security.sasl.util.AuthenticationTimeoutSaslServerFactory$DelegatingTimeoutSaslServer@27df54d7->org.wildfly.security.sasl.util.AuthenticationCompleteCallbackSaslServerFactory$1@62d3e4c9->org.wildfly.security.sasl.localuser.LocalUserServer@66e25eec]
for mechanism [JBOSS-LOCAL-USER]
2023-11-26 23:41:32,271 TRACE [org.wildfly.security] (default
task-1) Handling NameCallback: authenticationName = admin
2023-11-26 23:41:32,271 TRACE [org.wildfly.security] (default
task-1) Principal assigning: [admin], pre-realm rewritten:
[admin], realm name: [local], post-realm rewritten: [admin],
realm rewritten: [admin]
2023-11-26 23:41:32,271 TRACE [org.wildfly.security] (default
task-1) Authorization failed - realm identity does not exists
2023-11-26 23:41:32,271 TRACE [org.wildfly.security] (default
task-1) Handling AuthorizeCallback: authenticationID = admin
authorizationID = admin authorized = false
2023-11-26 23:41:32,272 TRACE [org.wildfly.security.sasl.local]
(default task-1) SASL Negotiation Failed
2023-11-26 23:41:32,272 TRACE [org.wildfly.security] (default
task-1) Handling AuthenticationCompleteCallback: fail
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Handling SocketAddressCallback
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Handling SocketAddressCallback
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Handling MechanismInformationCallback type='SASL'
name='DIGEST-MD5' host-name='localhost' protocol='remote'
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Handling MechanismInformationCallback type='SASL'
name='DIGEST-MD5' host-name='localhost' protocol='remote'
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Handling AvailableRealmsCallback: realms =
[ApplicationRealm]
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Creating SaslServer
[org.wildfly.security.sasl.digest.DigestSaslServer@16b2d341] for
mechanism [DIGEST-MD5] and protocol [remote]
2023-11-26 23:41:32,276 TRACE [org.wildfly.security] (default
I/O-5) Created SaslServer
[org.wildfly.security.sasl.util.SecurityIdentitySaslServerFactory$1@1a543de9->org.wildfly.security.sasl.util.AuthenticationTimeoutSaslServerFactory$DelegatingTimeoutSaslServer@47f0ab98->org.wildfly.security.sasl.util.AuthenticationCompleteCallbackSaslServerFactory$1@3a78ea03->org.wildfly.security.sasl.digest.DigestSaslServer@16b2d341]
for mechanism [DIGEST-MD5]
2023-11-26 23:41:32,285 TRACE [org.wildfly.security] (default
task-1) Handling RealmCallback: selected = [ApplicationRealm]
2023-11-26 23:41:32,285 TRACE [org.wildfly.security] (default
task-1) Handling NameCallback: authenticationName = admin
2023-11-26 23:41:32,285 TRACE [org.wildfly.security] (default
task-1) Principal assigning: [admin], pre-realm rewritten:
[admin], realm name: [ApplicationRealm], post-realm rewritten:
[admin], realm rewritten: [admin]
2023-11-26 23:41:32,285 TRACE [org.wildfly.security] (default
task-1) Executing principalQuery select password from
security_users where principalId=? with value admin
2023-11-26 23:41:32,285 TRACE [org.wildfly.security] (default
task-1) Key Mapper: Password credential created using algorithm
column value [clear]
2023-11-26 23:41:32,285 TRACE [org.wildfly.security] (default
task-1) Executing principalQuery select role, 'Roles' from
security_roles where principalId=? with value admin
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling CredentialCallback: failed to obtain credential
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling RealmCallback: selected = [ApplicationRealm]
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling NameCallback: authenticationName = admin
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling CredentialCallback: obtained credential:
org.wildfly.security.credential.PasswordCredential@24893dcb
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Role mapping: principal [admin] -> decoded roles []
-> domain decoded roles [] -> realm mapped roles [] ->
domain mapped roles []
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Authorizing principal admin.
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Authorizing against the following attributes: [Roles]
=> [loginRole, writeAddressRole, createAddressRole,
readArchiveFileRole, createOptionGroupRole, commonReportRole,
createArchiveFileRole, writeOptionGroupRole,
removeAddressRole, confidentialReportRole, readAddressRole,
adminRole, writeArchiveFileRole, removeArchiveFileRole,
deleteOptionGroupRole, importRole]
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Authorizing against the following runtime attributes:
[Source-Address] => [127.0.0.1]
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Permission mapping: identity [admin] with roles []
implies ("org.wildfly.security.auth.permission.LoginPermission"
"") = true
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Authorization succeed
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) RunAs authorization succeed - the same identity
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling AuthorizeCallback: authenticationID = admin
authorizationID = admin authorized = true
2023-11-26 23:41:32,286 TRACE [org.wildfly.security.sasl.digest]
(default task-1) SASL Negotiation Completed
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling AuthenticationCompleteCallback: succeed
2023-11-26 23:41:32,286 TRACE [org.wildfly.security] (default
task-1) Handling SecurityIdentityCallback: identity =
SecurityIdentity{principal=admin,
securityDomain=org.wildfly.security.auth.server.SecurityDomain@83cd397,
authorizationIdentity=EMPTY,
realmInfo=RealmInfo{name='ApplicationRealm',
securityRealm=org.wildfly.security.auth.realm.jdbc.JdbcSecurityRealm@6ea53af9},
creationTime=2023-11-26T22:41:32.286637572Z}
2023-11-26 23:41:32,329 TRACE [org.wildfly.security] (default
task-1) Role mapping: principal [admin] -> decoded roles []
-> domain decoded roles [] -> realm mapped roles [] ->
domain mapped roles []
If I read the logs right, it seems to authenticate, then load
the roles, even retrieves the roles, but then says "not allowed".
At this point I am totally stuck and countless hours have not
yielded any progress.
Questions:
(1) Is the client really supposed to provide the hashed value?
In Wildfly 16, there was no such thing needed. Also, I wonder
whether that would work at all with a web module using HTTP BASIC
auth - the browser cannot do the client-side hashing. Am I doing
something wrong on a conceptional level?
(2) Why do the logs not indicate an issue, but the remote
client receives a "not allowed" exception?
(3) Any ideas whether my configuration is wrong?
Thanks all for helping!
Cheers,
Jens