Setup LDAP server and configure a LDAP Realm on WildFly with secured connection

For Enterprise Application, it is very common to found Application Server and LDAP integration. LDAP provides centralize authentication and authorization for application access. So in this post, I will demonstrate how to setup LDAP server by using Openldap server and Integrate with Wildfly Application Server. For my environment, I have use CentOS 6 to install Open LDAP server.

Install LDAP by CentOS 6 and OpenLDAP

First, you need to set up hostname add below.
#vi /etc/hosts
151.80.166.51 ldap.itstikk.pro  ldap
Next is
#vi /etc/sysconfig/network
HOSTNAME="ldap.itstikk.pro"
NETWORKING="yes"
GATEWAYDEV="venet0"
NETWORKING_IPV6="yes"
IPV6_DEFAULTDEV="venet0"
Create ldap user and add to ldap group
#adduser ldap
#passwd ldap
#usermod -a -G ldap, wheel ldap

you need to install required package for LDAP server
#yum -y install openldap openldap-clients openldap-servers
After install the packages, in your machine you should have below
[root@ldap ~]# ls -la /etc/openldap/slapd.d/cn\=config
total 88
drwxr-x--- 3 ldap ldap  4096 Apr 17 00:42 .
drwxr-x--- 3 ldap ldap  4096 Apr 17 05:27 ..
drwxr-x--- 2 ldap ldap  4096 Apr 16 09:03 cn=schema
-rw-r----- 1 ldap ldap 59398 Apr 16 09:03 cn=schema.ldif
-rw-r----- 1 ldap ldap   596 Apr 16 09:03 olcDatabase={-1}frontend.ldif
-rw-r----- 1 ldap ldap   663 Apr 16 09:03 olcDatabase={0}config.ldif
-rw------- 1 ldap ldap   739 Apr 16 09:42 olcDatabase={1}monitor.ldif
-rw------- 1 ldap ldap  1401 Apr 17 00:42 olcDatabase={2}bdb.ldif

here you needs to change 2 files
-rw------- 1 ldap ldap   739 Apr 16 09:42 olcDatabase={1}monitor.ldif
-rw------- 1 ldap ldap  1401 Apr 17 00:42 olcDatabase={2}bdb.ldif
but don't directly edit these files,  you need create ldif file and use those files to update olcDatabase={1}monitor.ldif and olcDatabase={2}bdb.ldif. I will create file as below. But first, you need to create passworld for LDAP server. Now start your ldap server.
#service slapd start
#chkconfig slapd on

Open Firewall Port

you need open firewall port for ldap to allow connection on that port
#vi /etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state NEW -m tcp -p tcp --dport 389 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 636 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 9830 -j ACCEPT

COMMIT
restart your firewall service
#service iptables restart

Edit olcDatabase={2}bdb.ldif

First, Create password of LDAP server
#slappasswd
New password: SecretLDAPRootPass2015
Re-enter new password: SecretLDAPRootPass2015
{SSHA}1pgok6qWn24lpBkVreTDboTr81rg4QC6
you need to note {SSHA}1pgok6qWn24lpBkVreTDboTr81rg4QC6, Next is to create bdb.ldif file.

#cd $HOME
#mkdir ldap

#cd ldap
#vi bdb.ldif
Edit as below
dn: olcDatabase={2}bdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=itstikk,d=pcro

dn: olcDatabase={2}bdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=ldapadm,dc=itstikk,dc=pro

dn: olcDatabase={2}bdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}1pgok6qWn24lpBkVreTDboTr81rg4QC6
Next is apply your change to olcDatabase={2}bdb.ldif by following command.
#ldapmodify -Y EXTERNAL -H ldapi:/// -f bdb.ldif

Update olcDatabase={1}monitor.ldif

To modify olcDatabase={1}monitor.ldif, you need to create monitor.ldif as below
#vi monitor
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *  by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read  by dn.base="cn=ldapadm,dc=itstikk,dc=pro" read  by * none
Next is to apply modification to olcDatabase={1}monitor.ldif
#ldapmodify -Y EXTERNAL -H ldapi:/// -f monitor.ldif

