blob: 8258dcf738d46e8e57c317812d03e76e1539fa88 [file] [log] [blame]
Bodmo3d6bd352017-04-25 11:31:39 +02001/* - Klasse zum Implementieren einer Benutzer-Authentifikation mittels LDAP
2 * in der IDM-Datenbank (Identit�tsmanagement) von Eric Seubert, IDS.
3 * - externe Bibliothek ist Novel JLDAP.
4 * 27.01.17/FB
5 *
6 * Sourcen:
7 * - https://www.novell.com/documentation/developer/samplecode/jldap_sample/VerifyPassword.java.html
8 * - https://www.novell.com/documentation/developer/samplecode/jldap_sample/LDAPOIDs.java.html
9 * - https://www.novell.com/documentation/developer/jldap/jldapenu/data/a90352e.html
10 * WICHTIG:
11 * - Novell-Bibliothek liefert 0 Treffer, wenn man nacheinander sucht!
12 * Grund daf�r nicht gefunden.
13 *
14 * Version von unboundID - 19.04.17/FB
15 *
16 * UnboundID LDAP SDK For Java � 3.2.1
17 * The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for
18 * communicating with LDAP directory servers and performing related tasks like reading and writing LDIF,
19 * encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package
20 * contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for
21 * communicating with LDAPv3 directory servers.
22 * TODO:
23 * - gesichertes Login mit gesch�tztem Passwort.
24 * - Passwort des Admin verschl�sseln.
25 */
26
margaretha139d0f72017-11-14 18:56:22 +010027package de.ids_mannheim.korap.authentication;
Bodmo3d6bd352017-04-25 11:31:39 +020028
margaretha235a6802018-06-06 19:21:53 +020029import com.nimbusds.jose.JOSEException;
Bodmo3d6bd352017-04-25 11:31:39 +020030import com.unboundid.ldap.sdk.*;
31
margaretha4de41192017-11-15 11:47:11 +010032import de.ids_mannheim.korap.config.KustvaktConfiguration;
margaretha0e8f4e72018-04-05 14:11:52 +020033import de.ids_mannheim.korap.constant.TokenType;
margaretha4de41192017-11-15 11:47:11 +010034
Bodmo3d6bd352017-04-25 11:31:39 +020035import java.io.*;
36import java.util.*;
37
38
39/**
40 * LDAP Login Tests
margaretha4de41192017-11-15 11:47:11 +010041 *
42 * @author bodmer, margaretha
43 * @see APIAuthentication
Bodmo3d6bd352017-04-25 11:31:39 +020044 */
margaretha4de41192017-11-15 11:47:11 +010045public class LdapAuth3 extends APIAuthentication {
Bodmo3d6bd352017-04-25 11:31:39 +020046
margaretha4de41192017-11-15 11:47:11 +010047 /* For SSL Connection to LDAP, see: https://www.novell.com/documentation/developer/jldap/jldapenu/data/cchcbejj.html.
Bodmo3d6bd352017-04-25 11:31:39 +020048 * and use DEFAULT_SSL_PORT.
49 * For now, plain text connection is used.
50 * FB
51 */
52 final static Boolean DEBUGLOG = false; // log debug output.
53 final static String attC2 = "idsC2"; // if value == TRUE: registered for COSMAS II (KorAP) Service.
54 final static String attStatus = "idsStatus"; // value must be 0..2, 3 = locked account.
55 final static int ldapPort = 389; //LDAPConnection.DEFAULT_PORT;
56 // final static int ldapVersion = LDAPConnection.LDAP_V3;
57 final static String ldapHost = "ldap.ids-mannheim.de";
58 final static String ldapBase = "dc=ids-mannheim,dc=de";
59 final static String sLoginDN = "cn=casaling,dc=ids-mannheim,dc=de";
60 static String sPwd = null;
61
62 /**
63 * return : 0 = OK, User Account + Pwd are OK, no restrictions;
64 * 1 = internal error: cannot verify User+Pwd;
65 * 2 = User Account or Pwd unknown;
66 * 3 = User Account locked;
67 * 4 = User known, but has not registered to KorAP/C2 Service yet;
68 */
69
70 public static final int LDAP_AUTH_ROK = 0;
71 public static final int LDAP_AUTH_RINTERR = 1;
72 public static final int LDAP_AUTH_RUNKNOWN = 2;
73 public static final int LDAP_AUTH_RLOCKED = 3;
74 public static final int LDAP_AUTH_RNOTREG = 4;
75
margaretha235a6802018-06-06 19:21:53 +020076 public LdapAuth3 (KustvaktConfiguration config) throws JOSEException {
margaretha4de41192017-11-15 11:47:11 +010077 super(config);
78 }
79
80
81 @Override
margaretha2afb97d2017-12-07 19:18:44 +010082 public TokenType getTokenType () {
83 return TokenType.API;
margaretha4de41192017-11-15 11:47:11 +010084 }
85
Bodmo3d6bd352017-04-25 11:31:39 +020086 /**
87 * getErrMessage:
88 * returns String Message for LDAP_AUTH_Rxxx code.
89 * @date 20.04.17/FB
90 * @param code
91 * @return Message in string form.
92 */
margaretha4de41192017-11-15 11:47:11 +010093 public static String getErrMessage(int code)
Bodmo3d6bd352017-04-25 11:31:39 +020094
95 {
96 switch(code)
97 {
98 case LDAP_AUTH_ROK:
99 return "LDAP Authentication successfull.";
100 case LDAP_AUTH_RINTERR:
101 return "LDAP Authentication failed due to an internal error!";
102 case LDAP_AUTH_RUNKNOWN:
103 return "LDAP Authentication failed due to unknown user or password!";
104 case LDAP_AUTH_RLOCKED:
105 return "LDAP Authentication: known user is locked!";
106 case LDAP_AUTH_RNOTREG:
107 return "LDAP Authentication: known user has not registered yet for COSMAS II/KorAP!";
108 default:
109 return "LDAP Authentication failed with unknown error code!";
110 }
111 } // getErrMessage
112
113 /**
114 * ldapCode2StatusCode:
115 * - converts a LDAP_AUTH_xxx Error Code to an Error Code of StatusCode.java.
116 * @param base : Base value inside of StatusCode.java reserved for LDAP_AUTH Error Codes.
117 * @param ldapErrCode : the LDAP_AUTH Error code
118 * @return the StatusCode in the range reserved for LDAP_AUTH Errors.
119 * @date 21.04.17/FB
120 */
121 public int ldapCode2StatusCode(int base, int ldapErrCode)
122
123 {
124 return base + ldapErrCode;
125 } // ldapCode2StatusCode
126
127 /*
128 * load properties for LDAP Handling.
129 * 17.02.17/FB
130 */
131
margaretha65b67142017-05-29 16:23:16 +0200132 static String loadProp(String sConfFile) throws IOException
Bodmo3d6bd352017-04-25 11:31:39 +0200133
134 {
135 String sPwd = null;
Bodmo3d6bd352017-04-25 11:31:39 +0200136 FileInputStream in;
137 Properties prop;
138
139 try {
140 in = new FileInputStream(sConfFile);
141 }
142 catch( IOException ex )
143 {
144 System.err.printf("Error: LDAP.loadProp: cannot load Property file '%s'!\n", sConfFile);
145 ex.printStackTrace();
146 return null;
147 }
148
149 if( in == null )
150 {
151 System.err.printf("Error: LDAP.loadProp: cannot load Property file '%s'!\n", sConfFile);
152 return null;
153 }
154 else
155 {
156 if( DEBUGLOG ) System.out.println("Debug: loaded: " + sConfFile);
157 }
158
159 prop = new Properties();
160 Enumeration<?> e;
161
162 try {
163 prop.load(in);
164 e = prop.propertyNames();
165
166 while( e.hasMoreElements() )
167 {
168 String key = (String)e.nextElement();
169 String val = prop.getProperty(key);
170 if( key.compareTo("pwd") == 0 )
171 return val;
172
173 //System.out.println("Property '" + key + "' = '" + val + "'.");
174 }
175 }
176 catch( IOException ex )
177 {
178 ex.printStackTrace();
179 }
180
181 return sPwd;
182
183 } // loadProp
184
185 /**
186 * ldapLogin
187 * Arguments:
188 * sUserDN : either COSMAS II specific Account Name or IDS wide (IDM) account name;
189 * sUserPwd : either COSMAS II specific Password or IDS wide (IDM) password;
190 * return : 0 = OK, User Account + Pwd are OK, no restrictions;
191 * 1 = internal error: cannot verify User+Pwd;
192 * 2 = User Account or Pwd unknown;
193 * 3 = User Account locked;
194 * 4 = User known, but has not registered to KorAP/C2 Service yet;
195 * LDAP Attributes that are checked (definition by Eric Seubert, 02.02.17):
196 * idsC2 = TRUE -> Zugang zu C2 (registriert und zugelassen)
197 * idsC2 = FALSE (bzw Attribut nicht vorhanden)
198 * -> kein Zugang zu C2 (nicht zugelassen, egal ob registriert oder nicht)
199 *
200 * idsStatus = 0 -> Nutzerkennung OK;
201 * idsStatus = 1 -> Nutzer ist kein aktiver IDS-Mitarbeiter
202 * idsStatus = 3 -> Nutzer ist LDAP-weit gesperrt
203 */
204
margaretha65b67142017-05-29 16:23:16 +0200205 public static int login(String sUserDN, String sUserPwd, String ldapConfig) throws LDAPException
Bodmo3d6bd352017-04-25 11:31:39 +0200206
207 {
208
209 String sUserC2DN = sUserDN;
210 String sUserC2Pwd = sUserPwd;
211
212 String ldapFilter = String.format("(|(&(uid=%s)(userPassword=%s))(&(idsC2Profile=%s)(idsC2Password=%s)))",
213 sUserDN, sUserPwd, sUserC2DN, sUserC2Pwd);
214 SearchResult srchRes = null;
215
216 try{
margaretha65b67142017-05-29 16:23:16 +0200217 sPwd = loadProp(ldapConfig);
Bodmo3d6bd352017-04-25 11:31:39 +0200218 }
219 catch( IOException e )
220 {
221 System.out.println("Error: LDAPAuth.login: cannot load Property file!");
222 return LDAP_AUTH_RINTERR;
223 }
224
225 if( DEBUGLOG )
226 {
227 //System.out.printf("LDAP Version = %d.\n", LDAPConnection.LDAP_V3);
228 System.out.printf("LDAP Host & Port = '%s':%d.\n", ldapHost, ldapPort);
229 System.out.printf("Login User & Pwd = '%s' + '%s'\n", sUserDN, sUserPwd);
230 }
231
232 // LDAP Connection:
233 if( DEBUGLOG ) System.out.println("");
234
235 LDAPConnection lc = new LDAPConnection();
236 try {
237 // connect to LDAP Server:
238 lc.connect(ldapHost, ldapPort);
239 if( DEBUGLOG ) System.out.println("LDAP Connection = OK\n");
240 }
241 catch( LDAPException e)
242 {
243 System.out.printf("Connecting to LDAP Server: failed: '%s'!\n", e.toString());
244 return LDAP_AUTH_RINTERR;
245 }
246
247 if( DEBUGLOG )
248 System.out.printf("Debug: isConnected=%d\n", lc.isConnected() ? 1 : 0);
249
250 try {
251 // bind to server:
252 if( DEBUGLOG ) System.out.printf("Binding with '%s' + '%s'...\n", sLoginDN, sPwd);
253 lc.bind(sLoginDN, sPwd);
254 if( DEBUGLOG ) System.out.printf("Binding: OK.\n");
255 }
256 catch( LDAPException e )
257 {
258 System.out.printf("Binding failed: '%s'!\n", e.toString());
259 return ldapTerminate(lc, LDAP_AUTH_RINTERR);
260 }
261
262 if( DEBUGLOG )
263 System.out.printf("Debug: isConnected=%d\n", lc.isConnected() ? 1 : 0);
264
265 if( DEBUGLOG ) System.out.printf("Finding user '%s'...\n", sUserDN);
266 try{
267 // SCOPE_SUB = Scope Subtree.
268 if( DEBUGLOG ) System.out.printf("Finding Filter: '%s'.\n", ldapFilter);
269
270 // hier werden alle Attribute abgefragt:
271 //srchRes = lc.search(ldapBase, SearchScope.SUB, ldapFilter, null);
272 // wir fragen nur diese Attribute ab:
273 srchRes = lc.search(ldapBase, SearchScope.SUB, ldapFilter, attStatus, attC2);
274
275 if( DEBUGLOG ) System.out.printf("Finding '%s': %d entries.\n", sUserDN, srchRes.getEntryCount());
276 }
277 catch( LDAPSearchException e )
278 {
279 System.out.printf("Search for User failed: '%s'!\n", e.toString());
280 return ldapTerminate(lc, LDAP_AUTH_RUNKNOWN);
281 }
282
283 if( srchRes.getEntryCount() == 0 )
284 {
285 if( DEBUGLOG ) System.out.printf("Finding '%s': no entry found!\n", sUserDN);
286 return ldapTerminate(lc, LDAP_AUTH_RUNKNOWN);
287 }
288
289 if( DEBUGLOG ) System.out.println("Display results:");
290
291 Boolean
292 bStatus = false,
293 bC2 = false;
294
295 // Attribute pr�fen:
296 for (SearchResultEntry e : srchRes.getSearchEntries())
297 {
298 for( Attribute attr : e.getAttributes() )
299 {
300 Integer val;
301
302 if( DEBUGLOG )
303 System.out.printf(" att: '%s'='%s'.\n", attr.getName(), attr.getValue());
304
305 // checking pertinent attribut/value pairs:
Bodmo11fb6f82017-06-01 11:39:15 +0200306 // "idsStatus": values 0=OK, 1=inaktiv=OK, 2-3 = locked account.
Bodmo3d6bd352017-04-25 11:31:39 +0200307 if( attr.getName().equals(attStatus) )
308 {
Bodmo11fb6f82017-06-01 11:39:15 +0200309 if( (val = attr.getValueAsInteger()) == null || (val != 0 && val != 1) )
Bodmo3d6bd352017-04-25 11:31:39 +0200310 {
311 if( DEBUGLOG ) System.out.printf("idsStatus = '%s' -> User locked!\n", attr.getValue());
312 return ldapTerminate(lc, LDAP_AUTH_RLOCKED);
313 }
314 if( DEBUGLOG ) System.out.printf(" att: '%s'='%s': OK.\n", attr.getName(), attr.getValue());
315 bStatus = true;
316 }
317
318 // "c2IDS" must be set to "TRUE" = User known, but has not yet registered to C2 Service -> KorAP Service.
319 if( attr.getName().equals(attC2) )
320 {
321 if( attr.getValue().equals("FALSE") )
322 {
323 if( DEBUGLOG )
324 System.out.printf("idsC2 = '%s'-> User known, but has not registered C2/KorAP Service yet!\n",
325 attr.getValue());
326 return ldapTerminate(lc, LDAP_AUTH_RNOTREG);
327 }
328 if( DEBUGLOG )
329 System.out.printf(" att: idsC2 = '%s'-> registered User: OK.\n", attr.getValue());
330 bC2 = true;
331 }
332 }
333
334 if( DEBUGLOG ) System.out.println();
335 }
336
337 if( bStatus == true && bC2 == true )
338 return ldapTerminate(lc, LDAP_AUTH_ROK); // OK.
339 else
340 return ldapTerminate(lc, LDAP_AUTH_RNOTREG); // Attribute konnten nicht gepr�ft werden.
341
342 } // ldapLogin
343
344/**
345 * ldapTerminate
346 */
347
348public static int ldapTerminate(LDAPConnection lc, int ret)
349
350 {
351 if( DEBUGLOG ) System.out.println("Terminating...");
352 /*
353 try{
354 lc.finalize();
355 if( DEBUGLOG ) System.out.println("Debug: finalize: OK.");
356 }
357 catch( LDAPException e )
358 {
359 System.out.printf("finalize failed: '%s'!\n", e.toString());
360 }
361 */
362
363 lc.close(null);
364 if( DEBUGLOG ) System.out.println("closing connection: done.\n");
365 return ret;
366 } // ldapTerminate
367
368}
369