blob: 26a81fbd45306867333e6054ab09d6328be405a6 [file] [log] [blame]
Marc Kupietz0a378672022-04-30 09:35:27 +02001/*
2 * user authentication via LDAP
Bodmo3d6bd352017-04-25 11:31:39 +02003 */
Marc Kupietz0a378672022-04-30 09:35:27 +02004
margaretha139d0f72017-11-14 18:56:22 +01005package de.ids_mannheim.korap.authentication;
Bodmo3d6bd352017-04-25 11:31:39 +02006
margaretha235a6802018-06-06 19:21:53 +02007import com.nimbusds.jose.JOSEException;
Marc Kupietz0a378672022-04-30 09:35:27 +02008import com.unboundid.ldap.sdk.*;
9import com.unboundid.util.ssl.SSLUtil;
10import com.unboundid.util.ssl.TrustAllTrustManager;
11import com.unboundid.util.ssl.TrustStoreTrustManager;
margaretha5225ed02018-06-25 18:38:40 +020012import de.ids_mannheim.korap.config.FullConfiguration;
margaretha0e8f4e72018-04-05 14:11:52 +020013import de.ids_mannheim.korap.constant.TokenType;
Marc Kupietz1e388b42022-04-30 18:37:03 +020014import de.ids_mannheim.korap.server.EmbeddedLdapServer;
Marc Kupietz0a378672022-04-30 09:35:27 +020015import org.apache.commons.text.StringSubstitutor;
16
17import javax.net.ssl.SSLSocketFactory;
Marc Kupietz0a378672022-04-30 09:35:27 +020018import java.io.IOException;
Marc Kupietz1e388b42022-04-30 18:37:03 +020019import java.net.UnknownHostException;
Marc Kupietz0a378672022-04-30 09:35:27 +020020import java.security.GeneralSecurityException;
21import java.util.HashMap;
22import java.util.Map;
Marc Kupietz1e388b42022-04-30 18:37:03 +020023
24import static de.ids_mannheim.korap.server.EmbeddedLdapServer.loadProp;
margaretha4de41192017-11-15 11:47:11 +010025
Bodmo3d6bd352017-04-25 11:31:39 +020026
27/**
Marc Kupietz0a378672022-04-30 09:35:27 +020028 * LDAP Login
29 *
30 * @author bodmer, margaretha, kupietz
margaretha4de41192017-11-15 11:47:11 +010031 * @see APIAuthentication
Bodmo3d6bd352017-04-25 11:31:39 +020032 */
margaretha4de41192017-11-15 11:47:11 +010033public class LdapAuth3 extends APIAuthentication {
Bodmo3d6bd352017-04-25 11:31:39 +020034
Marc Kupietz0a378672022-04-30 09:35:27 +020035 public static final int LDAP_AUTH_ROK = 0;
36 public static final int LDAP_AUTH_RCONNECT = 1; // cannot connect to LDAP Server
37 public static final int LDAP_AUTH_RINTERR = 2; // internal error: cannot verify User+Pwd.
38 /* cannot be distinguished, currently
39 public static final int LDAP_AUTH_RUNKNOWN = 3; // User Account or Pwd unknown;
40 public static final int LDAP_AUTH_RLOCKED = 4; // User Account locked;
41 public static final int LDAP_AUTH_RNOTREG = 5; // User known, but has not registered to KorAP/C2 Service yet;
42 */
43 public static final int LDAP_AUTH_RNOEMAIL = 6; // cannot obtain email for sUserDN
44 public static final int LDAP_AUTH_RNAUTH = 7; // User Account or Pwd unknown, or not authorized
45 final static Boolean DEBUGLOG = false; // log debug output.
Bodmo3d6bd352017-04-25 11:31:39 +020046
Marc Kupietz0a378672022-04-30 09:35:27 +020047 public LdapAuth3(FullConfiguration config) throws JOSEException {
margaretha4de41192017-11-15 11:47:11 +010048 super(config);
Marc Kupietz0a378672022-04-30 09:35:27 +020049 }
50
51 public static String getErrMessage(int code) {
52 switch (code) {
53 case LDAP_AUTH_ROK:
54 return "LDAP Authentication successful.";
55 case LDAP_AUTH_RCONNECT:
56 return "LDAP Authentication: connecting to LDAP Server failed!";
57 case LDAP_AUTH_RINTERR:
58 return "LDAP Authentication failed due to an internal error!";
59/* cannot be distinguished, currently
60 case LDAP_AUTH_RUNKNOWN:
61 return "LDAP Authentication failed due to unknown user or password!";
62 case LDAP_AUTH_RLOCKED:
63 return "LDAP Authentication: known user is locked!";
64 case LDAP_AUTH_RNOTREG:
65 return "LDAP Authentication: known user has not registered yet!";
66*/
67 case LDAP_AUTH_RNOEMAIL:
68 return "LDAP Authentication: known user, but cannot obtain email!";
69 case LDAP_AUTH_RNAUTH:
70 return "LDAP Authentication: unknown user or password, or user is locked or not authorized!";
71 default:
72 return "LDAP Authentication failed with unknown error code!";
73 }
74 }
75
Marc Kupietz0a378672022-04-30 09:35:27 +020076
77 public static int login(String sUserDN, String sUserPwd, String ldapConfigFilename) throws LDAPException {
78
79 sUserDN = Filter.encodeValue(sUserDN);
80 sUserPwd = Filter.encodeValue(sUserPwd);
81
82 Map<String, String> ldapConfig;
83 try {
84 ldapConfig = loadProp(ldapConfigFilename);
85 } catch (IOException e) {
86 System.out.println("Error: LDAPAuth.login: cannot load Property file!");
87 return LDAP_AUTH_RINTERR;
88 }
89
90 final Boolean ldapS = Boolean.parseBoolean(ldapConfig.getOrDefault("ldapS", "false"));
91 final String ldapHost = ldapConfig.getOrDefault("ldapHost", "localhost");
92 final int ldapPort = Integer.parseInt(ldapConfig.getOrDefault("ldapPort", (ldapS ? "636" : "389")));
93 final String ldapBase = ldapConfig.getOrDefault("ldapBase", "dc=example,dc=com");
94 final String sLoginDN = ldapConfig.getOrDefault("sLoginDN", "cn=admin,dc=example,dc=com");
95 final String ldapFilter = ldapConfig.getOrDefault("ldapFilter", "(&(|(&(mail=${username})(idsC2Password=${password}))(&(idsC2Profile=${username})(idsC2Password=${password})))(&(idsC2=TRUE)(|(idsStatus=1)(|(idsStatus=0)(xidsStatus=\00)))))");
96 final String sPwd = ldapConfig.getOrDefault("pwd", "");
97 final String trustStorePath = ldapConfig.getOrDefault("trustStore", null);
Marc Kupietz1e388b42022-04-30 18:37:03 +020098 final Boolean useEmbeddedServer = Boolean.parseBoolean(ldapConfig.getOrDefault("useEmbeddedServer", "false"));
99
100 if (useEmbeddedServer && EmbeddedLdapServer.server == null) {
101 try {
102 EmbeddedLdapServer.start(ldapConfigFilename);
103 } catch (GeneralSecurityException e) {
104 throw new RuntimeException(e);
105 } catch (UnknownHostException e) {
106 throw new RuntimeException(e);
107 }
108 }
Marc Kupietz0a378672022-04-30 09:35:27 +0200109
110 Map<String, String> valuesMap = new HashMap<>();
111 valuesMap.put("username", sUserDN);
112 valuesMap.put("password", sUserPwd);
113 StringSubstitutor sub = new StringSubstitutor(valuesMap);
114 String ldapFilterInstance = sub.replace(ldapFilter);
115
116 if (DEBUGLOG) {
117 //System.out.printf("LDAP Version = %d.\n", LDAPConnection.LDAP_V3);
118 System.out.printf("LDAP Host & Port = '%s':%d.\n", ldapHost, ldapPort);
119 System.out.printf("Login User = '%s'\n", sUserDN);
120 }
121
122 // LDAP Connection:
123 if (DEBUGLOG) System.out.println("LDAPS " + ldapS);
124
125 LDAPConnection lc = null;
126
127 if (ldapS) {
128 try {
129 SSLUtil sslUtil;
130 if (trustStorePath != null && !trustStorePath.isEmpty()) {
131 sslUtil = new SSLUtil(new TrustStoreTrustManager(trustStorePath));
132 } else {
133 sslUtil = new SSLUtil(new TrustAllTrustManager());
Bodmo3d6bd352017-04-25 11:31:39 +0200134 }
Marc Kupietz0a378672022-04-30 09:35:27 +0200135 SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
136 lc = new LDAPConnection(socketFactory, ldapHost, ldapPort);
137 } catch (GeneralSecurityException e) {
138 System.err.printf("Error: login: Connecting to LDAPS Server: failed: '%s'!\n", e);
139 return ldapTerminate(lc, LDAP_AUTH_RCONNECT);
140 }
141 } else {
142 lc = new LDAPConnection();
143 try {
144 lc.connect(ldapHost, ldapPort);
145 if (DEBUGLOG && ldapS) System.out.println("LDAPS Connection = OK\n");
146 if (DEBUGLOG && !ldapS) System.out.println("LDAP Connection = OK\n");
147 } catch (LDAPException e) {
148 System.err.printf("Error: login: Connecting to LDAP Server: failed: '%s'!\n", e);
149 return ldapTerminate(lc, LDAP_AUTH_RCONNECT);
150 }
151 }
Bodmo3d6bd352017-04-25 11:31:39 +0200152
Bodmo3d6bd352017-04-25 11:31:39 +0200153
Marc Kupietz0a378672022-04-30 09:35:27 +0200154 if (DEBUGLOG) System.out.printf("Debug: isConnected=%d\n", lc.isConnected() ? 1 : 0);
Bodmo3d6bd352017-04-25 11:31:39 +0200155
Marc Kupietz0a378672022-04-30 09:35:27 +0200156 try {
157 // bind to server:
158 if (DEBUGLOG) System.out.printf("Binding with '%s' ...\n", sLoginDN);
159 lc.bind(sLoginDN, sPwd);
160 if (DEBUGLOG) System.out.printf("Binding: OK.\n");
161 } catch (LDAPException e) {
162 System.err.printf("Error: login: Binding failed: '%s'!\n", e);
163 return ldapTerminate(lc, LDAP_AUTH_RINTERR);
164 }
Bodmo3d6bd352017-04-25 11:31:39 +0200165
Marc Kupietz0a378672022-04-30 09:35:27 +0200166 if (DEBUGLOG) System.out.printf("Debug: isConnected=%d\n", lc.isConnected() ? 1 : 0);
Bodmo3d6bd352017-04-25 11:31:39 +0200167
Marc Kupietz0a378672022-04-30 09:35:27 +0200168 if (DEBUGLOG) System.out.printf("Finding user '%s'...\n", sUserDN);
Bodmo3d6bd352017-04-25 11:31:39 +0200169
Marc Kupietz0a378672022-04-30 09:35:27 +0200170 SearchResult srchRes;
171 try {
172 // SCOPE_SUB = Scope Subtree.
173 if (DEBUGLOG) System.out.printf("Finding Filter: '%s'.\n", ldapFilterInstance);
Bodmo3d6bd352017-04-25 11:31:39 +0200174
Marc Kupietz0a378672022-04-30 09:35:27 +0200175 srchRes = lc.search(ldapBase, SearchScope.SUB, ldapFilterInstance);
Bodmo3d6bd352017-04-25 11:31:39 +0200176
Marc Kupietz0a378672022-04-30 09:35:27 +0200177 if (DEBUGLOG) System.out.printf("Finding '%s': %d entries.\n", sUserDN, srchRes.getEntryCount());
178 } catch (LDAPSearchException e) {
179 System.err.printf("Error: login: Search for User failed: '%s'!\n", e);
180 return ldapTerminate(lc, LDAP_AUTH_RNAUTH);
181 }
Bodmo3d6bd352017-04-25 11:31:39 +0200182
Marc Kupietz0a378672022-04-30 09:35:27 +0200183 if (srchRes.getEntryCount() == 0) {
184 if (DEBUGLOG) System.out.printf("Finding '%s': no entry found!\n", sUserDN);
185 return ldapTerminate(lc, LDAP_AUTH_RNAUTH);
186 }
Bodmo3d6bd352017-04-25 11:31:39 +0200187
Marc Kupietz0a378672022-04-30 09:35:27 +0200188 return ldapTerminate(lc, LDAP_AUTH_ROK); // OK.
189 }
Bodmo3d6bd352017-04-25 11:31:39 +0200190
Marc Kupietz0a378672022-04-30 09:35:27 +0200191 public static int ldapTerminate(LDAPConnection lc, int ret) {
192 if (DEBUGLOG) System.out.println("Terminating...");
Bodmo3d6bd352017-04-25 11:31:39 +0200193
Marc Kupietz0a378672022-04-30 09:35:27 +0200194 lc.close(null);
195 if (DEBUGLOG) System.out.println("closing connection: done.\n");
196 return ret;
197 }
Bodmo3d6bd352017-04-25 11:31:39 +0200198
Marc Kupietz0a378672022-04-30 09:35:27 +0200199 @Override
200 public TokenType getTokenType() {
201 return TokenType.API;
202 }
Bodmo3d6bd352017-04-25 11:31:39 +0200203
204}