Import Database and Schema

First import database
# cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
# chown -R ldap:ldap /var/lib/ldap
import schemas
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

Create base entry for the domain

to create base entry for the domain, create as base.ldif and add to ldap.
#vi base.ldif
dn: dc=itstikk,dc=pro
dc: itstikk
objectClass: top
objectClass: domain

dn: cn=ldapadm,dc=itstikk,dc=pro
objectClass: organizationalRole
cn: ldapadm
description: LDAP Aministrator

dn: ou=People,dc=itstikk,dc=pro
objectClass: organizationalUnit
ou: People

dn: ou=Users,dc=itstikk,dc=pro
objectClass: organizationalUnit
ou: Users

dn: ou=Groups,dc=itstikk,dc=pro
objectClass: organizationalUnit
ou: Groups
add base entry to your LDAP server
# ldapadd -x -W -D "cn=ldapadm,dc=itstikk,dc=pro" -f base.ldif
Enter LDAP Password:
Next is to create user entry
#vi usr01.ldif
dn: uid=usr01,ou=Users,dc=itstikk,dc=pro
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: usr01
uid: usr01
uidNumber: 1005
gidNumber: 1005
homeDirectory: /home/usr01
userPassword: {SSHA}8vaPDSghO1WKLjhBhdupJZR1xjELjt8N
loginShell: /bin/bash
gecos: usr01
shadowLastChange: 0
shadowMax: 0
shadowWarning: 0
add user to LDAP server
#ldapadd  -x -D -W "cn=ldapadm,dc=itstikk,dc=pro" -f  usr01.ldif
#ldappasswd -s myUser01@Password -W -D "cn=ldapadm,dc=itstikk,dc=pro" -x "uid=usr01,ou=Users,dc=itstikk,dc=pro"

Setup LDAPS with SSL/TLS

To establish secure connection for LDAP by SSL/TLS. you need to create keystore and certificate. you can use openssl to create those file. first is to create private key.
#cd /etc/pki/tls/certs/
#make ldaps.key
#openssl rsa -in ldaps.key -out ldaps.key
Next is to create certificate
#make ldaps.csr
#openssl req -x509 -days 3650 -in ldaps.csr -key ldaps.key -out ldaps.crt
After you create private key and certificates you should have below.
#ls
Makefile       ca-bundle.trust.crt  ldaps.csr  make-dummy-cert
ca-bundle.crt  ldaps.crt            ldaps.key  renew-dummy-cert
copy CA certificate, private key and certificate you have created to /etc/openldap/certs/
#cp ca-bundle.crt /etc/openldap/certs/
# mv ldaps.* /etc/openldap/certs/
# ls /etc/openldap/certs/
ca-bundle.crt  key3.db    ldaps.csr  password
cert8.db       ldaps.crt  ldaps.key  secmod.db
# chown ldap:ldap /etc/openldap/certs/ldaps.*

Update cn=config.ldif

Create ssl.ldif as below and apply to ldap server
dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/openldap/certs/ca-bundle.crt
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/ldaps.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/ldaps.key
Apply change
# ldapadd -Y EXTERNAL -H ldapi:// -f ssl.ldif
Edit configuration file to enable LDAPS and restart
#vi /etc/sysconfig/ldap
SLAPD_LDAPS=yes
#vi /etc/openldap/ldap.conf
TLS_REQCERT never
#service slapd restart
#netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      609/sshd
tcp        0      0 0.0.0.0:636                 0.0.0.0:*                   LISTEN      10569/slapd
tcp        0      0 0.0.0.0:389                 0.0.0.0:*                   LISTEN      10569/slapd
tcp        0      0 :::22                       :::*                        LISTEN      609/sshd
tcp        0      0 :::636                      :::*                        LISTEN      10569/slapd
tcp        0      0 :::389                      :::*                        LISTEN      10569/slapd

Disable Anonymous login

