I have password encrypted by Argon2id in database.
How can I change my configuration to let JBoss know that it have to use Argon2 to verify password?
standalone.xml
<security-domain name="databaseDomain">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:/datasources/hotel"/>
<module-option name="principalsQuery" value="select password from users where login=?"/>
<module-option name="rolesQuery" value="SELECT employee.position,'Roles' FROM users, employee WHERE employee.id=users.employeeId and login=?"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
web.xml
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/error.html</form-error-page>
</form-login-config>
</login-config>
jboss-web.xml
<jboss-web>
<security-domain>databaseDomain</security-domain>
</jboss-web>
I added ARGON2 with
<dependency>
<groupId>de.mkammerer</groupId>
<artifactId>argon2-jvm</artifactId>
<version>2.7</version>
</dependency>
I tried adding to standalone.xml
<module-option name="hashAlgorithm" value="ARGON2id"/>
but it didn't work and I wasn't that suprised about this. My form is calling to j_security_check
You need to implement your own login module, sounds scary, but actually it's not.
Find out which version of Picketbox you're Wildfly is bundled with - look in the modules/system/layers/base/org/picketbox/main directory. I.e. for WF 21 the version of Picketbox is 5.0.3.Final
Add the Picketbox library as a provided-scoped dependency to your project
Implement your custom login module by extending the org.jboss.security.auth.spi.DatabaseServerLoginModule class and overriding the convertRawPassword method - this is where you need to convert the user's input into the Argon2 form
Provide the full class name in the code parameter in your login module configuration in standalone.xml. Wildfly will pick it from your deployment and use your implementation instead of the default one.
This should work.
Related
I am trying to find a way to migrate our security solution from WildFly 22 to WildFly 26, where the legacy way with custom login modules is no longer supported. I found for example this blog post https://wildfly-security.github.io/wildfly-elytron/blog/jaas-realm/ suggesting to use jaas-realm, but I am not able to configure it to be honest.
What exactly should I do, if I want to migrate this example? This was in earlier versions of WildFly defined like this:
<security-domain name="my-form-auth" cache-type="default">
<authentication>
<login-module name="FirstLoginModule" code="my.first.lm.FirstLoginModule" flag="sufficient">
<module-option name="config.filename" value=".first_lm_props" />
</login-module>
<login-module name="SecondLoginModule" code="my.second.lm.SecondLoginModule" flag="sufficient">
<module-option name="config.filename" value=".second_lm_props" />
</login-module>
</authentication>
</security-domain>
Actual code of these login modules was available to WildFly as a dependency of deployed application.
So far, I managed to set configuration of WildFly 26 like this (with basic scenario - just one login module):
<security-domains>
...
<security-domain name="mySD" default-realm="myJaasRealm" permission-mapper="default-permission-mapper">
<realm name="myJaasRealm"/>
</security-domain>
</security-domains>
<security-realms>
...
<jaas-realm name="myJaasRealm" entry="myEntry" module="my.module.with.lm">
<file path="D:\APP\Wildfly\wildfly-26.0.1.Final\bin\elytron\JAAS-login-module.conf"/>
</jaas-realm>
</security-realms>
....
<http>
<http-authentication-factory name="example-loginconfig-http-auth" security-domain="mySD" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="FORM">
<mechanism-realm realm-name="myJaasRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
</http>
....
<subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
...
<application-security-domains>
<application-security-domain name="other" http-authentication-factory="example-loginconfig-http-auth"/>
</application-security-domains>
</subsystem>
JAAS-login-module.conf:
MyEntry {
my.first.lm.FirstLoginModule sufficient;
};
jboss-web.xml:
<jboss-web>
<context-root>${context-root}</context-root>
<security-domain>other</security-domain>
</jboss-web>
Still, I am not able to get it to work.
<jboss-web>
<context-root>${context-root}</context-root>
<security-domain>mySD</security-domain>
</jboss-web>
In web.xml also you have to configure your realm name like
<login-config>
<auth-method>FORM</auth-method>
<realm-name>myJaasRealm</realm-name>
</login-config>
I'm developing a webapp using Spring MVC, Maven and Wildfly. I'm not using the web.xml to configure the datasources. My config is applied through Java classes.
I need to access the LDAP server info (url, base dn, username, password), which is in the standalone.xml located in the Wildfly configuration folder of the server, from the Java Spring Security configuration class. For security issues, I'm not allowed to code the LDAP info in the application.properties file. I don't know how to do it without using the web.xml. Any suggestions?
Here's what I have so far...
--standalone.xml (LDAP Config)
<security-domain name="MYDOMAIN">
<authentication>
<login-module code="LdapExtended" flag="required">
<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
<module-option name="java.naming.provider.url" value="ldap://myurl:000/"/>
<module-option name="java.naming.security.authentication" value="simple"/>
<module-option name="bindDN" value="mybinddn"/>
<module-option name="bindCredential" value="00000000000"/>
<module-option name="baseCtxDN" value="DC=bla,DC=bla,DC=bla"/>
<module-option name="baseFilter" value="(sAMAccountName={0})"/>
<module-option name="rolesCtxDN" value="OU=Ludopatia,DC=iplyc,DC=gov,DC=ar"/>
<module-option name="roleFilter" value="(member={1})"/>
<module-option name="roleAttributeID" value="cn"/>
<module-option name="searchScope" value="ONELEVEL_SCOPE"/>
<module-option name="allowEmptyPasswords" value="false"/>
</login-module>
</authentication>
</security-domain>
--SecurityConfiguration.java
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${ldap.urls}")
private String ldapUrls;
#Value("${ldap.base.dn}")
private String ldapBaseDn;
#Value("${ldap.username}")
private String ldapUsername;
#Value("${ldap.password}")
private String ldapPassword;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.ldapAuthentication()
.userSearchFilter("sAMAccountName={0}")
.groupSearchBase("ou=Ludopatia")
.groupSearchFilter("member={0}")
.contextSource()
.url(ldapUrls+ldapBaseDn)
.managerDn(ldapUsername)
.managerPassword(ldapPassword);
}
}
--pom.xml (part in which the wildfly-maven-plugin is set)
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>1.0.1.Final</version>
<configuration>
<jboss-home>${wildfly.home}</jboss-home>
<modules-path>${wildfly.home}/modules</modules-path>
<server-config>standalone.xml</server-config>
<filename>${project.build.finalName}.war</filename>
</configuration>
</plugin>
--application.properties
ldap.urls=ldap://myurl:000/
ldap.base.dn=dc=bla,dc=bla,dc=bla
ldap.username=mybinddn
ldap.password=000000000000
Configured like this, it works perfectly. But I need to remove the LDAP info from the application.properties and directly take it from the standalone.xml, without using the web.xml.
Thanks in advance for your help.
You can directly set these values from WILDFLY console as system properties and they will be automatically populated into the standalone.xml file.
For that, kindly follow the following steps:
Enable the management console by adding an admin user (add-user.bat for Windows/add-user.sh for Linux).
After adding a user, access management console (http://127.0.0.1:9990/management).
It will prompt for username and password. Enter username and password.
Navigate to Configuration -> System properties and add as many as properties you want. They will be displayed in the configuration file.
<system-properties>
<property name="ldap.urls" value="ldap://myurl:000/"/>
<property name="ldap.base.dn" value="dc=bla,dc=bla,dc=bla"/>
<property name="ldap.username" value="mybinddn"/>
<property name="ldap.password" value="000000000000"/>
</system-properties>
To access these properties in your code, you need to access them as system properties such as
String ldapUsername= System.getProperty("ldap.username");
String ldapPassword= System.getProperty("ldap.password");
The only drawback of this approach is that the values of these properties will be visible all the time that's why I suggested vault project.
One more suggestion is to provide the encrypted values for ldap configuration and decrypt them after reading.
I have two groups of users - employees and members, employees are in LDAP server and members are in properties file. I need to configure both of them in a single security domain, which means I need to get authentication from different login modules - employees from LdapExtLoginModule, and, members from UsersRoles login module. Something like this:
<security-domain name="EmpMem" cache-type="default">
<authentication>
<login-module code="UsersRoles" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="usersProperties" value="app-users.properties"/>
<module-option name="rolesProperties" value="app-roles.properties"/>
</login-module>
<login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="java.naming.provider.url" value="ldap://ha-adds-global.xxx.com:3268"/>
<module-option name="bindDN" value="CN=prodjbsvc,OU=ServiceAccounts,OU=NOPOL,dc=eagle,dc=xxx,dc=com"/>
<module-option name="bindCredential" value="XQtU#1lc"/>
<module-option name="baseCtxDN" value="dc=eagle,dc=xxx,dc=com"/>
<module-option name="baseFilter" value="(sAMAccountName={0})"/>
<module-option name="rolesCtxDN" value="ou=COSAs,dc=eagle,dc=xxx,dc=com"/>
<module-option name="roleFilter" value="(sAMAccountName={0})"/>
<module-option name="roleAttributeID" value="memberOf"/>
<module-option name="roleAttributeIsDN" value="true"/>
<module-option name="roleNameAttributeID" value="cn"/>
<module-option name="roleRecursion" value="-1"/>
<module-option name="searchScope" value="SUBTREE_SCOPE"/>
<module-option name="allowEmptyPasswords" value="false"/>
<module-option name="java.naming.referral" value="follow"/>
</login-module>
</authentication>
</security-domain>
I know that there is a login module called Password Stacking which can chain multiple login modules together, but looks like LdapExtLoginModule doesn't support that? Please suggest a way to accomplish this.
My Requirement:
When the user is employee, he gets authenticated from LDAP server and should be able to to access employee resources (java packages/classes)only, and when the user is member, he gets authenticated from properties file and should be able to access member resources (java packages/classes) only.
If sufficient for your needs use LdapLoginModule instead of LdapExtLoginModule.
Password Stacking is supported by that LoginModule.
However, judging by your Requirement I don't think Password Stacking is what you're looking for ...
If a previous module configured for password stacking has authenticated the user, all the other stacking modules will consider the user authenticated and only attempt to provide a set of roles for the authorization step.
Seems like a User will either be a employee or a member? If so, use "sufficient" as the LoginModule "flag" attribute
sufficient : The login module is not required to succeed. If it does succeed, control immediately returns to the application. If it fails, authentication continues down the login stack.
I have some strange behaviour, and I am not sure why. I have two apps that work well in Tomcat 7, but do not behave correctly in Wildfly 8.2 and 9Beta2.
In Tomcat, I can log in on one app, go to the 2nd app and I can see my login state is correct, log out in the 2nd app, return to the 1st app, and I am logged out there. This is correct.
In Tomcat, I can log in on one app, go to the 2nd app and I can see my login state is correct, return to the 1st app, log out in the 1st app, return to the 2nd app, and I am logged out there. This is correct.
In Wildfly, I log in to the 1st app, go to the 2nd app and I can see my login state is correct, log out of the 2nd app, return to the 1st app, but I am still logged in. Incorrect.
In Wildfly, I log in to the 1st app, go to the 2nd app and I can see my login state is correct, return to the 1st app, log out of the 1st app, go to the 2nd app, and I am logged out there as well. Correct.
Why does Wildfly fail the first test (3. above)?
Any pointers would be greatly appreciated.
Here are some of the extracts from my files:
From standalone.xml
<security-realm name="DataSourceRealm">
<authentication>
<jaas name="app"/>
</authentication>
</security-realm>
<security-domain name="app" cache-type="default">
<authentication>
<login-module code="Database" flag="requisite">
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="dsJndiName" value="jdbc/icedb"/>
<module-option name="principalsQuery" value="select PASSWORD from WSV_USR_PRFL_DEF where USR_PRFL_DEF_ID=?"/>
<module-option name="rolesQuery" value="select USR_GRP_DEF_ID, 'Roles' from WSV_USR_GRP_MAP where USR_PRFL_DEF_ID = ?"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
<login-module code="RoleMapping" flag="requisite">
<module-option name="rolesProperties" value="file:${jboss.server.config.dir}/app.properties"/>
<module-option name="replaceRole" value="false"/>
</login-module>
</authentication>
</security-domain>
<subsystem xmlns="urn:jboss:domain:undertow:2.0">
<buffer-cache name="default"/>
<server name="default-server">
<http-listener name="default" socket-binding="http"/>
<host name="default-host" alias="localhost">
<single-sign-on path="/"/>
.....
from the various applications (WAR) jboss-web.xml:
<jboss-web>
<context-root>/APPNAME</context-root>
<security-domain flushOnSessionInvalidation="true">app</security-domain>
</jboss-web>
From my logout.java:
#WebServlet(name="logout", urlPatterns={"/lo.xhtml"}, loadOnStartup=2)
public class Logout extends HttpServlet{
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (request.getSession(false) != null) {
HttpSession ses = request.getSession(false);
ses.invalidate(); // remove session.
}
request.logout();
response.sendRedirect(request.getContextPath());
}
}
I've set up a login-module in my JBoss 7.1 server using LDAP like that:
<login-module code="org.jboss.security.auth.spi.LdapLoginModule" flag="required">
<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
<module-option name="java.naming.provider.url" value="ldap://ldap.domain.com:port"/>
<module-option name="java.naming.security.authentication" value="simple"/>
<module-option name="principalDNPrefix" value="uid="/>
<module-option name="principalDNSuffix" value=",ou=peoples,dc=domain,dc=com"/>
<module-option name="searchTimeLimit" value="5000"/>
<module-option name="searchScope" value="ONELEVEL"/>
</login-module>
But, sometimes, this LDAP server maintained by my company crashes and I like to specify an alternative LDAP server (who exists) in my configuration.
Is that possible?
Thanks
You may be able to use a space separated list:
ie:
<module-option name="java.naming.provider.url" value="ldap://ldap.domain.com:port ldap://ldap2.domain.com:port"/>
See: JNDI LDAP & LDAPS URLs
Consider using an LDAP Directory Proxy Server to manage the high-availability of the LDAP service. This method removes the dependency of the application server requiring knowledge of more than one specific IP address or hostname - resulting in a simpler configuration that is easier to use, maintain, and operate.