diff options
author | Nils Schwabe | 2014-04-08 12:23:58 +0200 |
---|---|---|
committer | Nils Schwabe | 2014-04-08 12:23:58 +0200 |
commit | c5c204b42ef294ecaf5ff7b048d26e117ddb8c57 (patch) | |
tree | e3aa563b42e631994818ca624796a076cbe50725 | |
parent | Initial Commit (diff) | |
download | masterserver-c5c204b42ef294ecaf5ff7b048d26e117ddb8c57.tar.gz masterserver-c5c204b42ef294ecaf5ff7b048d26e117ddb8c57.tar.xz masterserver-c5c204b42ef294ecaf5ff7b048d26e117ddb8c57.zip |
LDAP functionallity
- added apache ldap client api to pom.xml
- added the LDAP user which authenticates to the LDAP server
- added testAuthentication to AppTest
- users get inserted into db after authenticating
- added log4j properties to filter unuseful debug messages
-rw-r--r-- | config/mysql.properties (renamed from config/mysql.properties.example) | 0 | ||||
-rw-r--r-- | pom.xml | 14 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/App.java | 5 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/db/DbSatellite.java | 36 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/db/DbUser.java | 49 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/db/LDAPUser.java | 134 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/db/MySQL.java | 5 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/server/ApiServer.java | 3 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/session/Authenticator.java | 24 | ||||
-rw-r--r-- | src/main/java/org/openslx/imagemaster/thrift/server/ImageServerHandler.java | 5 | ||||
-rw-r--r-- | src/main/properties/log4j.properties | 11 | ||||
-rw-r--r-- | src/test/java/org/openslx/imagemaster/AppTest.java | 40 | ||||
-rwxr-xr-x | thrift-compile.sh | 6 |
13 files changed, 300 insertions, 32 deletions
diff --git a/config/mysql.properties.example b/config/mysql.properties index a434dff..a434dff 100644 --- a/config/mysql.properties.example +++ b/config/mysql.properties @@ -47,6 +47,14 @@ </configuration> </plugin> </plugins> + <resources> + <resource> + <directory>src/main/properties</directory> + <includes> + <include>**</include> + </includes> + </resource> + </resources> </build> <dependencies> @@ -86,5 +94,11 @@ <version>0.6.0</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>org.apache.directory.api</groupId> + <artifactId>api-all</artifactId> + <version>1.0.0-M21</version> + <scope>compile</scope> + </dependency> </dependencies> </project> diff --git a/src/main/java/org/openslx/imagemaster/App.java b/src/main/java/org/openslx/imagemaster/App.java index ef04e54..8040d35 100644 --- a/src/main/java/org/openslx/imagemaster/App.java +++ b/src/main/java/org/openslx/imagemaster/App.java @@ -3,7 +3,6 @@ package org.openslx.imagemaster; import java.util.ArrayList; import java.util.List; -import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; import org.openslx.imagemaster.thrift.server.BinaryListener; @@ -20,8 +19,8 @@ public class App public static void main( String[] args ) { // Init logging - BasicConfigurator.configure(); - log.info( "Starting Application" ); + log.info( "Starting Application" ); + // Create binary listener Thread t; t = new Thread(new BinaryListener(), "BinaryListener"); diff --git a/src/main/java/org/openslx/imagemaster/db/DbSatellite.java b/src/main/java/org/openslx/imagemaster/db/DbSatellite.java new file mode 100644 index 0000000..da20fbc --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/db/DbSatellite.java @@ -0,0 +1,36 @@ +package org.openslx.imagemaster.db; + +public class DbSatellite { + /* + * Get row from mysql db and + */ + + private String organization, address, name; + + // needs to be public in order to be found by MySQL + public DbSatellite(String organization, String address, String name) { + this.organization = organization; + this.address = address; + this.name = name; + } + + public static DbSatellite createDbSatellite(String organization) { + return MySQL + .findUniqueOrNull( + DbSatellite.class, + "SELECT satellite.organization, satellite.address, satellite.name FROM satellite WHERE satellite.organization = ? LIMIT 1", + organization); + } + + public String getAddress() { + return address; + } + + public String getName() { + return name; + } + + public String getOrganization() { + return organization; + } +}
\ No newline at end of file diff --git a/src/main/java/org/openslx/imagemaster/db/DbUser.java b/src/main/java/org/openslx/imagemaster/db/DbUser.java index f8400a9..9370f40 100644 --- a/src/main/java/org/openslx/imagemaster/db/DbUser.java +++ b/src/main/java/org/openslx/imagemaster/db/DbUser.java @@ -1,30 +1,45 @@ package org.openslx.imagemaster.db; +import org.apache.log4j.Logger; +import org.openslx.imagemaster.session.Authenticator; import org.openslx.imagemaster.session.User; - -public class DbUser extends User -{ - public DbUser(String username, String password, String organization, String firstName, String lastName, String eMail, - String satelliteAddress) - { - super( username, password, organization, firstName, lastName, eMail, satelliteAddress ); +public class DbUser extends User { + private static Logger log = Logger.getLogger( Authenticator.class ); + + public DbUser(String username, String password, String organization, + String firstName, String lastName, String eMail, + String satelliteAddress) { + super(username, password, organization, firstName, lastName, eMail, + satelliteAddress); } /** * Query database for user with given login - * @param login (user@organization) - * @return instance of DbUser for matching entry from DB, or null if not found + * + * @param login + * (user@organization) + * @return instance of DbUser for matching entry from DB, or null if not + * found */ - public static DbUser forLogin( final String login ) - { - final String[] parts = login.split( "@" ); - if ( parts.length != 2 ) + public static DbUser forLogin(final String login) { + final String[] parts = login.split("@"); + if (parts.length != 2) return null; - return MySQL.findUniqueOrNull( DbUser.class, - "SELECT user.username, user.password, user.organization, user.firstname, user.lastname, user.email, satellite.address FROM user" + - " LEFT JOIN satellite USING (organization)" + - " WHERE user.username = ? AND user.organization = ? LIMIT 1", parts[0], parts[1] ); + return MySQL + .findUniqueOrNull( + DbUser.class, + "SELECT user.username, user.password, user.organization, user.firstname, user.lastname, user.email, satellite.address FROM user" + + " LEFT JOIN satellite USING (organization)" + + " WHERE user.username = ? AND user.organization = ? LIMIT 1", + parts[0], parts[1]); + } + + public static boolean insertOrUpdate(User user) { + log.debug("Inserted user '" + user.username + "' into db."); + MySQL.update("INSERT INTO user (username, password, organization, firstname, lastname, email) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE password=VALUES(password), organization=VALUES(organization), firstname=VALUES(firstname), lastname=VALUES(lastname), email=VALUES(email)", + user.username, user.password, user.organization, user.firstName, user.lastName, user.eMail); + return false; } } diff --git a/src/main/java/org/openslx/imagemaster/db/LDAPUser.java b/src/main/java/org/openslx/imagemaster/db/LDAPUser.java new file mode 100644 index 0000000..ae8d38d --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/db/LDAPUser.java @@ -0,0 +1,134 @@ +package org.openslx.imagemaster.db; + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.X509TrustManager; + +import org.apache.directory.api.ldap.model.cursor.CursorException; +import org.apache.directory.api.ldap.model.cursor.EntryCursor; +import org.apache.directory.api.ldap.model.entry.Entry; +import org.apache.directory.api.ldap.model.exception.LdapException; +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.openslx.imagemaster.session.User; +import org.openslx.imagemaster.thrift.iface.AuthenticationException; +import org.openslx.imagemaster.util.Sha512Crypt; + +/* + * This TrustManager is used to accept custom certificates. + */ +class MyTrustManager implements X509TrustManager { + + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException {} + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException {} + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + +} + +public class LDAPUser extends User { + + protected LDAPUser(String username, String password, String organization, + String firstName, String lastName, String eMail, + String satelliteAddress) { + super(username, password, organization, firstName, lastName, eMail, + satelliteAddress); + } + + /** + * Query LDAP for user with given login + * @param login (user@organization) + * @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; + + LdapConnectionConfig ldapConfig = new LdapConnectionConfig(); + ldapConfig.setTrustManagers(new MyTrustManager()); + ldapConfig.setLdapPort(636); + ldapConfig.setLdapHost("bv1.ruf.uni-freiburg.de"); + ldapConfig.setUseSsl(true); + + LdapNetworkConnection connection = new LdapNetworkConnection( ldapConfig ); + + // bind connection + try { + connection.bind("uid=" + login + ",ou=people,dc=uni-freiburg,dc=de", password); + } catch (LdapException e1) { + try { + connection.unBind(); + connection.close(); + } catch (LdapException | IOException e) { + } finally { + AuthenticationException ae = new AuthenticationException(); + ae.message = "Could not bind to LDAP server. Invalid credentials."; + throw ae; + } + } + + // test authorization + if (!connection.isConnected() || !connection.isAuthenticated()) { + try { + connection.unBind(); + connection.close(); + } catch (LdapException | IOException e) { + } finally { + AuthenticationException ae = new AuthenticationException(); + ae.message = "Could not connect / authenticate to LDAP server. Invalid credentials?"; + throw ae; + } + } + + // make search query + try { + EntryCursor cursor = connection.search("ou=people,dc=uni-freiburg,dc=de", "(&(objectclass=person)(uid=" + + login + "))", SearchScope.SUBTREE); + // only use the first result + cursor.next(); + Entry entry = cursor.get(); + username = entry.get("uid").getString(); + organization = "Test Organization"; // will be filled with bwIDM LDAP server + firstName = entry.get("givenName").getString(); + lastName = entry.get("sn").getString(); + eMail = entry.get("rufPreferredMail").getString(); + // get the satellite address from db + DbSatellite dbSatellite = DbSatellite.createDbSatellite(organization); + if (dbSatellite != null) { + satelliteAddress = dbSatellite.getAddress(); + } else { + /* + * Organization is not known.. + * TODO: Handle this + */ + satelliteAddress = "addressNotKown"; + } + } catch (LdapException | CursorException e1) { + return null; + } finally { + // close connection + try { + connection.unBind(); + } catch (LdapException e) { + return null; + } + try { + connection.close(); + } catch (IOException e) { + return null; + } + } + return new LDAPUser(username, Sha512Crypt.Sha512_crypt(password, null, 0), organization, firstName, lastName, eMail, satelliteAddress); + } +} diff --git a/src/main/java/org/openslx/imagemaster/db/MySQL.java b/src/main/java/org/openslx/imagemaster/db/MySQL.java index 15bf5e2..a31046d 100644 --- a/src/main/java/org/openslx/imagemaster/db/MySQL.java +++ b/src/main/java/org/openslx/imagemaster/db/MySQL.java @@ -76,5 +76,8 @@ class MySQL { return db.findUniqueOrNull( clazz, sql, args ); } - + + protected static int update(String query, Object... args) { + return db.update(query, args); + } } diff --git a/src/main/java/org/openslx/imagemaster/server/ApiServer.java b/src/main/java/org/openslx/imagemaster/server/ApiServer.java index e62b61b..dd0ec9e 100644 --- a/src/main/java/org/openslx/imagemaster/server/ApiServer.java +++ b/src/main/java/org/openslx/imagemaster/server/ApiServer.java @@ -36,8 +36,7 @@ public class ApiServer * @throws AuthenticationException if login not successful */ public static SessionData authenticate( String login, String password ) - throws AuthenticationException - { + throws AuthenticationException { if ( login == null || password == null ) { throw new AuthenticationException( AuthenticationError.INVALID_CREDENTIALS, "Empty username or password!" ); } diff --git a/src/main/java/org/openslx/imagemaster/session/Authenticator.java b/src/main/java/org/openslx/imagemaster/session/Authenticator.java index f730c72..d1cca94 100644 --- a/src/main/java/org/openslx/imagemaster/session/Authenticator.java +++ b/src/main/java/org/openslx/imagemaster/session/Authenticator.java @@ -2,16 +2,17 @@ package org.openslx.imagemaster.session; import org.apache.log4j.Logger; import org.openslx.imagemaster.db.DbUser; +import org.openslx.imagemaster.db.LDAPUser; import org.openslx.imagemaster.thrift.iface.AuthenticationError; import org.openslx.imagemaster.thrift.iface.AuthenticationException; -import org.openslx.imagemaster.util.Sha512Crypt; + public class Authenticator { private static Logger log = Logger.getLogger( Authenticator.class ); /** - * Authenticate the user against whatever backend... currently MySQL only + * Authenticate the user against whatever backend * @param username * @param password * @return @@ -19,12 +20,23 @@ public class Authenticator */ public static User authenticate( String username, String password ) throws AuthenticationException { - DbUser user = DbUser.forLogin( username ); - if ( user == null || !Sha512Crypt.verifyPassword( password, user.password ) ) { - log.debug( "Login failed: " + username ); +// DbUser user = DbUser.forLogin( username ); +// if ( user == null || !Sha512Crypt.verifyPassword( password, user.password ) ) { +// log.debug( "Login failed: " + username ); +// throw new AuthenticationException( AuthenticationError.INVALID_CREDENTIALS, "Invalid username or password!" ); +// } +// log.debug( "Login successful: " + username ); + + LDAPUser user = LDAPUser.forLogin( username, password ); // throws exception if credentials are invalid + if (user == null) { + log.debug( "Login failed: " + username); throw new AuthenticationException( AuthenticationError.INVALID_CREDENTIALS, "Invalid username or password!" ); } - log.debug( "Login successful: " + username ); + log.debug( "Login succesful: " + username ); + + // if successfull: update/insert into db + DbUser.insertOrUpdate(user); + return user; } // 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 6be5d40..c1d3aa8 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,6 @@ package org.openslx.imagemaster.thrift.server; +import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.openslx.imagemaster.server.ApiServer; import org.openslx.imagemaster.thrift.iface.AuthenticationException; @@ -10,10 +11,12 @@ import org.openslx.imagemaster.thrift.iface.UserInfo; public class ImageServerHandler implements ImageServer.Iface { - + private static Logger log = Logger.getLogger( ApiServer.class ); + @Override public boolean ping() throws TException { + log.debug("Ping..."); // TODO: Return false if service unavailable but running return true; } diff --git a/src/main/properties/log4j.properties b/src/main/properties/log4j.properties new file mode 100644 index 0000000..4ef8d15 --- /dev/null +++ b/src/main/properties/log4j.properties @@ -0,0 +1,11 @@ +log4j.rootLogger=DEBUG, A1 + +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +log4j.appender.A1.layout=org.apache.log4j.PatternLayout + +log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n + +log4j.logger.org.apache.directory=ERROR +log4j.logger.org.apache.mina.filter.codec.ProtocolCodecFilter=ERROR +log4j.logger.org.apache.mina.filter.ssl=ERROR
\ No newline at end of file diff --git a/src/test/java/org/openslx/imagemaster/AppTest.java b/src/test/java/org/openslx/imagemaster/AppTest.java index 38cff57..775d5c8 100644 --- a/src/test/java/org/openslx/imagemaster/AppTest.java +++ b/src/test/java/org/openslx/imagemaster/AppTest.java @@ -4,6 +4,16 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; +import org.openslx.imagemaster.thrift.iface.ImageServer.Client; +import org.openslx.imagemaster.thrift.iface.SessionData; +import org.openslx.imagemaster.thrift.iface.UserInfo; + /** * Unit test for simple App. */ @@ -35,4 +45,34 @@ public class AppTest { assertTrue( true ); } + + /** + * Test the authentication + */ + public void testAuthentication() { + TTransport transport = new TSocket("localhost", 9090); + try { + transport.open(); + } catch (TTransportException e) { + assertTrue("Could not connect", false); + } + + TProtocol protocol = new TBinaryProtocol(transport); + Client client = new Client(protocol); + + try { + assertTrue("Could not ping server", client.ping()); + } catch (TException e) { + assertTrue("Could not ping server", false); + } + try { + SessionData sessionData = client.authenticate("ns202", "xxxxxxxxxx"); + UserInfo userInfo = client.getUserFromToken(sessionData.getAuthToken()); + System.out.println("User info: " + userInfo); + System.out.println("Server address from MySQL: " + sessionData.serverAddress); + } catch (TException e) { + e.printStackTrace(); + assertTrue("Could not login", false); + } + } } diff --git a/thrift-compile.sh b/thrift-compile.sh index 0a1099b..76be97c 100755 --- a/thrift-compile.sh +++ b/thrift-compile.sh @@ -1,7 +1,9 @@ #!/bin/sh rm -r gen-java -thrift --gen java src/main/thrift/imagemaster.thrift && \ - rm -r src/main/java/org/openslx/imagemaster/thrift/iface && \ +thrift --gen java src/main/thrift/imagemaster.thrift && { + rm -r src/main/java/org/openslx/imagemaster/thrift/iface cp -r gen-java/org src/main/java/ +} + |