diff --git a/README.md b/README.md index 6ede063..0320873 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Simple all-in-one LDAP server (wrapped [ApacheDS](http://directory.apache.org/ap You don't need any configuration files to get it working. Just launch the JAR and that's it. +Server data are not persisted, they just live in memory. + ## Download Download latest tag from [GitHub releases](https://github.com/kwart/ldap-server/releases) @@ -25,7 +27,9 @@ You can simply build the software yourself. You should have [git](http://git-scm.com/) installed - $ git clone git://github.com/kwart/ldap-server.git +``` +git clone git://github.com/kwart/ldap-server.git +``` or you can download [current sources as a zip file](https://github.com/kwart/ldap-server/archive/master.zip) @@ -33,73 +37,100 @@ or you can download [current sources as a zip file](https://github.com/kwart/lda You need to have [Maven](http://maven.apache.org/) installed - $ cd ldap-server - $ mvn clean package +```bash +mvn clean package +``` ### How to run it - $ java -jar ldap-server.jar [data.ldif] +```bash +java -jar ldap-server.jar [data.ldif] +``` #### Help - $ java -jar ldap-server.jar --help - The ldap-server is a simple LDAP server implementation based on ApacheDS. It - creates one user partition with root 'dc=jboss,dc=org'. - - Usage: java -jar ldap-server.jar [options] [LDIFs to import] - Options: - --bind, -b - takes [bindAddress] as a parameter and binds the LDAP server on the - address - Default: 0.0.0.0 - --help, -h - shows this help and exits - Default: false - --port, -p - takes [portNumber] as a parameter and binds the LDAP server on that port - Default: 10389 - - Examples: - - $ java -jar ldap-server.jar users.ldif - Starts LDAP server on port 10389 (all interfaces) and imports users.ldif - - $ java -jar ldap-server.jar -b 127.0.0.1 -p 389 - Starts LDAP server on address 127.0.0.1:389 and imports default data (one user - entry 'uid=jduke,ou=Users,dc=jboss,dc=org' +``` +$ java -jar target/ldap-server.jar --help +The ldap-server is a simple LDAP server implementation based on ApacheDS. It +creates one user partition with root 'dc=jboss,dc=org'. + +Usage: java -jar ldap-server.jar [options] [LDIFs to import] + Options: + --allow-anonymous, -a + allows anonymous bind to the server + Default: false + --bind, -b + takes [bindAddress] as a parameter and binds the LDAP server on the + address + Default: 0.0.0.0 + --help, -h + shows this help and exits + Default: false + --port, -p + takes [portNumber] as a parameter and binds the LDAP server on that port + Default: 10389 + --ssl-enabled-ciphersuite, -scs + takes [sslCipherSuite] as argument and enables it for 'ldaps'. Can be + used multiple times. + --ssl-enabled-protocol, -sep + takes [sslProtocolName] as argument and enables it for 'ldaps'. Can be + used multiple times. If the argument is not provided following are used: + TLSv1, TLSv1.1, TLSv1.2 + --ssl-need-client-auth, -snc + enables SSL 'needClientAuth' flag + Default: false + --ssl-port, -sp + adds SSL transport layer (i.e. 'ldaps' protocol). It takes [portNumber] + as a parameter and binds the LDAPs server on the port + --ssl-want-client-auth, -swc + enables SSL 'wantClientAuth' flag + Default: false + +Examples: + +$ java -jar ldap-server.jar users.ldif +Starts LDAP server on port 10389 (all interfaces) and imports users.ldif + +$ java -jar ldap-server.jar -b 127.0.0.1 -p 389 +Starts LDAP server on address 127.0.0.1:389 and imports default data (one user +entry 'uid=jduke,ou=Users,dc=jboss,dc=org' +``` ## Default LDIF - dn: dc=jboss,dc=org - dc: jboss - objectClass: top - objectClass: domain - - dn: ou=Users,dc=jboss,dc=org - objectClass: organizationalUnit - objectClass: top - ou: Users - - dn: uid=jduke,ou=Users,dc=jboss,dc=org - objectClass: top - objectClass: person - objectClass: inetOrgPerson - cn: Java Duke - sn: duke - uid: jduke - userPassword: theduke - - dn: ou=Roles,dc=jboss,dc=org - objectclass: top - objectclass: organizationalUnit - ou: Roles - - dn: cn=Admin,ou=Roles,dc=jboss,dc=org - objectClass: top - objectClass: groupOfNames - cn: Admin - member: uid=jduke,ou=Users,dc=jboss,dc=org - +``` +version: 1 + +dn: dc=jboss,dc=org +dc: jboss +objectClass: top +objectClass: domain + +dn: ou=Users,dc=jboss,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Users + +dn: uid=jduke,ou=Users,dc=jboss,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +cn: Java Duke +sn: duke +uid: jduke +userPassword: theduke + +dn: ou=Roles,dc=jboss,dc=org +objectclass: top +objectclass: organizationalUnit +ou: Roles + +dn: cn=Admin,ou=Roles,dc=jboss,dc=org +objectClass: top +objectClass: groupOfNames +cn: Admin +member: uid=jduke,ou=Users,dc=jboss,dc=org +``` ## License diff --git a/src/main/java/org/jboss/test/ldap/CLIArguments.java b/src/main/java/org/jboss/test/ldap/CLIArguments.java index a761e32..6c339fb 100644 --- a/src/main/java/org/jboss/test/ldap/CLIArguments.java +++ b/src/main/java/org/jboss/test/ldap/CLIArguments.java @@ -41,7 +41,7 @@ public class CLIArguments { @Parameter(names = { "--allow-anonymous", "-a" }, description = "allows anonymous bind to the server") private boolean allowAnonymous; - + @Parameter(names = { "--port", "-p" }, description = "takes [portNumber] as a parameter and binds the LDAP server on that port") private int port = DEFAULT_PORT; @@ -50,6 +50,24 @@ public class CLIArguments { "-b" }, description = "takes [bindAddress] as a parameter and binds the LDAP server on the address") private String bindAddress = DEFAULT_ADDR; + @Parameter(names = { "--ssl-port", + "-sp" }, description = "adds SSL transport layer (i.e. 'ldaps' protocol). It takes [portNumber] as a parameter and binds the LDAPs server on the port") + private Integer sslPort = null; + + @Parameter(names = { "--ssl-need-client-auth", "-snc" }, description = "enables SSL 'needClientAuth' flag") + private boolean sslNeedClientAuth; + + @Parameter(names = { "--ssl-want-client-auth", "-swc" }, description = "enables SSL 'wantClientAuth' flag") + private boolean sslWantClientAuth; + + @Parameter(names = { "--ssl-enabled-protocol", + "-sep" }, description = "takes [sslProtocolName] as argument and enables it for 'ldaps'. Can be used multiple times." + + " If the argument is not provided following are used: TLSv1, TLSv1.1, TLSv1.2") + private List sslEnabledProtocols; + + @Parameter(names = { "--ssl-enabled-ciphersuite", "-scs" }, description = "takes [sslCipherSuite] as argument and enables it for 'ldaps'. Can be used multiple times.") + private List sslCipherSuite; + public List getLdifFiles() { return ldifFiles; } @@ -70,4 +88,24 @@ public boolean isAllowAnonymous() { return allowAnonymous; } + public Integer getSslPort() { + return sslPort; + } + + public boolean isSslNeedClientAuth() { + return sslNeedClientAuth; + } + + public boolean isSslWantClientAuth() { + return sslWantClientAuth; + } + + public List getSslEnabledProtocols() { + return sslEnabledProtocols; + } + + public List getSslCipherSuite() { + return sslCipherSuite; + } + } diff --git a/src/main/java/org/jboss/test/ldap/LdapServer.java b/src/main/java/org/jboss/test/ldap/LdapServer.java index a956cc7..29eeca2 100644 --- a/src/main/java/org/jboss/test/ldap/LdapServer.java +++ b/src/main/java/org/jboss/test/ldap/LdapServer.java @@ -60,6 +60,8 @@ public static void main(String[] args) throws Exception { jCmd.setUsageTail("Examples:\n\n" // + "$ java -jar ldap-server.jar users.ldif\n" // + " Starts LDAP server on port 10389 (all interfaces) and imports users.ldif\n\n" // + + "$ java -jar ldap-server.jar -sp 10636 users.ldif\n" // + + " Starts LDAP server on port 10389 and LDAPs on port 10636 and imports the LDIF\n\n" // + "$ java -jar ldap-server.jar -b 127.0.0.1 -p 389\n" // + " Starts LDAP server on address 127.0.0.1:389 and imports default data (one user entry 'uid=jduke,ou=Users,dc=jboss,dc=org'"); if (cliArguments.isHelp()) { @@ -88,7 +90,18 @@ public LdapServer(CLIArguments cliArguments) throws Exception { importLdif(cliArguments.getLdifFiles()); ldapServer = new org.apache.directory.server.ldap.LdapServer(); - ldapServer.setTransports(new TcpTransport(cliArguments.getBindAddress(), cliArguments.getPort())); + TcpTransport tcp = new TcpTransport(cliArguments.getBindAddress(), cliArguments.getPort()); + if (cliArguments.getSslPort() != null) { + TcpTransport ldapsTcp = new TcpTransport(cliArguments.getBindAddress(), cliArguments.getSslPort()); + ldapsTcp.setEnableSSL(true); + ldapsTcp.setEnabledProtocols(cliArguments.getSslEnabledProtocols()); + ldapsTcp.setEnabledCiphers(cliArguments.getSslCipherSuite()); + ldapsTcp.setNeedClientAuth(cliArguments.isSslNeedClientAuth()); + ldapsTcp.setWantClientAuth(cliArguments.isSslWantClientAuth()); + ldapServer.setTransports(tcp, ldapsTcp); + } else { + ldapServer.setTransports(tcp); + } ldapServer.setDirectoryService(directoryService); ldapServer.start(); @@ -101,6 +114,9 @@ public LdapServer(CLIArguments cliArguments) throws Exception { host = cliArguments.getBindAddress(); } System.out.println("URL: ldap://" + formatPossibleIpv6(host) + ":" + cliArguments.getPort()); + if (cliArguments.getSslPort() != null) { + System.out.println(" ldaps://" + formatPossibleIpv6(host) + ":" + cliArguments.getSslPort()); + } System.out.println("User DN: uid=admin,ou=system"); System.out.println("Password: secret"); System.out.println("LDAP server started in " + (System.currentTimeMillis() - startTime) + "ms"); diff --git a/src/main/java/org/jboss/test/ldap/LdapTest.java b/src/main/java/org/jboss/test/ldap/LdapTest.java index fe5415a..f2c620c 100644 --- a/src/main/java/org/jboss/test/ldap/LdapTest.java +++ b/src/main/java/org/jboss/test/ldap/LdapTest.java @@ -19,6 +19,12 @@ package org.jboss.test.ldap; +import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.Properties; import javax.naming.Context; @@ -29,6 +35,10 @@ import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509ExtendedTrustManager; /** * A simple test of running LDAP server. @@ -44,9 +54,18 @@ public class LdapTest { * * @param args * @throws NamingException + * @throws NoSuchAlgorithmException + * @throws KeyManagementException */ - public static void main(String[] args) throws NamingException { - final String ldapUrl = "ldap://[::1]:10389"; + public static void main(String[] args) throws NamingException, NoSuchAlgorithmException, KeyManagementException { + String ldapUrl = "ldap://[::1]:10389"; + + if (Boolean.parseBoolean(System.getProperty("ldaptest.ssl"))) { + SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(null, new TrustManager[] { new NoVerificationTrustManager() }, new SecureRandom()); + SSLContext.setDefault(sslCtx); + ldapUrl = "ldaps://[::1]:10636"; + } final Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, ldapUrl); @@ -54,6 +73,7 @@ public static void main(String[] args) throws NamingException { env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); env.put(Context.SECURITY_CREDENTIALS, "secret"); final LdapContext ctx = new InitialLdapContext(env, null); + // ctx.setRequestControls(null); final SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); @@ -66,4 +86,34 @@ public static void main(String[] args) throws NamingException { namingEnum.close(); ctx.close(); } + + public static class NoVerificationTrustManager extends X509ExtendedTrustManager { + + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { + } + + } }