diff --git a/etc/sample.csv b/etc/sample.csv
new file mode 100644
index 0000000..7acf573
--- /dev/null
+++ b/etc/sample.csv
@@ -0,0 +1 @@
+"Max Muster","max.muster@example.com","Max","Muster"
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 78bf5ae..6cdc267 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,120 +1,126 @@
-
-
+
4.0.0
de.jalin.ldapadmin
ldapadmin
war
1.0.2
LDAP Admin Webapp
-
-
- UTF-8
- UTF-8
- dev
-
-
-
- dev
-
- dev
-
-
-
- test
-
- test
-
-
-
- prod
-
- prod
-
-
-
-
-
- javax.servlet
- javax.servlet-api
- 4.0.1
- provided
-
-
- javax.servlet.jsp
- javax.servlet.jsp-api
- 2.3.3
- provided
-
-
- javax.servlet
- jstl
- 1.2
-
-
- commons-net
- commons-net
- 3.8.0
-
+
+ UTF-8
+ UTF-8
+ dev
+
+
+
+
+ dev
+
+ dev
+
+
+
+ test
+
+ test
+
+
+
+ prod
+
+ prod
+
+
+
+
- org.webjars
- bootstrap
- 3.4.1
-
-
- org.apache.directory.server
- apacheds-service
- 2.0.0.AM26
-
-
- junit
- junit
- 4.13.2
- test
-
-
+ javax.servlet
+ javax.servlet-api
+ 4.0.1
+ provided
+
+
+ javax.servlet.jsp
+ javax.servlet.jsp-api
+ 2.3.3
+ provided
+
+
+ javax.servlet
+ jstl
+ 1.2
+
+
+ commons-net
+ commons-net
+ 3.8.0
+
+
+ org.apache.commons
+ commons-csv
+ 1.9.0
+
+
+ org.webjars
+ bootstrap
+ 3.4.1
+
+
+ org.apache.directory.server
+ apacheds-service
+ 2.0.0.AM26
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
-
-
-
- src/main/resources
- false
-
-
-
-
- org.apache.maven.plugins
- maven-war-plugin
- 3.2.3
-
- false
-
-
-
- org.eclipse.jetty
- jetty-maven-plugin
- 9.4.19.v20190610
-
- etc/jetty.xml
- 10
-
- /
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.1
-
- 1.8
- 1.8
-
-
-
-
- ldapadmin
-
+
+
+
+ src/main/resources
+ false
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 3.2.3
+
+ false
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ 9.4.19.v20190610
+
+ etc/jetty.xml
+ 10
+
+ /
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 1.8
+ 1.8
+
+
+
+
+ ldapadmin
+
diff --git a/src/main/java/de/jalin/ldapadmin/ldap/LDAPSession.java b/src/main/java/de/jalin/ldapadmin/ldap/LDAPSession.java
index 1d89cfc..638ace0 100644
--- a/src/main/java/de/jalin/ldapadmin/ldap/LDAPSession.java
+++ b/src/main/java/de/jalin/ldapadmin/ldap/LDAPSession.java
@@ -21,6 +21,7 @@ import javax.naming.directory.SearchResult;
public class LDAPSession {
private InitialDirContext ctx;
+ private String connectString;
public LDAPSession(final String providerURL, final String principal, final String password) throws LDAPSessionException {
final Properties env = new Properties();
@@ -30,6 +31,7 @@ public class LDAPSession {
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, principal);
env.put(Context.SECURITY_CREDENTIALS, password);
+ connectString = providerURL;
try {
ctx = new InitialDirContext(env);
} catch (NamingException e) {
@@ -152,6 +154,10 @@ public class LDAPSession {
ctx = null;
}
}
+
+ public String getSessionInfo() {
+ return connectString;
+ }
private void createOrgUnitNodesIfNotExist() throws LDAPSessionException {
try {
diff --git a/src/main/java/de/jalin/ldapadmin/ldap/RequiredAttributeException.java b/src/main/java/de/jalin/ldapadmin/ldap/RequiredAttributeException.java
index 7c7e269..94cba36 100644
--- a/src/main/java/de/jalin/ldapadmin/ldap/RequiredAttributeException.java
+++ b/src/main/java/de/jalin/ldapadmin/ldap/RequiredAttributeException.java
@@ -7,10 +7,12 @@ public class RequiredAttributeException extends Exception {
private final String fieldname;
public RequiredAttributeException(final String fieldname) {
+ super("required attribute '" + fieldname + "' missing");
this.fieldname = fieldname;
}
public String getFieldname() {
return fieldname;
}
+
}
diff --git a/src/main/java/de/jalin/ldapadmin/tools/ImportUsersFromCSV.java b/src/main/java/de/jalin/ldapadmin/tools/ImportUsersFromCSV.java
new file mode 100644
index 0000000..5a53b20
--- /dev/null
+++ b/src/main/java/de/jalin/ldapadmin/tools/ImportUsersFromCSV.java
@@ -0,0 +1,76 @@
+package de.jalin.ldapadmin.tools;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.SortedMap;
+
+import javax.naming.NamingException;
+
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+
+import de.jalin.ldapadmin.beans.User;
+import de.jalin.ldapadmin.ldap.AlreadyBoundException;
+import de.jalin.ldapadmin.ldap.LDAPConfig;
+import de.jalin.ldapadmin.ldap.LDAPSession;
+import de.jalin.ldapadmin.ldap.LDAPSessionException;
+import de.jalin.ldapadmin.ldap.RequiredAttributeException;
+import de.jalin.ldapadmin.ldap.UsersDAO;
+
+public class ImportUsersFromCSV {
+
+ public static void main(String[] args) {
+ LDAPSession ldapSession = null;
+ if (args.length != 2) {
+ System.out.println("usage:");
+ System.out.println("ImportUsersFromCSV command csvfile");
+ System.out.println("valid commands: verfiy, import");
+ return;
+ }
+ try {
+ ldapSession = connectLDAP();
+ System.out.println("connected " + ldapSession.getSessionInfo());
+ final UsersDAO usersDAO = new UsersDAO(ldapSession);
+ final SortedMap users = usersDAO.loadUsers();
+ System.out.println("existing users: " + users.size());
+ final File csvFile = new File(args[1]);
+ final InputStreamReader csvStreamReader = new InputStreamReader(new FileInputStream(csvFile));
+ final CSVParser csvParser = CSVFormat.DEFAULT.parse(csvStreamReader);
+ for (CSVRecord record : csvParser) {
+ final String userid = record.get(0);
+ final String email = record.get(1);
+ final String firstname = record.get(2);
+ final String lastname = record.get(3);
+ System.out.println(userid + "/" + email);
+ final User user = new User(userid);
+ user.setEmail(email);
+ user.setFirstname(firstname);
+ user.setLastname(lastname);
+ user.setPassword(PasswordTool.generatePassword());
+ try {
+ usersDAO.create(user);
+ } catch (RequiredAttributeException | AlreadyBoundException e) {
+ System.err.println("user failed: " + userid + " => " + e.getLocalizedMessage());
+ }
+ }
+ } catch (LDAPSessionException | IOException e) {
+ System.err.println(e.getLocalizedMessage());
+ } finally {
+ if (ldapSession != null) {
+ try { ldapSession.close(); } catch (NamingException e) { }
+ }
+ }
+ }
+
+ private static LDAPSession connectLDAP() throws LDAPSessionException {
+ final LDAPConfig config = LDAPConfig.getConfig();
+ final String providerUrl = config.getLdapProviderUrl();
+ final String securityPrincipal = config.getLdapSecurityPrincipal();
+ final String securityPassword = config.getLdapSecurityPassword();
+ return new LDAPSession(providerUrl, securityPrincipal, securityPassword);
+ }
+
+}
diff --git a/src/main/java/de/jalin/ldapadmin/tools/PasswordGenerator.java b/src/main/java/de/jalin/ldapadmin/tools/PasswordGenerator.java
new file mode 100644
index 0000000..6b58c6e
--- /dev/null
+++ b/src/main/java/de/jalin/ldapadmin/tools/PasswordGenerator.java
@@ -0,0 +1,147 @@
+package de.jalin.ldapadmin.tools;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public final class PasswordGenerator {
+
+ private static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
+ private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final String DIGITS = "0123456789";
+ private static final String PUNCTUATION = "!@#$%&*()_+-=[]|,./?><";
+ private boolean useLower;
+ private boolean useUpper;
+ private boolean useDigits;
+ private boolean usePunctuation;
+
+ private PasswordGenerator() {
+ throw new UnsupportedOperationException("Empty constructor is not supported.");
+ }
+
+ private PasswordGenerator(PasswordGeneratorBuilder builder) {
+ this.useLower = builder.useLower;
+ this.useUpper = builder.useUpper;
+ this.useDigits = builder.useDigits;
+ this.usePunctuation = builder.usePunctuation;
+ }
+
+ public static class PasswordGeneratorBuilder {
+
+ private boolean useLower;
+ private boolean useUpper;
+ private boolean useDigits;
+ private boolean usePunctuation;
+
+ public PasswordGeneratorBuilder() {
+ this.useLower = false;
+ this.useUpper = false;
+ this.useDigits = false;
+ this.usePunctuation = false;
+ }
+
+ /**
+ * Set true in case you would like to include lower characters (abc...xyz).
+ * Default false.
+ *
+ * @param useLower true in case you would like to include lower characters
+ * (abc...xyz). Default false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useLower(boolean useLower) {
+ this.useLower = useLower;
+ return this;
+ }
+
+ /**
+ * Set true in case you would like to include upper characters (ABC...XYZ).
+ * Default false.
+ *
+ * @param useUpper true in case you would like to include upper characters
+ * (ABC...XYZ). Default false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useUpper(boolean useUpper) {
+ this.useUpper = useUpper;
+ return this;
+ }
+
+ /**
+ * Set true in case you would like to include digit characters (123..). Default
+ * false.
+ *
+ * @param useDigits true in case you would like to include digit characters
+ * (123..). Default false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useDigits(boolean useDigits) {
+ this.useDigits = useDigits;
+ return this;
+ }
+
+ /**
+ * Set true in case you would like to include punctuation characters (!@#..).
+ * Default false.
+ *
+ * @param usePunctuation true in case you would like to include punctuation
+ * characters (!@#..). Default false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder usePunctuation(boolean usePunctuation) {
+ this.usePunctuation = usePunctuation;
+ return this;
+ }
+
+ /**
+ * Get an object to use.
+ *
+ * @return the {@link gr.idrymavmela.business.lib.PasswordGenerator} object.
+ */
+ public PasswordGenerator build() {
+ return new PasswordGenerator(this);
+ }
+ }
+
+ /**
+ * This method will generate a password depending the use* properties you
+ * define. It will use the categories with a probability. It is not sure that
+ * all of the defined categories will be used.
+ *
+ * @param length the length of the password you would like to generate.
+ * @return a password that uses the categories you define when constructing the
+ * object with a probability.
+ */
+ public String generate(int length) {
+ // Argument Validation.
+ if (length <= 0) {
+ return "";
+ }
+
+ // Variables.
+ StringBuilder password = new StringBuilder(length);
+ Random random = new Random(System.nanoTime());
+
+ // Collect the categories to use.
+ List charCategories = new ArrayList<>(4);
+ if (useLower) {
+ charCategories.add(LOWER);
+ }
+ if (useUpper) {
+ charCategories.add(UPPER);
+ }
+ if (useDigits) {
+ charCategories.add(DIGITS);
+ }
+ if (usePunctuation) {
+ charCategories.add(PUNCTUATION);
+ }
+
+ // Build the password.
+ for (int i = 0; i < length; i++) {
+ String charCategory = charCategories.get(random.nextInt(charCategories.size()));
+ int position = random.nextInt(charCategory.length());
+ password.append(charCategory.charAt(position));
+ }
+ return new String(password);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/jalin/ldapadmin/tools/PasswordTool.java b/src/main/java/de/jalin/ldapadmin/tools/PasswordTool.java
new file mode 100644
index 0000000..35ea909
--- /dev/null
+++ b/src/main/java/de/jalin/ldapadmin/tools/PasswordTool.java
@@ -0,0 +1,46 @@
+package de.jalin.ldapadmin.tools;
+
+import de.jalin.ldapadmin.ldap.SimplePasswordException;
+
+public final class PasswordTool {
+
+ public static final int MIN_COMPLEXITY = 3;
+ public static final int MIN_PASSWORD_LENGTH = 6;
+
+ private static final PasswordGenerator passwordGenerator = new PasswordGenerator.PasswordGeneratorBuilder()
+ .useDigits(true)
+ .useLower(true)
+ .useUpper(true)
+ .build();
+
+ public static String generatePassword() {
+ return passwordGenerator.generate(14);
+ }
+
+ public static void checkPasswordComplexity(final String password) throws SimplePasswordException {
+ int containsLowercaseCharacter = 0;
+ int containsUppercaseCharacter = 0;
+ int containsSpecialCharacter = 0;
+ int containsDigit = 0;
+ for (int idx = 0; idx < password.length(); idx++) {
+ char chr = password.charAt(idx);
+ if (chr >= 'a' && chr <= 'z') {
+ containsLowercaseCharacter = 1;
+ } else
+ if (chr >= 'A' && chr <= 'Z') {
+ containsUppercaseCharacter = 1;
+ } else
+ if (chr >= '0' && chr <= '1') {
+ containsDigit = 1;
+ } else {
+ containsSpecialCharacter = 1;
+ }
+ }
+ int complexity = containsLowercaseCharacter + containsUppercaseCharacter
+ + containsSpecialCharacter + containsDigit;
+ if (complexity < MIN_COMPLEXITY || password.length() < MIN_PASSWORD_LENGTH) {
+ throw new SimplePasswordException("simple password");
+ }
+ }
+
+}