add csv import

This commit is contained in:
Peter Hormanns 2022-06-02 14:28:31 +02:00
parent ffa11c0e58
commit 90c690b5dd
7 changed files with 392 additions and 108 deletions

1
etc/sample.csv Normal file
View File

@ -0,0 +1 @@
"Max Muster","max.muster@example.com","Max","Muster"
1 Max Muster max.muster@example.com Max Muster

218
pom.xml
View File

@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
@ -8,113 +9,118 @@
<version>1.0.2</version>
<name>LDAP Admin Webapp</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<env>dev</env>
</properties>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<env>dev</env>
</properties>
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<env>test</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version>
</dependency>
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<env>test</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-service</artifactId>
<version>2.0.0.AM26</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-service</artifactId>
<version>2.0.0.AM26</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<archiveClasses>false</archiveClasses>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.19.v20190610</version>
<configuration>
<jettyXml>etc/jetty.xml</jettyXml>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgument></compilerArgument>
</configuration>
</plugin>
</plugins>
<finalName>ldapadmin</finalName>
</build>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<archiveClasses>false</archiveClasses>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.19.v20190610</version>
<configuration>
<jettyXml>etc/jetty.xml</jettyXml>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgument></compilerArgument>
</configuration>
</plugin>
</plugins>
<finalName>ldapadmin</finalName>
</build>
</project>

View File

@ -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) {
@ -153,6 +155,10 @@ public class LDAPSession {
}
}
public String getSessionInfo() {
return connectString;
}
private void createOrgUnitNodesIfNotExist() throws LDAPSessionException {
try {
final BasicAttributes usersAttributes = new BasicAttributes();

View File

@ -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;
}
}

View File

@ -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<String,User> 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);
}
}

View File

@ -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<String> 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);
}
}

View File

@ -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");
}
}
}