Verwaltung von LDAP Accounts und Gruppen
Peter Hormanns
2019-07-23 8c1f3d7a4077d7105008d58f3bcbd0f20c41c4b9
mostly working
2 files added
20 files modified
378 ■■■■■ changed files
.gitignore 1 ●●●● patch | view | raw | blame | history
etc/jetty.xml 2 ●●● patch | view | raw | blame | history
etc/realm.properties 2 ●●● patch | view | raw | blame | history
pom.xml 5 ●●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/ldap/DirectoryServiceRunner.java 63 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/server/LDAPUriParser.java 37 ●●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/server/WebappDirectoryServer.java 23 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/GroupServlet.java 12 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/GroupsServlet.java 4 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/LogoutServlet.java 2 ●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/Messages.java 2 ●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/ProfileServlet.java 12 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/ResetPasswordServlet.java 20 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/UserServlet.java 16 ●●●● patch | view | raw | blame | history
src/main/java/de/jalin/ldapadmin/web/UsersServlet.java 4 ●●●● patch | view | raw | blame | history
src/main/resources/config.properties 4 ●●●● patch | view | raw | blame | history
src/main/webapp/WEB-INF/web.xml 24 ●●●● patch | view | raw | blame | history
src/main/webapp/group.jsp 2 ●●● patch | view | raw | blame | history
src/main/webapp/login.jsp 58 ●●●● patch | view | raw | blame | history
src/main/webapp/loginfail.jsp 66 ●●●● patch | view | raw | blame | history
src/main/webapp/user.jsp 2 ●●● patch | view | raw | blame | history
src/test/java/de/jalin/ldapadmin/server/TestLDAPUriParser.java 17 ●●●●● patch | view | raw | blame | history
.gitignore
@@ -1,4 +1,5 @@
target/
nb-configuration.xml
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
etc/jetty.xml
@@ -3,7 +3,7 @@
    <Call name="addBean">
      <Arg>
        <New class="org.eclipse.jetty.security.HashLoginService">
          <Set name="name">Administration Area</Set>
          <Set name="name">LDAP</Set>
          <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
        </New>
      </Arg>
etc/realm.properties
@@ -1 +1 @@
peter: Test123,login,admins
admin: Test123,login,admins
pom.xml
@@ -54,11 +54,6 @@
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.4.1</version>
        </dependency>
