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.
Related
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.
I would like to know if it is possible to make an additional query from the wildfly level after correct authentication and authorization. After logging in correctly to the database, I need to add an information record to the database (SQL) about the login date. Is it possible to do this from the xml level?
(I'm using wildfly 17, the configuration works below)
<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.security.protocol" value="ssl"/>
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="java.naming.security.authentication" value="simple"/>
<module-option name="java.naming.provider.url" value="ldaps://xxx.xxx.xxx:636"/>
<module-option name="bindDN" value="cn=xxx,dc=xxx,dc=xxx"/>
<module-option name="bindCredential" value="xxx"/>
<module-option name="baseCtxDN" value="ou=xxx,dc=xxx,dc=xxx"/>
<module-option name="baseFilter" value="(uid={0})"/>
<module-option name="roleAttributeID" value="cn"/>
<module-option name="searchScope" value="SUBTREE_SCOPE"/>
<module-option name="allowEmptyPasswords" value="true"/>
<module-option name="defaultRole" value="xxx"/>
</login-module>
<login-module code="Database" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="dsJndiName" value="java:/xxxJNDI"/>
<module-option name="rolesQuery" value="query for roles)"/>
</login-module>
</authentication>
You can't configure it from within the PicketBox (old security module of JBoss/Wildfly) Database LoginModule. You will have to write your own custom LoginModule (see e.g. here: http://www.mastertheboss.com/jboss-server/jboss-security/creating-a-custom-jboss-login-module)
Maybe it is also an opportunity to migrate to the new security module Elytron which no longer provides LoginModules but supports a jdbc-realm where you can directly query against a DB. (see here https://docs.jboss.org/author/display/WFLY/Database+Authentication+Migration)
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.
Perhaps I could ask you if you guys if you could help me out how to configure JBoss 6 with a custom auth-method?
We are moving from JBoss 5 to JBoss 6.
In 5 we got a web.xml with this login-tag
<login-config>
<auth-method>OURSSO</auth-method>
<realm-name>oursso</realm-name>
</login-config>
And a jboss-app.xml
<security-domain>oursso</security-domain>
And in login-config.xml
<application-policy name="oursso">
<authentication>
<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="sufficient">
<module-option name="usersProperties">props/mycomp-users.properties</module-option>
<module-option name="rolesProperties">props/mycomp-roles.properties</module-option>
<module-option name="unauthenticatedIdentity">anonymous</module-option>
</login-module>
<login-module code="rsa.ps.ct.jboss.jaas.OURSSOServerLoginModule" flag="required">
<module-option name="connectionProvider">rsa.access.manager:type=Service,name=RuntimeAPIClient</module-option>
</login-module>
<login-module code="org.jboss.security.auth.spi.RoleMappingLoginModule" flag="optional">
<module-option name="rolesProperties">props/mycomp-rolemapping-roles.properties</module-option>
<module-option name="replaceRole">true</module-option>
</login-module>
</authentication>
</application-policy>
And in war-deployers-jboss-beans.xml
<property name="authenticators">
<map class="java.util.Properties" keyClass="java.lang.String" valueClass="java.lang.String">
<entry>
<key>BASIC</key>
<value>org.apache.catalina.authenticator.BasicAuthenticator</value>
</entry>
...
<entry>
<key>OURSSO</key>
<value>com.mycomp.OurssoAuthenticator</value>
</entry>
</map>
</property>
It seems like the auth-method in web.xml must match a key in war-deployers-jboss-beans.xml. How is the same accomplish in JBoss 6?
Best regards
Fredrik
I added these to my standalone-full.xml
<security-domain name="my-security-domain" cache-type="default">
<authentication>
<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
<module-option name="usersProperties" value="file://${jboss.server.config.dir}/users.properties"/>
<module-option name="rolesProperties" value="file://${jboss.server.config.dir}/roles.properties"/>
</login-module>
</authentication>
</security-domain>
In the file users.properties
123=qwe
456=asd
In the file roles.properties
123=role.A,role.B
456=role.B
In one of my beans in the server I annotate it with
#Stateless
#SecurityDomain("my-security-domain")
#RolesAllowed("role.A")
public class SecureStatelessBean extends SecureReturnAString implements SecureStatelessBeanLocal, SecureStatelessBeanRemote
{
...
In my web-application (running in the same server) I lookup the bean and login with this code
#EJB(lookup = "java:global/ejbtest-app/ejbtest-server-0.0.1-SNAPSHOT/SecureStatelessBean!se.albinoni.ejbtest.stateless.SecureStatelessBeanRemote")
private SecureStatelessBeanRemote secureStatelessBeanRemote;
...
private static SecurityClient getClientLogin() throws Exception
{
final SecurityClient client = SecurityClientFactory.getSecurityClient();
client.setSimple("123", "qwe");
return client;
}
...
SecurityClient client = getClientLogin();
client.login();
secureStatelessBeanRemote.someMethod();
Think that was it.
But I still have not found out how to do the same from a remote standalone app.
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.