summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/db/LdapUser.java
blob: b026e7eac3884df28b879e5018b71179ebddb3dc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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 );
	}
}