src/main/java/de/jalin/ldapadmin/ldap/DirectoryServiceRunner.java
@@ -3,9 +3,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.sf.ehcache.Cache;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.name.Dn;
@@ -24,16 +22,40 @@
public class DirectoryServiceRunner {
    private static DirectoryServiceRunner serviceRunner = null;
    public static void assureServiceRunning(final String name) throws DirectoryServiceException {
        if (serviceRunner == null) {
            final String dnName = "dc=" + name + ",dc=example,dc=com";
            try {
                serviceRunner = new DirectoryServiceRunner("example", dnName, "127.0.0.1", "10389", false);
            } catch (Exception e) {
                throw new DirectoryServiceException(e);
            }
        }
    }
    public static void main(final String[] args) {
        final String dnString = "dc=" + args[0] + ",dc=example,dc=com";
        final String ip = args[1];
        final String port = args[2];
        try {
            final DirectoryServiceRunner ads = new DirectoryServiceRunner("example", dnString, ip, port, false);
            final Entry result = ads.service.getAdminSession().lookup(new Dn(dnString));
            System.out.println("Found entry : " + result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }
    private final DirectoryService service;
    public DirectoryServiceRunner(final String partition, final String dnString, final String ip, final String port) throws Exception {
    public DirectoryServiceRunner(final String partition, final String dnString, final String ip, final String port, final boolean useTLS) throws Exception {
        this.service = initService(partition);
        addPartition("ou=config", "config");
        addPartition(dnString, partition);
        this.service.startup();
        loadData();
        startServer(ip, port);
        startServer(ip, port, useTLS);
    }
    private DirectoryService initService(final String partition) throws Exception {
@@ -58,13 +80,19 @@
        service.addPartition(partition);
    }
    private void startServer(final String ip, final String port) throws Exception {
    private void startServer(final String ip, final String port, final boolean useTLS) throws Exception {
        final LdapServer ldapServer = new LdapServer();
        ldapServer.setTransports(new TcpTransport(ip, Integer.parseInt(port)));
        final TcpTransport tcpTransport = new TcpTransport(ip, Integer.parseInt(port));
        tcpTransport.enableSSL(useTLS);
        ldapServer.setTransports(tcpTransport);
        ldapServer.setDirectoryService(service);
        ldapServer.start();
    }
    public void shutdown() throws Exception {
        service.shutdown();
    }
    private void loadData() {
        final File ldifDirectory = new File("ldif");
        if (ldifDirectory.exists() && ldifDirectory.isDirectory()) {
@@ -80,29 +108,6 @@
        }
    }
    public static void assureServiceRunning(final String name) throws DirectoryServiceException {
        if (serviceRunner == null) {
            final String dnName = "dc=" + name + ",dc=example,dc=com";
            try {
                serviceRunner = new DirectoryServiceRunner("example", dnName, "127.0.0.1", "10389");
            } catch (Exception e) {
                throw new DirectoryServiceException(e);
            }
        }
    }
    public static void main(final String[] args) {
        final String dnString = "dc=" + args[0] + ",dc=example,dc=com";
        final String ip = args[1];
        final String port = args[2];
        try {
            final DirectoryServiceRunner ads = new DirectoryServiceRunner("example", dnString, ip, port);
            final Entry result = ads.service.getAdminSession().lookup(new Dn(dnString));
            System.out.println("Found entry : " + result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }
    static class DirectoryServiceException extends Exception {
src/main/java/de/jalin/ldapadmin/server/LDAPUriParser.java
New file
@@ -0,0 +1,37 @@
package de.jalin.ldapadmin.server;
public class LDAPUriParser {
    private final boolean useTLS;
    private final String dn;
    private final String port;
    private final String host;
    public LDAPUriParser (final String uri) {
        final String[] uriParts = uri.split("\\/");
        final String protocol = uriParts[0];
        final String hostAndPort = uriParts[2];
        final String[] hostAndPortParts = hostAndPort.split(":");
        host = hostAndPortParts[0];
        port = hostAndPortParts[1];
        dn = uriParts[3];
        useTLS = protocol.toLowerCase().startsWith("ldaps");
    }
    public String getDn() {
        return dn;
    }
    public String getHost() {
        return host;
    }
    public String getPort() {
        return port;
    }
    public boolean isUseTLS() {
        return useTLS;
    }
}
src/main/java/de/jalin/ldapadmin/server/WebappDirectoryServer.java
@@ -1,20 +1,37 @@
package de.jalin.ldapadmin.server;
import de.jalin.ldapadmin.ldap.DirectoryServiceRunner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class WebappDirectoryServer implements ServletContextListener {
    private DirectoryServiceRunner directoryServer;
    @Override
    public void contextInitialized(final ServletContextEvent evt) {
        final ServletContext ctx = evt.getServletContext();
        final String uri = ctx.getInitParameter("uri");
        try {
            final ServletContext ctx = evt.getServletContext();
            final String uri = ctx.getInitParameter("uri");
            final LDAPUriParser uriParser = new LDAPUriParser(uri);
            directoryServer = new DirectoryServiceRunner("main", uriParser.getDn(), uriParser.getHost(), uriParser.getPort(), uriParser.isUseTLS());
        } catch (Exception ex) {
            Logger.getLogger(WebappDirectoryServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    @Override
    public void contextDestroyed(final ServletContextEvent evt) {
        try {
            directoryServer.shutdown();
        } catch (Exception ex) {
            Logger.getLogger(WebappDirectoryServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
src/main/java/de/jalin/ldapadmin/web/GroupServlet.java
@@ -20,7 +20,7 @@
import de.jalin.ldapadmin.ldap.NoGroupMembersException;
import de.jalin.ldapadmin.ldap.UsersDAO;
@WebServlet(name = "LdapGroup", urlPatterns = {"/group/*"})
@WebServlet(name = "LdapGroup", urlPatterns = {"/group/*"}, loadOnStartup = 1)
public class GroupServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
@@ -56,7 +56,7 @@
        } catch (LDAPSessionException e) {
            throwServletException(httpSession, e);
        }
        req.getRequestDispatcher("/WEB-INF/group.jsp").forward(req, resp); //$NON-NLS-1$
        req.getRequestDispatcher("/group.jsp").forward(req, resp); //$NON-NLS-1$
    }
    @Override
@@ -98,7 +98,7 @@
                if (grp.getMembers().isEmpty()) {
                    httpSession.setAttribute("group", grp); //$NON-NLS-1$
                    httpSession.setAttribute("errormessage", messages.getString("GroupServlet.no_empty_group")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/group.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/group.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                }
                try {
@@ -106,7 +106,7 @@
                } catch (NoGroupMembersException e) {
                    httpSession.setAttribute("group", grp); //$NON-NLS-1$
                    httpSession.setAttribute("errormessage", messages.getString("GroupServlet.no_empty_group")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/group.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/group.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                }
            }
@@ -122,7 +122,7 @@
                if (grp.getMembers().isEmpty()) {
                    httpSession.setAttribute("group", grp); //$NON-NLS-1$
                    httpSession.setAttribute("errormessage", messages.getString("GroupServlet.no_empty_group")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/group.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/group.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                }
                try {
@@ -130,7 +130,7 @@
                } catch (AlreadyBoundException e) {
                    httpSession.setAttribute("group", grp); //$NON-NLS-1$
                    httpSession.setAttribute("errormessage", messages.getString("GroupServlet.group_exists")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/group.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/group.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                }
                resp.sendRedirect(req.getContextPath() + req.getServletPath() + "/" + grp.getDn()); //$NON-NLS-1$
src/main/java/de/jalin/ldapadmin/web/GroupsServlet.java
@@ -14,7 +14,7 @@
import de.jalin.ldapadmin.ldap.LDAPSessionException;
import de.jalin.ldapadmin.ldap.UsersDAO;
@WebServlet(name = "LdapGroups", urlPatterns = {"/groups"})
@WebServlet(name = "LdapGroups", urlPatterns = {"/groups"}, loadOnStartup = 1)
public class GroupsServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
@@ -33,7 +33,7 @@
        } catch (LDAPSessionException e) {
            throwServletException(httpSession, e);
        }
        req.getRequestDispatcher("/WEB-INF/groups.jsp").forward(req, resp); //$NON-NLS-1$
        req.getRequestDispatcher("/groups.jsp").forward(req, resp); //$NON-NLS-1$
    }
}
src/main/java/de/jalin/ldapadmin/web/LogoutServlet.java
@@ -8,7 +8,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(name = "Logout", urlPatterns = {"/logout"})
@WebServlet(name = "Logout", urlPatterns = {"/logout"}, loadOnStartup = 1)
public class LogoutServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
src/main/java/de/jalin/ldapadmin/web/Messages.java
@@ -6,7 +6,7 @@
public class Messages {
    private static final String BUNDLE_NAME = "de.jalin.ldapadmin.admin.web.messages"; //$NON-NLS-1$
    private static final String BUNDLE_NAME = "de.jalin.ldapadmin.web.messages"; //$NON-NLS-1$
    private final ResourceBundle resourceBundle;
src/main/java/de/jalin/ldapadmin/web/ProfileServlet.java
@@ -18,7 +18,7 @@
import de.jalin.ldapadmin.ldap.SimplePasswordException;
import de.jalin.ldapadmin.ldap.UsersDAO;
@WebServlet(name = "LdapProfile", urlPatterns = {"/profile", "/profile/*"})
@WebServlet(name = "LdapProfile", urlPatterns = {"/profile", "/profile/*"}, loadOnStartup = 1)
public class ProfileServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
@@ -52,7 +52,7 @@
        } catch (LDAPSessionException e) {
            throwServletException(httpSession, e);
        }
        req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
        req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
    }
    @Override
@@ -85,12 +85,12 @@
        } catch (SimplePasswordException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.simple_password")); //$NON-NLS-1$ //$NON-NLS-2$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
            return;
        } catch (ValidationException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("ProfileServlet.inputfield") + e.getFieldname() + " " + e.getCondition()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
            return;
        }
        try {
@@ -102,14 +102,14 @@
                httpSession.setAttribute("successmessage", messages.getString("ProfileServlet.password_changed")); //$NON-NLS-1$ //$NON-NLS-2$
                httpSession.setAttribute("operation", "profile"); //$NON-NLS-1$ //$NON-NLS-2$
                httpSession.setAttribute("user", usr); //$NON-NLS-1$
                req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp);
                req.getRequestDispatcher("/user.jsp").forward(req, resp);
            }
        } catch (LDAPSessionException e) {
            final String excMessage = e.getMessage();
            if (excMessage != null && excMessage.contains("invalid reuse of password")) { //$NON-NLS-1$
                httpSession.setAttribute("user", usr); //$NON-NLS-1$
                httpSession.setAttribute("errormessage", messages.getString("ProfileServlet.invalid_reuse")); //$NON-NLS-1$ //$NON-NLS-2$
                req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
                req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
                return;
            }
            throwServletException(httpSession, e);
src/main/java/de/jalin/ldapadmin/web/ResetPasswordServlet.java
@@ -26,7 +26,7 @@
import de.jalin.ldapadmin.ldap.SimplePasswordException;
import de.jalin.ldapadmin.ldap.UsersDAO;
@WebServlet(name = "ResetPassword", urlPatterns = {"/passwordreset"})
@WebServlet(name = "ResetPassword", urlPatterns = {"/passwordreset"}, loadOnStartup = 1)
public class ResetPasswordServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
@@ -57,17 +57,17 @@
                    final UsersDAO usrDAO = new UsersDAO(ldapSession);
                    final User usr = usrDAO.read("uid=" + uidAndEMail[0] + ",ou=users,"); //$NON-NLS-1$ //$NON-NLS-2$
                    httpSession.setAttribute("user", usr); //$NON-NLS-1$
                    req.getRequestDispatcher("/WEB-INF/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                } catch (LDAPSessionException e) {
                    LOG.warning("no valid password reset request");
                    httpSession.setAttribute("errormessage", new Messages(req.getLocale()).getString("ResetPasswordServlet.no_valid_passwordreset_request")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                }
            }
        }
        req.getRequestDispatcher("/WEB-INF/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
        req.getRequestDispatcher("/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
    }
    @Override
@@ -85,26 +85,26 @@
            if (password1 != null && !password1.isEmpty()) {
                if (password2 == null || !password2.equals(password1)) {
                    httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.passwords_donot_match")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                } else {
                    try {
                        sessUsr.setAndValidatePassword(password1);
                        usrDAO.update(sessUsr);
                        httpSession.setAttribute("successmessage", messages.getString("ResetPasswordServlet.password_changed")); //$NON-NLS-1$ //$NON-NLS-2$
                        req.getRequestDispatcher("/WEB-INF/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                        req.getRequestDispatcher("/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                        return;
                    } catch (SimplePasswordException e) {
                        httpSession.setAttribute("user", sessUsr); //$NON-NLS-1$
                        httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.simple_password")); //$NON-NLS-1$ //$NON-NLS-2$
                        req.getRequestDispatcher("/WEB-INF/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                        req.getRequestDispatcher("/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                        return;
                    } catch (LDAPSessionException e) {
                        final String excMessage = e.getMessage();
                        if (excMessage != null && excMessage.contains("invalid reuse of password")) { //$NON-NLS-1$
                            httpSession.setAttribute("user", sessUsr); //$NON-NLS-1$
                            httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.invalid_password_reuse")); //$NON-NLS-1$ //$NON-NLS-2$
                            req.getRequestDispatcher("/WEB-INF/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                            req.getRequestDispatcher("/new-password.jsp").forward(req, resp); //$NON-NLS-1$
                            return;
                        }
                        throwServletException(httpSession, e);
@@ -139,7 +139,7 @@
                }
                if (login.isEmpty() || email.isEmpty()) {
                    httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.error_sending_password_reset")); //$NON-NLS-1$ //$NON-NLS-2$
                    req.getRequestDispatcher("/WEB-INF/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
                    req.getRequestDispatcher("/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
                    return;
                }
                printStream.println(login + ":" + email); //$NON-NLS-1$
@@ -156,7 +156,7 @@
        } catch (LDAPSessionException | IOException e) {
            LOG.severe("smtp problem");
            httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.error_sending_password_reset")); //$NON-NLS-1$ //$NON-NLS-2$
            req.getRequestDispatcher("/WEB-INF/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/reset-password.jsp").forward(req, resp); //$NON-NLS-1$
            return;
        }
        httpSession.invalidate();
src/main/java/de/jalin/ldapadmin/web/UserServlet.java
@@ -23,7 +23,7 @@
import de.jalin.ldapadmin.ldap.SimplePasswordException;
import de.jalin.ldapadmin.ldap.UsersDAO;
@WebServlet(name = "LdapUser", urlPatterns = {"/user/*"})
@WebServlet(name = "LdapUser", urlPatterns = {"/user/*"}, loadOnStartup = 1)
public class UserServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
@@ -59,7 +59,7 @@
        } catch (LDAPSessionException e) {
            throwServletException(httpSession, e);
        }
        req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
        req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
    }
    @Override
@@ -126,12 +126,12 @@
        } catch (SimplePasswordException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("ResetPasswordServlet.simple_password")); //$NON-NLS-1$ //$NON-NLS-2$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
            return;
        } catch (ValidationException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("UserServlet.input_field") + " \"" + e.getFieldname() + "\" " + e.getCondition()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
            return;
        }
        final GroupsDAO groupsDAO = new GroupsDAO(ldapSession);
@@ -168,22 +168,22 @@
            if (excMessage != null && excMessage.contains("invalid reuse of password")) { //$NON-NLS-1$
                httpSession.setAttribute("user", usr); //$NON-NLS-1$
                httpSession.setAttribute("errormessage", messages.getString("UserServlet.invalid_password_reuse")); //$NON-NLS-1$ //$NON-NLS-2$
                req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
                req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
                return;
            }
            throwServletException(httpSession, e);
        } catch (NoGroupMembersException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("UserServlet.group_last_member")); //$NON-NLS-1$ //$NON-NLS-2$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
        } catch (RequiredAttributeException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("UserServlet.the_input_field") + " " + e.getFieldname() + " " + messages.getString("UserServlet.is_required")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
        } catch (AlreadyBoundException e) {
            httpSession.setAttribute("user", usr); //$NON-NLS-1$
            httpSession.setAttribute("errormessage", messages.getString("UserServlet.user_exists")); //$NON-NLS-1$ //$NON-NLS-2$
            req.getRequestDispatcher("/WEB-INF/user.jsp").forward(req, resp); //$NON-NLS-1$
            req.getRequestDispatcher("/user.jsp").forward(req, resp); //$NON-NLS-1$
        }
    }
src/main/java/de/jalin/ldapadmin/web/UsersServlet.java
@@ -15,7 +15,7 @@
import de.jalin.ldapadmin.ldap.LDAPSessionException;
import de.jalin.ldapadmin.ldap.UsersDAO;
@WebServlet(name = "LdapUsers", urlPatterns = {"/users"})
@WebServlet(name = "LdapUsers", urlPatterns = {"/users"}, loadOnStartup = 1)
public class UsersServlet extends AbstractLDAPServlet {
    private static final long serialVersionUID = 1L;
@@ -35,7 +35,7 @@
        } catch (LDAPSessionException e) {
            throwServletException(httpSession, e);
        }
        req.getRequestDispatcher("/WEB-INF/users.jsp").forward(req, resp); //$NON-NLS-1$
        req.getRequestDispatcher("/users.jsp").forward(req, resp); //$NON-NLS-1$
    }
}
src/main/resources/config.properties
@@ -1,4 +1,4 @@
provider.url=ldap://localhost:10389/dc=example,dc=com
provider.url=ldap://localhost:10389/dc=domain,dc=example,dc=com
security.principal=uid=admin,ou=system
security.password=secret
security.password=streng-geheim
smtp.host=localhost
src/main/webapp/WEB-INF/web.xml
@@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <session-config>
        <tracking-mode>COOKIE</tracking-mode>
    </session-config>
    <context-param>
        <param-name>uri</param-name>
        <param-value>ldap://localhost:10389/dc=domain,dc=example,dc=com</param-value>
    </context-param>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/css/*</url-pattern>
@@ -15,11 +14,9 @@
        <url-pattern>*.css</url-pattern>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>/contact.jsp</welcome-file>
    </welcome-file-list>
    <error-page>
        <error-code>403</error-code>
        <location>/access-denied.jsp</location>
@@ -32,7 +29,6 @@
        <error-code>503</error-code>
        <location>/servlet-exception.jsp</location>
    </error-page>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Public access</web-resource-name>
@@ -47,7 +43,6 @@
            <url-pattern>/servlet-exception.jsp</url-pattern>
        </web-resource-collection>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Profile Area</web-resource-name>
@@ -60,7 +55,6 @@
            <role-name>login</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Administrative Area</web-resource-name>
@@ -73,22 +67,18 @@
            <role-name>admins</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>Administration Area</realm-name>
        <realm-name>LDAP</realm-name>
        <form-login-config>
            <form-login-page>/login.jsp</form-login-page>
            <form-error-page>/loginfail.jsp</form-error-page>
        </form-login-config>
    </login-config>
    <security-role>
        <role-name>admins</role-name>
    </security-role>
    <security-role>
        <role-name>login</role-name>
    </security-role>
</web-app>
</web-app>
src/main/webapp/group.jsp
@@ -50,7 +50,7 @@
                        <div class="col-sm-9" id ="membership">
                            <c:forEach items="${users}" var="userentry" >
                                <div class="checkbox">
                                    <jsp:useBean id="checker" class="de.jalin.ldapadmin.admin.beans.MembershipCheck" />
                                    <jsp:useBean id="checker" class="de.jalin.ldapadmin.beans.MembershipCheck" />
                                    <jsp:setProperty property="user" name="checker" value="${userentry.value}" />
                                    <jsp:setProperty property="group" name="checker" value="${group}" />
                                    <label><input type="checkbox" id="${userentry.value.login}" name="check_user_${userentry.value.login}" ${checker.checked}>${userentry.value.firstname} ${userentry.value.lastname} (${userentry.value.login})</label>
src/main/webapp/login.jsp
@@ -6,39 +6,39 @@
<html lang="{language}">
<jsp:include page="template/header.jsp"/>
<body>
    <jsp:include page="template/empty-navbar.jsp"/>
    <jsp:include page="template/empty-navbar.jsp"/>
    <!-- Page Content -->
    <c:url var="formaction" value="j_security_check" />
    <c:url var="passwordreset" value="/passwordreset" />
    <c:url var="formaction" value="j_security_check" />
    <c:url var="passwordreset" value="/passwordreset" />
    <div class="container">
        <h1><fmt:message key="login.title"/></h1>
        <h1><fmt:message key="login.title"/></h1>
        <div class="control-group col-sm-8 additional-space-top">
            <form class="form-horizontal" method="post" action="${formaction}">
                <fieldset class="">
                    <div class="form-group">
                        <label for="j_username" class="col-sm-4 control-label"><fmt:message key="login.username"/></label>
                        <div class="col-sm-8">
                            <input
                                type="text" class="form-control" id="j_username" name="j_username"
                                value="" placeholder="Login name">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="j_password" class="col-sm-4 control-label"><fmt:message key="login.password"/></label>
                        <div class="col-sm-8">
                            <input
                                type="password" class="form-control" id="j_password" name="j_password"
                                value="" placeholder="Password">
                        </div>
                    </div>
                    <button type="submit" class="col-sm-offset-4 btn btn-primary additional-space-top"><fmt:message key="login.submit"/></button>
                    <div class="form-group additional-space-top">
                        <a href="${passwordreset}" class="col-sm-offset-4"><fmt:message key="login.reset.password"/></a>
                    </div>
                </fieldset>
            </form>
            <form class="form-horizontal" method="post" action="${formaction}">
                <fieldset class="">
                    <div class="form-group">
                        <label for="j_username" class="col-sm-4 control-label"><fmt:message key="login.username"/></label>
                        <div class="col-sm-8">
                            <input
                                type="text" class="form-control" id="j_username" name="j_username"
                                value="" placeholder="Login name">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="j_password" class="col-sm-4 control-label"><fmt:message key="login.password"/></label>
                        <div class="col-sm-8">
                            <input
                                type="password" class="form-control" id="j_password" name="j_password"
                                value="" placeholder="Password">
                        </div>
                    </div>
                    <button type="submit" class="col-sm-offset-4 btn btn-primary additional-space-top"><fmt:message key="login.submit"/></button>
                    <div class="form-group additional-space-top">
                        <a href="${passwordreset}" class="col-sm-offset-4"><fmt:message key="login.reset.password"/></a>
                    </div>
                </fieldset>
            </form>
        </div>
    </div>
    </div>
    <jsp:include page="template/footer.jsp"/>
</body>
</html>
src/main/webapp/loginfail.jsp
@@ -6,43 +6,43 @@
<html lang="{language}">
<jsp:include page="template/header.jsp"/>
<body>
    <jsp:include page="template/empty-navbar.jsp"/>
    <jsp:include page="template/empty-navbar.jsp"/>
    <!-- Page Content -->
    <c:url var="formaction" value="j_security_check" />
    <c:url var="passwordreset" value="/passwordreset" />
    <c:url var="formaction" value="j_security_check" />
    <c:url var="passwordreset" value="/passwordreset" />
    <div class="container">
        <h1><fmt:message key="login.title"/></h1>
        <div class="alert">
              <a class="close" data-dismiss="alert">×</a>
              <strong><fmt:message key="login.error.title"/></strong><fmt:message key="login.error.message"/>
        </div>
        <h1><fmt:message key="login.title"/></h1>
        <div class="alert">
            <a class="close" data-dismiss="alert">×</a>
            <strong><fmt:message key="login.error.title"/></strong> <fmt:message key="login.error.message"/>
        </div>
        <div class="control-group col-sm-6 additional-space-top">
            <form class="form-horizontal" method="post" action="${formaction}">
                <fieldset class="">
                    <div class="form-group">
                        <label for="j_username" class="col-sm-4 control-label"><fmt:message key="login.username"/></label>
                        <div class="col-sm-8">
                            <input
                                type="text" class="form-control" id="j_username" name="j_username"
                                value="" placeholder="Login name">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="j_password" class="col-sm-4 control-label"><fmt:message key="login.password"/></label>
                        <div class="col-sm-8">
                            <input
                                type="password" class="form-control" id="j_password" name="j_password"
                                value="" placeholder="Password">
                        </div>
                    </div>
                    <button type="submit" class="col-sm-offset-4 btn btn-primary additional-space-top"><fmt:message key="login.submit"/></button>
                    <div class="form-group additional-space-top">
                        <a href="${passwordreset}" class="col-sm-offset-4"><fmt:message key="login.reset.password"/></a>
                    </div>
                </fieldset>
            </form>
            <form class="form-horizontal" method="post" action="${formaction}">
                <fieldset class="">
                    <div class="form-group">
                        <label for="j_username" class="col-sm-4 control-label"><fmt:message key="login.username"/></label>
                        <div class="col-sm-8">
                            <input
                                type="text" class="form-control" id="j_username" name="j_username"
                                value="" placeholder="Login name">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="j_password" class="col-sm-4 control-label"><fmt:message key="login.password"/></label>
                        <div class="col-sm-8">
                            <input
                                type="password" class="form-control" id="j_password" name="j_password"
                                value="" placeholder="Password">
                        </div>
                    </div>
                    <button type="submit" class="col-sm-offset-4 btn btn-primary additional-space-top"><fmt:message key="login.submit"/></button>
                    <div class="form-group additional-space-top">
                        <a href="${passwordreset}" class="col-sm-offset-4"><fmt:message key="login.reset.password"/></a>
                    </div>
                </fieldset>
            </form>
        </div>
    </div>
    </div>
    <jsp:include page="template/footer.jsp"/>
</body>
</html>
src/main/webapp/user.jsp
@@ -128,7 +128,7 @@
                            <div class="col-sm-9" id ="membership">
                                <c:forEach items="${groups}" var="groupentry" >
                                    <div class="checkbox">
                                        <jsp:useBean id="checker" class="de.jalin.ldapadmin.admin.beans.MembershipCheck" />
                                        <jsp:useBean id="checker" class="de.jalin.ldapadmin.beans.MembershipCheck" />
                                        <jsp:setProperty property="user" name="checker" value="${user}" />
                                        <jsp:setProperty property="group" name="checker" value="${groupentry.value}" />
                                        <label><input type="checkbox" id="${groupentry.value.name}" name="check_group_${groupentry.value.name}" ${checker.checked}>${groupentry.value.name}</label>
src/test/java/de/jalin/ldapadmin/server/TestLDAPUriParser.java
New file
@@ -0,0 +1,17 @@
package de.jalin.ldapadmin.server;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class TestLDAPUriParser {
    @Test
    public void testLDAPUriParser() {
        final LDAPUriParser ldapUriParser = new LDAPUriParser("ldap://localhost:10389/dc=example,dc=com");
        assertEquals("localhost", ldapUriParser.getHost());
        assertEquals("10389", ldapUriParser.getPort());
        assertEquals("dc=example,dc=com", ldapUriParser.getDn());
        assertEquals(false, ldapUriParser.isUseTLS());
    }
}