diff options
author | Nils Schwabe | 2014-04-22 16:56:07 +0200 |
---|---|---|
committer | Nils Schwabe | 2014-04-22 16:56:07 +0200 |
commit | 01e662bdfff823c4f5f0b6a270807fd0a3d2825f (patch) | |
tree | daf063bc84c06781768794c17cc76f08decaa9c3 | |
parent | Added test case for sha512crypt, removed try/catch blocks from other tests, s... (diff) | |
download | masterserver-01e662bdfff823c4f5f0b6a270807fd0a3d2825f.tar.gz masterserver-01e662bdfff823c4f5f0b6a270807fd0a3d2825f.tar.xz masterserver-01e662bdfff823c4f5f0b6a270807fd0a3d2825f.zip |
added a method to imageserver so that finshed uploads can be signaled
did some todos from simon
moved FtpCredentials creation to MasterFtpServer.java
moved some options to to config file
10 files changed, 233 insertions, 62 deletions
diff --git a/config/global.properties.example b/config/global.properties.example index c628288..e2e1a3b 100644 --- a/config/global.properties.example +++ b/config/global.properties.example @@ -1,2 +1,34 @@ # fill in properties and rename to global.properties + +##################### +# Directories # +##################### + +# the base dir of the ftp server (should exists) ftp_base_dir=/tmp + +# the dir where the images are stored +image_dir=/tmp + +##################### +# LDAP data # +##################### + +# the port of the LDAP server +ldap_port=636 + +# the host address of the LDAP server +ldap_host=bv1.ruf.uni-freiburg.de + +# SSL usage +ldap_ssl=true + +# bind query (don't forget to escape \= and use a % for the username replacement +ldap_bind_query=uid\=%,ou\=people,dc\=uni-freiburg,dc\=de + +# search baseDn +ldap_search_base_dn=ou\=people,dc\=uni-freiburg,dc\=de + + +# search filter (use a % for the username replacement +ldap_search_filter=(&(objectclass\=person)(uid\=%))
\ No newline at end of file diff --git a/src/main/java/org/openslx/imagemaster/App.java b/src/main/java/org/openslx/imagemaster/App.java index 3a309c5..aba2cd6 100644 --- a/src/main/java/org/openslx/imagemaster/App.java +++ b/src/main/java/org/openslx/imagemaster/App.java @@ -25,6 +25,10 @@ public class App { stream = new BufferedInputStream(new FileInputStream( "config/global.properties")); Globals.properties.load(stream); + if (!Globals.propertiesValid()) { + log.error("Config file contains errors."); + System.exit(1); + } } catch (IOException e) { log.error("Could not load config file. Quitting."); error = true; diff --git a/src/main/java/org/openslx/imagemaster/Globals.java b/src/main/java/org/openslx/imagemaster/Globals.java index b766b27..653e255 100644 --- a/src/main/java/org/openslx/imagemaster/Globals.java +++ b/src/main/java/org/openslx/imagemaster/Globals.java @@ -2,10 +2,57 @@ package org.openslx.imagemaster; import java.util.Properties; +import org.apache.commons.lang3.StringUtils; import org.openslx.imagemaster.server.MasterFtpServer; public class Globals { public static final Properties properties = new Properties(); + public static final MasterFtpServer ftpServer = new MasterFtpServer(2221, "admin", "SI*HoZCC!]V)p>B2", Globals.properties.getProperty("ftp_base_dir")); + + // properties + public static final String ftpBaseDir = "ftp_base_dir"; + public static final String imageDir = "image_dir"; + public static final String ldapPort = "ldap_port"; + public static final String ldapHost = "ldap_host"; + public static final String ldapSsl = "ldap_ssl"; + public static final String ldapBindQuery = "ldap_bind_query"; + public static final String ldapSearchBaseDn = "ldap_search_base_dn"; + public static final String ldapSearchFilter = "ldap_search_filter"; + + public static boolean propertiesValid() { + if (Globals.properties.getProperty(ftpBaseDir).isEmpty() + || Globals.properties.getProperty(imageDir).isEmpty() + || Globals.properties.getProperty(ldapPort).isEmpty() + || Globals.properties.getProperty(ldapHost).isEmpty() + || Globals.properties.getProperty(ldapSsl).isEmpty() + || Globals.properties.getProperty(ldapBindQuery).isEmpty() + || Globals.properties.getProperty(ldapSearchBaseDn).isEmpty() + || Globals.properties.getProperty(ldapSearchBaseDn).isEmpty() + ) { + return false; + } + + if (StringUtils.countMatches(Globals.properties.getProperty(ldapBindQuery), "%") != 1) { + return false; + } + + if (StringUtils.countMatches(Globals.properties.getProperty(ldapSearchFilter), "%") != 1) { + return false; + } + + // remove "/" at the end of the path + String ftp = Globals.properties.getProperty(ftpBaseDir); + if (ftp.endsWith("/")) { + Globals.properties.put(ftpBaseDir, ftp.substring(0, ftp.length() - 1)); + } + + String image = Globals.properties.getProperty(imageDir); + if (image.endsWith("/")) { + Globals.properties.put(imageDir, image.substring(0, image.length() -1 )); + } + + return true; + } } diff --git a/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java b/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java index d43b507..8c8bd8c 100644 --- a/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java +++ b/src/main/java/org/openslx/imagemaster/db/ImageProcessor.java @@ -12,10 +12,18 @@ public class ImageProcessor { private static Logger log = Logger.getLogger(ImageProcessor.class); private static HashMap<String, ImageData> images = new HashMap<>(); - public static void processImageAfterUpload(String username, String filename) { - /* - * TODO: Process the image after download - */ + + /** + * 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 + "'"); @@ -27,7 +35,7 @@ public class ImageProcessor { if (!imageFile.exists()) { // image file does not exist - return; + return false; } imageFile.renameTo( new File(newFileName) ); @@ -40,6 +48,9 @@ public class ImageProcessor { // update database DbImage.update(images.get(username), newFileName); log.info("Updated db: " + images.get(username).uuid); + + images.remove(username); + return true; } /** diff --git a/src/main/java/org/openslx/imagemaster/db/LdapUser.java b/src/main/java/org/openslx/imagemaster/db/LdapUser.java index 17bf65e..1124696 100644 --- a/src/main/java/org/openslx/imagemaster/db/LdapUser.java +++ b/src/main/java/org/openslx/imagemaster/db/LdapUser.java @@ -14,6 +14,7 @@ import org.apache.directory.api.ldap.model.message.SearchScope; import org.apache.directory.ldap.client.api.LdapConnectionConfig; import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.log4j.Logger; +import org.openslx.imagemaster.Globals; import org.openslx.imagemaster.session.User; import org.openslx.imagemaster.thrift.iface.AuthenticationError; import org.openslx.imagemaster.thrift.iface.AuthenticationException; @@ -63,24 +64,27 @@ public class LdapUser extends User * @param login Login of user in the form "user@organization.com" * @return instance of LDAPUser for matching entry from LDAP, or null if not found */ - @SuppressWarnings("finally") public static LdapUser forLogin( final String login, final String password ) throws AuthenticationException { - String username, organization, firstName, lastName, eMail, satelliteAddress; + String username, organization, firstName, lastName, eMail, satelliteAddress; + + String[] temp = login.split("@"); + if (temp.length != 2) throw new AuthenticationException( AuthenticationError.GENERIC_ERROR, "Login must be in form user@organization.com"); + username = temp[0]; - // TODO: Read connection info from config file LdapConnectionConfig ldapConfig = new LdapConnectionConfig(); ldapConfig.setTrustManagers(new MyTrustManager()); - ldapConfig.setLdapPort(636); - ldapConfig.setLdapHost("bv1.ruf.uni-freiburg.de"); - ldapConfig.setUseSsl(true); + ldapConfig.setLdapPort(Integer.valueOf(Globals.properties.getProperty(Globals.ldapPort))); + ldapConfig.setLdapHost(Globals.properties.getProperty(Globals.ldapHost)); + ldapConfig.setUseSsl(Boolean.valueOf(Globals.properties.getProperty(Globals.ldapSsl))); LdapNetworkConnection connection = new LdapNetworkConnection( ldapConfig ); // bind connection - // TODO: Hard coded stuff here too. binddn, search query etc. need to be configurable try { - if ( connection.connect() ) - connection.bind("uid=" + login + ",ou=people,dc=uni-freiburg,dc=de", password); + if ( connection.connect() ) { + String name = Globals.properties.getProperty(Globals.ldapBindQuery).replace("%", username); + connection.bind(name, password); + } } catch (LdapException e1) { log.warn( "Connection to LDAP failed: " + e1.getMessage() ); } @@ -108,8 +112,8 @@ public class LdapUser extends User // make search query try { - EntryCursor cursor = connection.search("ou=people,dc=uni-freiburg,dc=de", "(&(objectclass=person)(uid=" - + login + "))", SearchScope.SUBTREE); + EntryCursor cursor = connection.search(Globals.properties.getProperty(Globals.ldapSearchBaseDn), + Globals.properties.getProperty(Globals.ldapSearchFilter).replace("%", username), SearchScope.SUBTREE); // only use the first result cursor.next(); Entry entry = cursor.get(); diff --git a/src/main/java/org/openslx/imagemaster/server/ApiServer.java b/src/main/java/org/openslx/imagemaster/server/ApiServer.java index eda48eb..fc1d9b0 100644 --- a/src/main/java/org/openslx/imagemaster/server/ApiServer.java +++ b/src/main/java/org/openslx/imagemaster/server/ApiServer.java @@ -1,7 +1,9 @@ package org.openslx.imagemaster.server; import java.io.File; +import java.util.HashMap; +import org.apache.ftpserver.ftplet.FtpException; import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.openslx.imagemaster.Globals; @@ -17,10 +19,13 @@ import org.openslx.imagemaster.session.SessionManager; import org.openslx.imagemaster.session.User; import org.openslx.imagemaster.thrift.iface.AuthenticationError; import org.openslx.imagemaster.thrift.iface.AuthenticationException; +import org.openslx.imagemaster.thrift.iface.AuthorizationError; import org.openslx.imagemaster.thrift.iface.AuthorizationException; import org.openslx.imagemaster.thrift.iface.FtpCredentials; import org.openslx.imagemaster.thrift.iface.ImageData; import org.openslx.imagemaster.thrift.iface.InvalidTokenException; +import org.openslx.imagemaster.thrift.iface.ServerAuthenticationError; +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; @@ -85,29 +90,22 @@ public class ApiServer { * @throws AuthorizationException if the uni/hs server has no valid session * @throws TException */ - public static FtpCredentials submitImage(ImageData imageDescription, - ServerSessionData serverSessionData) throws AuthorizationException, + public static FtpCredentials submitImage(String serverSessionId, + ImageData imageDescription) throws AuthorizationException, TException { - if (ServerSessionManager.getSession(serverSessionData.sessionId) == null) { - throw new AuthenticationException(AuthenticationError.GENERIC_ERROR, "No valid serverSessionData"); + if (ServerSessionManager.getSession(serverSessionId) == null) { + throw new AuthorizationException(AuthorizationError.NOT_AUTHENTICATED, "No valid serverSessionData"); } - String generatedUser = RandomString.generate(10, false); - String generatedPass = RandomString.generate(16, true); + // create new user + FtpCredentials ftpCredentials = Globals.ftpServer.addUser(serverSessionId); - if (!ImageProcessor.addImageDataToProcess(imageDescription, generatedUser)) { + if (!ImageProcessor.addImageDataToProcess(imageDescription, ftpCredentials.username)) { + Globals.ftpServer.removeUser(serverSessionId); throw new TException("ImageData is not valid."); } - - String dir = Globals.properties.getProperty("ftp_base_dir") + "/" - + generatedUser + "/"; - if (new File(dir).mkdir()) { - Globals.ftpServer.addUser(generatedUser, generatedPass, dir, true); - log.info("Generated user/pass: " + generatedUser + "\t" - + generatedPass + "\n with home dir: " + dir); - } - - return new FtpCredentials(generatedUser, generatedPass); + + return ftpCredentials; } /** @@ -115,16 +113,15 @@ public class ApiServer { * @param organization the organization that the server belongs to * @return a random string that needs to be encrypted with the private * key of the requesting satellite server - * @throws TException + * @throws ServerAuthenticationException when organization is invalid/unknown */ public static String startServerAuthentication(String organization) - throws TException { - // TODO: Proper exceptions + throws ServerAuthenticationException { if (organization == null || organization == "") { - throw new TException("Empty organization"); + throw new ServerAuthenticationException(ServerAuthenticationError.INVALID_ORGANIZATION, "Empty organization"); } if (DbSatellite.fromOrganization(organization) == null) { - throw new TException("Unkown organization"); + throw new ServerAuthenticationException(ServerAuthenticationError.INVALID_ORGANIZATION, "Unknown organization"); } return ServerAuthenticator.startServerAuthentication(organization); } @@ -140,13 +137,12 @@ public class ApiServer { public static ServerSessionData serverAuthenticate(String organization, String challengeResponse) throws AuthenticationException, TException { - // TODO: Proper exceptions if (organization == null || challengeResponse == null) { - throw new TException("Empty organization org challengeResponse"); + throw new ServerAuthenticationException(ServerAuthenticationError.INVALID_ORGANIZATION, "Empty organization or challengeResponse"); } DbSatellite satellite = DbSatellite.fromOrganization(organization); if (satellite == null) { - throw new TException("Unkown organization"); + throw new ServerAuthenticationException(ServerAuthenticationError.INVALID_ORGANIZATION, "Unknown organization"); } final ServerUser serverUser = ServerAuthenticator.serverAuthenticate( organization, satellite.getAddress(), challengeResponse); @@ -155,4 +151,39 @@ public class ApiServer { return ServerSessionManager.addSession(session); } + /** + * Tell the masterserver that the image upload finished. + * @param serverSessionId The session id of the hs/uni server + * @param imageDescription the description of the uploaded image + * @return if nothing went wrong + * @throws AuthorizationException if no valid session exists + */ + public static boolean finishedUpload(String serverSessionId, + ImageData imageDescription) throws AuthorizationException { + // check if valid session exists + if (ServerSessionManager.getSession(serverSessionId) == null) { + throw new AuthorizationException(AuthorizationError.NOT_AUTHENTICATED, "No valid serverSessionData"); + } + + // process the image + String username = Globals.ftpServer.getCredentialsFromSessionId(serverSessionId).username; + + File userDirectory = new File(Globals.properties.getProperty(Globals.ftpBaseDir) + "/" + username); + File[] list = userDirectory.listFiles(); + + if (list.length != 1) return false; + + log.info(username + " is done with upload"); + + // remove user that is not needed anymore + Globals.ftpServer.removeUser(username); + log.info("Removed user: " + username); + + ImageProcessor.processImageAfterUpload(username, list[0].getName()); + + Globals.ftpServer.removeUser(serverSessionId); + + return true; + } + } diff --git a/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java b/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java index 973c768..c6592bc 100644 --- a/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java +++ b/src/main/java/org/openslx/imagemaster/server/MasterFtpServer.java @@ -17,11 +17,15 @@ 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; + private HashMap<String, FtpCredentials> users = new HashMap<>(); public MasterFtpServer(int port, String adminUsername, String adminPassword, String ftproot) { FtpServerFactory serverFactory = new FtpServerFactory(); @@ -39,7 +43,7 @@ public class MasterFtpServer implements Runnable { userManager = userManagerFactory.createUserManager(); // create new admin user - addUser(adminUsername, adminPassword, ftproot, true); + //addUser(adminUsername, adminPassword, ftproot, true); serverFactory.setUserManager(userManager); // add the Ftplet @@ -51,38 +55,57 @@ public class MasterFtpServer implements Runnable { server = serverFactory.createServer(); } - public boolean addUser(final String username, final String password, final String ftproot, final boolean writeAccess) { + public FtpCredentials addUser(final String serverSessionId) { // TODO: enable SSL - boolean result = true; + + FtpCredentials ftpCredentials = null; + + String generatedUser = RandomString.generate(10, false); + String generatedPass = RandomString.generate(16, true); + + String dir = Globals.properties.getProperty(Globals.ftpBaseDir) + "/" + + generatedUser + "/"; + + if (!new File(dir).mkdir()) { + return ftpCredentials; + } BaseUser user = new BaseUser(); - user.setName(username); - user.setPassword(password); - user.setHomeDirectory(ftproot); + user.setName(generatedUser); + user.setPassword(generatedPass); + user.setHomeDirectory(dir); List<Authority> authorities = new ArrayList<Authority>(); - if (writeAccess) authorities.add(new WritePermission()); + authorities.add(new WritePermission()); user.setAuthorities(authorities); try { userManager.save(user); + ftpCredentials = new FtpCredentials(generatedUser, generatedPass); + users.put(serverSessionId, ftpCredentials); } catch (FtpException e) { - result = false; } - return result; + log.info("Generated user/pass: " + generatedUser + "\t" + + generatedPass + "\n with home dir: " + dir); + + return ftpCredentials; } - public boolean removeUser(final String username) { - boolean result = true; + public boolean removeUser(final String serverSessionId) { + if (!users.containsKey(serverSessionId)) return false; try { - userManager.delete(username); + userManager.delete(users.get(serverSessionId).username); + users.remove(serverSessionId); + return true; } catch (FtpException e) { - result = false; + return false; } - - return result; + } + + public FtpCredentials getCredentialsFromSessionId(String serverSessionId) { + return users.get(serverSessionId); } @Override 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 096f63f..899af1a 100644 --- a/src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java +++ b/src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java @@ -53,10 +53,16 @@ public class ImageServerHandler implements ImageServer.Iface } @Override - public FtpCredentials submitImage(ImageData imageDescription, - ServerSessionData serverSessionData) throws AuthorizationException, + public FtpCredentials submitImage(String serverSessionId, + ImageData imageDescription) throws AuthorizationException, TException { - return ApiServer.submitImage(imageDescription, serverSessionData); + return ApiServer.submitImage(serverSessionId, imageDescription); + } + + @Override + public boolean finshedUpload(String serverSessionId, + ImageData imageDescription) throws AuthorizationException { + return ApiServer.finishedUpload(serverSessionId, imageDescription); } } diff --git a/src/main/thrift/imagemaster.thrift b/src/main/thrift/imagemaster.thrift index a164e9b..fdf63ee 100644 --- a/src/main/thrift/imagemaster.thrift +++ b/src/main/thrift/imagemaster.thrift @@ -23,6 +23,12 @@ enum AuthenticationError { BANNED_NETWORK } +enum ServerAuthenticationError { + GENERIC_ERROR, + INVALID_ORGANIZATION, + BANNED_NETWORK, +} + exception AuthorizationException { 1: AuthorizationError number, 2: string message @@ -36,6 +42,11 @@ exception AuthenticationException { exception InvalidTokenException { } +exception ServerAuthenticationException { + 1: ServerAuthenticationError number, + 2: string message +} + struct UserInfo { 1: string userId, 2: string firstName, @@ -82,9 +93,11 @@ service ImageServer { string startServerAuthentication(1:string organization), - ServerSessionData serverAuthenticate(1:string organization, 2:string challengeResponse) throws (1:AuthenticationException failure), + ServerSessionData serverAuthenticate(1:string organization, 2:string challengeResponse) throws (1:ServerAuthenticationException failure), + + FtpCredentials submitImage(1:string serverSessionId, 2:ImageData imageDescription) throws (1:AuthorizationException failure), - FtpCredentials submitImage(1:ImageData imageDescription, 2:ServerSessionData serverSessionData) throws (1:AuthorizationException failure) + bool finshedUpload(1:string serverSessionId, 2:ImageData imageDescription) throws (1:AuthorizationException failure) } diff --git a/src/test/java/org/openslx/imagemaster/AppTest.java b/src/test/java/org/openslx/imagemaster/AppTest.java index 120bd9e..a491242 100644 --- a/src/test/java/org/openslx/imagemaster/AppTest.java +++ b/src/test/java/org/openslx/imagemaster/AppTest.java @@ -122,7 +122,7 @@ public class AppTest System.out.println("Created imageData"); - FtpCredentials ftpCredentials = client.submitImage(imageData, data); + FtpCredentials ftpCredentials = client.submitImage(data.sessionId, imageData); System.out.println("Got FTP credentials. User: " + ftpCredentials.username + ", password: " + ftpCredentials.password); FTPClient FtpClient = new FTPClient(); |