From 4eb93bd8236e03b4f3a19af41fe98f6aaba28b35 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Sun, 13 Sep 2015 17:50:48 +0200 Subject: Add LDAP support to previously AD-only tasks --- .../taskmanager/tasks/CreateLdapConfig.java | 199 +++++++++++++++++++++ .../openslx/taskmanager/tasks/LdadpLauncher.java | 2 +- .../org/openslx/taskmanager/tasks/LdapSearch.java | 96 +++++++--- 3 files changed, 270 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/openslx/taskmanager/tasks/CreateLdapConfig.java (limited to 'src') diff --git a/src/main/java/org/openslx/taskmanager/tasks/CreateLdapConfig.java b/src/main/java/org/openslx/taskmanager/tasks/CreateLdapConfig.java new file mode 100644 index 0000000..8fb8287 --- /dev/null +++ b/src/main/java/org/openslx/taskmanager/tasks/CreateLdapConfig.java @@ -0,0 +1,199 @@ +package org.openslx.taskmanager.tasks; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.io.FileUtils; +import org.openslx.satserver.util.Archive; +import org.openslx.satserver.util.Constants; +import org.openslx.satserver.util.Exec; +import org.openslx.satserver.util.Template; +import org.openslx.satserver.util.Util; +import org.openslx.taskmanager.api.AbstractTask; + +import com.google.gson.annotations.Expose; + +public class CreateLdapConfig extends AbstractTask +{ + @Expose + private int moduleid = 0; + @Expose + private String filename = null; + @Expose + private String server = null; + @Expose + private String searchbase = null; + @Expose + private String binddn = null; + @Expose + private String bindpw = null; + @Expose + private String proxyip = null; + @Expose + private int proxyport = 0; + @Expose + private int adport = 0; + @Expose + private String home = null; + @Expose + private String fingerprint = ""; + @Expose + private boolean plainldap = false; + + private Output status = new Output(); + + @Override + protected boolean initTask() + { + // TODO: Check path is allowed + this.setStatusObject( this.status ); + if ( filename == null || server == null || searchbase == null || proxyip == null || proxyport == 0 || moduleid == 0 ) { + status.error = "Missing argument to task"; + return false; + } + if ( this.home == null ) + this.home = ""; + if ( this.binddn == null ) + this.binddn = ""; + if ( this.bindpw == null ) + this.bindpw = ""; + return true; + } + + @Override + protected boolean execute() + { + TarArchiveOutputStream outArchive = null; + String keyFile = "/opt/ldadp/configs/" + this.moduleid + ".key.pem"; + String certFile = "/opt/ldadp/configs/" + this.moduleid + ".crt.pem"; + String uri = "ldaps://" + this.proxyip + ":" + this.proxyport + "/"; + String cacertPath = "/etc/ldap-proxy.pem"; + try { + // Generate keys + { + int ret = Exec.sync( 10, "openssl", "req", + "-x509", "-new", "-newkey", "rsa:4096", "-keyout", keyFile, "-out", certFile, "-days", "5000", "-nodes", + "-subj", "/C=DE/ST=Nowhere/L=Springfield/O=Dis/CN=" + this.proxyip ); + if ( ret == -1 ) { + status.error = "openssl process didn't finish in time."; + } else if ( ret == -2 ) { + status.error = "Internal error generating certificate."; + } else if ( ret != 0 ) { + status.error = "openssl exited with code " + ret; + } + if ( ret != 0 ) + return false; + } + // ldadp config + String ldadpConf = String.format( + "[%s]\n" + + "binddn=%s\n" + + "bindpw=%s\n" + + "base=%s\n" + + "home=%s\n" + + "port=%s\n" + + "fingerprint=%s\n" + + "plainldap=%s\n" + + "[local]\n" + + "port=%s\n" + + "cert=%s\n" + + "privkey=%s\n" + + "\n", + this.server, + this.binddn, + this.bindpw, + this.searchbase, + this.home, + this.adport, + this.fingerprint, + Boolean.toString( this.plainldap ), + this.proxyport, + certFile, + keyFile ); + // Generic ldap config + final Template ldapConf = new Template( "./data/ad/ldap.conf.template" ); + ldapConf.replace( "%URI%", uri ); + ldapConf.replace( "%SEARCHBASE%", this.searchbase ); + ldapConf.replace( "%CACERT%", cacertPath ); + // sssd config + final Template sssdConf = new Template( "./data/ad/sssd.conf.template" ); + sssdConf.replace( "%URI%", uri ); + sssdConf.replace( "%SEARCHBASE%", this.searchbase ); + sssdConf.replace( "%CACERT%", cacertPath ); + String fileName = "/opt/ldadp/configs/" + this.moduleid + ".cfg"; + try { + Files.deleteIfExists( Paths.get( this.filename ) ); + } catch ( IOException e1 ) { + } + try { + FileUtils.writeStringToFile( new File( fileName ), ldadpConf, StandardCharsets.UTF_8 ); + if ( 0 != Exec.sync( 10, + "/usr/bin/sudo", + "-n", + "-u", "root", + Constants.BASEDIR + "/scripts/ldadp-setperms", + Integer.toString( this.moduleid ) ) ) + status.error = "Could not chown/chmod ldadp config!"; + } catch ( IOException e ) { + status.error = e.toString(); + return false; + } + try { + outArchive = Archive.createTarArchive( this.filename ); + } catch ( IOException e ) { + status.error = "Could not create archive at " + this.filename; + return false; + } + // The cert we just created + if ( !Archive.tarAddFile( outArchive, cacertPath, new File( certFile ), 0644 ) ) { + status.error = "Could not add ldap-proxy.pem to module"; + return false; + } + // nsswitch.conf with ldap enabled + if ( !Archive.tarAddFile( outArchive, "/etc/nsswitch.conf", new File( "./data/ad/nsswitch.conf" ), 0644 ) ) { + status.error = "Could not add nsswitch.conf to module"; + return false; + } + // All the pam.d common-XXXX files + for ( String file : new String[] { "common-auth", "common-account", "common-session", "common-session-noninteractive", "common-password" } ) { + if ( !Archive.tarAddFile( outArchive, "/etc/pam.d/" + file, new File( "./data/ad/" + file ), 0644 ) ) { + status.error = "Could not add " + file + " to module"; + return false; + } + } + // Home if present + if ( !Archive.tarAddFile( outArchive, "/opt/openslx/scripts/pam_script_mount_persistent", new File( "./data/ad/mountscript" ), 0644 ) ) { + status.error = "Could not add mount script to module"; + return false; + } + boolean ret = Archive.tarCreateFileFromString( outArchive, "/etc/ldap.conf", ldapConf.toString(), 0644 ) + && Archive.tarCreateFileFromString( outArchive, "/etc/sssd/sssd.conf", sssdConf.toString(), 0600 ) + && Archive.tarCreateSymlink( outArchive, "/etc/ldap.conf", "/etc/ldap/ldap.conf" ) + && Archive.tarCreateSymlink( outArchive, "/etc/ldap.conf", "/etc/openldap/ldap.conf" ) + && Archive.tarCreateSymlink( outArchive, "../sssd.service", "/etc/systemd/system/basic.target.wants/sssd.service" ); + if ( !ret ) { + status.error = "Could not add ldap configs to module"; + } + return ret; + } catch ( IOException e ) { + status.error = e.toString(); + return false; + } finally { + Util.multiClose( outArchive ); + } + } + + /** + * Output - contains additional status data of this task + */ + @SuppressWarnings( "unused" ) + private static class Output + { + protected String error = null; + } + +} diff --git a/src/main/java/org/openslx/taskmanager/tasks/LdadpLauncher.java b/src/main/java/org/openslx/taskmanager/tasks/LdadpLauncher.java index 73c792b..725b7ab 100644 --- a/src/main/java/org/openslx/taskmanager/tasks/LdadpLauncher.java +++ b/src/main/java/org/openslx/taskmanager/tasks/LdadpLauncher.java @@ -41,7 +41,7 @@ public class LdadpLauncher extends SystemCommandTask for ( int i = 0; i < ids.length; ++i ) { args.add( Integer.toString( this.ids[i] ) ); } - this.timeoutSeconds = 5; + this.timeoutSeconds = 8; return args.toArray( new String[ args.size() ] ); } diff --git a/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java b/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java index 37443d5..37d09d8 100644 --- a/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java +++ b/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java @@ -23,6 +23,8 @@ public class LdapSearch extends SystemCommandTask private String bindpw = null; @Expose private String username = null; + @Expose + private boolean plainldap = false; private String fifo = null; @@ -36,10 +38,14 @@ public class LdapSearch extends SystemCommandTask protected boolean initTask() { this.setStatusObject( this.status ); - if ( this.server == null || this.searchbase == null || this.binddn == null ) { + if ( this.server == null || this.searchbase == null ) { status.messages = "Missing parameter"; return false; } + if ( this.binddn == null ) + this.binddn = ""; + if ( this.bindpw == null ) + this.bindpw = ""; this.timeoutSeconds = 5; return true; } @@ -47,20 +53,20 @@ public class LdapSearch extends SystemCommandTask @Override protected String[] initCommandLine() { - if ( this.bindpw == null ) - this.bindpw = ""; - this.fifo = String.format( "/tmp/bwlp-%s-%s.ldap", System.currentTimeMillis(), new Random().nextInt() ); - File pwFile = new File( this.fifo ); - FileUtils.deleteQuietly( pwFile ); - try { - pwFile.createNewFile(); - pwFile.setReadable( false, false ); - pwFile.setReadable( true, true ); - FileUtils.writeStringToFile( pwFile, this.bindpw, StandardCharsets.UTF_8 ); - } catch ( IOException e ) { + if ( !this.bindpw.isEmpty() ) { + this.fifo = String.format( "/tmp/bwlp-%s-%s.ldap", System.currentTimeMillis(), new Random().nextInt() ); + File pwFile = new File( this.fifo ); FileUtils.deleteQuietly( pwFile ); - status.messages = e.toString(); - return null; + try { + pwFile.createNewFile(); + pwFile.setReadable( false, false ); + pwFile.setReadable( true, true ); + FileUtils.writeStringToFile( pwFile, this.bindpw, StandardCharsets.UTF_8 ); + } catch ( IOException e ) { + FileUtils.deleteQuietly( pwFile ); + status.messages = e.toString(); + return null; + } } if ( this.username == null ) { status.addMessage( "Trying to find 4 random AD users to verify everything is all right..." ); @@ -68,9 +74,34 @@ public class LdapSearch extends SystemCommandTask } else { this.getDn = true; } + String filter; + String wantedAttr; + if ( this.plainldap ) { + filter = "(&(objectClass=posixAccount)(uid=" + this.username + "))"; + wantedAttr = "uid"; + } else { + filter = "(&(objectClass=user)(objectClass=person)(sAMAccountName=" + this.username + "))"; + wantedAttr = "sAMAccountName"; + } // As we don't care about the certificate here, you might want to put TLS_REQCERT never // in /etc/ldap/ldap.conf + if ( this.binddn.isEmpty() ) { + return new String[] { + "ldapsearch", + "-x", // Simple auth + "-LLL", // No additional stuff + "-H", this.server, // Host + "-b", this.searchbase, // SB + "-l", "4", // Time limit in seconds + "-o", "nettimeout=4", + "-z", "4", // Max number of results + "-o", "ldif-wrap=no", // Turn off retarded line wrapping done by ldapsearch + filter, + wantedAttr, // Find account name + "dn" // And dn + }; + } return new String[] { "ldapsearch", "-x", // Simple auth @@ -83,8 +114,8 @@ public class LdapSearch extends SystemCommandTask "-o", "nettimeout=4", "-z", "4", // Max number of results "-o", "ldif-wrap=no", // Turn off retarded line wrapping done by ldapsearch - "(&(objectClass=user)(objectClass=person)(sAMAccountName=" + this.username + "))", - "sAMAccountName", // Find account name + filter, + wantedAttr, // Find account name "dn" // And dn }; } @@ -92,26 +123,39 @@ public class LdapSearch extends SystemCommandTask @Override protected boolean processEnded( int exitCode ) { - FileUtils.deleteQuietly( new File( this.fifo ) ); + if ( this.fifo != null ) { + FileUtils.deleteQuietly( new File( this.fifo ) ); + } if ( exitCode == 4 ) // Means size limit exceeded, ignore exitCode = 0; if ( exitCode != 0 ) status.addMessage( "Exit code is " + exitCode ); if ( exitCode == 0 && this.userCount < 4 && !this.getDn ) - status.addMessage( "Found less than 4 users. Are you sure you got the right credentials." ); + status.addMessage( "Found less than 4 users. Are you sure you got the right credentials?" ); return this.userCount >= 4 || ( this.getDn && status.dn != null ); } @Override protected void processStdOut( String line ) { - if ( line.startsWith( "sAMAccountName: " ) ) { - status.addMessage( "Found AD user " + line.substring( 16 ) + " :-)" ); - this.userCount++; - } - if ( line.startsWith( "sAMAccountName:: " ) ) { - status.addMessage( "Found AD user " + line.substring( 17 ) + " :-)" ); - this.userCount++; + if ( this.plainldap ) { + if ( line.startsWith( "uid: " ) ) { + status.addMessage( "Found LDAP user " + line.substring( 5 ) + " :-)" ); + this.userCount++; + } + if ( line.startsWith( "uid:: " ) ) { + status.addMessage( "Found LDAP user " + line.substring( 6 ) + " :-)" ); + this.userCount++; + } + } else { + if ( line.startsWith( "sAMAccountName: " ) ) { + status.addMessage( "Found AD user " + line.substring( 16 ) + " :-)" ); + this.userCount++; + } + if ( line.startsWith( "sAMAccountName:: " ) ) { + status.addMessage( "Found AD user " + line.substring( 17 ) + " :-)" ); + this.userCount++; + } } if ( this.getDn && line.startsWith( "dn: " ) ) { status.dn = line.substring( 4 ); @@ -131,7 +175,7 @@ public class LdapSearch extends SystemCommandTask private String messages = null; public String dn = null; - private void addMessage( String str ) + private synchronized void addMessage( String str ) { if ( messages == null ) { messages = str; -- cgit v1.2.3-55-g7522