From 40d528627efc309681496b47d66558e15eb3fe5e Mon Sep 17 00:00:00 2001 From: Nils Schwabe Date: Fri, 25 Apr 2014 14:28:56 +0200 Subject: Finally: Add _real_ server authentication. (this challengeresponse thing) --- src/main/java/org/openslx/imagemaster/App.java | 4 +- src/main/java/org/openslx/imagemaster/Globals.java | 22 +++- .../org/openslx/imagemaster/db/ImageProcessor.java | 89 ------------- .../imagemaster/ftp/FtpCredentialsScheduler.java | 63 +++++++++ .../openslx/imagemaster/ftp/ImageProcessor.java | 90 +++++++++++++ .../openslx/imagemaster/ftp/MasterFtpServer.java | 144 +++++++++++++++++++++ .../org/openslx/imagemaster/ftp/MasterFtplet.java | 64 +++++++++ .../org/openslx/imagemaster/server/ApiServer.java | 5 +- .../server/FtpCredentialsScheduler.java | 63 --------- .../imagemaster/server/MasterFtpServer.java | 143 -------------------- .../openslx/imagemaster/server/MasterFtplet.java | 64 --------- .../serversession/ServerAuthenticator.java | 42 ++++-- .../thrift/server/ImageServerHandler.java | 5 +- .../openslx/imagemaster/util/AsymMessageSign.java | 63 +++++++++ .../java/org/openslx/imagemaster/util/Util.java | 20 ++- src/main/thrift/imagemaster.thrift | 2 +- 16 files changed, 504 insertions(+), 379 deletions(-) delete mode 100644 src/main/java/org/openslx/imagemaster/db/ImageProcessor.java create mode 100644 src/main/java/org/openslx/imagemaster/ftp/FtpCredentialsScheduler.java create mode 100644 src/main/java/org/openslx/imagemaster/ftp/ImageProcessor.java create mode 100644 src/main/java/org/openslx/imagemaster/ftp/MasterFtpServer.java create mode 100644 src/main/java/org/openslx/imagemaster/ftp/MasterFtplet.java delete mode 100644 src/main/java/org/openslx/imagemaster/server/FtpCredentialsScheduler.java delete mode 100644 src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java delete mode 100644 src/main/java/org/openslx/imagemaster/server/MasterFtplet.java create mode 100644 src/main/java/org/openslx/imagemaster/util/AsymMessageSign.java (limited to 'src/main') diff --git a/src/main/java/org/openslx/imagemaster/App.java b/src/main/java/org/openslx/imagemaster/App.java index 85ec50b..a73e1ef 100644 --- a/src/main/java/org/openslx/imagemaster/App.java +++ b/src/main/java/org/openslx/imagemaster/App.java @@ -6,8 +6,8 @@ import java.util.List; import org.apache.log4j.Logger; import org.openslx.imagemaster.Globals.PropInt; -import org.openslx.imagemaster.server.FtpCredentialsScheduler; -import org.openslx.imagemaster.server.MasterFtpServer; +import org.openslx.imagemaster.ftp.FtpCredentialsScheduler; +import org.openslx.imagemaster.ftp.MasterFtpServer; import org.openslx.imagemaster.thrift.server.BinaryListener; public class App diff --git a/src/main/java/org/openslx/imagemaster/Globals.java b/src/main/java/org/openslx/imagemaster/Globals.java index 717cb1e..166e629 100644 --- a/src/main/java/org/openslx/imagemaster/Globals.java +++ b/src/main/java/org/openslx/imagemaster/Globals.java @@ -7,7 +7,6 @@ import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; -import org.openslx.imagemaster.server.MasterFtpServer; public class Globals { @@ -23,7 +22,7 @@ public class Globals public static enum PropString { - IMAGEDIR, KEYSTORE, LDAPHOST, LDAPBINDQUERY, LDAPSEARCHBASEDN, LDAPSEARCHFILTER, FTPBASEDIR + IMAGEDIR, KEYSTOREFILE, KEYSTOREALIAS, KEYSTOREPASSWORD, LDAPHOST, LDAPBINDQUERY, LDAPSEARCHBASEDN, LDAPSEARCHFILTER, FTPBASEDIR } public static enum PropBool @@ -64,8 +63,12 @@ public class Globals || Globals.getPropertyString( PropString.LDAPSEARCHFILTER ).isEmpty() || Globals.getPropertyString( PropString.FTPBASEDIR ) == null || Globals.getPropertyString( PropString.FTPBASEDIR ).isEmpty() - || Globals.getPropertyString( PropString.KEYSTORE ) == null - || Globals.getPropertyString( PropString.KEYSTORE ).isEmpty() + || Globals.getPropertyString( PropString.KEYSTOREFILE ) == null + || Globals.getPropertyString( PropString.KEYSTOREFILE ).isEmpty() + || Globals.getPropertyString( PropString.KEYSTOREALIAS ) == null + || Globals.getPropertyString( PropString.KEYSTOREALIAS ).isEmpty() + || Globals.getPropertyString( PropString.KEYSTOREPASSWORD ) == null + || Globals.getPropertyString( PropString.KEYSTOREPASSWORD ).isEmpty() || Globals.getPropertyInt( PropInt.LDAPPORT ) == 0 || Globals.getPropertyInt( PropInt.SESSIONTIMEOUTUSER ) == 0 @@ -88,7 +91,7 @@ public class Globals } // check keystore - if ( !Globals.getPropertyString( PropString.KEYSTORE ).endsWith( ".jks" )) { + if ( !Globals.getPropertyString( PropString.KEYSTOREFILE ).endsWith( ".jks" )) { log.error( "Keystore is not in jks format." ); return false; } @@ -146,6 +149,15 @@ public class Globals case IMAGEDIR: result = properties.getProperty( "image_dir" ); break; + case KEYSTOREFILE: + result = properties.getProperty( "keystore_file" ); + break; + case KEYSTOREALIAS: + result = properties.getProperty( "keystore_alias" ); + break; + case KEYSTOREPASSWORD: + result = properties.getProperty( "keystore_password" ); + break; case LDAPHOST: result = properties.getProperty( "ldap_host" ); break; diff --git a/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java b/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java deleted file mode 100644 index d0ac5c6..0000000 --- a/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.openslx.imagemaster.db; - -import java.io.File; -import java.util.HashMap; - -import org.apache.log4j.Logger; -import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.thrift.iface.ImageData; - -public class ImageProcessor -{ - - private static Logger log = Logger.getLogger( ImageProcessor.class ); - private static HashMap images = new HashMap<>(); - - /** - * Processes an image after upload - * - * @param username the user that uploaded the file - * @param filename the name of the file that was uploaded (_no_ absolute path) - * @return - */ - public static boolean processImageAfterUpload( String username, String filename ) - { - if ( !images.containsKey( username ) ) { - return false; - } - - log.info( "Will now process '" + filename + "' from user '" + username - + "'" ); - - // move image to right location - String oldFileName = Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + username + "/" + filename; - String newFileName = Globals.getPropertyString( Globals.PropString.IMAGEDIR ) + "/" + images.get( username ).uuid; - - File imageFile = new File( oldFileName ); - - if ( !imageFile.exists() ) { - // image file does not exist - return false; - } - - imageFile.renameTo( new File( newFileName ) ); - - log.info( "Moved file from " + oldFileName + " to " + newFileName ); - - File tempUserDir = new File( Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + username ); - tempUserDir.delete(); - - // update database - DbImage.update( images.get( username ), newFileName ); - log.info( "Updated db: " + images.get( username ).uuid ); - - images.remove( username ); - return true; - } - - /** - * Try to add imageData to database. - * - * @param imageData - * the data for the image to add - * @return false if submit fails - */ - public static boolean addImageDataToProcess( ImageData imageData, String username ) - { - log.info( "Adding image to process list: " + imageData.imageName + ", submitted by " + username ); - - if ( imageData.uuid.isEmpty() || imageData.imageName.isEmpty() - || imageData.imageOwner.isEmpty() || imageData.conentOperatingSystem.isEmpty() - || imageData.imageShortDescription.isEmpty() - || imageData.imageLongDescription.isEmpty() ) { - return false; - } - - // TODO: check some regex? - - if ( DbImage.exists( imageData ) ) { - return false; - } - - // if everything went fine, add image to db - DbImage.insert( imageData ); - - // and to processinglist - images.put( username, imageData ); - return true; - } -} diff --git a/src/main/java/org/openslx/imagemaster/ftp/FtpCredentialsScheduler.java b/src/main/java/org/openslx/imagemaster/ftp/FtpCredentialsScheduler.java new file mode 100644 index 0000000..b0b23aa --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/ftp/FtpCredentialsScheduler.java @@ -0,0 +1,63 @@ +package org.openslx.imagemaster.ftp; + +import java.io.File; +import java.util.Date; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.log4j.Logger; +import org.openslx.imagemaster.App; +import org.openslx.imagemaster.Globals; +import org.openslx.imagemaster.thrift.iface.FtpCredentials; +import org.openslx.imagemaster.util.Util; + +public class FtpCredentialsScheduler extends TimerTask +{ + private static Logger log = Logger.getLogger( FtpCredentialsScheduler.class ); + + public static final long timeout = Long.valueOf( Globals.getPropertyInt( Globals.PropInt.FTPTIMEOUT ) ) * 60L * 1000L; // timeout in ms + + @Override + public void run() + { + // check all folders + for ( Map.Entry entry : App.ftpServer.users.entrySet() ) { + String sessionId = entry.getKey(); + String username = entry.getValue().username; + File dir = new File( Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + username ); + if ( !dir.exists() ) + continue; + File[] list = dir.listFiles(); + if ( list.length == 1 ) { + if ( ( new Date().getTime() - list[0].lastModified() ) >= timeout ) { + log.info( username + "'s files are too old. Deleting him and his folder." ); + Util.deleteFolder( dir ); + App.ftpServer.removeUser( sessionId ); + } + } else if ( list.length > 1 ) { + log.info( username + " uploaded too many files. Deleting his account and his folder." ); + Util.deleteFolder( dir ); + App.ftpServer.removeUser( sessionId ); + } else { + // check the creation time of the user + if ( ( new Date().getTime() - App.ftpServer.timeouts.get( username ).getTime() ) >= timeout ) { + // remove user and his folder + Util.deleteFolder( dir ); + App.ftpServer.removeUser( sessionId ); + log.info( username + " did nothing for too long. Deleting him and his folder" ); + } + } + } + //TODO: remove image from process list + } + + public static void startScheduling() + { + Timer timer = new Timer(); + + // start timer now and fire every 60 seconds + timer.schedule( new FtpCredentialsScheduler(), 0, 60000 ); + } + +} diff --git a/src/main/java/org/openslx/imagemaster/ftp/ImageProcessor.java b/src/main/java/org/openslx/imagemaster/ftp/ImageProcessor.java new file mode 100644 index 0000000..4c09907 --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/ftp/ImageProcessor.java @@ -0,0 +1,90 @@ +package org.openslx.imagemaster.ftp; + +import java.io.File; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.openslx.imagemaster.Globals; +import org.openslx.imagemaster.db.DbImage; +import org.openslx.imagemaster.thrift.iface.ImageData; + +public class ImageProcessor +{ + + private static Logger log = Logger.getLogger( ImageProcessor.class ); + private static HashMap images = new HashMap<>(); + + /** + * Processes an image after upload + * + * @param username the user that uploaded the file + * @param filename the name of the file that was uploaded (_no_ absolute path) + * @return + */ + public static boolean processImageAfterUpload( String username, String filename ) + { + if ( !images.containsKey( username ) ) { + return false; + } + + log.info( "Will now process '" + filename + "' from user '" + username + + "'" ); + + // move image to right location + String oldFileName = Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + username + "/" + filename; + String newFileName = Globals.getPropertyString( Globals.PropString.IMAGEDIR ) + "/" + images.get( username ).uuid; + + File imageFile = new File( oldFileName ); + + if ( !imageFile.exists() ) { + // image file does not exist + return false; + } + + imageFile.renameTo( new File( newFileName ) ); + + log.info( "Moved file from " + oldFileName + " to " + newFileName ); + + File tempUserDir = new File( Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + username ); + tempUserDir.delete(); + + // update database + DbImage.update( images.get( username ), newFileName ); + log.info( "Updated db: " + images.get( username ).uuid ); + + images.remove( username ); + return true; + } + + /** + * Try to add imageData to database. + * + * @param imageData + * the data for the image to add + * @return false if submit fails + */ + public static boolean addImageDataToProcess( ImageData imageData, String username ) + { + log.info( "Adding image to process list: " + imageData.imageName + ", submitted by " + username ); + + if ( imageData.uuid.isEmpty() || imageData.imageName.isEmpty() + || imageData.imageOwner.isEmpty() || imageData.conentOperatingSystem.isEmpty() + || imageData.imageShortDescription.isEmpty() + || imageData.imageLongDescription.isEmpty() ) { + return false; + } + + // TODO: check some regex? + + if ( DbImage.exists( imageData ) ) { + return false; + } + + // if everything went fine, add image to db + DbImage.insert( imageData ); + + // and to processinglist + images.put( username, imageData ); + return true; + } +} diff --git a/src/main/java/org/openslx/imagemaster/ftp/MasterFtpServer.java b/src/main/java/org/openslx/imagemaster/ftp/MasterFtpServer.java new file mode 100644 index 0000000..992c49a --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/ftp/MasterFtpServer.java @@ -0,0 +1,144 @@ +package org.openslx.imagemaster.ftp; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +import org.apache.ftpserver.FtpServer; +import org.apache.ftpserver.FtpServerFactory; +import org.apache.ftpserver.ftplet.Authority; +import org.apache.ftpserver.ftplet.FtpException; +import org.apache.ftpserver.ftplet.Ftplet; +import org.apache.ftpserver.ftplet.UserManager; +import org.apache.ftpserver.listener.ListenerFactory; +import org.apache.ftpserver.ssl.SslConfigurationFactory; +import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory; +import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor; +import org.apache.ftpserver.usermanager.impl.BaseUser; +import org.apache.ftpserver.usermanager.impl.WritePermission; +import org.apache.log4j.Logger; +import org.openslx.imagemaster.Globals; +import org.openslx.imagemaster.Globals.PropString; +import org.openslx.imagemaster.thrift.iface.FtpCredentials; +import org.openslx.imagemaster.util.RandomString; + +public class MasterFtpServer implements Runnable +{ + private static Logger log = Logger.getLogger( MasterFtpServer.class ); + private FtpServer server; + private UserManager userManager; + // key: serverSessionId, value: FtpCredentials + public final HashMap users = new HashMap<>(); + // key: ftpUsername, value: createTime + public final HashMap timeouts = new HashMap<>(); + private boolean ini = false; + + public void init( int port ) + { + if ( ini ) + return; + + FtpServerFactory serverFactory = new FtpServerFactory(); + ListenerFactory factory = new ListenerFactory(); + + // config ssl + SslConfigurationFactory sslConfigFactory = new SslConfigurationFactory(); + sslConfigFactory.setKeystoreFile( new File( Globals.getPropertyString( PropString.KEYSTOREFILE ) ) ); + sslConfigFactory.setKeyAlias( Globals.getPropertyString( PropString.KEYSTOREALIAS ) ); + sslConfigFactory.setKeystorePassword( Globals.getPropertyString( PropString.KEYSTOREPASSWORD ) ); + + // set the port of the listener + factory.setPort( port ); + factory.setSslConfiguration( sslConfigFactory.createSslConfiguration() ); + factory.setImplicitSsl( true ); + + // replace the default listener + serverFactory.addListener( "default", factory.createListener() ); + + // create user manager + PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory(); + userManagerFactory.setFile( new File( "src/main/properties/ftp.properties" ) ); + userManagerFactory.setPasswordEncryptor( new SaltedPasswordEncryptor() ); + userManager = userManagerFactory.createUserManager(); + serverFactory.setUserManager( userManager ); + + // add the Ftplet + HashMap map = new HashMap(); + map.put( "Ftplet1", new MasterFtplet() ); + serverFactory.setFtplets( map ); + + // start the server + server = serverFactory.createServer(); + ini = true; + } + + public FtpCredentials addUser( final String serverSessionId ) + { + FtpCredentials ftpCredentials = null; + + String generatedUser = RandomString.generate( 10, false ); + String generatedPass = RandomString.generate( 16, true ); + + String dir = Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + + generatedUser + "/"; + + if ( !new File( dir ).mkdir() ) { + return ftpCredentials; + } + + BaseUser user = new BaseUser(); + user.setName( generatedUser ); + user.setPassword( generatedPass ); + user.setHomeDirectory( dir ); + + List authorities = new ArrayList(); + authorities.add( new WritePermission() ); + user.setAuthorities( authorities ); + + try { + userManager.save( user ); + ftpCredentials = new FtpCredentials( generatedUser, generatedPass ); + users.put( serverSessionId, ftpCredentials ); + timeouts.put( ftpCredentials.username, new Date() ); + } catch ( FtpException e ) { + } + + log.info( "Generated user/pass: " + generatedUser + "\t" + + generatedPass + "\n with home dir: " + dir ); + + return ftpCredentials; + } + + public boolean removeUser( final String serverSessionId ) + { + if ( !users.containsKey( serverSessionId ) ) + return false; + + try { + userManager.delete( users.get( serverSessionId ).username ); + // remove user from both maps + timeouts.remove( users.remove( serverSessionId ).username ); + return true; + } catch ( FtpException e ) { + return false; + } + } + + public FtpCredentials getCredentialsFromSessionId( String serverSessionId ) + { + return users.get( serverSessionId ); + } + + @Override + public void run() + { + try { + log.info( "Starting FTP Sever" ); + server.start(); + } catch ( FtpException e1 ) { + e1.printStackTrace(); + } + } +} diff --git a/src/main/java/org/openslx/imagemaster/ftp/MasterFtplet.java b/src/main/java/org/openslx/imagemaster/ftp/MasterFtplet.java new file mode 100644 index 0000000..3c73dba --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/ftp/MasterFtplet.java @@ -0,0 +1,64 @@ +package org.openslx.imagemaster.ftp; + +import java.io.IOException; + +import org.apache.ftpserver.ftplet.FtpException; +import org.apache.ftpserver.ftplet.FtpReply; +import org.apache.ftpserver.ftplet.FtpRequest; +import org.apache.ftpserver.ftplet.FtpSession; +import org.apache.ftpserver.ftplet.Ftplet; +import org.apache.ftpserver.ftplet.FtpletContext; +import org.apache.ftpserver.ftplet.FtpletResult; +import org.apache.log4j.Logger; + +public class MasterFtplet implements Ftplet +{ + private static Logger log = Logger.getLogger( Ftplet.class ); + + @Override + public void init( FtpletContext ftpletContext ) throws FtpException + { + // not used + } + + @Override + public void destroy() + { + // not used + } + + @Override + public FtpletResult beforeCommand( FtpSession session, FtpRequest request ) + throws FtpException, IOException + { + if ( session.getUser() != null ) { + log.info( session.getUser().getName() + " issued command: " + request.getRequestLine() ); + } + return null; + } + + @Override + public FtpletResult afterCommand( FtpSession session, FtpRequest request, + FtpReply reply ) throws FtpException, IOException + { + // not used + return null; + } + + @Override + public FtpletResult onConnect( FtpSession session ) throws FtpException, + IOException + { + // not used + return null; + } + + @Override + public FtpletResult onDisconnect( FtpSession session ) throws FtpException, + IOException + { + // not used + return null; + } + +} diff --git a/src/main/java/org/openslx/imagemaster/server/ApiServer.java b/src/main/java/org/openslx/imagemaster/server/ApiServer.java index c88bd05..7479fd3 100644 --- a/src/main/java/org/openslx/imagemaster/server/ApiServer.java +++ b/src/main/java/org/openslx/imagemaster/server/ApiServer.java @@ -1,13 +1,14 @@ package org.openslx.imagemaster.server; import java.io.File; +import java.nio.ByteBuffer; import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.openslx.imagemaster.App; import org.openslx.imagemaster.Globals; import org.openslx.imagemaster.db.DbSatellite; -import org.openslx.imagemaster.db.ImageProcessor; +import org.openslx.imagemaster.ftp.ImageProcessor; import org.openslx.imagemaster.serversession.ServerAuthenticator; import org.openslx.imagemaster.serversession.ServerSession; import org.openslx.imagemaster.serversession.ServerSessionManager; @@ -146,7 +147,7 @@ public class ApiServer * @throws TException */ public static ServerSessionData serverAuthenticate( String organization, - String challengeResponse ) throws AuthenticationException, + ByteBuffer challengeResponse ) throws AuthenticationException, TException { if ( organization == null || challengeResponse == null ) { diff --git a/src/main/java/org/openslx/imagemaster/server/FtpCredentialsScheduler.java b/src/main/java/org/openslx/imagemaster/server/FtpCredentialsScheduler.java deleted file mode 100644 index ba88f33..0000000 --- a/src/main/java/org/openslx/imagemaster/server/FtpCredentialsScheduler.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.openslx.imagemaster.server; - -import java.io.File; -import java.util.Date; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; - -import org.apache.log4j.Logger; -import org.openslx.imagemaster.App; -import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.thrift.iface.FtpCredentials; -import org.openslx.imagemaster.util.Util; - -public class FtpCredentialsScheduler extends TimerTask -{ - private static Logger log = Logger.getLogger( FtpCredentialsScheduler.class ); - - public static final long timeout = Long.valueOf( Globals.getPropertyInt( Globals.PropInt.FTPTIMEOUT ) ) * 60L * 1000L; // timeout in ms - - @Override - public void run() - { - // check all folders - for ( Map.Entry entry : App.ftpServer.users.entrySet() ) { - String sessionId = entry.getKey(); - String username = entry.getValue().username; - File dir = new File( Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" + username ); - if ( !dir.exists() ) - continue; - File[] list = dir.listFiles(); - if ( list.length == 1 ) { - if ( ( new Date().getTime() - list[0].lastModified() ) >= timeout ) { - log.info( username + "'s files are too old. Deleting him and his folder." ); - Util.deleteFolder( dir ); - App.ftpServer.removeUser( sessionId ); - } - } else if ( list.length > 1 ) { - log.info( username + " uploaded too many files. Deleting his account and his folder." ); - Util.deleteFolder( dir ); - App.ftpServer.removeUser( sessionId ); - } else { - // check the creation time of the user - if ( ( new Date().getTime() - App.ftpServer.timeouts.get( username ).getTime() ) >= timeout ) { - // remove user and his folder - Util.deleteFolder( dir ); - App.ftpServer.removeUser( sessionId ); - log.info( username + " did nothing for too long. Deleting him and his folder" ); - } - } - } - //TODO: remove image from process list - } - - public static void startScheduling() - { - Timer timer = new Timer(); - - // start timer now and fire every 60 seconds - timer.schedule( new FtpCredentialsScheduler(), 0, 60000 ); - } - -} diff --git a/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java b/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java deleted file mode 100644 index de0d758..0000000 --- a/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.openslx.imagemaster.server; - -import java.io.File; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; - -import org.apache.ftpserver.FtpServer; -import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.ftplet.Authority; -import org.apache.ftpserver.ftplet.FtpException; -import org.apache.ftpserver.ftplet.Ftplet; -import org.apache.ftpserver.ftplet.UserManager; -import org.apache.ftpserver.listener.ListenerFactory; -import org.apache.ftpserver.ssl.SslConfigurationFactory; -import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory; -import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor; -import org.apache.ftpserver.usermanager.impl.BaseUser; -import org.apache.ftpserver.usermanager.impl.WritePermission; -import org.apache.log4j.Logger; -import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.thrift.iface.FtpCredentials; -import org.openslx.imagemaster.util.RandomString; - -public class MasterFtpServer implements Runnable -{ - private static Logger log = Logger.getLogger( MasterFtpServer.class ); - private FtpServer server; - private UserManager userManager; - // key: serverSessionId, value: FtpCredentials - public final HashMap users = new HashMap<>(); - // key: ftpUsername, value: createTime - public final HashMap timeouts = new HashMap<>(); - private boolean ini = false; - - public void init( int port ) - { - if ( ini ) - return; - - FtpServerFactory serverFactory = new FtpServerFactory(); - ListenerFactory factory = new ListenerFactory(); - - // config ssl - SslConfigurationFactory sslConfigFactory = new SslConfigurationFactory(); - sslConfigFactory.setKeystoreFile( new File( "./keyfiles/ftp.jks" ) ); - sslConfigFactory.setKeyAlias( "ftp" ); - sslConfigFactory.setKeystorePassword( "password" ); - - // set the port of the listener - factory.setPort( port ); - factory.setSslConfiguration( sslConfigFactory.createSslConfiguration() ); - factory.setImplicitSsl( true ); - - // replace the default listener - serverFactory.addListener( "default", factory.createListener() ); - - // create user manager - PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory(); - userManagerFactory.setFile( new File( "src/main/properties/ftp.properties" ) ); - userManagerFactory.setPasswordEncryptor( new SaltedPasswordEncryptor() ); - userManager = userManagerFactory.createUserManager(); - serverFactory.setUserManager( userManager ); - - // add the Ftplet - HashMap map = new HashMap(); - map.put( "Ftplet1", new MasterFtplet() ); - serverFactory.setFtplets( map ); - - // start the server - server = serverFactory.createServer(); - ini = true; - } - - public FtpCredentials addUser( final String serverSessionId ) - { - FtpCredentials ftpCredentials = null; - - String generatedUser = RandomString.generate( 10, false ); - String generatedPass = RandomString.generate( 16, true ); - - String dir = Globals.getPropertyString( Globals.PropString.FTPBASEDIR ) + "/" - + generatedUser + "/"; - - if ( !new File( dir ).mkdir() ) { - return ftpCredentials; - } - - BaseUser user = new BaseUser(); - user.setName( generatedUser ); - user.setPassword( generatedPass ); - user.setHomeDirectory( dir ); - - List authorities = new ArrayList(); - authorities.add( new WritePermission() ); - user.setAuthorities( authorities ); - - try { - userManager.save( user ); - ftpCredentials = new FtpCredentials( generatedUser, generatedPass ); - users.put( serverSessionId, ftpCredentials ); - timeouts.put( ftpCredentials.username, new Date() ); - } catch ( FtpException e ) { - } - - log.info( "Generated user/pass: " + generatedUser + "\t" - + generatedPass + "\n with home dir: " + dir ); - - return ftpCredentials; - } - - public boolean removeUser( final String serverSessionId ) - { - if ( !users.containsKey( serverSessionId ) ) - return false; - - try { - userManager.delete( users.get( serverSessionId ).username ); - // remove user from both maps - timeouts.remove( users.remove( serverSessionId ).username ); - return true; - } catch ( FtpException e ) { - return false; - } - } - - public FtpCredentials getCredentialsFromSessionId( String serverSessionId ) - { - return users.get( serverSessionId ); - } - - @Override - public void run() - { - try { - log.info( "Starting FTP Sever" ); - server.start(); - } catch ( FtpException e1 ) { - e1.printStackTrace(); - } - } -} diff --git a/src/main/java/org/openslx/imagemaster/server/MasterFtplet.java b/src/main/java/org/openslx/imagemaster/server/MasterFtplet.java deleted file mode 100644 index a8c1cbe..0000000 --- a/src/main/java/org/openslx/imagemaster/server/MasterFtplet.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.openslx.imagemaster.server; - -import java.io.IOException; - -import org.apache.ftpserver.ftplet.FtpException; -import org.apache.ftpserver.ftplet.FtpReply; -import org.apache.ftpserver.ftplet.FtpRequest; -import org.apache.ftpserver.ftplet.FtpSession; -import org.apache.ftpserver.ftplet.Ftplet; -import org.apache.ftpserver.ftplet.FtpletContext; -import org.apache.ftpserver.ftplet.FtpletResult; -import org.apache.log4j.Logger; - -public class MasterFtplet implements Ftplet -{ - private static Logger log = Logger.getLogger( Ftplet.class ); - - @Override - public void init( FtpletContext ftpletContext ) throws FtpException - { - // not used - } - - @Override - public void destroy() - { - // not used - } - - @Override - public FtpletResult beforeCommand( FtpSession session, FtpRequest request ) - throws FtpException, IOException - { - if ( session.getUser() != null ) { - log.info( session.getUser().getName() + " issued command: " + request.getRequestLine() ); - } - return null; - } - - @Override - public FtpletResult afterCommand( FtpSession session, FtpRequest request, - FtpReply reply ) throws FtpException, IOException - { - // not used - return null; - } - - @Override - public FtpletResult onConnect( FtpSession session ) throws FtpException, - IOException - { - // not used - return null; - } - - @Override - public FtpletResult onDisconnect( FtpSession session ) throws FtpException, - IOException - { - // not used - return null; - } - -} diff --git a/src/main/java/org/openslx/imagemaster/serversession/ServerAuthenticator.java b/src/main/java/org/openslx/imagemaster/serversession/ServerAuthenticator.java index 726b062..24e2928 100644 --- a/src/main/java/org/openslx/imagemaster/serversession/ServerAuthenticator.java +++ b/src/main/java/org/openslx/imagemaster/serversession/ServerAuthenticator.java @@ -1,10 +1,14 @@ package org.openslx.imagemaster.serversession; +import java.nio.ByteBuffer; import java.util.HashMap; import org.apache.log4j.Logger; import org.apache.thrift.TException; +import org.openslx.imagemaster.Globals; +import org.openslx.imagemaster.Globals.PropString; import org.openslx.imagemaster.thrift.iface.AuthenticationException; +import org.openslx.imagemaster.util.AsymMessageSign; import org.openslx.imagemaster.util.RandomString; public class ServerAuthenticator @@ -12,6 +16,22 @@ public class ServerAuthenticator private static Logger log = Logger.getLogger( ServerAuthenticator.class ); // map of currently authenticating servers private static HashMap authenticatingServers = new HashMap(); + private static AsymMessageSign messageSign = null; + + /** + * Initialize the message signer/verifier + */ + static { + try { + messageSign = new AsymMessageSign( Globals.getPropertyString( PropString.KEYSTOREALIAS ), + Globals.getPropertyString( PropString.KEYSTOREPASSWORD ), + Globals.getPropertyString( PropString.KEYSTOREFILE ) ); + log.info( "Loaded keystore" ); + } catch ( Exception e ) { + log.error( "Error loading the keystore", e ); + System.exit(1); + } + } /** * Start the server authentification. @@ -43,20 +63,26 @@ public class ServerAuthenticator * @throws TException */ public static ServerUser serverAuthenticate( String organization, - String address, String challengeResponse ) + String address, ByteBuffer challengeResponse ) throws AuthenticationException, TException { - /* - * TODO: Decrypt the given challengeResponse and check whether it was - * right or not. Authenticate server if so. - */ - if ( !challengeResponse.equals( authenticatingServers.get( organization ) ) ) { + byte[] bytes = challengeResponse.array(); + log.info( "Response was: " + challengeResponse + " with length: " + bytes.length); + + boolean result = false; + + try { + result = messageSign.verifyMessage( bytes, authenticatingServers.get( organization ).getBytes() ); + } catch (Exception e) { + log.error( "Error while verifying message", e ); + } + + if ( !result ) { throw new AuthenticationException(); } log.info( "Server of organinzation '" + organization - + " authenticated. With response: '" + challengeResponse - + "'" ); + + " authenticated."); authenticatingServers.remove( organization ); diff --git a/src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java b/src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java index 16496a2..5cc82fc 100644 --- a/src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java +++ b/src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java @@ -1,5 +1,7 @@ package org.openslx.imagemaster.thrift.server; +import java.nio.ByteBuffer; + import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.openslx.imagemaster.server.ApiServer; @@ -9,6 +11,7 @@ import org.openslx.imagemaster.thrift.iface.FtpCredentials; import org.openslx.imagemaster.thrift.iface.ImageData; import org.openslx.imagemaster.thrift.iface.ImageServer; import org.openslx.imagemaster.thrift.iface.InvalidTokenException; +import org.openslx.imagemaster.thrift.iface.ServerAuthenticationException; import org.openslx.imagemaster.thrift.iface.ServerSessionData; import org.openslx.imagemaster.thrift.iface.SessionData; import org.openslx.imagemaster.thrift.iface.UserInfo; @@ -48,7 +51,7 @@ public class ImageServerHandler implements ImageServer.Iface @Override public ServerSessionData serverAuthenticate( String organization, - String challengeResponse ) throws AuthenticationException, + ByteBuffer challengeResponse ) throws AuthenticationException, TException { return ApiServer.serverAuthenticate( organization, challengeResponse ); diff --git a/src/main/java/org/openslx/imagemaster/util/AsymMessageSign.java b/src/main/java/org/openslx/imagemaster/util/AsymMessageSign.java new file mode 100644 index 0000000..134b399 --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/util/AsymMessageSign.java @@ -0,0 +1,63 @@ +package org.openslx.imagemaster.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; + +public class AsymMessageSign +{ + + KeyPair pair; + +// String alias = "ftp"; +// String password = "password"; +// String file = "./config/keystore.jks"; + + + public AsymMessageSign(String alias, String password, String file) throws NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, KeyStoreException, UnrecoverableKeyException + { + KeyStore keystore = KeyStore.getInstance( "JKS" ); + keystore.load( new FileInputStream( new File( file ) ), password.toCharArray() ); + Certificate cert = null; + + Key key = keystore.getKey( alias, + password.toCharArray() ); + + if ( key instanceof PrivateKey ) { + cert = keystore.getCertificate( alias ); + PublicKey publicKey = cert.getPublicKey(); + pair = new KeyPair( publicKey, (PrivateKey)key ); + } + } + + public byte[] signMessage( String message ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException + { + Signature signature = Signature.getInstance( "SHA256WITHRSA" ); + signature.initSign( pair.getPrivate() ); + signature.update( message.getBytes() ); + return signature.sign(); + } + + public boolean verifyMessage( byte[] signedMessage, byte[] realMessage ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException + { + Signature signature = Signature.getInstance( "SHA256WITHRSA" ); + signature.initVerify( pair.getPublic() ); + signature.update( realMessage ); + return signature.verify( signedMessage ); + } + +} diff --git a/src/main/java/org/openslx/imagemaster/util/Util.java b/src/main/java/org/openslx/imagemaster/util/Util.java index 0df4212..9805c21 100644 --- a/src/main/java/org/openslx/imagemaster/util/Util.java +++ b/src/main/java/org/openslx/imagemaster/util/Util.java @@ -1,9 +1,27 @@ package org.openslx.imagemaster.util; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.util.Random; import org.apache.log4j.Logger; +import org.openslx.imagemaster.Globals; +import org.openslx.imagemaster.Globals.PropString; public class Util { @@ -70,5 +88,5 @@ public class Util } folder.delete(); } - + } diff --git a/src/main/thrift/imagemaster.thrift b/src/main/thrift/imagemaster.thrift index fdf63ee..5db7b05 100644 --- a/src/main/thrift/imagemaster.thrift +++ b/src/main/thrift/imagemaster.thrift @@ -93,7 +93,7 @@ service ImageServer { string startServerAuthentication(1:string organization), - ServerSessionData serverAuthenticate(1:string organization, 2:string challengeResponse) throws (1:ServerAuthenticationException failure), + ServerSessionData serverAuthenticate(1:string organization, 2:binary challengeResponse) throws (1:ServerAuthenticationException failure), FtpCredentials submitImage(1:string serverSessionId, 2:ImageData imageDescription) throws (1:AuthorizationException failure), -- cgit v1.2.3-55-g7522