It is very important to not allow any anonymous login. By default, openldap allow anonymous login, to disable that feature, you need to modify cn=config.ldif by create below ldif as
#cd ldap
#vim disable.ldif
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon
-

dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcRequires

olcRequires: authc
and update ldif to cn=config.ldif
#ldapmodify -Y EXTERNAL -H ldapi:// -f disable.ldif

Create Client to Connect to LDAPS

next is to create Client to test connection. But first you need to import your java certificate. if you don't you can use certified certificate.
>cd C:\Program Files\Java\jre1.8.0_121\lib\security
>keytool -import -file ldaps.crt -keystore cacerts -storpass changeit
>cd C:\Program Files\Java\jdk1.8.0_121\jre\lib\security
>keytool -import -file ldaps.crt -keystore cacerts -storpass changeit
create java client as below.
package pro.itstikk.ldap;

import java.util.Hashtable;

import javax.naming.AuthenticationException;
import javax.naming.AuthenticationNotSupportedException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public class Main {

private static final String url = "ldaps://ldap.itstikk.pro:636";

public static void main(String[] args) {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
// Specify SSL
env.put(Context.SECURITY_PROTOCOL, "ssl");

env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=usr01,ou=Users,dc=itstikk,dc=pro");
env.put(Context.SECURITY_CREDENTIALS, "password");
 
try {
    DirContext ctx = new InitialDirContext(env);
    System.out.println("connected");
    System.out.println(ctx.getEnvironment());
     
    // do something useful with the context...
 
    ctx.close();
 
} catch (AuthenticationNotSupportedException ex) {
ex.printStackTrace();
    System.out.println("The authentication is not supported by the server");
} catch (AuthenticationException ex) {
ex.printStackTrace();
    System.out.println("incorrect password or username");
} catch (NamingException ex) {
ex.printStackTrace();
    System.out.println("error when trying to create the context");
}
}
}

Integrate Wildfly with Opendlap with secured connection

It is very easy to integrate wildyfly with LDAP. You just need to standalone.xml as below
<security-realms>
<security-realm name="LDAPRealm">
<authentication>
<ldap connection="ldapconnection" base-dn="ou=Users,dc=itstikk,dc=pro">
<username-filter attribute="uid"/>
</ldap>
</authentication>
</security-realm>
    <security-realm name="ManagementRealm">
        <authentication>
            <local default-user="$local" skip-group-loading="true"/>
            <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
        </authentication>
        <authorization map-groups-to-roles="false">
            <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
        </authorization>
    </security-realm>
    <security-realm name="ApplicationRealm">
        <server-identities>
            <ssl>
                <keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
            </ssl>
        </server-identities>
        <authentication>
            <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
            <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
        </authentication>
        <authorization>
            <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
        </authorization>
    </security-realm>
</security-realms>
<outbound-connections>
<ldap name="ldapconnection" url="ldaps://ldap.itstikk.pro:636" search-dn="cn=ldapadm,dc=itstikk,dc=pro" search-credential="qf48d8uv"/>
</outbound-connections>

Apply the realm to management-interface
<management-interfaces>
    <http-interface security-realm="LDAPRealm" http-upgrade-enabled="true">
        <socket-binding http="management-http"/>
    </http-interface>
</management-interfaces>
start you server then you should be able to access to the server by username and password you have register in the LDAP Server.
Fig 1. Login Dialog

Fig 2. Management Console


Secured Web Application by Using LDAP Authentication

First you need to create roles in the ldap server.
#vim role.ldif
dn: ou=RealmRoles,dc=itstikk,dc=pro
objectclass: top
objectclass: organizationalUnit
ou: RealmRoles


