package org.openslx.imagemaster.db; import java.io.File; import java.io.IOException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.cert.CertificateException; import javax.net.ssl.TrustManagerFactory; 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.LdapConnection; import org.apache.directory.ldap.client.api.LdapConnectionConfig; import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.log4j.Logger; import org.apache.mina.filter.ssl.KeyStoreFactory; 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; import org.openslx.imagemaster.util.Sha512Crypt; /** * Represents a user instance that was queries (primarily) from LDAP. * Additional information that is not provided by the LDAP server might * be fetched from other sources, like the local database (DbUser.java). */ public class LdapUser extends User { private static final Logger log = Logger.getLogger( LdapUser.class ); protected LdapUser(int userId, String username, String password, String organization, String firstName, String lastName, String eMail, String satelliteAddress) { super( userId, username, password, organization, firstName, lastName, eMail, satelliteAddress ); } /** * Query LDAP for user with given login * * @param login Login of user in the form "prefix_username" * @return instance of LDAPUser for matching entry from LDAP or null if sth went wrong */ public static LdapUser forLogin( final String login, final String password ) throws AuthenticationException { String username, organization, firstName, lastName, eMail, satelliteAddress = ""; final String[] split = login.split( "_" ); if (split.length != 2) throw new AuthenticationException(AuthenticationError.GENERIC_ERROR, "Login must be in form: prefix_username"); LdapConnection connection = null; try { LdapConnectionConfig config = new LdapConnectionConfig(); String ldapHost = Globals.getLdapHost(); log.debug( "Setting host... " + ldapHost ); config.setLdapHost( ldapHost ); boolean useSsl = Globals.getLdapSsl(); log.debug( "Setting use ssl... " + useSsl); config.setUseSsl( useSsl ); int ldapPort = Globals.getLdapPort(); log.debug( "Setting port... " + ldapPort ); config.setLdapPort( ldapPort ); // load keystore ... KeyStoreFactory ksf = new KeyStoreFactory(); ksf.setDataFile( new File(Globals.getLdapKeystorePath()) ); ksf.setPassword( Globals.getLdapKeystorePassword()); ksf.setType( "jks" ); // ... and set TrustManager TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() ); tmf.init( ksf.newInstance() ); config.setTrustManagers( tmf.getTrustManagers() ); connection = new LdapNetworkConnection( config ); log.debug( "Trying to bind..." ); String bind = Globals.getLdapBindQuery().replace( "%", login ); connection.bind( bind, password ); //connection.bind(); log.debug( "Bind successful" ); // make search query EntryCursor cursor = connection.search( Globals.getLdapSearchBaseDn(), Globals.getLdapSearchFilter().replace( "%", login ), SearchScope.SUBTREE ); // only use the first result cursor.next(); Entry entry = cursor.get(); username = entry.get( "cn" ).toString().split( " " )[1].split( "@" )[0]; organization = entry.get( "cn" ).toString().split( "@" )[1]; firstName = entry.get( "givenName" ).getString(); lastName = entry.get( "sn" ).getString(); eMail = entry.get( "mail" ).getString(); // get the satellite address from db DbSatellite dbSatellite = DbSatellite.fromSuffix( organization ); if ( dbSatellite != null ) { satelliteAddress = dbSatellite.getAddress(); } else { // Organization is not known. This should not happen because the login would have failed then. throw new AuthenticationException( AuthenticationError.GENERIC_ERROR, "Your Organization is not known by the server. Please contact your administrator." ); } // everything went fine return new LdapUser( 0, username, Sha512Crypt.Sha512_crypt( password, null, 0 ), organization, firstName, lastName, eMail, satelliteAddress ); } catch ( LdapException e) { if ( e.getMessage().contains( "Cannot connect on the server" ) ) { DbSatellite dbSatellite = DbSatellite.fromPrefix(split[0]); if (dbSatellite == null) throw new AuthenticationException(AuthenticationError.INVALID_CREDENTIALS, "Credentials invalid."); String lo = split[1] + "@" + dbSatellite.getOrganizationId(); log.info( "LDAP server could not be reached. Trying to connect locally with: " + lo ); return LdapUser.localLogin(lo, password); } e.printStackTrace(); throw new AuthenticationException( AuthenticationError.GENERIC_ERROR, "Something went wrong." ); } catch ( CursorException e ) { e.printStackTrace(); throw new AuthenticationException( AuthenticationError.INVALID_CREDENTIALS, "Could not find user entry." ); } catch ( IOException e ) { // could not load keyfile e.printStackTrace(); } catch ( NoSuchAlgorithmException e ) { // could not load algorithm e.printStackTrace(); } catch ( KeyStoreException | NoSuchProviderException | CertificateException e ) { // some problem with the key e.printStackTrace(); } finally { // close connection try { connection.unBind(); connection.close(); } catch ( IOException | LdapException e ) { // was not connected so don't do anything... } } return null; } /** * Login user locally if external Ldap server is not available * @param eppn Must be in form "username@organization" * @param password The user's password */ private static LdapUser localLogin( String login, String password ) { DbUser user = DbUser.forLogin( login ); if (user == null) return null; // no user found // check users password if (!Sha512Crypt.verifyPassword( password, user.password )) return null; // return ldapuser if valid return new LdapUser( user.userId, user.eppn, Sha512Crypt.Sha512_crypt( password, null, 0 ), user.organizationId, user.firstName, user.lastName, user.eMail, user.satelliteAddress ); } }