Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/jndi/ldap/LdapPoolManager.java
38924 views
1
/*
2
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.jndi.ldap;
27
28
import java.io.PrintStream;
29
import java.io.OutputStream;
30
import java.util.Hashtable;
31
import java.util.Locale;
32
import java.util.StringTokenizer;
33
34
import javax.naming.ldap.Control;
35
import javax.naming.NamingException;
36
import javax.naming.CommunicationException;
37
import java.security.AccessController;
38
import java.security.PrivilegedAction;
39
40
import com.sun.jndi.ldap.pool.PoolCleaner;
41
import com.sun.jndi.ldap.pool.Pool;
42
import sun.misc.InnocuousThread;
43
44
/**
45
* Contains utilities for managing connection pools of LdapClient.
46
* Contains method for
47
* - checking whether attempted connection creation may be pooled
48
* - creating a pooled connection
49
* - closing idle connections.
50
*
51
* If a timeout period has been configured, then it will automatically
52
* close and remove idle connections (those that have not been
53
* used for the duration of the timeout period).
54
*
55
* @author Rosanna Lee
56
*/
57
58
public final class LdapPoolManager {
59
private static final String DEBUG =
60
"com.sun.jndi.ldap.connect.pool.debug";
61
62
public static final boolean debug =
63
"all".equalsIgnoreCase(getProperty(DEBUG, null));
64
65
public static final boolean trace = debug ||
66
"fine".equalsIgnoreCase(getProperty(DEBUG, null));
67
68
// ---------- System properties for connection pooling
69
70
// Authentication mechanisms of connections that may be pooled
71
private static final String POOL_AUTH =
72
"com.sun.jndi.ldap.connect.pool.authentication";
73
74
// Protocol types of connections that may be pooled
75
private static final String POOL_PROTOCOL =
76
"com.sun.jndi.ldap.connect.pool.protocol";
77
78
// Maximum number of identical connections per pool
79
private static final String MAX_POOL_SIZE =
80
"com.sun.jndi.ldap.connect.pool.maxsize";
81
82
// Preferred number of identical connections per pool
83
private static final String PREF_POOL_SIZE =
84
"com.sun.jndi.ldap.connect.pool.prefsize";
85
86
// Initial number of identical connections per pool
87
private static final String INIT_POOL_SIZE =
88
"com.sun.jndi.ldap.connect.pool.initsize";
89
90
// Milliseconds to wait before closing idle connections
91
private static final String POOL_TIMEOUT =
92
"com.sun.jndi.ldap.connect.pool.timeout";
93
94
// Properties for DIGEST
95
private static final String SASL_CALLBACK =
96
"java.naming.security.sasl.callback";
97
98
// --------- Constants
99
private static final int DEFAULT_MAX_POOL_SIZE = 0;
100
private static final int DEFAULT_PREF_POOL_SIZE = 0;
101
private static final int DEFAULT_INIT_POOL_SIZE = 1;
102
private static final int DEFAULT_TIMEOUT = 0; // no timeout
103
private static final String DEFAULT_AUTH_MECHS = "none simple";
104
private static final String DEFAULT_PROTOCOLS = "plain";
105
106
private static final int NONE = 0; // indices into pools
107
private static final int SIMPLE = 1;
108
private static final int DIGEST = 2;
109
110
// --------- static fields
111
private static final long idleTimeout;// ms to wait before closing idle conn
112
private static final int maxSize; // max num of identical conns/pool
113
private static final int prefSize; // preferred num of identical conns/pool
114
private static final int initSize; // initial num of identical conns/pool
115
116
private static boolean supportPlainProtocol = false;
117
private static boolean supportSslProtocol = false;
118
119
// List of pools used for different auth types
120
private static final Pool[] pools = new Pool[3];
121
122
static {
123
maxSize = getInteger(MAX_POOL_SIZE, DEFAULT_MAX_POOL_SIZE);
124
125
prefSize = getInteger(PREF_POOL_SIZE, DEFAULT_PREF_POOL_SIZE);
126
127
initSize = getInteger(INIT_POOL_SIZE, DEFAULT_INIT_POOL_SIZE);
128
129
idleTimeout = getLong(POOL_TIMEOUT, DEFAULT_TIMEOUT);
130
131
// Determine supported authentication mechanisms
132
String str = getProperty(POOL_AUTH, DEFAULT_AUTH_MECHS);
133
StringTokenizer parser = new StringTokenizer(str);
134
int count = parser.countTokens();
135
String mech;
136
int p;
137
for (int i = 0; i < count; i++) {
138
mech = parser.nextToken().toLowerCase(Locale.ENGLISH);
139
if (mech.equals("anonymous")) {
140
mech = "none";
141
}
142
143
p = findPool(mech);
144
if (p >= 0 && pools[p] == null) {
145
pools[p] = new Pool(initSize, prefSize, maxSize);
146
}
147
}
148
149
// Determine supported protocols
150
str= getProperty(POOL_PROTOCOL, DEFAULT_PROTOCOLS);
151
parser = new StringTokenizer(str);
152
count = parser.countTokens();
153
String proto;
154
for (int i = 0; i < count; i++) {
155
proto = parser.nextToken();
156
if ("plain".equalsIgnoreCase(proto)) {
157
supportPlainProtocol = true;
158
} else if ("ssl".equalsIgnoreCase(proto)) {
159
supportSslProtocol = true;
160
} else {
161
// ignore
162
}
163
}
164
165
if (idleTimeout > 0) {
166
// Create cleaner to expire idle connections
167
PrivilegedAction<Void> pa = new PrivilegedAction<Void>() {
168
public Void run() {
169
Thread t = InnocuousThread.newSystemThread(
170
"LDAP PoolCleaner",
171
new PoolCleaner(idleTimeout, pools));
172
assert t.getContextClassLoader() == null;
173
t.setDaemon(true);
174
t.start();
175
return null;
176
}};
177
AccessController.doPrivileged(pa);
178
}
179
180
if (debug) {
181
showStats(System.err);
182
}
183
}
184
185
// Cannot instantiate one of these
186
private LdapPoolManager() {
187
}
188
189
/**
190
* Find the index of the pool for the specified mechanism. If not
191
* one of "none", "simple", "DIGEST-MD5", or "GSSAPI",
192
* return -1.
193
* @param mech mechanism type
194
*/
195
private static int findPool(String mech) {
196
if ("none".equalsIgnoreCase(mech)) {
197
return NONE;
198
} else if ("simple".equalsIgnoreCase(mech)) {
199
return SIMPLE;
200
} else if ("digest-md5".equalsIgnoreCase(mech)) {
201
return DIGEST;
202
}
203
return -1;
204
}
205
206
/**
207
* Determines whether pooling is allowed given information on how
208
* the connection will be used.
209
*
210
* Non-configurable rejections:
211
* - nonstandard socketFactory has been specified: the pool manager
212
* cannot track input or parameters used by the socket factory and
213
* thus has no way of determining whether two connection requests
214
* are equivalent. Maybe in the future it might add a list of allowed
215
* socket factories to be configured
216
* - trace enabled (except when debugging)
217
* - for Digest authentication, if a callback handler has been specified:
218
* the pool manager cannot track input collected by the handler
219
* and thus has no way of determining whether two connection requests are
220
* equivalent. Maybe in the future it might add a list of allowed
221
* callback handlers.
222
*
223
* Configurable tests:
224
* - Pooling for the requested protocol (plain or ssl) is supported
225
* - Pooling for the requested authentication mechanism is supported
226
*
227
*/
228
static boolean isPoolingAllowed(String socketFactory, OutputStream trace,
229
String authMech, String protocol, Hashtable<?,?> env)
230
throws NamingException {
231
232
if (trace != null && !debug
233
234
// Requesting plain protocol but it is not supported
235
|| (protocol == null && !supportPlainProtocol)
236
237
// Requesting ssl protocol but it is not supported
238
|| ("ssl".equalsIgnoreCase(protocol) && !supportSslProtocol)) {
239
240
d("Pooling disallowed due to tracing or unsupported pooling of protocol");
241
return false;
242
}
243
// pooling of custom socket factory is possible only if the
244
// socket factory interface implements java.util.comparator
245
String COMPARATOR = "java.util.Comparator";
246
boolean foundSockCmp = false;
247
if ((socketFactory != null) &&
248
!socketFactory.equals(LdapCtx.DEFAULT_SSL_FACTORY)) {
249
try {
250
Class<?> socketFactoryClass = Obj.helper.loadClass(socketFactory);
251
Class<?>[] interfaces = socketFactoryClass.getInterfaces();
252
for (int i = 0; i < interfaces.length; i++) {
253
if (interfaces[i].getCanonicalName().equals(COMPARATOR)) {
254
foundSockCmp = true;
255
}
256
}
257
} catch (Exception e) {
258
CommunicationException ce =
259
new CommunicationException("Loading the socket factory");
260
ce.setRootCause(e);
261
throw ce;
262
}
263
if (!foundSockCmp) {
264
return false;
265
}
266
}
267
// Cannot use pooling if authMech is not a supported mechs
268
// Cannot use pooling if authMech contains multiple mechs
269
int p = findPool(authMech);
270
if (p < 0 || pools[p] == null) {
271
d("authmech not found: ", authMech);
272
273
return false;
274
}
275
276
d("using authmech: ", authMech);
277
278
switch (p) {
279
case NONE:
280
case SIMPLE:
281
return true;
282
283
case DIGEST:
284
// Provider won't be able to determine connection identity
285
// if an alternate callback handler is used
286
return (env == null || env.get(SASL_CALLBACK) == null);
287
}
288
return false;
289
}
290
291
/**
292
* Obtains a pooled connection that either already exists or is
293
* newly created using the parameters supplied. If it is newly
294
* created, it needs to go through the authentication checks to
295
* determine whether an LDAP bind is necessary.
296
*
297
* Caller needs to invoke ldapClient.authenticateCalled() to
298
* determine whether ldapClient.authenticate() needs to be invoked.
299
* Caller has that responsibility because caller needs to deal
300
* with the LDAP bind response, which might involve referrals,
301
* response controls, errors, etc. This method is responsible only
302
* for establishing the connection.
303
*
304
* @return an LdapClient that is pooled.
305
*/
306
static LdapClient getLdapClient(String host, int port, String socketFactory,
307
int connTimeout, int readTimeout, OutputStream trace, int version,
308
String authMech, Control[] ctls, String protocol, String user,
309
Object passwd, Hashtable<?,?> env) throws NamingException {
310
311
// Create base identity for LdapClient
312
ClientId id = null;
313
Pool pool;
314
315
int p = findPool(authMech);
316
if (p < 0 || (pool=pools[p]) == null) {
317
throw new IllegalArgumentException(
318
"Attempting to use pooling for an unsupported mechanism: " +
319
authMech);
320
}
321
switch (p) {
322
case NONE:
323
id = new ClientId(version, host, port, protocol,
324
ctls, trace, socketFactory);
325
break;
326
327
case SIMPLE:
328
// Add identity information used in simple authentication
329
id = new SimpleClientId(version, host, port, protocol,
330
ctls, trace, socketFactory, user, passwd);
331
break;
332
333
case DIGEST:
334
// Add user/passwd/realm/authzid/qop/strength/maxbuf/mutual/policy*
335
id = new DigestClientId(version, host, port, protocol,
336
ctls, trace, socketFactory, user, passwd, env);
337
break;
338
}
339
340
return (LdapClient) pool.getPooledConnection(id, connTimeout,
341
new LdapClientFactory(host, port, socketFactory, connTimeout,
342
readTimeout, trace));
343
}
344
345
public static void showStats(PrintStream out) {
346
out.println("***** start *****");
347
out.println("idle timeout: " + idleTimeout);
348
out.println("maximum pool size: " + maxSize);
349
out.println("preferred pool size: " + prefSize);
350
out.println("initial pool size: " + initSize);
351
out.println("protocol types: " + (supportPlainProtocol ? "plain " : "") +
352
(supportSslProtocol ? "ssl" : ""));
353
out.println("authentication types: " +
354
(pools[NONE] != null ? "none " : "") +
355
(pools[SIMPLE] != null ? "simple " : "") +
356
(pools[DIGEST] != null ? "DIGEST-MD5 " : ""));
357
358
for (int i = 0; i < pools.length; i++) {
359
if (pools[i] != null) {
360
out.println(
361
(i == NONE ? "anonymous pools" :
362
i == SIMPLE ? "simple auth pools" :
363
i == DIGEST ? "digest pools" : "")
364
+ ":");
365
pools[i].showStats(out);
366
}
367
}
368
out.println("***** end *****");
369
}
370
371
/**
372
* Closes idle connections idle since specified time.
373
*
374
* @param threshold Close connections idle since this time, as
375
* specified in milliseconds since "the epoch".
376
* @see java.util.Date
377
*/
378
public static void expire(long threshold) {
379
for (int i = 0; i < pools.length; i++) {
380
if (pools[i] != null) {
381
pools[i].expire(threshold);
382
}
383
}
384
}
385
386
private static void d(String msg) {
387
if (debug) {
388
System.err.println("LdapPoolManager: " + msg);
389
}
390
}
391
392
private static void d(String msg, String o) {
393
if (debug) {
394
System.err.println("LdapPoolManager: " + msg + o);
395
}
396
}
397
398
private static final String getProperty(final String propName,
399
final String defVal) {
400
return AccessController.doPrivileged(
401
new PrivilegedAction<String>() {
402
public String run() {
403
try {
404
return System.getProperty(propName, defVal);
405
} catch (SecurityException e) {
406
return defVal;
407
}
408
}
409
});
410
}
411
412
private static final int getInteger(final String propName,
413
final int defVal) {
414
Integer val = AccessController.doPrivileged(
415
new PrivilegedAction<Integer>() {
416
public Integer run() {
417
try {
418
return Integer.getInteger(propName, defVal);
419
} catch (SecurityException e) {
420
return new Integer(defVal);
421
}
422
}
423
});
424
return val.intValue();
425
}
426
427
private static final long getLong(final String propName,
428
final long defVal) {
429
Long val = AccessController.doPrivileged(
430
new PrivilegedAction<Long>() {
431
public Long run() {
432
try {
433
return Long.getLong(propName, defVal);
434
} catch (SecurityException e) {
435
return new Long(defVal);
436
}
437
}
438
});
439
return val.longValue();
440
}
441
}
442
443