dn: cn=wildfly-user,ou=RealmRoles,dc=itstikk,dc=pro
objectclass: top
objectclass: groupOfNames
cn: wildfly-user
member: uid=usr01,ou=Users,dc=itstikk,dc=pro
Add role.ldif to the ldap server
#ldapadd -x -D"cn=ldapadm,dc=itstikk,dc=pro" -W -H ldapi:/// -f roles.ldif
Enter LDAP Password:
Next is to edit standalone.xml and add below to security-domains
<security-domain name="LDAPAuth">
  <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="ldaps://ldap.itstikk.pro:636"/>
  <module-option name="java.naming.security.authentication" value="simple"/>
  <module-option name="bindDN" value="uid=usr01,ou=Users,dc=itstikk,dc=pro"/>
  <module-option name="bindCredential" value="qf48d8uv"/>
  <module-option name="baseCtxDN" value="ou=Users,dc=itstikk,dc=pro"/>
  <module-option name="baseFilter" value="(uid={0})"/>
  <module-option name="rolesCtxDN" value="ou=RealmRoles,dc=itstikk,dc=pro"/>
  <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="true"/>
</login-module>
  </authentication> 
</security-domain>
Then you need to add below to web.xml in your web application
<security-constraint>
    <web-resource-collection>
        <web-resource-name>HtmlAuth</web-resource-name>
        <description>application security constraints</description>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>wildfly-user</role-name>
    </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>LDAPAuth realm</realm-name>
</login-config>
<security-role>
    <role-name>wildfly-user</role-name>
</security-role>
Then create jboss-web.xml in the WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
       <security-domain>java:/jaas/LDAPAuth</security-domain>
</jboss-web>
Now restart wildfly and try to login.

Utilize Wildfly login-form authentication.

Basic authentication method is very simple enough. But in most application, it is common to use login form to provide user to fill out and perform log in to application.

Wildfly ( or Tomcat, servlet container) provides very easy way to enable form login authentication. What to need to is just provide login in page and error page. After that you just need to edit web.xml.
In my application, I have create login.xhtml and error.xhtml as below.

Fig 03. Login and Error Page
The detail of login and error page is coded as below.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"> 

<h:head></h:head> 
<body> 
<form action="j_security_check" method="post">
<p>
Username : <input type="text" name="j_username"/>
</p>
<p>
Password : <input type="password" name="j_password"/>
</p>
<input type="submit" value="submit"/>
</form>
</body> 
</html>

And for error.xhtml, I have just put as following code.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:rich="http://richfaces.org/rich"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:h="http://java.sun.com/jsf/html"> 

<h:head></h:head> 
<body>
    <rich:panel>
        <f:facet name="header">
        Write your own custom rich components with built-in AJAX support
        </f:facet>
                <p>
<h:outputText value="Login Error" />        
                </p>
<p>
<a href="index.xhtml">Log in</a>
</p>
</rich:panel>
</body> 
</html>


for the web.xml, you just can simply put as following.

aaaaaa
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>java-ee-01-web</display-name>
  <welcome-file-list>
    <welcome-file>index.xhtml</welcome-file>
  </welcome-file-list>
   <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  <context-param>
    <param-name>org.richfaces.skin</param-name>
    <param-value>blueSky</param-value>
  </context-param>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
   <security-constraint>
       <web-resource-collection>
           <web-resource-name>HtmlAuth</web-resource-name>
           <description>application security constraints</description>
           <url-pattern>/*</url-pattern>
           <http-method>GET</http-method>
           <http-method>POST</http-method>
       </web-resource-collection>
       <auth-constraint>
           <role-name>wildfly-user</role-name>
       </auth-constraint>
   </security-constraint>
   <login-config>
       <auth-method>FORM</auth-method>
           <realm-name>LDAPAuth realm</realm-name>
   <form-login-config>
    <form-login-page>/login.xhtml</form-login-page>
    <form-error-page>/error.xhtml</form-error-page>
   </form-login-config>
   </login-config>
   <security-role>
       <role-name>wildfly-user</role-name>
   </security-role>
</web-app>
Then you can test to access as below.

Fig 04. Wildlfly Login

Fig 05. After login

Reference





No comments:

Post a Comment

Feature Recently

Running Wildfly Application Server in Domain Mode

  Wildfly application server provides two modes of how to run application one wildfly application server. It is very simple if you run your ...

Most Views