diff options
author | Simon Rettberg | 2014-11-18 18:40:49 +0100 |
---|---|---|
committer | Simon Rettberg | 2014-11-18 18:40:49 +0100 |
commit | ecb072b02e1a70555db0fdf4ed47375d3080a074 (patch) | |
tree | 75db05621458eee14a96ff2d825a30072eb06e40 | |
parent | Added class ProxyHandler for for configuring proxy settings system wide once ... (diff) | |
download | tmlite-bwlp-ecb072b02e1a70555db0fdf4ed47375d3080a074.tar.gz tmlite-bwlp-ecb072b02e1a70555db0fdf4ed47375d3080a074.tar.xz tmlite-bwlp-ecb072b02e1a70555db0fdf4ed47375d3080a074.zip |
Many improvements and additions:
- Added task+script for lighttpd https config
- Added task for reloading proxy config
- ldapsearch now supports searching for specific user
- DownloadFile now supports checking file integrity through optional gpg signature
-rwxr-xr-x | scripts/install-https | 68 | ||||
-rwxr-xr-x | scripts/system-backup | 5 | ||||
-rwxr-xr-x | scripts/system-restore | 62 | ||||
-rw-r--r-- | src/main/java/org/openslx/satserver/util/Exec.java | 20 | ||||
-rw-r--r-- | src/main/java/org/openslx/satserver/util/ProxyHandler.java | 35 | ||||
-rw-r--r-- | src/main/java/org/openslx/satserver/util/Util.java | 19 | ||||
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/DownloadFile.java | 47 | ||||
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java | 8 | ||||
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/LighttpdHttps.java | 105 | ||||
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/ReloadProxy.java | 26 |
10 files changed, 359 insertions, 36 deletions
diff --git a/scripts/install-https b/scripts/install-https new file mode 100755 index 0000000..84a6184 --- /dev/null +++ b/scripts/install-https @@ -0,0 +1,68 @@ +#!/bin/bash + +CERT="/etc/lighttpd/server.pem" + +op_disable () +{ + [ -e "$CERT" ] || exit 0 + rm -f -- "$CERT" || exit 1 +} + +op_test () +{ + [ $# -eq 2 ] || exit 1 + local K=$1 + local C=$2 + [ -r "$K" ] || exit 2 + [ -r "$C" ] || exit 3 + # Encrypt something, then decrypt again and compare + local TEST_IN=$(mktemp --tmpdir bwlp-XXXXXXXX) + local TEST_OUT=$(mktemp --tmpdir bwlp-XXXXXXXX) + local TEST_DIFF=$(mktemp --tmpdir bwlp-XXXXXXXX) + [ -z "$TEST_IN" ] && exit 4 + [ -z "$TEST_OUT" ] && exit 5 + [ -z "$TEST_DIFF" ] && exit 6 + date > "$TEST_IN" + openssl smime -encrypt -binary -aes-256-cbc -in "$TEST_IN" -out "$TEST_OUT" -outform DER "$C" || exit 7 + openssl smime -decrypt -binary -in "$TEST_OUT" -inform DER -out "$TEST_DIFF" -inkey "$K" || exit 8 + diff -q "$TEST_IN" "$TEST_DIFF" || exit 9 + exit 0 # No restart either way +} + +op_import () +{ + [ $# -eq 2 ] || exit 1 + local K=$1 + local C=$2 + [ -r "$K" ] || exit 2 + [ -r "$C" ] || exit 3 + # Create server.pem + cat "$C" "$K" > "$CERT" + chmod 0600 "$CERT" || exit 4 + rm -f -- "$C" "$K" +} + +op_random () +{ + [ -z "$1" ] && exit 1 + openssl req -x509 -new -newkey rsa:4096 -keyout "$CERT" -out "$CERT" -days 5000 -nodes -subj "/C=DE/ST=Nowhere/L=Springfield/O=bwLehrpool/CN=$1" || exit 2 +} + +OP=$1 +shift + +case "$OP" in + --random) op_random "$@" ;; + --test) op_test "$@" ;; + --import) op_import "$@" ;; + --disable) op_disable ;; + *) + echo "Invalid operation: $1" + exit 1 + ;; +esac + +service lighttpd restart + +exit 0 + diff --git a/scripts/system-backup b/scripts/system-backup index 666180b..8042b08 100755 --- a/scripts/system-backup +++ b/scripts/system-backup @@ -15,7 +15,7 @@ fi mkdir -p "$DIR" cd "$DIR" || exit 1 -mysqldump --add-locks --defaults-extra-file=/etc/mysql/debian.cnf --default-character-set=utf8 --databases openslx bwLehrpool > db.sql +mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --add-locks --add-drop-database --default-character-set=utf8 --databases openslx bwLehrpool > db.sql RET=$? if [ $RET -ne 0 ]; then echo "Database dump failed with exit code $RET" @@ -25,6 +25,7 @@ fi FILELIST=" /opt/openslx/configs /opt/syncdaemon/config/identity.properties + /etc/lighttpd/server.pem " tar --ignore-failed-read -k -c -p -z -f files.tgz $FILELIST # no quotes here! @@ -46,7 +47,7 @@ fi chown www-data backup.tgz chmod 0600 backup.tgz -FILE="/tmp/bwlp-backup-$(date +%s).tgz" +FILE="/tmp/bwlp-backup-$(date +%s)-${RANDOM}.tgz" if ! mv backup.tgz "$FILE"; then echo "moving backup to $FILE failed." exit 1 diff --git a/scripts/system-restore b/scripts/system-restore new file mode 100755 index 0000000..a95a185 --- /dev/null +++ b/scripts/system-restore @@ -0,0 +1,62 @@ +#!/bin/bash + +BACKUP="$1" +if [ -z "$BACKUP" ] || [ ! -f "$BACKUP" ]; then + echo "Backup file not found: $BACKUP" + exit 1 +fi + +if [ "$(whoami)" != "root" ]; then + echo "Must be running as root!" + exit 1 +fi + +DIR="/root/restore/$(date +%s)" + +if [ -d "$DIR" ]; then + echo "Restore already running!?" + exit 1 +fi + +mkdir -p "$DIR" +if ! cd "$DIR"; then + echo "Could not cd to $DIR" + exit 1 +fi + +if ! tar --ignore-failed-read -x -f "$BACKUP"; then + echo "Could not extract $BACKUP - make sure it's a valid .tar.gz / .tgz" + exit 1 +fi + +if [ ! -f db.sql ]; then + echo "Error: database dump not found in backup - are you sure this is a valid backup?" + exit 1 +fi + +if [ ! -f files.tgz ]; then + echo "Error: files.tgz not found in backup - are your sure this is a valid backup?" + exit 1 +fi + +mysql --defaults-extra-file=/etc/mysql/debian.cnf --default-character-set=utf8 < db.sql +RET=$? +if [ $RET -ne 0 ]; then + echo "Error: Restoring database contents failed with exit code $RET" + exit 1 +fi +echo "UPDATE openslx.property SET value = 'invalid' WHERE name = 'server-ip' LIMIT 1" | mysql --defaults-extra-file=/etc/mysql/debian.cnf --default-character-set=utf8 + +tar --ignore-failed-read -x -f files.tgz -C / +RET=$? +if [ $RET -ne 0 ]; then + echo "WARNING: Restoring filesystem contents failed with exit code $RET - backup might be incomplete!" +fi + +rm -rf -- "$DIR" +rm -f -- "$BACKUP" + +echo "Success." + +exit 0 + diff --git a/src/main/java/org/openslx/satserver/util/Exec.java b/src/main/java/org/openslx/satserver/util/Exec.java index e7b27da..1f810eb 100644 --- a/src/main/java/org/openslx/satserver/util/Exec.java +++ b/src/main/java/org/openslx/satserver/util/Exec.java @@ -6,17 +6,23 @@ import java.io.IOException; public class Exec { + /** + * Run command, return exit status of process, or -1 on error + * + * @param command Command and arguments + * @return exit code + */ public static int sync( String... command ) { ProcessBuilder pb = new ProcessBuilder( command ); pb.directory( new File( "/" ) ); - Process p; - try { - p = pb.start(); - return p.waitFor(); - } catch ( IOException | InterruptedException e ) { - return -1; - } + Process p; + try { + p = pb.start(); + return p.waitFor(); + } catch ( IOException | InterruptedException e ) { + return -1; + } } } diff --git a/src/main/java/org/openslx/satserver/util/ProxyHandler.java b/src/main/java/org/openslx/satserver/util/ProxyHandler.java index 9a702fe..f70a496 100644 --- a/src/main/java/org/openslx/satserver/util/ProxyHandler.java +++ b/src/main/java/org/openslx/satserver/util/ProxyHandler.java @@ -3,19 +3,36 @@ package org.openslx.satserver.util; import org.openslx.network.ProxyConfiguration; /** - * Class for handling proxy configuration in task manager. Just configure proxy - * setting system wide, if it was not done already. + * Class for handling proxy configuration in task manager. + * * @author bjoern - * + * */ -public class ProxyHandler { +public class ProxyHandler +{ private static boolean hasDoneConfigProxy = false; + private static final Object proxyMutex = new Object(); - public static void configProxy() { - // Just configuring proxy settings system wide, if not done already. - if (!hasDoneConfigProxy) { - ProxyConfiguration.configProxy(); - hasDoneConfigProxy = true; + /** + * Do proxy setup if not done already + */ + public static void configProxy() + { + configProxy( false ); + } + + /** + * Do proxy setup if not done already, or if explicitly forced. + * + * @param force Do setup even if already done + */ + public static synchronized void configProxy( boolean force ) + { + synchronized ( proxyMutex ) { + if ( !hasDoneConfigProxy || force ) { + ProxyConfiguration.configProxy(); + hasDoneConfigProxy = true; + } } } } diff --git a/src/main/java/org/openslx/satserver/util/Util.java b/src/main/java/org/openslx/satserver/util/Util.java index fe7eb6e..2df4c73 100644 --- a/src/main/java/org/openslx/satserver/util/Util.java +++ b/src/main/java/org/openslx/satserver/util/Util.java @@ -5,6 +5,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.FileUtils; @@ -30,6 +31,7 @@ public class Util /** * Close all given Closables. Can handle null references. + * * @param streams one or more closables/streams */ public static void multiClose( Closeable... streams ) @@ -64,14 +66,15 @@ public class Util } return true; } - - public static String readFileToString(String file) + + public static String readFileToString( String file ) throws IOException { - try { - return FileUtils.readFileToString( new File( file ) ); - } catch ( Exception e ) { - return null; - } + return FileUtils.readFileToString( new File( file ), StandardCharsets.UTF_8 ); } - + + public static void writeStringToFile( File file, String string ) throws IOException + { + FileUtils.writeStringToFile( file, string, StandardCharsets.UTF_8 ); + } + } diff --git a/src/main/java/org/openslx/taskmanager/tasks/DownloadFile.java b/src/main/java/org/openslx/taskmanager/tasks/DownloadFile.java index ac9ea0e..1129200 100644 --- a/src/main/java/org/openslx/taskmanager/tasks/DownloadFile.java +++ b/src/main/java/org/openslx/taskmanager/tasks/DownloadFile.java @@ -6,9 +6,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLConnection; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.openslx.satserver.util.Exec; import org.openslx.satserver.util.ProxyHandler; import org.openslx.satserver.util.Util; import org.openslx.taskmanager.api.AbstractTask; @@ -22,11 +24,13 @@ public class DownloadFile extends AbstractTask private String url = null; @Expose private String destination = null; + @Expose + private String gpg = null; private Output status = new Output(); private static final String[] ALLOWED_DIRS = - { "/srv/openslx/www/boot/" }; + { "/srv/openslx/www/boot/", "/tmp/" }; @Override protected boolean initTask() @@ -50,30 +54,57 @@ public class DownloadFile extends AbstractTask URLConnection connection = null; BufferedInputStream in = null; FileOutputStream fout = null; - + // Handle proxy settings before opening connection for downloading. ProxyHandler.configProxy(); try { - File dest = new File( this.destination ); - FileUtils.forceMkdir( new File( dest.getParent() ) ); - FileUtils.deleteQuietly( dest ); + File tmpFile = File.createTempFile( "bwlp-", ".tmp", null ); connection = new URL( this.url ).openConnection(); in = new BufferedInputStream( connection.getInputStream() ); - fout = new FileOutputStream( dest ); + fout = new FileOutputStream( tmpFile ); status.size = connection.getContentLengthLong(); + if ( status.size <= 0 ) // If size is unknown, fake progress... + status.progress = 10; - final byte data[] = new byte[ 9000 ]; + final byte data[] = new byte[ 90000 ]; int count; while ( ( count = in.read( data, 0, data.length ) ) != -1 ) { fout.write( data, 0, count ); status.complete += count; if ( status.size > 0 ) status.progress = (int) ( 100l * status.complete / status.size ); + else if ( status.progress < 99 && System.currentTimeMillis() % 20 == 0 ) + status.progress++; + } + fout.close(); + // If we have a gpg sig, validate + if ( this.gpg != null ) { + File gpgTempFile = null; + try { + gpgTempFile = File.createTempFile( "bwlp-", ".gpg", null ); + Util.writeStringToFile( gpgTempFile, this.gpg ); + } catch ( Exception e ) { + status.error = "Could not create temporary file for gpg signature"; + return false; + } + if ( 0 != Exec.sync( "gpg", "--homedir", "/opt/openslx/gpg", "--verify", gpgTempFile.getAbsolutePath(), tmpFile.getAbsolutePath() ) ) { + status.error = "GPG signature of downloaded file not valid!"; + return false; + } + gpgTempFile.delete(); + } + // Move file to destination + File dest = new File( this.destination ); + FileUtils.forceMkdir( new File( dest.getParent() ) ); + if ( dest.exists() ) + dest.delete(); + if ( !tmpFile.renameTo( dest ) ) { + status.error = "Could not move downloaded file to destination directory!"; + return false; } return true; } catch ( IOException e ) { status.error = "Download error: " + e.toString(); - FileUtils.deleteQuietly( new File( this.destination ) ); return false; } finally { Util.multiClose( in, fout ); diff --git a/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java b/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java index 157b5e1..dbb76b1 100644 --- a/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java +++ b/src/main/java/org/openslx/taskmanager/tasks/LdapSearch.java @@ -93,9 +93,9 @@ public class LdapSearch extends SystemCommandTask exitCode = 0; if ( exitCode != 0 ) status.addMessage( "Exit code is " + exitCode ); - if ( exitCode == 0 && this.userCount < 4 ) + if ( exitCode == 0 && this.userCount < 4 && !this.getDn ) status.addMessage( "Found less than 4 users. Are you sure you got the right credentials." ); - return this.userCount >= 4; + return this.userCount >= 4 || (this.getDn && status.dn != null); } @Override @@ -105,6 +105,10 @@ public class LdapSearch extends SystemCommandTask 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 ); } diff --git a/src/main/java/org/openslx/taskmanager/tasks/LighttpdHttps.java b/src/main/java/org/openslx/taskmanager/tasks/LighttpdHttps.java new file mode 100644 index 0000000..1b5e8e8 --- /dev/null +++ b/src/main/java/org/openslx/taskmanager/tasks/LighttpdHttps.java @@ -0,0 +1,105 @@ +package org.openslx.taskmanager.tasks; + +import java.io.File; + +import org.openslx.satserver.util.Exec; +import org.openslx.satserver.util.Util; +import org.openslx.taskmanager.api.AbstractTask; + +import com.google.gson.annotations.Expose; + +public class LighttpdHttps extends AbstractTask +{ + + private Output status = new Output(); + + @Expose + private String importcert = null; + @Expose + private String importkey = null; + + @Expose + private String proxyip = null; + + @Override + protected boolean initTask() + { + this.setStatusObject( this.status ); + return true; + } + + @Override + protected boolean execute() + { + if ( this.importcert != null && this.importkey != null ) + return createFromInput(); + if ( this.proxyip != null ) + return createRandom(); + return disableHttps(); + } + + private boolean createRandom() + { + int ret = Exec.sync( "sudo", "-n", "-u", "root", "/opt/taskmanager/scripts/install-https", "--random", this.proxyip ); + if ( ret != 0 ) { + status.error = "generator exited with code " + ret; + return false; + } + return true; + } + + private boolean createFromInput() + { + // Import supplied certificate and key. Test if they are valid first + File tmpKey = null; + File tmpCert = null; + try { + try { + tmpKey = File.createTempFile( "bwlp-", ".pem" ); + tmpCert = File.createTempFile( "bwlp-", ".pem" ); + Util.writeStringToFile( tmpCert, this.importcert ); + Util.writeStringToFile( tmpKey, this.importkey ); + } catch ( Exception e ) { + status.error = "Could not create temporary files!"; + return false; + } + int ret; + ret = Exec.sync( "/opt/taskmanager/scripts/install-https", "--test", tmpKey.getAbsolutePath(), tmpCert.getAbsolutePath() ); + if ( ret != 0 ) { + status.error = "Given key and certificate do not match, or have invalid format (exit code: " + ret + ")"; + return false; + } + ret = Exec.sync( "sudo", "-n", "-u", "root", "/opt/taskmanager/scripts/install-https", "--import", tmpKey.getAbsolutePath(), tmpCert.getAbsolutePath() ); + if ( ret != 0 ) { + status.error = "import exited with code " + ret; + return false; + } + return true; + } finally { + if ( tmpKey != null ) + tmpKey.delete(); + if ( tmpCert != null ) + tmpCert.delete(); + } + } + + private boolean disableHttps() + { + int ret = Exec.sync( "sudo", "-n", "-u", "root", "/opt/taskmanager/scripts/install-https", "--disable" ); + if ( ret != 0 ) { + status.error = "import exited with code " + ret; + return false; + } + return true; + } + + /** + * 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/ReloadProxy.java b/src/main/java/org/openslx/taskmanager/tasks/ReloadProxy.java new file mode 100644 index 0000000..b3216dd --- /dev/null +++ b/src/main/java/org/openslx/taskmanager/tasks/ReloadProxy.java @@ -0,0 +1,26 @@ +package org.openslx.taskmanager.tasks; + +import org.openslx.satserver.util.ProxyHandler; +import org.openslx.taskmanager.api.AbstractTask; + +/** + * Just force reloading and setting up proxy configuration. + * Used after modifying settings in the webgui. + */ +public class ReloadProxy extends AbstractTask +{ + + @Override + protected boolean initTask() + { + return true; + } + + @Override + protected boolean execute() + { + ProxyHandler.configProxy( true ); + return true; + } + +} |