feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
408
jdkSrc/jdk8/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java
Normal file
408
jdkSrc/jdk8/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* Basic enumeration for NameClassPair, Binding, and SearchResults.
|
||||
*/
|
||||
|
||||
abstract class AbstractLdapNamingEnumeration<T extends NameClassPair>
|
||||
implements NamingEnumeration<T>, ReferralEnumeration<T> {
|
||||
|
||||
protected Name listArg;
|
||||
|
||||
private boolean cleaned = false;
|
||||
private LdapResult res;
|
||||
private LdapClient enumClnt;
|
||||
private Continuation cont; // used to fill in exceptions
|
||||
private Vector<LdapEntry> entries = null;
|
||||
private int limit = 0;
|
||||
private int posn = 0;
|
||||
protected LdapCtx homeCtx;
|
||||
private LdapReferralException refEx = null;
|
||||
private NamingException errEx = null;
|
||||
|
||||
/*
|
||||
* Record the next set of entries and/or referrals.
|
||||
*/
|
||||
AbstractLdapNamingEnumeration(LdapCtx homeCtx, LdapResult answer, Name listArg,
|
||||
Continuation cont) throws NamingException {
|
||||
|
||||
// These checks are to accommodate referrals and limit exceptions
|
||||
// which will generate an enumeration and defer the exception
|
||||
// to be thrown at the end of the enumeration.
|
||||
// All other exceptions are thrown immediately.
|
||||
// Exceptions shouldn't be thrown here anyhow because
|
||||
// process_return_code() is called before the constructor
|
||||
// is called, so these are just safety checks.
|
||||
|
||||
if ((answer.status != LdapClient.LDAP_SUCCESS) &&
|
||||
(answer.status != LdapClient.LDAP_SIZE_LIMIT_EXCEEDED) &&
|
||||
(answer.status != LdapClient.LDAP_TIME_LIMIT_EXCEEDED) &&
|
||||
(answer.status != LdapClient.LDAP_ADMIN_LIMIT_EXCEEDED) &&
|
||||
(answer.status != LdapClient.LDAP_REFERRAL) &&
|
||||
(answer.status != LdapClient.LDAP_PARTIAL_RESULTS)) {
|
||||
|
||||
// %%% need to deal with referral
|
||||
NamingException e = new NamingException(
|
||||
LdapClient.getErrorMessage(
|
||||
answer.status, answer.errorMessage));
|
||||
|
||||
throw cont.fillInException(e);
|
||||
}
|
||||
|
||||
// otherwise continue
|
||||
|
||||
res = answer;
|
||||
entries = answer.entries;
|
||||
limit = (entries == null) ? 0 : entries.size(); // handle empty set
|
||||
this.listArg = listArg;
|
||||
this.cont = cont;
|
||||
|
||||
if (answer.refEx != null) {
|
||||
refEx = answer.refEx;
|
||||
}
|
||||
|
||||
// Ensures that context won't get closed from underneath us
|
||||
this.homeCtx = homeCtx;
|
||||
homeCtx.incEnumCount();
|
||||
enumClnt = homeCtx.clnt; // remember
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T nextElement() {
|
||||
try {
|
||||
return next();
|
||||
} catch (NamingException e) {
|
||||
// can't throw exception
|
||||
cleanup();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasMoreElements() {
|
||||
try {
|
||||
return hasMore();
|
||||
} catch (NamingException e) {
|
||||
// can't throw exception
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the next set of entries and/or referrals.
|
||||
*/
|
||||
private void getNextBatch() throws NamingException {
|
||||
|
||||
res = homeCtx.getSearchReply(enumClnt, res);
|
||||
if (res == null) {
|
||||
limit = posn = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
entries = res.entries;
|
||||
limit = (entries == null) ? 0 : entries.size(); // handle empty set
|
||||
posn = 0; // reset
|
||||
|
||||
// mimimize the number of calls to processReturnCode()
|
||||
// (expensive when batchSize is small and there are many results)
|
||||
if ((res.status != LdapClient.LDAP_SUCCESS) ||
|
||||
((res.status == LdapClient.LDAP_SUCCESS) &&
|
||||
(res.referrals != null))) {
|
||||
|
||||
try {
|
||||
// convert referrals into a chain of LdapReferralException
|
||||
homeCtx.processReturnCode(res, listArg);
|
||||
|
||||
} catch (LimitExceededException | PartialResultException e) {
|
||||
setNamingException(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// merge any newly received referrals with any current referrals
|
||||
if (res.refEx != null) {
|
||||
if (refEx == null) {
|
||||
refEx = res.refEx;
|
||||
} else {
|
||||
refEx = refEx.appendUnprocessedReferrals(res.refEx);
|
||||
}
|
||||
res.refEx = null; // reset
|
||||
}
|
||||
|
||||
if (res.resControls != null) {
|
||||
homeCtx.respCtls = res.resControls;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean more = true; // assume we have something to start with
|
||||
private boolean hasMoreCalled = false;
|
||||
|
||||
/*
|
||||
* Test if unprocessed entries or referrals exist.
|
||||
*/
|
||||
@Override
|
||||
public final boolean hasMore() throws NamingException {
|
||||
|
||||
if (hasMoreCalled) {
|
||||
return more;
|
||||
}
|
||||
|
||||
hasMoreCalled = true;
|
||||
|
||||
if (!more) {
|
||||
return false;
|
||||
} else {
|
||||
return (more = hasMoreImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the next entry.
|
||||
*/
|
||||
@Override
|
||||
public final T next() throws NamingException {
|
||||
|
||||
if (!hasMoreCalled) {
|
||||
hasMore();
|
||||
}
|
||||
hasMoreCalled = false;
|
||||
return nextImpl();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if unprocessed entries or referrals exist.
|
||||
*/
|
||||
private boolean hasMoreImpl() throws NamingException {
|
||||
// when page size is supported, this
|
||||
// might generate an exception while attempting
|
||||
// to fetch the next batch to determine
|
||||
// whether there are any more elements
|
||||
|
||||
// test if the current set of entries has been processed
|
||||
if (posn == limit) {
|
||||
getNextBatch();
|
||||
}
|
||||
|
||||
// test if any unprocessed entries exist
|
||||
if (posn < limit) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
try {
|
||||
// try to process another referral
|
||||
return hasMoreReferrals();
|
||||
|
||||
} catch (LdapReferralException |
|
||||
LimitExceededException |
|
||||
PartialResultException e) {
|
||||
cleanup();
|
||||
throw e;
|
||||
|
||||
} catch (NamingException e) {
|
||||
cleanup();
|
||||
PartialResultException pre = new PartialResultException();
|
||||
pre.setRootCause(e);
|
||||
throw pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the next entry.
|
||||
*/
|
||||
private T nextImpl() throws NamingException {
|
||||
try {
|
||||
return nextAux();
|
||||
} catch (NamingException e) {
|
||||
cleanup();
|
||||
throw cont.fillInException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private T nextAux() throws NamingException {
|
||||
if (posn == limit) {
|
||||
getNextBatch(); // updates posn and limit
|
||||
}
|
||||
|
||||
if (posn >= limit) {
|
||||
cleanup();
|
||||
throw new NoSuchElementException("invalid enumeration handle");
|
||||
}
|
||||
|
||||
LdapEntry result = entries.elementAt(posn++);
|
||||
|
||||
// gets and outputs DN from the entry
|
||||
return createItem(result.DN, result.attributes, result.respCtls);
|
||||
}
|
||||
|
||||
protected final String getAtom(String dn) {
|
||||
// need to strip off all but lowest component of dn
|
||||
// so that is relative to current context (currentDN)
|
||||
try {
|
||||
Name parsed = new LdapName(dn);
|
||||
return parsed.get(parsed.size() - 1);
|
||||
} catch (NamingException e) {
|
||||
return dn;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T createItem(String dn, Attributes attrs,
|
||||
Vector<Control> respCtls) throws NamingException;
|
||||
|
||||
/*
|
||||
* Append the supplied (chain of) referrals onto the
|
||||
* end of the current (chain of) referrals.
|
||||
*/
|
||||
@Override
|
||||
public void appendUnprocessedReferrals(LdapReferralException ex) {
|
||||
if (refEx != null) {
|
||||
refEx = refEx.appendUnprocessedReferrals(ex);
|
||||
} else {
|
||||
refEx = ex.appendUnprocessedReferrals(refEx);
|
||||
}
|
||||
}
|
||||
|
||||
final void setNamingException(NamingException e) {
|
||||
errEx = e;
|
||||
}
|
||||
|
||||
protected abstract AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException;
|
||||
|
||||
/*
|
||||
* Iterate through the URLs of a referral. If successful then perform
|
||||
* a search operation and merge the received results with the current
|
||||
* results.
|
||||
*/
|
||||
protected final boolean hasMoreReferrals() throws NamingException {
|
||||
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
|
||||
if (homeCtx.handleReferrals == LdapClient.LDAP_REF_THROW) {
|
||||
throw (NamingException)(refEx.fillInStackTrace());
|
||||
}
|
||||
|
||||
// process the referrals sequentially
|
||||
while (true) {
|
||||
|
||||
LdapReferralContext refCtx =
|
||||
(LdapReferralContext)refEx.getReferralContext(
|
||||
homeCtx.envprops, homeCtx.reqCtls);
|
||||
|
||||
try {
|
||||
|
||||
update(getReferredResults(refCtx));
|
||||
break;
|
||||
|
||||
} catch (LdapReferralException re) {
|
||||
|
||||
// record a previous exception
|
||||
if (errEx == null) {
|
||||
errEx = re.getNamingException();
|
||||
}
|
||||
refEx = re;
|
||||
continue;
|
||||
|
||||
} finally {
|
||||
// Make sure we close referral context
|
||||
refCtx.close();
|
||||
}
|
||||
}
|
||||
return hasMoreImpl();
|
||||
|
||||
} else {
|
||||
cleanup();
|
||||
|
||||
if (errEx != null) {
|
||||
throw errEx;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge the entries and/or referrals from the supplied enumeration
|
||||
* with those of the current enumeration.
|
||||
*/
|
||||
protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) {
|
||||
// Cleanup previous context first
|
||||
homeCtx.decEnumCount();
|
||||
|
||||
// New enum will have already incremented enum count and recorded clnt
|
||||
homeCtx = ne.homeCtx;
|
||||
enumClnt = ne.enumClnt;
|
||||
|
||||
// Do this to prevent referral enumeration (ne) from decrementing
|
||||
// enum count because we'll be doing that here from this
|
||||
// enumeration.
|
||||
ne.homeCtx = null;
|
||||
|
||||
// Record rest of information from new enum
|
||||
posn = ne.posn;
|
||||
limit = ne.limit;
|
||||
res = ne.res;
|
||||
entries = ne.entries;
|
||||
refEx = ne.refEx;
|
||||
listArg = ne.listArg;
|
||||
}
|
||||
|
||||
protected final void finalize() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
protected final void cleanup() {
|
||||
if (cleaned) return; // been there; done that
|
||||
|
||||
if(enumClnt != null) {
|
||||
enumClnt.clearSearchReply(res, homeCtx.reqCtls);
|
||||
}
|
||||
|
||||
enumClnt = null;
|
||||
cleaned = true;
|
||||
if (homeCtx != null) {
|
||||
homeCtx.decEnumCount();
|
||||
homeCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void close() {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
118
jdkSrc/jdk8/com/sun/jndi/ldap/BasicControl.java
Normal file
118
jdkSrc/jdk8/com/sun/jndi/ldap/BasicControl.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
/**
|
||||
* This class provides a basic implementation of the <tt>Control</tt>
|
||||
* interface. It represents an LDAPv3 Control as defined in RFC-2251.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public class BasicControl implements Control {
|
||||
|
||||
/**
|
||||
* The control's object identifier string.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected String id;
|
||||
|
||||
/**
|
||||
* The control's criticality.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected boolean criticality = false; // default
|
||||
|
||||
/**
|
||||
* The control's ASN.1 BER encoded value.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected byte[] value = null;
|
||||
|
||||
private static final long serialVersionUID = -5914033725246428413L;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of BasicControl.
|
||||
* It is a non-critical control.
|
||||
*
|
||||
* @param id The control's object identifier string.
|
||||
*
|
||||
*/
|
||||
public BasicControl(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of BasicControl.
|
||||
*
|
||||
* @param id The control's object identifier string.
|
||||
* @param criticality The control's criticality.
|
||||
* @param value The control's ASN.1 BER encoded value.
|
||||
* May be null.
|
||||
*/
|
||||
public BasicControl(String id, boolean criticality, byte[] value) {
|
||||
this.id = id;
|
||||
this.criticality = criticality;
|
||||
if (value != null) {
|
||||
this.value = value.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the control's object identifier string.
|
||||
*
|
||||
* @return The non-null object identifier string.
|
||||
*/
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the control's criticality.
|
||||
*
|
||||
* @return true if the control is critical; false otherwise.
|
||||
*/
|
||||
public boolean isCritical() {
|
||||
return criticality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the control's ASN.1 BER encoded value.
|
||||
* The result is the raw BER bytes including the tag and length of
|
||||
* the control's value. It does not include the control's object
|
||||
* identifier string or criticality.
|
||||
*
|
||||
* @return A possibly null byte array representing the control's
|
||||
* ASN.1 BER encoded value.
|
||||
*/
|
||||
public byte[] getEncodedValue() {
|
||||
return value == null ? null : value.clone();
|
||||
}
|
||||
}
|
||||
109
jdkSrc/jdk8/com/sun/jndi/ldap/Ber.java
Normal file
109
jdkSrc/jdk8/com/sun/jndi/ldap/Ber.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import sun.misc.HexDumpEncoder;
|
||||
|
||||
/**
|
||||
* Base class that defines common fields, constants, and debug method.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
*/
|
||||
public abstract class Ber {
|
||||
|
||||
protected byte buf[];
|
||||
protected int offset;
|
||||
protected int bufsize;
|
||||
|
||||
protected Ber() {
|
||||
}
|
||||
|
||||
public static void dumpBER(OutputStream outStream, String tag, byte[] bytes,
|
||||
int from, int to) {
|
||||
|
||||
try {
|
||||
outStream.write('\n');
|
||||
outStream.write(tag.getBytes("UTF8"));
|
||||
|
||||
new HexDumpEncoder().encodeBuffer(
|
||||
new ByteArrayInputStream(bytes, from, to),
|
||||
outStream);
|
||||
|
||||
outStream.write('\n');
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
outStream.write(
|
||||
"Ber.dumpBER(): error encountered\n".getBytes("UTF8"));
|
||||
} catch (IOException e2) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// some ASN defines
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static final int ASN_BOOLEAN = 0x01;
|
||||
public static final int ASN_INTEGER = 0x02;
|
||||
public static final int ASN_BIT_STRING = 0x03;
|
||||
public static final int ASN_SIMPLE_STRING = 0x04;
|
||||
public static final int ASN_OCTET_STR = 0x04;
|
||||
public static final int ASN_NULL = 0x05;
|
||||
public static final int ASN_OBJECT_ID = 0x06;
|
||||
public static final int ASN_SEQUENCE = 0x10;
|
||||
public static final int ASN_SET = 0x11;
|
||||
|
||||
|
||||
public static final int ASN_PRIMITIVE = 0x00;
|
||||
public static final int ASN_UNIVERSAL = 0x00;
|
||||
public static final int ASN_CONSTRUCTOR = 0x20;
|
||||
public static final int ASN_APPLICATION = 0x40;
|
||||
public static final int ASN_CONTEXT = 0x80;
|
||||
public static final int ASN_PRIVATE = 0xC0;
|
||||
|
||||
public static final int ASN_ENUMERATED = 0x0a;
|
||||
|
||||
final static class EncodeException extends IOException {
|
||||
private static final long serialVersionUID = -5247359637775781768L;
|
||||
EncodeException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
final static class DecodeException extends IOException {
|
||||
private static final long serialVersionUID = 8735036969244425583L;
|
||||
DecodeException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
341
jdkSrc/jdk8/com/sun/jndi/ldap/BerDecoder.java
Normal file
341
jdkSrc/jdk8/com/sun/jndi/ldap/BerDecoder.java
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A BER decoder. Contains methods to parse a BER buffer.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public final class BerDecoder extends Ber {
|
||||
|
||||
private int origOffset; // The start point in buf to decode
|
||||
|
||||
/**
|
||||
* Creates a BER decoder that reads bytes from the specified buffer.
|
||||
*/
|
||||
public BerDecoder(byte buf[], int offset, int bufsize) {
|
||||
|
||||
this.buf = buf; // shared buffer, be careful to use this class
|
||||
this.bufsize = bufsize;
|
||||
this.origOffset = offset;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this decode to start parsing from the initial offset
|
||||
* (ie., same state as after calling the constructor).
|
||||
*/
|
||||
public void reset() {
|
||||
offset = origOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current parse position.
|
||||
* It points to the byte that will be parsed next.
|
||||
* Useful for parsing sequences.
|
||||
*/
|
||||
public int getParsePosition() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a possibly variable length field.
|
||||
*/
|
||||
public int parseLength() throws DecodeException {
|
||||
|
||||
int lengthbyte = parseByte();
|
||||
|
||||
if ((lengthbyte & 0x80) == 0x80) {
|
||||
|
||||
lengthbyte &= 0x7f;
|
||||
|
||||
if (lengthbyte == 0) {
|
||||
throw new DecodeException(
|
||||
"Indefinite length not supported");
|
||||
}
|
||||
|
||||
if (lengthbyte > 4) {
|
||||
throw new DecodeException("encoding too long");
|
||||
}
|
||||
|
||||
if (bufsize - offset < lengthbyte) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
int retval = 0;
|
||||
|
||||
for( int i = 0; i < lengthbyte; i++) {
|
||||
retval = (retval << 8) + (buf[offset++] & 0xff);
|
||||
}
|
||||
if (retval < 0) {
|
||||
throw new DecodeException("Invalid length bytes");
|
||||
}
|
||||
return retval;
|
||||
} else {
|
||||
return lengthbyte;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next sequence in this BER buffer.
|
||||
* @param rlen An array for returning size of the sequence in bytes. If null,
|
||||
* the size is not returned.
|
||||
* @return The sequence's tag.
|
||||
*/
|
||||
public int parseSeq(int rlen[]) throws DecodeException {
|
||||
|
||||
int seq = parseByte();
|
||||
int len = parseLength();
|
||||
if (rlen != null) {
|
||||
rlen[0] = len;
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to skip bytes. Usually used when trying to recover from parse error.
|
||||
* Don't need to be public right now?
|
||||
* @param i The number of bytes to skip
|
||||
*/
|
||||
void seek(int i) throws DecodeException {
|
||||
if (offset + i > bufsize || offset + i < 0) {
|
||||
throw new DecodeException("array index out of bounds");
|
||||
}
|
||||
offset += i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next byte in this BER buffer.
|
||||
* @return The byte parsed.
|
||||
*/
|
||||
public int parseByte() throws DecodeException {
|
||||
if (bufsize - offset < 1) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
return buf[offset++] & 0xff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next byte in this BER buffer without consuming it.
|
||||
* @return The next byte.
|
||||
*/
|
||||
public int peekByte() throws DecodeException {
|
||||
if (bufsize - offset < 1) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
return buf[offset] & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN_BOOLEAN tagged integer from this BER buffer.
|
||||
* @return true if the tagged integer is 0; false otherwise.
|
||||
*/
|
||||
public boolean parseBoolean() throws DecodeException {
|
||||
return ((parseIntWithTag(ASN_BOOLEAN) == 0x00) ? false : true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN_ENUMERATED tagged integer from this BER buffer.
|
||||
* @return The tag of enumeration.
|
||||
*/
|
||||
public int parseEnumeration() throws DecodeException {
|
||||
return parseIntWithTag(ASN_ENUMERATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN_INTEGER tagged integer from this BER buffer.
|
||||
* @return The value of the integer.
|
||||
*/
|
||||
public int parseInt() throws DecodeException {
|
||||
return parseIntWithTag(ASN_INTEGER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer that's preceded by a tag.
|
||||
*<blockquote><pre>
|
||||
* BER integer ::= tag length byte {byte}*
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
private int parseIntWithTag(int tag) throws DecodeException {
|
||||
if (parseByte() != tag) {
|
||||
// Ber could have been reset;
|
||||
String s;
|
||||
if (offset > 0) {
|
||||
s = Integer.toString(buf[offset - 1] & 0xff);
|
||||
} else {
|
||||
s = "Empty tag";
|
||||
}
|
||||
throw new DecodeException("Encountered ASN.1 tag " +
|
||||
s + " (expected tag " + Integer.toString(tag) + ")");
|
||||
}
|
||||
|
||||
int len = parseLength();
|
||||
|
||||
if (len > 4) {
|
||||
throw new DecodeException("INTEGER too long");
|
||||
} else if (len > bufsize - offset) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
byte fb = buf[offset++];
|
||||
int value = 0;
|
||||
|
||||
value = fb & 0x7F;
|
||||
for( int i = 1 /* first byte already read */ ; i < len; i++) {
|
||||
value <<= 8;
|
||||
value |= (buf[offset++] & 0xff);
|
||||
}
|
||||
|
||||
if ((fb & 0x80) == 0x80) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string.
|
||||
*/
|
||||
public String parseString(boolean decodeUTF8) throws DecodeException {
|
||||
return parseStringWithTag(ASN_SIMPLE_STRING, decodeUTF8, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string of a given tag from this BER buffer.
|
||||
*<blockquote><pre>
|
||||
*BER simple string ::= tag length {byte}*
|
||||
*</pre></blockquote>
|
||||
* @param rlen An array for holding the relative parsed offset; if null
|
||||
* offset not set.
|
||||
* @param decodeUTF8 If true, use UTF-8 when decoding the string; otherwise
|
||||
* use ISO-Latin-1 (8859_1). Use true for LDAPv3; false for LDAPv2.
|
||||
* @param tag The tag that precedes the string.
|
||||
* @return The non-null parsed string.
|
||||
*/
|
||||
public String parseStringWithTag(int tag, boolean decodeUTF8, int rlen[])
|
||||
throws DecodeException {
|
||||
|
||||
int st;
|
||||
int origOffset = offset;
|
||||
|
||||
if ((st = parseByte()) != tag) {
|
||||
throw new DecodeException("Encountered ASN.1 tag " +
|
||||
Integer.toString((byte)st) + " (expected tag " + tag + ")");
|
||||
}
|
||||
|
||||
int len = parseLength();
|
||||
|
||||
if (len > bufsize - offset) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
String retstr;
|
||||
if (len == 0) {
|
||||
retstr = "";
|
||||
} else {
|
||||
byte[] buf2 = new byte[len];
|
||||
|
||||
System.arraycopy(buf, offset, buf2, 0, len);
|
||||
if (decodeUTF8) {
|
||||
try {
|
||||
retstr = new String(buf2, "UTF8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new DecodeException("UTF8 not available on platform");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
retstr = new String(buf2, "8859_1");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new DecodeException("8859_1 not available on platform");
|
||||
}
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (rlen != null) {
|
||||
rlen[0] = offset - origOffset;
|
||||
}
|
||||
|
||||
return retstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an octet string of a given type(tag) from this BER buffer.
|
||||
* <blockquote><pre>
|
||||
* BER Binary Data of type "tag" ::= tag length {byte}*
|
||||
*</pre></blockquote>
|
||||
*
|
||||
* @param tag The tag to look for.
|
||||
* @param rlen An array for returning the relative parsed position. If null,
|
||||
* the relative parsed position is not returned.
|
||||
* @return A non-null array containing the octet string.
|
||||
* @throws DecodeException If the next byte in the BER buffer is not
|
||||
* <tt>tag</tt>, or if length specified in the BER buffer exceeds the
|
||||
* number of bytes left in the buffer.
|
||||
*/
|
||||
public byte[] parseOctetString(int tag, int rlen[]) throws DecodeException {
|
||||
|
||||
int origOffset = offset;
|
||||
int st;
|
||||
if ((st = parseByte()) != tag) {
|
||||
|
||||
throw new DecodeException("Encountered ASN.1 tag " +
|
||||
Integer.toString(st) +
|
||||
" (expected tag " + Integer.toString(tag) + ")");
|
||||
}
|
||||
|
||||
int len = parseLength();
|
||||
|
||||
if (len > bufsize - offset) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
byte retarr[] = new byte[len];
|
||||
if (len > 0) {
|
||||
System.arraycopy(buf, offset, retarr, 0, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (rlen != null) {
|
||||
rlen[0] = offset - origOffset;
|
||||
}
|
||||
|
||||
return retarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of unparsed bytes in this BER buffer.
|
||||
*/
|
||||
public int bytesLeft() {
|
||||
return bufsize - offset;
|
||||
}
|
||||
}
|
||||
429
jdkSrc/jdk8/com/sun/jndi/ldap/BerEncoder.java
Normal file
429
jdkSrc/jdk8/com/sun/jndi/ldap/BerEncoder.java
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A BER encoder.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
* @author Scott Seligman
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public final class BerEncoder extends Ber {
|
||||
|
||||
private int curSeqIndex;
|
||||
private int seqOffset[];
|
||||
private static final int INITIAL_SEQUENCES = 16;
|
||||
private static final int DEFAULT_BUFSIZE = 1024;
|
||||
|
||||
// When buf is full, expand its size by the following factor.
|
||||
private static final int BUF_GROWTH_FACTOR = 8;
|
||||
|
||||
/**
|
||||
* Creates a BER buffer for encoding.
|
||||
*/
|
||||
public BerEncoder() {
|
||||
this(DEFAULT_BUFSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BER buffer of a specified size for encoding.
|
||||
* Specify the initial bufsize. Buffer will be expanded as needed.
|
||||
* @param bufsize The number of bytes for the buffer.
|
||||
*/
|
||||
public BerEncoder(int bufsize) {
|
||||
buf = new byte[bufsize];
|
||||
this.bufsize = bufsize;
|
||||
offset = 0;
|
||||
|
||||
seqOffset = new int[INITIAL_SEQUENCES];
|
||||
curSeqIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets encoder to state when newly constructed. Zeros out
|
||||
* internal data structures.
|
||||
*/
|
||||
public void reset() {
|
||||
while (offset > 0) {
|
||||
buf[--offset] = 0;
|
||||
}
|
||||
while (curSeqIndex > 0) {
|
||||
seqOffset[--curSeqIndex] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ Accessor methods ------------
|
||||
|
||||
/**
|
||||
* Gets the number of encoded bytes in this BER buffer.
|
||||
*/
|
||||
public int getDataLen() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer that contains the BER encoding. Throws an
|
||||
* exception if unmatched beginSeq() and endSeq() pairs were
|
||||
* encountered. Not entire buffer contains encoded bytes.
|
||||
* Use getDataLen() to determine number of encoded bytes.
|
||||
* Use getBuffer(true) to get rid of excess bytes in array.
|
||||
* @throws IllegalStateException If buffer contains unbalanced sequence.
|
||||
*/
|
||||
public byte[] getBuf() {
|
||||
if (curSeqIndex != 0) {
|
||||
throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");
|
||||
}
|
||||
return buf; // shared buffer, be careful to use this method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer that contains the BER encoding, trimming unused bytes.
|
||||
*
|
||||
* @throws IllegalStateException If buffer contains unbalanced sequence.
|
||||
*/
|
||||
public byte[] getTrimmedBuf() {
|
||||
int len = getDataLen();
|
||||
byte[] trimBuf = new byte[len];
|
||||
|
||||
System.arraycopy(getBuf(), 0, trimBuf, 0, len);
|
||||
return trimBuf;
|
||||
}
|
||||
|
||||
// -------------- encoding methods -------------
|
||||
|
||||
/**
|
||||
* Begin encoding a sequence with a tag.
|
||||
*/
|
||||
public void beginSeq(int tag) {
|
||||
|
||||
// Double the size of the SEQUENCE array if it overflows
|
||||
if (curSeqIndex >= seqOffset.length) {
|
||||
int[] seqOffsetTmp = new int[seqOffset.length * 2];
|
||||
|
||||
for (int i = 0; i < seqOffset.length; i++) {
|
||||
seqOffsetTmp[i] = seqOffset[i];
|
||||
}
|
||||
seqOffset = seqOffsetTmp;
|
||||
}
|
||||
|
||||
encodeByte(tag);
|
||||
seqOffset[curSeqIndex] = offset;
|
||||
|
||||
// Save space for sequence length.
|
||||
// %%% Currently we save enough space for sequences up to 64k.
|
||||
// For larger sequences we'll need to shift the data to the right
|
||||
// in endSeq(). If we could instead pad the length field with
|
||||
// zeros, it would be a big win.
|
||||
ensureFreeBytes(3);
|
||||
offset += 3;
|
||||
|
||||
curSeqIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate a BER sequence.
|
||||
*/
|
||||
public void endSeq() throws EncodeException {
|
||||
curSeqIndex--;
|
||||
if (curSeqIndex < 0) {
|
||||
throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");
|
||||
}
|
||||
|
||||
int start = seqOffset[curSeqIndex] + 3; // index beyond length field
|
||||
int len = offset - start;
|
||||
|
||||
if (len <= 0x7f) {
|
||||
shiftSeqData(start, len, -2);
|
||||
buf[seqOffset[curSeqIndex]] = (byte) len;
|
||||
} else if (len <= 0xff) {
|
||||
shiftSeqData(start, len, -1);
|
||||
buf[seqOffset[curSeqIndex]] = (byte) 0x81;
|
||||
buf[seqOffset[curSeqIndex] + 1] = (byte) len;
|
||||
} else if (len <= 0xffff) {
|
||||
buf[seqOffset[curSeqIndex]] = (byte) 0x82;
|
||||
buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 8);
|
||||
buf[seqOffset[curSeqIndex] + 2] = (byte) len;
|
||||
} else if (len <= 0xffffff) {
|
||||
shiftSeqData(start, len, 1);
|
||||
buf[seqOffset[curSeqIndex]] = (byte) 0x83;
|
||||
buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 16);
|
||||
buf[seqOffset[curSeqIndex] + 2] = (byte) (len >> 8);
|
||||
buf[seqOffset[curSeqIndex] + 3] = (byte) len;
|
||||
} else {
|
||||
throw new EncodeException("SEQUENCE too long");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts contents of buf in the range [start,start+len) a specified amount.
|
||||
* Positive shift value means shift to the right.
|
||||
*/
|
||||
private void shiftSeqData(int start, int len, int shift) {
|
||||
if (shift > 0) {
|
||||
ensureFreeBytes(shift);
|
||||
}
|
||||
System.arraycopy(buf, start, buf, start + shift, len);
|
||||
offset += shift;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a single byte.
|
||||
*/
|
||||
public void encodeByte(int b) {
|
||||
ensureFreeBytes(1);
|
||||
buf[offset++] = (byte) b;
|
||||
}
|
||||
|
||||
/*
|
||||
private void deleteByte() {
|
||||
offset--;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Encodes an int.
|
||||
*<blockquote><pre>
|
||||
* BER integer ::= 0x02 berlength byte {byte}*
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeInt(int i) {
|
||||
encodeInt(i, 0x02);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an int and a tag.
|
||||
*<blockquote><pre>
|
||||
* BER integer w tag ::= tag berlength byte {byte}*
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeInt(int i, int tag) {
|
||||
int mask = 0xff800000;
|
||||
int intsize = 4;
|
||||
|
||||
while( (((i & mask) == 0) || ((i & mask) == mask)) && (intsize > 1) ) {
|
||||
intsize--;
|
||||
i <<= 8;
|
||||
}
|
||||
|
||||
encodeInt(i, tag, intsize);
|
||||
}
|
||||
|
||||
//
|
||||
// encodes an int using numbytes for the actual encoding.
|
||||
//
|
||||
private void encodeInt(int i, int tag, int intsize) {
|
||||
|
||||
//
|
||||
// integer ::= 0x02 asnlength byte {byte}*
|
||||
//
|
||||
|
||||
if (intsize > 4) {
|
||||
throw new IllegalArgumentException("BER encode error: INTEGER too long.");
|
||||
}
|
||||
|
||||
ensureFreeBytes(2 + intsize);
|
||||
|
||||
buf[offset++] = (byte) tag;
|
||||
buf[offset++] = (byte) intsize;
|
||||
|
||||
int mask = 0xff000000;
|
||||
|
||||
while (intsize-- > 0) {
|
||||
buf[offset++] = (byte) ((i & mask) >> 24);
|
||||
i <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a boolean.
|
||||
*<blockquote><pre>
|
||||
* BER boolean ::= 0x01 0x01 {0xff|0x00}
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeBoolean(boolean b) {
|
||||
encodeBoolean(b, ASN_BOOLEAN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a boolean and a tag
|
||||
*<blockquote><pre>
|
||||
* BER boolean w TAG ::= tag 0x01 {0xff|0x00}
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeBoolean(boolean b, int tag) {
|
||||
ensureFreeBytes(3);
|
||||
|
||||
buf[offset++] = (byte) tag;
|
||||
buf[offset++] = 0x01;
|
||||
buf[offset++] = b ? (byte) 0xff : (byte) 0x00;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a string.
|
||||
*<blockquote><pre>
|
||||
* BER string ::= 0x04 strlen byte1 byte2...
|
||||
*</pre></blockquote>
|
||||
* The string is converted into bytes using UTF-8 or ISO-Latin-1.
|
||||
*/
|
||||
public void encodeString(String str, boolean encodeUTF8)
|
||||
throws EncodeException {
|
||||
encodeString(str, ASN_OCTET_STR, encodeUTF8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a string and a tag.
|
||||
*<blockquote><pre>
|
||||
* BER string w TAG ::= tag strlen byte1 byte2...
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeString(String str, int tag, boolean encodeUTF8)
|
||||
throws EncodeException {
|
||||
|
||||
encodeByte(tag);
|
||||
|
||||
int i = 0;
|
||||
int count;
|
||||
byte[] bytes = null;
|
||||
|
||||
if (str == null) {
|
||||
count = 0;
|
||||
} else if (encodeUTF8) {
|
||||
try {
|
||||
bytes = str.getBytes("UTF8");
|
||||
count = bytes.length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new EncodeException("UTF8 not available on platform");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
bytes = str.getBytes("8859_1");
|
||||
count = bytes.length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new EncodeException("8859_1 not available on platform");
|
||||
}
|
||||
}
|
||||
|
||||
encodeLength(count);
|
||||
|
||||
ensureFreeBytes(count);
|
||||
while (i < count) {
|
||||
buf[offset++] = bytes[i++];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a portion of an octet string and a tag.
|
||||
*/
|
||||
public void encodeOctetString(byte tb[], int tag, int tboffset, int length)
|
||||
throws EncodeException {
|
||||
|
||||
encodeByte(tag);
|
||||
encodeLength(length);
|
||||
|
||||
if (length > 0) {
|
||||
ensureFreeBytes(length);
|
||||
System.arraycopy(tb, tboffset, buf, offset, length);
|
||||
offset += length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an octet string and a tag.
|
||||
*/
|
||||
public void encodeOctetString(byte tb[], int tag) throws EncodeException {
|
||||
encodeOctetString(tb, tag, 0, tb.length);
|
||||
}
|
||||
|
||||
private void encodeLength(int len) throws EncodeException {
|
||||
ensureFreeBytes(4); // worst case
|
||||
|
||||
if (len < 128) {
|
||||
buf[offset++] = (byte) len;
|
||||
} else if (len <= 0xff) {
|
||||
buf[offset++] = (byte) 0x81;
|
||||
buf[offset++] = (byte) len;
|
||||
} else if (len <= 0xffff) {
|
||||
buf[offset++] = (byte) 0x82;
|
||||
buf[offset++] = (byte) (len >> 8);
|
||||
buf[offset++] = (byte) (len & 0xff);
|
||||
} else if (len <= 0xffffff) {
|
||||
buf[offset++] = (byte) 0x83;
|
||||
buf[offset++] = (byte) (len >> 16);
|
||||
buf[offset++] = (byte) (len >> 8);
|
||||
buf[offset++] = (byte) (len & 0xff);
|
||||
} else {
|
||||
throw new EncodeException("string too long");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an array of strings.
|
||||
*/
|
||||
public void encodeStringArray(String strs[], boolean encodeUTF8)
|
||||
throws EncodeException {
|
||||
if (strs == null)
|
||||
return;
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
encodeString(strs[i], encodeUTF8);
|
||||
}
|
||||
}
|
||||
/*
|
||||
private void encodeNull() {
|
||||
|
||||
//
|
||||
// NULL ::= 0x05 0x00
|
||||
//
|
||||
encodeByte(0x05);
|
||||
encodeByte(0x00);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensures that there are at least "len" unused bytes in "buf".
|
||||
* When more space is needed "buf" is expanded by a factor of
|
||||
* BUF_GROWTH_FACTOR, then "len" bytes are added if "buf" still
|
||||
* isn't large enough.
|
||||
*/
|
||||
private void ensureFreeBytes(int len) {
|
||||
if (bufsize - offset < len) {
|
||||
int newsize = bufsize * BUF_GROWTH_FACTOR;
|
||||
if (newsize - offset < len) {
|
||||
newsize += len;
|
||||
}
|
||||
byte newbuf[] = new byte[newsize];
|
||||
// Only copy bytes in the range [0, offset)
|
||||
System.arraycopy(buf, 0, newbuf, 0, offset);
|
||||
|
||||
buf = newbuf;
|
||||
bufsize = newsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
jdkSrc/jdk8/com/sun/jndi/ldap/BindingWithControls.java
Normal file
44
jdkSrc/jdk8/com/sun/jndi/ldap/BindingWithControls.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
class BindingWithControls extends Binding implements HasControls {
|
||||
private Control[] controls;
|
||||
|
||||
public BindingWithControls(String name, Object obj, Control[] controls) {
|
||||
super(name, obj);
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 9117274533692320040L;
|
||||
}
|
||||
227
jdkSrc/jdk8/com/sun/jndi/ldap/ClientId.java
Normal file
227
jdkSrc/jdk8/com/sun/jndi/ldap/ClientId.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Arrays; // JDK 1.2
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.ldap.Control;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
/**
|
||||
* Represents identity information about an anonymous LDAP connection.
|
||||
* This base class contains the following information:
|
||||
* - protocol version number
|
||||
* - server's hostname (case-insensitive)
|
||||
* - server's port number
|
||||
* - prototype type (plain or ssl)
|
||||
* - controls to be sent with the LDAP bind request
|
||||
*
|
||||
* All other identity classes must be a subclass of ClientId.
|
||||
* Identity subclasses would add more distinguishing information, depending
|
||||
* on the type of authentication that the connection is to have.
|
||||
*
|
||||
* The equals() and hashCode() methods of this class and its subclasses are
|
||||
* important because they are used to determine whether two requests for
|
||||
* the same connection are identical, and thus whether the same connection
|
||||
* may be shared. This is especially important for authenticated connections
|
||||
* because a mistake would result in a serious security violation.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
class ClientId {
|
||||
final private int version;
|
||||
final private String hostname;
|
||||
final private int port;
|
||||
final private String protocol;
|
||||
final private Control[] bindCtls;
|
||||
final private OutputStream trace;
|
||||
final private String socketFactory;
|
||||
final private int myHash;
|
||||
final private int ctlHash;
|
||||
|
||||
private SocketFactory factory = null;
|
||||
private Method sockComparator = null;
|
||||
private boolean isDefaultSockFactory = false;
|
||||
final public static boolean debug = false;
|
||||
|
||||
ClientId(int version, String hostname, int port, String protocol,
|
||||
Control[] bindCtls, OutputStream trace, String socketFactory) {
|
||||
this.version = version;
|
||||
this.hostname = hostname.toLowerCase(Locale.ENGLISH); // ignore case
|
||||
this.port = port;
|
||||
this.protocol = protocol;
|
||||
this.bindCtls = (bindCtls != null ? bindCtls.clone() : null);
|
||||
this.trace = trace;
|
||||
//
|
||||
// Needed for custom socket factory pooling
|
||||
//
|
||||
this.socketFactory = socketFactory;
|
||||
if ((socketFactory != null) &&
|
||||
!socketFactory.equals(LdapCtx.DEFAULT_SSL_FACTORY)) {
|
||||
try {
|
||||
Class<?> socketFactoryClass =
|
||||
Obj.helper.loadClass(socketFactory);
|
||||
Class<?> objClass = Class.forName("java.lang.Object");
|
||||
this.sockComparator = socketFactoryClass.getMethod(
|
||||
"compare", new Class<?>[]{objClass, objClass});
|
||||
Method getDefault = socketFactoryClass.getMethod(
|
||||
"getDefault", new Class<?>[]{});
|
||||
this.factory =
|
||||
(SocketFactory)getDefault.invoke(null, new Object[]{});
|
||||
} catch (Exception e) {
|
||||
// Ignore it here, the same exceptions are/will be handled by
|
||||
// LdapPoolManager and Connection classes.
|
||||
if (debug) {
|
||||
System.out.println("ClientId received an exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isDefaultSockFactory = true;
|
||||
}
|
||||
|
||||
// The SocketFactory field is not used in the myHash
|
||||
// computation as there is no right way to compute the hash code
|
||||
// for this field. There is no harm in skipping it from the hash
|
||||
// computation
|
||||
myHash = version + port
|
||||
+ (trace != null ? trace.hashCode() : 0)
|
||||
+ (this.hostname != null ? this.hostname.hashCode() : 0)
|
||||
+ (protocol != null ? protocol.hashCode() : 0)
|
||||
+ (ctlHash=hashCodeControls(bindCtls));
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ClientId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientId other = (ClientId)obj;
|
||||
|
||||
return myHash == other.myHash
|
||||
&& version == other.version
|
||||
&& port == other.port
|
||||
&& trace == other.trace
|
||||
&& (hostname == other.hostname // null OK
|
||||
|| (hostname != null && hostname.equals(other.hostname)))
|
||||
&& (protocol == other.protocol // null OK
|
||||
|| (protocol != null && protocol.equals(other.protocol)))
|
||||
&& ctlHash == other.ctlHash
|
||||
&& (equalsControls(bindCtls, other.bindCtls))
|
||||
&& (equalsSockFactory(other));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
|
||||
private static int hashCodeControls(Control[] c) {
|
||||
if (c == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int code = 0;
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
code = code * 31 + c[i].getID().hashCode();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private static boolean equalsControls(Control[] a, Control[] b) {
|
||||
if (a == b) {
|
||||
return true; // both null or same
|
||||
}
|
||||
if (a == null || b == null) {
|
||||
return false; // one is non-null
|
||||
}
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (!a[i].getID().equals(b[i].getID())
|
||||
|| a[i].isCritical() != b[i].isCritical()
|
||||
|| !Arrays.equals(a[i].getEncodedValue(),
|
||||
b[i].getEncodedValue())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean equalsSockFactory(ClientId other) {
|
||||
if (this.isDefaultSockFactory && other.isDefaultSockFactory) {
|
||||
return true;
|
||||
}
|
||||
else if (!other.isDefaultSockFactory) {
|
||||
return invokeComparator(other, this);
|
||||
} else {
|
||||
return invokeComparator(this, other);
|
||||
}
|
||||
}
|
||||
|
||||
// delegate the comparison work to the SocketFactory class
|
||||
// as there is no enough information here, to do the comparison
|
||||
private boolean invokeComparator(ClientId c1, ClientId c2) {
|
||||
Object ret;
|
||||
try {
|
||||
ret = (c1.sockComparator).invoke(
|
||||
c1.factory, c1.socketFactory, c2.socketFactory);
|
||||
} catch(Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("ClientId received an exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Failed to invoke the comparator; flag unequality
|
||||
return false;
|
||||
}
|
||||
if (((Integer) ret) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String toStringControls(Control[] ctls) {
|
||||
if (ctls == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer str = new StringBuffer();
|
||||
for (int i = 0; i < ctls.length; i++) {
|
||||
str.append(ctls[i].getID());
|
||||
str.append(' ');
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (hostname + ":" + port + ":" +
|
||||
(protocol != null ? protocol : "") + ":" +
|
||||
toStringControls(bindCtls) + ":" +
|
||||
socketFactory);
|
||||
}
|
||||
}
|
||||
1046
jdkSrc/jdk8/com/sun/jndi/ldap/Connection.java
Normal file
1046
jdkSrc/jdk8/com/sun/jndi/ldap/Connection.java
Normal file
File diff suppressed because it is too large
Load Diff
86
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultLdapDnsProvider.java
Normal file
86
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultLdapDnsProvider.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProvider;
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProviderResult;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DefaultLdapDnsProvider {
|
||||
|
||||
public Optional<LdapDnsProviderResult> lookupEndpoints(String url,
|
||||
Map<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
if (url == null || env == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
String domainName;
|
||||
List<String> endpoints = new ArrayList<>();
|
||||
LdapURL ldapUrl = new LdapURL(url);
|
||||
String dn = ldapUrl.getDN();
|
||||
String host = ldapUrl.getHost();
|
||||
int port = ldapUrl.getPort();
|
||||
String[] hostports;
|
||||
|
||||
// handle a URL with no hostport (ldap:/// or ldaps:///)
|
||||
// locate the LDAP service using the URL's distinguished name
|
||||
if (host == null
|
||||
&& port == -1
|
||||
&& dn != null
|
||||
&& (domainName = ServiceLocator.mapDnToDomainName(dn)) != null
|
||||
&& (hostports = ServiceLocator.getLdapService(domainName, env)) != null) {
|
||||
// Generate new URLs that include the discovered hostports.
|
||||
// Reuse the original URL scheme.
|
||||
String scheme = ldapUrl.getScheme() + "://";
|
||||
String query = ldapUrl.getQuery();
|
||||
String urlSuffix = ldapUrl.getPath() + (query != null ? query : "");
|
||||
for (String hostPort : hostports) {
|
||||
// the hostports come from the DNS SRV records
|
||||
// we assume the SRV record is scheme aware
|
||||
endpoints.add(scheme + hostPort + urlSuffix);
|
||||
}
|
||||
} else {
|
||||
// we don't have enough information to set the domain name
|
||||
// correctly
|
||||
domainName = "";
|
||||
endpoints.add(url);
|
||||
}
|
||||
|
||||
LdapDnsProviderResult res = new LdapDnsProviderResult(domainName, endpoints);
|
||||
if (res.getEndpoints().isEmpty() && res.getDomainName().isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(res);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
100
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultResponseControlFactory.java
Normal file
100
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultResponseControlFactory.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
/**
|
||||
* This class represents a factory for creating LDAPv3 response controls.
|
||||
* The following response controls are supported:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Paged results, as defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>.
|
||||
* <li>
|
||||
* Server-side sorting, as defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
|
||||
* <li>
|
||||
* Entry change response control, as defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-psearch-02.txt">draft-ietf-ldapext-psearch-02.txt</a>.
|
||||
* </ul>
|
||||
*
|
||||
* @see javax.naming.ldap.SortResponseControl
|
||||
* @see javax.naming.ldap.PagedResultsResponseControl
|
||||
* @see PersistentSearchControl
|
||||
* @see EntryChangeResponseControl
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public class DefaultResponseControlFactory extends ControlFactory {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the response control factory.
|
||||
*/
|
||||
public DefaultResponseControlFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of a response control class from a more
|
||||
* generic control class (BasicControl).
|
||||
*
|
||||
* @param ctl A non-null control.
|
||||
* @return The LDAP control created or null if it cannot be created.
|
||||
* Null indicates that another factory should be attempted.
|
||||
* @exception NamingException if this control factory encountered an
|
||||
* error condition while attempting to create the LDAP control,
|
||||
* and no other control factories are to be tried.
|
||||
*/
|
||||
public Control getControlInstance(Control ctl)
|
||||
throws NamingException {
|
||||
|
||||
String id = ctl.getID();
|
||||
//System.out.println(id);
|
||||
|
||||
try {
|
||||
if (id.equals(SortResponseControl.OID)) {
|
||||
return new SortResponseControl(id, ctl.isCritical(),
|
||||
ctl.getEncodedValue());
|
||||
|
||||
} else if (id.equals(PagedResultsResponseControl.OID)) {
|
||||
return new PagedResultsResponseControl(id, ctl.isCritical(),
|
||||
ctl.getEncodedValue());
|
||||
|
||||
} else if (id.equals(EntryChangeResponseControl.OID)) {
|
||||
return new EntryChangeResponseControl(id, ctl.isCritical(),
|
||||
ctl.getEncodedValue());
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
113
jdkSrc/jdk8/com/sun/jndi/ldap/DigestClientId.java
Normal file
113
jdkSrc/jdk8/com/sun/jndi/ldap/DigestClientId.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Arrays; // JDK 1.2
|
||||
import java.util.Hashtable;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* Extends SimpleClientId to add property values specific for Digest-MD5.
|
||||
* This includes:
|
||||
* realm, authzid, qop, strength, maxbuffer, mutual-auth, reuse,
|
||||
* all policy-related selection properties.
|
||||
* Two DigestClientIds are identical iff they pass the SimpleClientId
|
||||
* equals() test and that all of these property values are the same.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
class DigestClientId extends SimpleClientId {
|
||||
private static final String[] SASL_PROPS = {
|
||||
"java.naming.security.sasl.authorizationId",
|
||||
"java.naming.security.sasl.realm",
|
||||
"javax.security.sasl.qop",
|
||||
"javax.security.sasl.strength",
|
||||
"javax.security.sasl.reuse",
|
||||
"javax.security.sasl.server.authentication",
|
||||
"javax.security.sasl.maxbuffer",
|
||||
"javax.security.sasl.policy.noplaintext",
|
||||
"javax.security.sasl.policy.noactive",
|
||||
"javax.security.sasl.policy.nodictionary",
|
||||
"javax.security.sasl.policy.noanonymous",
|
||||
"javax.security.sasl.policy.forward",
|
||||
"javax.security.sasl.policy.credentials",
|
||||
};
|
||||
|
||||
final private String[] propvals;
|
||||
final private int myHash;
|
||||
|
||||
DigestClientId(int version, String hostname, int port,
|
||||
String protocol, Control[] bindCtls, OutputStream trace,
|
||||
String socketFactory, String username,
|
||||
Object passwd, Hashtable<?,?> env) {
|
||||
|
||||
super(version, hostname, port, protocol, bindCtls, trace,
|
||||
socketFactory, username, passwd);
|
||||
|
||||
if (env == null) {
|
||||
propvals = null;
|
||||
} else {
|
||||
// Could be smarter and apply default values for props
|
||||
// but for now, we just record and check exact matches
|
||||
propvals = new String[SASL_PROPS.length];
|
||||
for (int i = 0; i < SASL_PROPS.length; i++) {
|
||||
propvals[i] = (String) env.get(SASL_PROPS[i]);
|
||||
}
|
||||
}
|
||||
myHash = super.hashCode() ^ Arrays.hashCode(propvals);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DigestClientId)) {
|
||||
return false;
|
||||
}
|
||||
DigestClientId other = (DigestClientId)obj;
|
||||
return myHash == other.myHash
|
||||
&& super.equals(obj)
|
||||
&& Arrays.equals(propvals, other.propvals);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (propvals != null) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < propvals.length; i++) {
|
||||
buf.append(':');
|
||||
if (propvals[i] != null) {
|
||||
buf.append(propvals[i]);
|
||||
}
|
||||
}
|
||||
return super.toString() + buf.toString();
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
167
jdkSrc/jdk8/com/sun/jndi/ldap/EntryChangeResponseControl.java
Normal file
167
jdkSrc/jdk8/com/sun/jndi/ldap/EntryChangeResponseControl.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Response Control for entry-change
|
||||
* notification as defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-psearch-02.txt">draft-ietf-ldapext-psearch-02.txt</a>.
|
||||
*
|
||||
* The control's value has the following ASN.1 definition:
|
||||
* <pre>
|
||||
*
|
||||
* EntryChangeNotification ::= SEQUENCE {
|
||||
* changeType ENUMERATED {
|
||||
* add (1),
|
||||
* delete (2),
|
||||
* modify (4),
|
||||
* modDN (8)
|
||||
* },
|
||||
* previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
|
||||
* changeNumber INTEGER OPTIONAL, -- if supported
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see PersistentSearchControl
|
||||
* @see com.sun.jndi.ldap.ctl.ResponseControlFactory ResponseControlFactory
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class EntryChangeResponseControl extends BasicControl {
|
||||
|
||||
/**
|
||||
* The entry-change response control's assigned object identifier
|
||||
* is 2.16.840.1.113730.3.4.7.
|
||||
*/
|
||||
public static final String OID = "2.16.840.1.113730.3.4.7";
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been added.
|
||||
*/
|
||||
public static final int ADD = 1;
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been deleted.
|
||||
*/
|
||||
public static final int DELETE = 2;
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been modified.
|
||||
*/
|
||||
public static final int MODIFY = 4;
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been renamed.
|
||||
*/
|
||||
public static final int RENAME = 8;
|
||||
|
||||
/**
|
||||
* The type of change that occurred.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private int changeType;
|
||||
|
||||
/**
|
||||
* The previous distinguished name (only applies to RENAME changes).
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private String previousDN = null;
|
||||
|
||||
/**
|
||||
* The change number (if supported by the server).
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private long changeNumber = -1L;
|
||||
|
||||
private static final long serialVersionUID = -2087354136750180511L;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of EntryChangeResponseControl.
|
||||
*
|
||||
* @param id The control's object identifier string.
|
||||
* @param criticality The control's criticality.
|
||||
* @param value The control's ASN.1 BER encoded value.
|
||||
* May be null.
|
||||
* @exception IOException if an error is encountered
|
||||
* while decoding the control's value.
|
||||
*/
|
||||
public EntryChangeResponseControl(String id, boolean criticality,
|
||||
byte[] value) throws IOException {
|
||||
|
||||
super(id, criticality, value);
|
||||
|
||||
// decode value
|
||||
if ((value != null) && (value.length > 0)) {
|
||||
BerDecoder ber = new BerDecoder(value, 0, value.length);
|
||||
|
||||
ber.parseSeq(null);
|
||||
changeType = ber.parseEnumeration();
|
||||
|
||||
if ((ber.bytesLeft() > 0) && (ber.peekByte() == Ber.ASN_OCTET_STR)){
|
||||
previousDN = ber.parseString(true);
|
||||
}
|
||||
if ((ber.bytesLeft() > 0) && (ber.peekByte() == Ber.ASN_INTEGER)) {
|
||||
changeNumber = ber.parseInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the type of change that occurred.
|
||||
*
|
||||
* @return The type of change.
|
||||
*/
|
||||
public int getChangeType() {
|
||||
return changeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the previous distinguished name of the entry before it was
|
||||
* renamed and/or moved. This method applies only to RENAME changes.
|
||||
*
|
||||
* @return The previous distinguished name or null if not applicable.
|
||||
*/
|
||||
public String getPreviousDN() {
|
||||
return previousDN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the change number assigned by the server for this change.
|
||||
* Returns -1 if this feature is not supported by the server.
|
||||
*
|
||||
* @return The change number or -1 if unsupported.
|
||||
*/
|
||||
public long getChangeNumber() {
|
||||
return changeNumber;
|
||||
}
|
||||
}
|
||||
176
jdkSrc/jdk8/com/sun/jndi/ldap/EventQueue.java
Normal file
176
jdkSrc/jdk8/com/sun/jndi/ldap/EventQueue.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.EventObject;
|
||||
|
||||
import javax.naming.event.NamingEvent;
|
||||
import javax.naming.event.NamingExceptionEvent;
|
||||
import javax.naming.event.NamingListener;
|
||||
import javax.naming.ldap.UnsolicitedNotificationEvent;
|
||||
import javax.naming.ldap.UnsolicitedNotificationListener;
|
||||
|
||||
/**
|
||||
* Package private class used by EventSupport to dispatch events.
|
||||
* This class implements an event queue, and a dispatcher thread that
|
||||
* dequeues and dispatches events from the queue.
|
||||
*
|
||||
* Pieces stolen from sun.misc.Queue.
|
||||
*
|
||||
* @author Bill Shannon (from javax.mail.event)
|
||||
* @author Rosanna Lee (modified for JNDI-related events)
|
||||
*/
|
||||
final class EventQueue implements Runnable {
|
||||
final static private boolean debug = false;
|
||||
|
||||
private static class QueueElement {
|
||||
QueueElement next = null;
|
||||
QueueElement prev = null;
|
||||
EventObject event = null;
|
||||
Vector<NamingListener> vector = null;
|
||||
|
||||
QueueElement(EventObject event, Vector<NamingListener> vector) {
|
||||
this.event = event;
|
||||
this.vector = vector;
|
||||
}
|
||||
}
|
||||
|
||||
private QueueElement head = null;
|
||||
private QueueElement tail = null;
|
||||
private Thread qThread;
|
||||
|
||||
// package private
|
||||
EventQueue() {
|
||||
qThread = Obj.helper.createThread(this);
|
||||
qThread.setDaemon(true); // not a user thread
|
||||
qThread.start();
|
||||
}
|
||||
|
||||
// package private;
|
||||
/**
|
||||
* Enqueue an event.
|
||||
* @param event Either a <tt>NamingExceptionEvent</tt> or a subclass
|
||||
* of <tt>NamingEvent</tt> or
|
||||
* <tt>UnsolicitedNotificatoniEvent</tt>.
|
||||
* If it is a subclass of <tt>NamingEvent</tt>, all listeners must implement
|
||||
* the corresponding subinterface of <tt>NamingListener</tt>.
|
||||
* For example, for a <tt>ObjectAddedEvent</tt>, all listeners <em>must</em>
|
||||
* implement the <tt>ObjectAddedListener</tt> interface.
|
||||
* <em>The current implementation does not check this before dispatching
|
||||
* the event.</em>
|
||||
* If the event is a <tt>NamingExceptionEvent</tt>, then all listeners
|
||||
* are notified.
|
||||
* @param vector List of NamingListeners that will be notified of event.
|
||||
*/
|
||||
synchronized void enqueue(EventObject event, Vector<NamingListener> vector) {
|
||||
QueueElement newElt = new QueueElement(event, vector);
|
||||
|
||||
if (head == null) {
|
||||
head = newElt;
|
||||
tail = newElt;
|
||||
} else {
|
||||
newElt.next = head;
|
||||
head.prev = newElt;
|
||||
head = newElt;
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeue the oldest object on the queue.
|
||||
* Used only by the run() method.
|
||||
*
|
||||
* @return the oldest object on the queue.
|
||||
* @exception java.lang.InterruptedException if any thread has
|
||||
* interrupted this thread.
|
||||
*/
|
||||
private synchronized QueueElement dequeue()
|
||||
throws InterruptedException {
|
||||
while (tail == null)
|
||||
wait();
|
||||
QueueElement elt = tail;
|
||||
tail = elt.prev;
|
||||
if (tail == null) {
|
||||
head = null;
|
||||
} else {
|
||||
tail.next = null;
|
||||
}
|
||||
elt.prev = elt.next = null;
|
||||
return elt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull events off the queue and dispatch them.
|
||||
*/
|
||||
public void run() {
|
||||
QueueElement qe;
|
||||
|
||||
try {
|
||||
while ((qe = dequeue()) != null) {
|
||||
EventObject e = qe.event;
|
||||
Vector<NamingListener> v = qe.vector;
|
||||
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
|
||||
// Dispatch to corresponding NamingListener
|
||||
// The listener should only be getting the event that
|
||||
// it is interested in. (No need to check mask or
|
||||
// instanceof subinterfaces.)
|
||||
// It is the responsibility of the enqueuer to
|
||||
// only enqueue events with listseners of the correct type.
|
||||
|
||||
if (e instanceof NamingEvent) {
|
||||
((NamingEvent)e).dispatch(v.elementAt(i));
|
||||
|
||||
// An exception occurred: if notify all naming listeners
|
||||
} else if (e instanceof NamingExceptionEvent) {
|
||||
((NamingExceptionEvent)e).dispatch(v.elementAt(i));
|
||||
} else if (e instanceof UnsolicitedNotificationEvent) {
|
||||
((UnsolicitedNotificationEvent)e).dispatch(
|
||||
(UnsolicitedNotificationListener)v.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
qe = null; e = null; v = null;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// just die
|
||||
}
|
||||
}
|
||||
|
||||
// package private; used by EventSupport;
|
||||
/**
|
||||
* Stop the dispatcher so we can be destroyed.
|
||||
*/
|
||||
void stop() {
|
||||
if (debug) System.err.println("EventQueue stopping");
|
||||
if (qThread != null) {
|
||||
qThread.interrupt(); // kill our thread
|
||||
qThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
352
jdkSrc/jdk8/com/sun/jndi/ldap/EventSupport.java
Normal file
352
jdkSrc/jdk8/com/sun/jndi/ldap/EventSupport.java
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.event.*;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.ldap.UnsolicitedNotificationListener;
|
||||
import javax.naming.ldap.UnsolicitedNotificationEvent;
|
||||
import javax.naming.ldap.UnsolicitedNotification;
|
||||
|
||||
/**
|
||||
* This is a utility class that can be used by a context that supports
|
||||
* event notification. You can use an instance of this class as a member field
|
||||
* of your context and delegate various work to it.
|
||||
* It is currently structured so that each context should have its own
|
||||
* EventSupport (instead of static version shared by all contexts
|
||||
* of a service provider).
|
||||
*<p>
|
||||
* This class supports two types of listeners: those that register for
|
||||
* NamingEvents, and those for UnsolicitedNotificationEvents (they can be mixed
|
||||
* into the same listener).
|
||||
* For NamingEvent listeners, it maintains a hashtable that maps
|
||||
* registration requests--the key--to
|
||||
* <em>notifiers</em>--the value. Each registration request consists of:
|
||||
*<ul>
|
||||
*<li>The name argument of the registration.
|
||||
*<li>The filter (default is "(objectclass=*)").
|
||||
*<li>The search controls (default is null SearchControls).
|
||||
*<li>The events that the listener is interested in. This is determined by
|
||||
* finding out which <tt>NamingListener</tt> interface the listener supports.
|
||||
*</ul>
|
||||
*<p>
|
||||
*A notifier (<tt>NamingEventNotifier</tt>) is a worker thread that is responsible
|
||||
*for gathering information for generating events requested by its listeners.
|
||||
*Each notifier maintains its own list of listeners; these listeners have
|
||||
*all made the same registration request (at different times) and implements
|
||||
*the same <tt>NamingListener</tt> interfaces.
|
||||
*<p>
|
||||
*For unsolicited listeners, this class maintains a vector, unsolicited.
|
||||
*When an unsolicited listener is registered, this class adds itself
|
||||
*to the context's LdapClient. When LdapClient receives an unsolicited
|
||||
*notification, it notifies this EventSupport to fire an event to the
|
||||
*the listeners. Special handling in LdapClient is done for the DISCONNECT
|
||||
*notification. [It results in the EventSupport firing also a
|
||||
*NamingExceptionEvent to the unsolicited listeners.]
|
||||
*<p>
|
||||
*
|
||||
*When a context no longer needs this EventSupport, it should invoke
|
||||
*cleanup() on it.
|
||||
*<p>
|
||||
*<h4>Registration</h4>
|
||||
*When a registration request is made, this class attempts to find an
|
||||
*existing notifier that's already working on the request. If one is
|
||||
*found, the listener is added to the notifier's list. If one is not found,
|
||||
*a new notifier is created for the listener.
|
||||
*
|
||||
*<h4>Deregistration</h4>
|
||||
*When a deregistration request is made, this class attemps to find its
|
||||
*corresponding notifier. If the notifier is found, the listener is removed
|
||||
*from the notifier's list. If the listener is the last listener on the list,
|
||||
*the notifier's thread is terminated and removed from this class's hashtable.
|
||||
*Nothing happens if the notifier is not found.
|
||||
*
|
||||
*<h4>Event Dispatching</h4>
|
||||
*The notifiers are responsible for gather information for generating events
|
||||
*requested by their respective listeners. When a notifier gets sufficient
|
||||
*information to generate an event, it creates invokes the
|
||||
*appropriate <tt>fireXXXEvent</tt> on this class with the information and list of
|
||||
*listeners. This causes an event and the list of listeners to be added
|
||||
*to the <em>event queue</em>.
|
||||
*This class maintains an event queue and a dispatching thread that dequeues
|
||||
*events from the queue and dispatches them to the listeners.
|
||||
*
|
||||
*<h4>Synchronization</h4>
|
||||
*This class is used by the main thread (LdapCtx) to add/remove listeners.
|
||||
*It is also used asynchronously by NamingEventNotifiers threads and
|
||||
*the context's Connection thread. It is used by the notifier threads to
|
||||
*queue events and to update the notifiers list when the notifiers exit.
|
||||
*It is used by the Connection thread to fire unsolicited notifications.
|
||||
*Methods that access/update the 'unsolicited' and 'notifiers' lists are
|
||||
*thread-safe.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class EventSupport {
|
||||
final static private boolean debug = false;
|
||||
|
||||
private LdapCtx ctx;
|
||||
|
||||
/**
|
||||
* NamingEventNotifiers; hashed by search arguments;
|
||||
*/
|
||||
private Hashtable<NotifierArgs, NamingEventNotifier> notifiers =
|
||||
new Hashtable<>(11);
|
||||
|
||||
/**
|
||||
* List of unsolicited notification listeners.
|
||||
*/
|
||||
private Vector<UnsolicitedNotificationListener> unsolicited = null;
|
||||
|
||||
/**
|
||||
* Constructs EventSupport for ctx.
|
||||
* <em>Do we need to record the name of the target context?
|
||||
* Or can we assume that EventSupport is called on a resolved
|
||||
* context? Do we need other add/remove-NamingListener methods?
|
||||
* package private;
|
||||
*/
|
||||
EventSupport(LdapCtx ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>l</tt> to list of listeners interested in <tt>nm</tt>.
|
||||
*/
|
||||
/*
|
||||
* Make the add/removeNamingListeners synchronized to:
|
||||
* 1. protect usage of 'unsolicited', which may be read by
|
||||
* the Connection thread when dispatching unsolicited notification.
|
||||
* 2. ensure that NamingEventNotifier thread's access to 'notifiers'
|
||||
* is safe
|
||||
*/
|
||||
synchronized void addNamingListener(String nm, int scope,
|
||||
NamingListener l) throws NamingException {
|
||||
|
||||
if (l instanceof ObjectChangeListener ||
|
||||
l instanceof NamespaceChangeListener) {
|
||||
NotifierArgs args = new NotifierArgs(nm, scope, l);
|
||||
|
||||
NamingEventNotifier notifier = notifiers.get(args);
|
||||
if (notifier == null) {
|
||||
notifier = new NamingEventNotifier(this, ctx, args, l);
|
||||
notifiers.put(args, notifier);
|
||||
} else {
|
||||
notifier.addNamingListener(l);
|
||||
}
|
||||
}
|
||||
if (l instanceof UnsolicitedNotificationListener) {
|
||||
// Add listener to this's list of unsolicited notifiers
|
||||
if (unsolicited == null) {
|
||||
unsolicited = new Vector<>(3);
|
||||
}
|
||||
|
||||
unsolicited.addElement((UnsolicitedNotificationListener)l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>l</tt> to list of listeners interested in <tt>nm</tt>
|
||||
* and filter.
|
||||
*/
|
||||
synchronized void addNamingListener(String nm, String filter,
|
||||
SearchControls ctls, NamingListener l) throws NamingException {
|
||||
|
||||
if (l instanceof ObjectChangeListener ||
|
||||
l instanceof NamespaceChangeListener) {
|
||||
NotifierArgs args = new NotifierArgs(nm, filter, ctls, l);
|
||||
|
||||
NamingEventNotifier notifier = notifiers.get(args);
|
||||
if (notifier == null) {
|
||||
notifier = new NamingEventNotifier(this, ctx, args, l);
|
||||
notifiers.put(args, notifier);
|
||||
} else {
|
||||
notifier.addNamingListener(l);
|
||||
}
|
||||
}
|
||||
if (l instanceof UnsolicitedNotificationListener) {
|
||||
// Add listener to this's list of unsolicited notifiers
|
||||
if (unsolicited == null) {
|
||||
unsolicited = new Vector<>(3);
|
||||
}
|
||||
unsolicited.addElement((UnsolicitedNotificationListener)l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes <tt>l</tt> from all notifiers in this context.
|
||||
*/
|
||||
synchronized void removeNamingListener(NamingListener l) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing listener");
|
||||
}
|
||||
// Go through list of notifiers, remove 'l' from each.
|
||||
// If 'l' is notifier's only listener, remove notifier too.
|
||||
Iterator<NamingEventNotifier> iterator = notifiers.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
NamingEventNotifier notifier = iterator.next();
|
||||
if (notifier != null) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing listener from notifier");
|
||||
}
|
||||
notifier.removeNamingListener(l);
|
||||
if (!notifier.hasNamingListeners()) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport stopping notifier");
|
||||
}
|
||||
notifier.stop();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove from list of unsolicited notifier
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing unsolicited: " + unsolicited);
|
||||
}
|
||||
if (unsolicited != null) {
|
||||
unsolicited.removeElement(l);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized boolean hasUnsolicited() {
|
||||
return (unsolicited != null && unsolicited.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* package private;
|
||||
* Called by NamingEventNotifier to remove itself when it encounters
|
||||
* a NamingException.
|
||||
*/
|
||||
synchronized void removeDeadNotifier(NotifierArgs info) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport.removeDeadNotifier: " + info.name);
|
||||
}
|
||||
notifiers.remove(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an event to unsolicited listeners.
|
||||
* package private;
|
||||
* Called by LdapCtx when its clnt receives an unsolicited notification.
|
||||
*/
|
||||
synchronized void fireUnsolicited(Object obj) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport.fireUnsolicited: " + obj + " "
|
||||
+ unsolicited);
|
||||
}
|
||||
if (unsolicited == null || unsolicited.size() == 0) {
|
||||
// This shouldn't really happen, but might in case
|
||||
// there is a timing problem that removes a listener
|
||||
// before a fired event event reaches here.
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj instanceof UnsolicitedNotification) {
|
||||
|
||||
// Fire UnsolicitedNotification to unsolicited listeners
|
||||
|
||||
UnsolicitedNotificationEvent evt =
|
||||
new UnsolicitedNotificationEvent(ctx, (UnsolicitedNotification)obj);
|
||||
queueEvent(evt, unsolicited);
|
||||
|
||||
} else if (obj instanceof NamingException) {
|
||||
|
||||
// Fire NamingExceptionEvent to unsolicited listeners.
|
||||
|
||||
NamingExceptionEvent evt =
|
||||
new NamingExceptionEvent(ctx, (NamingException)obj);
|
||||
queueEvent(evt, unsolicited);
|
||||
|
||||
// When an exception occurs, the unsolicited listeners
|
||||
// are automatically deregistered.
|
||||
// When LdapClient.processUnsolicited() fires a NamingException,
|
||||
// it will update its listener list so we don't have to.
|
||||
// Likewise for LdapCtx.
|
||||
|
||||
unsolicited = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops notifier threads that are collecting event data and
|
||||
* stops the event queue from dispatching events.
|
||||
* Package private; used by LdapCtx.
|
||||
*/
|
||||
synchronized void cleanup() {
|
||||
if (debug) System.err.println("EventSupport clean up");
|
||||
if (notifiers != null) {
|
||||
for (NamingEventNotifier notifier : notifiers.values()) {
|
||||
notifier.stop();
|
||||
}
|
||||
notifiers = null;
|
||||
}
|
||||
if (eventQueue != null) {
|
||||
eventQueue.stop();
|
||||
eventQueue = null;
|
||||
}
|
||||
// %%% Should we fire NamingExceptionEvents to unsolicited listeners?
|
||||
}
|
||||
|
||||
/*
|
||||
* The queue of events to be delivered.
|
||||
*/
|
||||
private EventQueue eventQueue;
|
||||
|
||||
/**
|
||||
* Add the event and vector of listeners to the queue to be delivered.
|
||||
* An event dispatcher thread dequeues events from the queue and dispatches
|
||||
* them to the registered listeners.
|
||||
* Package private; used by NamingEventNotifier to fire events
|
||||
*/
|
||||
synchronized void queueEvent(EventObject event,
|
||||
Vector<? extends NamingListener> vector) {
|
||||
if (eventQueue == null)
|
||||
eventQueue = new EventQueue();
|
||||
|
||||
/*
|
||||
* Copy the vector in order to freeze the state of the set
|
||||
* of EventListeners the event should be delivered to prior
|
||||
* to delivery. This ensures that any changes made to the
|
||||
* Vector from a target listener's method during the delivery
|
||||
* of this event will not take effect until after the event is
|
||||
* delivered.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
Vector<NamingListener> v =
|
||||
(Vector<NamingListener>)vector.clone();
|
||||
eventQueue.enqueue(event, v);
|
||||
}
|
||||
|
||||
// No finalize() needed because EventSupport is always owned by
|
||||
// an LdapCtx. LdapCtx's finalize() and close() always call cleanup() so
|
||||
// there is no need for EventSupport to have a finalize().
|
||||
}
|
||||
870
jdkSrc/jdk8/com/sun/jndi/ldap/Filter.java
Normal file
870
jdkSrc/jdk8/com/sun/jndi/ldap/Filter.java
Normal file
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.InvalidSearchFilterException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LDAP (RFC-1960) and LDAPv3 (RFC-2254) search filters.
|
||||
*
|
||||
* @author Xuelei Fan
|
||||
* @author Vincent Ryan
|
||||
* @author Jagane Sundar
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final class Filter {
|
||||
|
||||
/**
|
||||
* First convert filter string into byte[].
|
||||
* For LDAP v3, the conversion uses Unicode -> UTF8
|
||||
* For LDAP v2, the conversion uses Unicode -> ISO 8859 (Latin-1)
|
||||
*
|
||||
* Then parse the byte[] as a filter, converting \hh to
|
||||
* a single byte, and encoding the resulting filter
|
||||
* into the supplied BER buffer
|
||||
*/
|
||||
static void encodeFilterString(BerEncoder ber, String filterStr,
|
||||
boolean isLdapv3) throws IOException, NamingException {
|
||||
|
||||
if ((filterStr == null) || (filterStr.equals(""))) {
|
||||
throw new InvalidSearchFilterException("Empty filter");
|
||||
}
|
||||
byte[] filter;
|
||||
int filterLen;
|
||||
if (isLdapv3) {
|
||||
filter = filterStr.getBytes("UTF8");
|
||||
} else {
|
||||
filter = filterStr.getBytes("8859_1");
|
||||
}
|
||||
filterLen = filter.length;
|
||||
if (dbg) {
|
||||
dbgIndent = 0;
|
||||
System.err.println("String filter: " + filterStr);
|
||||
System.err.println("size: " + filterLen);
|
||||
dprint("original: ", filter, 0, filterLen);
|
||||
}
|
||||
|
||||
encodeFilter(ber, filter, 0, filterLen);
|
||||
}
|
||||
|
||||
private static void encodeFilter(BerEncoder ber, byte[] filter,
|
||||
int filterStart, int filterEnd) throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encFilter: ", filter, filterStart, filterEnd);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
if ((filterEnd - filterStart) <= 0) {
|
||||
throw new InvalidSearchFilterException("Empty filter");
|
||||
}
|
||||
|
||||
int nextOffset;
|
||||
int parens, balance;
|
||||
boolean escape;
|
||||
|
||||
parens = 0;
|
||||
|
||||
int filtOffset[] = new int[1];
|
||||
|
||||
for (filtOffset[0] = filterStart; filtOffset[0] < filterEnd;) {
|
||||
switch (filter[filtOffset[0]]) {
|
||||
case '(':
|
||||
filtOffset[0]++;
|
||||
parens++;
|
||||
switch (filter[filtOffset[0]]) {
|
||||
case '&':
|
||||
encodeComplexFilter(ber, filter,
|
||||
LDAP_FILTER_AND, filtOffset, filterEnd);
|
||||
// filtOffset[0] has pointed to char after right paren
|
||||
parens--;
|
||||
break;
|
||||
|
||||
case '|':
|
||||
encodeComplexFilter(ber, filter,
|
||||
LDAP_FILTER_OR, filtOffset, filterEnd);
|
||||
// filtOffset[0] has pointed to char after right paren
|
||||
parens--;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
encodeComplexFilter(ber, filter,
|
||||
LDAP_FILTER_NOT, filtOffset, filterEnd);
|
||||
// filtOffset[0] has pointed to char after right paren
|
||||
parens--;
|
||||
break;
|
||||
|
||||
default:
|
||||
balance = 1;
|
||||
escape = false;
|
||||
nextOffset = filtOffset[0];
|
||||
while (nextOffset < filterEnd && balance > 0) {
|
||||
if (!escape) {
|
||||
if (filter[nextOffset] == '(')
|
||||
balance++;
|
||||
else if (filter[nextOffset] == ')')
|
||||
balance--;
|
||||
}
|
||||
if (filter[nextOffset] == '\\' && !escape)
|
||||
escape = true;
|
||||
else
|
||||
escape = false;
|
||||
if (balance > 0)
|
||||
nextOffset++;
|
||||
}
|
||||
if (balance != 0)
|
||||
throw new InvalidSearchFilterException(
|
||||
"Unbalanced parenthesis");
|
||||
|
||||
encodeSimpleFilter(ber, filter, filtOffset[0], nextOffset);
|
||||
|
||||
// points to the char after right paren.
|
||||
filtOffset[0] = nextOffset + 1;
|
||||
|
||||
parens--;
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ')':
|
||||
//
|
||||
// End of sequence
|
||||
//
|
||||
ber.endSeq();
|
||||
filtOffset[0]++;
|
||||
parens--;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
filtOffset[0]++;
|
||||
break;
|
||||
|
||||
default: // assume simple type=value filter
|
||||
encodeSimpleFilter(ber, filter, filtOffset[0], filterEnd);
|
||||
filtOffset[0] = filterEnd; // force break from outer
|
||||
break;
|
||||
}
|
||||
|
||||
if (parens < 0) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"Unbalanced parenthesis");
|
||||
}
|
||||
}
|
||||
|
||||
if (parens != 0) {
|
||||
throw new InvalidSearchFilterException("Unbalanced parenthesis");
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* convert character 'c' that represents a hexadecimal digit to an integer.
|
||||
* if 'c' is not a hexadecimal digit [0-9A-Fa-f], -1 is returned.
|
||||
* otherwise the converted value is returned.
|
||||
*/
|
||||
private static int hexchar2int( byte c ) {
|
||||
if ( c >= '0' && c <= '9' ) {
|
||||
return( c - '0' );
|
||||
}
|
||||
if ( c >= 'A' && c <= 'F' ) {
|
||||
return( c - 'A' + 10 );
|
||||
}
|
||||
if ( c >= 'a' && c <= 'f' ) {
|
||||
return( c - 'a' + 10 );
|
||||
}
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
// called by the LdapClient.compare method
|
||||
static byte[] unescapeFilterValue(byte[] orig, int start, int end)
|
||||
throws NamingException {
|
||||
boolean escape = false, escStart = false;
|
||||
int ival;
|
||||
byte ch;
|
||||
|
||||
if (dbg) {
|
||||
dprint("unescape: " , orig, start, end);
|
||||
}
|
||||
|
||||
int len = end - start;
|
||||
byte tbuf[] = new byte[len];
|
||||
int j = 0;
|
||||
for (int i = start; i < end; i++) {
|
||||
ch = orig[i];
|
||||
if (escape) {
|
||||
// Try LDAP V3 escape (\xx)
|
||||
if ((ival = hexchar2int(ch)) < 0) {
|
||||
|
||||
/**
|
||||
* If there is no hex char following a '\' when
|
||||
* parsing a LDAP v3 filter (illegal by v3 way)
|
||||
* we fallback to the way we unescape in v2.
|
||||
*/
|
||||
if (escStart) {
|
||||
// V2: \* \( \)
|
||||
escape = false;
|
||||
tbuf[j++] = ch;
|
||||
} else {
|
||||
// escaping already started but we can't find 2nd hex
|
||||
throw new InvalidSearchFilterException("invalid escape sequence: " + orig);
|
||||
}
|
||||
} else {
|
||||
if (escStart) {
|
||||
tbuf[j] = (byte)(ival<<4);
|
||||
escStart = false;
|
||||
} else {
|
||||
tbuf[j++] |= (byte)ival;
|
||||
escape = false;
|
||||
}
|
||||
}
|
||||
} else if (ch != '\\') {
|
||||
tbuf[j++] = ch;
|
||||
escape = false;
|
||||
} else {
|
||||
escStart = escape = true;
|
||||
}
|
||||
}
|
||||
byte[] answer = new byte[j];
|
||||
System.arraycopy(tbuf, 0, answer, 0, j);
|
||||
if (dbg) {
|
||||
Ber.dumpBER(System.err, "", answer, 0, j);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
private static int indexOf(byte[] str, char ch, int start, int end) {
|
||||
for (int i = start; i < end; i++) {
|
||||
if (str[i] == ch)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int indexOf(byte[] str, String target, int start, int end) {
|
||||
int where = indexOf(str, target.charAt(0), start, end);
|
||||
if (where >= 0) {
|
||||
for (int i = 1; i < target.length(); i++) {
|
||||
if (str[where+i] != target.charAt(i)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
private static int findUnescaped(byte[] str, char ch, int start, int end) {
|
||||
while (start < end) {
|
||||
int where = indexOf(str, ch, start, end);
|
||||
|
||||
/*
|
||||
* Count the immediate preceding '\' to find out if
|
||||
* this is an escaped '*'. This is a made-up way for
|
||||
* parsing an escaped '*' in v2. This is how the other leading
|
||||
* SDK vendors interpret v2.
|
||||
* For v3 we fallback to the way we parse "\*" in v2.
|
||||
* It's not legal in v3 to use "\*" to escape '*'; the right
|
||||
* way is to use "\2a" instead.
|
||||
*/
|
||||
int backSlashPos;
|
||||
int backSlashCnt = 0;
|
||||
for (backSlashPos = where - 1;
|
||||
((backSlashPos >= start) && (str[backSlashPos] == '\\'));
|
||||
backSlashPos--, backSlashCnt++);
|
||||
|
||||
// if at start of string, or not there at all, or if not escaped
|
||||
if (where == start || where == -1 || ((backSlashCnt % 2) == 0))
|
||||
return where;
|
||||
|
||||
// start search after escaped star
|
||||
start = where + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private static void encodeSimpleFilter(BerEncoder ber, byte[] filter,
|
||||
int filtStart, int filtEnd) throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encSimpleFilter: ", filter, filtStart, filtEnd);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
String type, value;
|
||||
int valueStart, valueEnd, typeStart, typeEnd;
|
||||
|
||||
int eq;
|
||||
if ((eq = indexOf(filter, '=', filtStart, filtEnd)) == -1) {
|
||||
throw new InvalidSearchFilterException("Missing 'equals'");
|
||||
}
|
||||
|
||||
|
||||
valueStart = eq + 1; // value starts after equal sign
|
||||
valueEnd = filtEnd;
|
||||
typeStart = filtStart; // beginning of string
|
||||
|
||||
int ftype;
|
||||
|
||||
switch (filter[eq - 1]) {
|
||||
case '<':
|
||||
ftype = LDAP_FILTER_LE;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
case '>':
|
||||
ftype = LDAP_FILTER_GE;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
case '~':
|
||||
ftype = LDAP_FILTER_APPROX;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
case ':':
|
||||
ftype = LDAP_FILTER_EXT;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
default:
|
||||
typeEnd = eq;
|
||||
//initializing ftype to make the compiler happy
|
||||
ftype = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
System.err.println("type: " + typeStart + ", " + typeEnd);
|
||||
System.err.println("value: " + valueStart + ", " + valueEnd);
|
||||
}
|
||||
|
||||
// check validity of type
|
||||
//
|
||||
// RFC4512 defines the type as the following ABNF:
|
||||
// attr = attributedescription
|
||||
// attributedescription = attributetype options
|
||||
// attributetype = oid
|
||||
// oid = descr / numericoid
|
||||
// descr = keystring
|
||||
// keystring = leadkeychar *keychar
|
||||
// leadkeychar = ALPHA
|
||||
// keychar = ALPHA / DIGIT / HYPHEN
|
||||
// numericoid = number 1*( DOT number )
|
||||
// number = DIGIT / ( LDIGIT 1*DIGIT )
|
||||
// options = *( SEMI option )
|
||||
// option = 1*keychar
|
||||
//
|
||||
// And RFC4515 defines the extensible type as the following ABNF:
|
||||
// attr [dnattrs] [matchingrule] / [dnattrs] matchingrule
|
||||
int optionsStart = -1;
|
||||
int extensibleStart = -1;
|
||||
if ((filter[typeStart] >= '0' && filter[typeStart] <= '9') ||
|
||||
(filter[typeStart] >= 'A' && filter[typeStart] <= 'Z') ||
|
||||
(filter[typeStart] >= 'a' && filter[typeStart] <= 'z')) {
|
||||
|
||||
boolean isNumericOid =
|
||||
filter[typeStart] >= '0' && filter[typeStart] <= '9';
|
||||
for (int i = typeStart + 1; i < typeEnd; i++) {
|
||||
// ';' is an indicator of attribute options
|
||||
if (filter[i] == ';') {
|
||||
if (isNumericOid && filter[i - 1] == '.') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// attribute options
|
||||
optionsStart = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// ':' is an indicator of extensible rules
|
||||
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
|
||||
if (isNumericOid && filter[i - 1] == '.') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// extensible matching
|
||||
extensibleStart = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNumericOid) {
|
||||
// numeric object identifier
|
||||
if ((filter[i] == '.' && filter[i - 1] == '.') ||
|
||||
(filter[i] != '.' &&
|
||||
!(filter[i] >= '0' && filter[i] <= '9'))) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
} else {
|
||||
// descriptor
|
||||
// The underscore ("_") character is not allowed by
|
||||
// the LDAP specification. We allow it here to
|
||||
// tolerate the incorrect use in practice.
|
||||
if (filter[i] != '-' && filter[i] != '_' &&
|
||||
!(filter[i] >= '0' && filter[i] <= '9') &&
|
||||
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
|
||||
!(filter[i] >= 'a' && filter[i] <= 'z')) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ftype == LDAP_FILTER_EXT && filter[typeStart] == ':') {
|
||||
// extensible matching
|
||||
extensibleStart = typeStart;
|
||||
} else {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// check attribute options
|
||||
if (optionsStart > 0) {
|
||||
for (int i = optionsStart + 1; i < typeEnd; i++) {
|
||||
if (filter[i] == ';') {
|
||||
if (filter[i - 1] == ';') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// ':' is an indicator of extensible rules
|
||||
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
|
||||
if (filter[i - 1] == ';') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// extensible matching
|
||||
extensibleStart = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// The underscore ("_") character is not allowed by
|
||||
// the LDAP specification. We allow it here to
|
||||
// tolerate the incorrect use in practice.
|
||||
if (filter[i] != '-' && filter[i] != '_' &&
|
||||
!(filter[i] >= '0' && filter[i] <= '9') &&
|
||||
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
|
||||
!(filter[i] >= 'a' && filter[i] <= 'z')) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check extensible matching
|
||||
if (extensibleStart > 0) {
|
||||
boolean isMatchingRule = false;
|
||||
for (int i = extensibleStart + 1; i < typeEnd; i++) {
|
||||
if (filter[i] == ':') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
} else if ((filter[i] >= '0' && filter[i] <= '9') ||
|
||||
(filter[i] >= 'A' && filter[i] <= 'Z') ||
|
||||
(filter[i] >= 'a' && filter[i] <= 'z')) {
|
||||
boolean isNumericOid = filter[i] >= '0' && filter[i] <= '9';
|
||||
i++;
|
||||
for (int j = i; j < typeEnd; j++, i++) {
|
||||
// allows no more than two extensible rules
|
||||
if (filter[j] == ':') {
|
||||
if (isMatchingRule) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
if (isNumericOid && filter[j - 1] == '.') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
isMatchingRule = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNumericOid) {
|
||||
// numeric object identifier
|
||||
if ((filter[j] == '.' && filter[j - 1] == '.') ||
|
||||
(filter[j] != '.' &&
|
||||
!(filter[j] >= '0' && filter[j] <= '9'))) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
} else {
|
||||
// descriptor
|
||||
// The underscore ("_") character is not allowed by
|
||||
// the LDAP specification. We allow it here to
|
||||
// tolerate the incorrect use in practice.
|
||||
if (filter[j] != '-' && filter[j] != '_' &&
|
||||
!(filter[j] >= '0' && filter[j] <= '9') &&
|
||||
!(filter[j] >= 'A' && filter[j] <= 'Z') &&
|
||||
!(filter[j] >= 'a' && filter[j] <= 'z')) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the latest byte is not isolated
|
||||
if (filter[typeEnd - 1] == '.' || filter[typeEnd - 1] == ';' ||
|
||||
filter[typeEnd - 1] == ':') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
if (typeEnd == eq) { // filter type is of "equal"
|
||||
if (findUnescaped(filter, '*', valueStart, valueEnd) == -1) {
|
||||
ftype = LDAP_FILTER_EQUALITY;
|
||||
} else if (filter[valueStart] == '*' &&
|
||||
valueStart == (valueEnd - 1)) {
|
||||
ftype = LDAP_FILTER_PRESENT;
|
||||
} else {
|
||||
encodeSubstringFilter(ber, filter,
|
||||
typeStart, typeEnd, valueStart, valueEnd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ftype == LDAP_FILTER_PRESENT) {
|
||||
ber.encodeOctetString(filter, ftype, typeStart, typeEnd-typeStart);
|
||||
} else if (ftype == LDAP_FILTER_EXT) {
|
||||
encodeExtensibleMatch(ber, filter,
|
||||
typeStart, typeEnd, valueStart, valueEnd);
|
||||
} else {
|
||||
ber.beginSeq(ftype);
|
||||
ber.encodeOctetString(filter, Ber.ASN_OCTET_STR,
|
||||
typeStart, typeEnd - typeStart);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, valueStart, valueEnd),
|
||||
Ber.ASN_OCTET_STR);
|
||||
ber.endSeq();
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
}
|
||||
|
||||
private static void encodeSubstringFilter(BerEncoder ber, byte[] filter,
|
||||
int typeStart, int typeEnd, int valueStart, int valueEnd)
|
||||
throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encSubstringFilter: type ", filter, typeStart, typeEnd);
|
||||
dprint(", val : ", filter, valueStart, valueEnd);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
ber.beginSeq(LDAP_FILTER_SUBSTRINGS);
|
||||
ber.encodeOctetString(filter, Ber.ASN_OCTET_STR,
|
||||
typeStart, typeEnd-typeStart);
|
||||
ber.beginSeq(LdapClient.LBER_SEQUENCE);
|
||||
int index;
|
||||
int previndex = valueStart;
|
||||
while ((index = findUnescaped(filter, '*', previndex, valueEnd)) != -1) {
|
||||
if (previndex == valueStart) {
|
||||
if (previndex < index) {
|
||||
if (dbg)
|
||||
System.err.println(
|
||||
"initial: " + previndex + "," + index);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, previndex, index),
|
||||
LDAP_SUBSTRING_INITIAL);
|
||||
}
|
||||
} else {
|
||||
if (previndex < index) {
|
||||
if (dbg)
|
||||
System.err.println("any: " + previndex + "," + index);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, previndex, index),
|
||||
LDAP_SUBSTRING_ANY);
|
||||
}
|
||||
}
|
||||
previndex = index + 1;
|
||||
}
|
||||
if (previndex < valueEnd) {
|
||||
if (dbg)
|
||||
System.err.println("final: " + previndex + "," + valueEnd);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, previndex, valueEnd),
|
||||
LDAP_SUBSTRING_FINAL);
|
||||
}
|
||||
ber.endSeq();
|
||||
ber.endSeq();
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
}
|
||||
|
||||
// The complex filter types look like:
|
||||
// "&(type=val)(type=val)"
|
||||
// "|(type=val)(type=val)"
|
||||
// "!(type=val)"
|
||||
//
|
||||
// The filtOffset[0] pointing to the '&', '|', or '!'.
|
||||
//
|
||||
private static void encodeComplexFilter(BerEncoder ber, byte[] filter,
|
||||
int filterType, int filtOffset[], int filtEnd)
|
||||
throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encComplexFilter: ", filter, filtOffset[0], filtEnd);
|
||||
dprint(", type: " + Integer.toString(filterType, 16));
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
filtOffset[0]++;
|
||||
|
||||
ber.beginSeq(filterType);
|
||||
|
||||
int[] parens = findRightParen(filter, filtOffset, filtEnd);
|
||||
encodeFilterList(ber, filter, filterType, parens[0], parens[1]);
|
||||
|
||||
ber.endSeq();
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// filter at filtOffset[0] - 1 points to a (. Find ) that matches it
|
||||
// and return substring between the parens. Adjust filtOffset[0] to
|
||||
// point to char after right paren
|
||||
//
|
||||
private static int[] findRightParen(byte[] filter, int filtOffset[], int end)
|
||||
throws IOException, NamingException {
|
||||
|
||||
int balance = 1;
|
||||
boolean escape = false;
|
||||
int nextOffset = filtOffset[0];
|
||||
|
||||
while (nextOffset < end && balance > 0) {
|
||||
if (!escape) {
|
||||
if (filter[nextOffset] == '(')
|
||||
balance++;
|
||||
else if (filter[nextOffset] == ')')
|
||||
balance--;
|
||||
}
|
||||
if (filter[nextOffset] == '\\' && !escape)
|
||||
escape = true;
|
||||
else
|
||||
escape = false;
|
||||
if (balance > 0)
|
||||
nextOffset++;
|
||||
}
|
||||
if (balance != 0) {
|
||||
throw new InvalidSearchFilterException("Unbalanced parenthesis");
|
||||
}
|
||||
|
||||
// String tmp = filter.substring(filtOffset[0], nextOffset);
|
||||
|
||||
int[] tmp = new int[] {filtOffset[0], nextOffset};
|
||||
|
||||
filtOffset[0] = nextOffset + 1;
|
||||
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Encode filter list of type "(filter1)(filter2)..."
|
||||
//
|
||||
private static void encodeFilterList(BerEncoder ber, byte[] filter,
|
||||
int filterType, int start, int end) throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encFilterList: ", filter, start, end);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
int filtOffset[] = new int[1];
|
||||
int listNumber = 0;
|
||||
for (filtOffset[0] = start; filtOffset[0] < end; filtOffset[0]++) {
|
||||
if (Character.isSpaceChar((char)filter[filtOffset[0]]))
|
||||
continue;
|
||||
|
||||
if ((filterType == LDAP_FILTER_NOT) && (listNumber > 0)) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"Filter (!) cannot be followed by more than one filters");
|
||||
}
|
||||
|
||||
if (filter[filtOffset[0]] == '(') {
|
||||
continue;
|
||||
}
|
||||
|
||||
int[] parens = findRightParen(filter, filtOffset, end);
|
||||
|
||||
// add enclosing parens
|
||||
int len = parens[1]-parens[0];
|
||||
byte[] newfilter = new byte[len+2];
|
||||
System.arraycopy(filter, parens[0], newfilter, 1, len);
|
||||
newfilter[0] = (byte)'(';
|
||||
newfilter[len+1] = (byte)')';
|
||||
encodeFilter(ber, newfilter, 0, newfilter.length);
|
||||
|
||||
listNumber++;
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Encode extensible match
|
||||
//
|
||||
private static void encodeExtensibleMatch(BerEncoder ber, byte[] filter,
|
||||
int matchStart, int matchEnd, int valueStart, int valueEnd)
|
||||
throws IOException, NamingException {
|
||||
|
||||
boolean matchDN = false;
|
||||
int colon;
|
||||
int colon2;
|
||||
int i;
|
||||
|
||||
ber.beginSeq(LDAP_FILTER_EXT);
|
||||
|
||||
// test for colon separator
|
||||
if ((colon = indexOf(filter, ':', matchStart, matchEnd)) >= 0) {
|
||||
|
||||
// test for match DN
|
||||
if ((i = indexOf(filter, ":dn", colon, matchEnd)) >= 0) {
|
||||
matchDN = true;
|
||||
}
|
||||
|
||||
// test for matching rule
|
||||
if (((colon2 = indexOf(filter, ':', colon + 1, matchEnd)) >= 0)
|
||||
|| (i == -1)) {
|
||||
|
||||
if (i == colon) {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_RULE,
|
||||
colon2 + 1, matchEnd - (colon2 + 1));
|
||||
|
||||
} else if ((i == colon2) && (i >= 0)) {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_RULE,
|
||||
colon + 1, colon2 - (colon + 1));
|
||||
|
||||
} else {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_RULE,
|
||||
colon + 1, matchEnd - (colon + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// test for attribute type
|
||||
if (colon > matchStart) {
|
||||
ber.encodeOctetString(filter,
|
||||
LDAP_FILTER_EXT_TYPE, matchStart, colon - matchStart);
|
||||
}
|
||||
} else {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_TYPE, matchStart,
|
||||
matchEnd - matchStart);
|
||||
}
|
||||
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, valueStart, valueEnd),
|
||||
LDAP_FILTER_EXT_VAL);
|
||||
|
||||
/*
|
||||
* This element is defined in RFC-2251 with an ASN.1 DEFAULT tag.
|
||||
* However, for Active Directory interoperability it is transmitted
|
||||
* even when FALSE.
|
||||
*/
|
||||
ber.encodeBoolean(matchDN, LDAP_FILTER_EXT_DN);
|
||||
|
||||
ber.endSeq();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// some debug print code that does indenting. Useful for debugging
|
||||
// the filter generation code
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private static final boolean dbg = false;
|
||||
private static int dbgIndent = 0;
|
||||
|
||||
private static void dprint(String msg) {
|
||||
dprint(msg, new byte[0], 0, 0);
|
||||
}
|
||||
|
||||
private static void dprint(String msg, byte[] str) {
|
||||
dprint(msg, str, 0, str.length);
|
||||
}
|
||||
|
||||
private static void dprint(String msg, byte[] str, int start, int end) {
|
||||
String dstr = " ";
|
||||
int i = dbgIndent;
|
||||
while (i-- > 0) {
|
||||
dstr += " ";
|
||||
}
|
||||
dstr += msg;
|
||||
|
||||
System.err.print(dstr);
|
||||
for (int j = start; j < end; j++) {
|
||||
System.err.print((char)str[j]);
|
||||
}
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
/////////////// Constants used for encoding filter //////////////
|
||||
|
||||
static final int LDAP_FILTER_AND = 0xa0;
|
||||
static final int LDAP_FILTER_OR = 0xa1;
|
||||
static final int LDAP_FILTER_NOT = 0xa2;
|
||||
static final int LDAP_FILTER_EQUALITY = 0xa3;
|
||||
static final int LDAP_FILTER_SUBSTRINGS = 0xa4;
|
||||
static final int LDAP_FILTER_GE = 0xa5;
|
||||
static final int LDAP_FILTER_LE = 0xa6;
|
||||
static final int LDAP_FILTER_PRESENT = 0x87;
|
||||
static final int LDAP_FILTER_APPROX = 0xa8;
|
||||
static final int LDAP_FILTER_EXT = 0xa9; // LDAPv3
|
||||
|
||||
static final int LDAP_FILTER_EXT_RULE = 0x81; // LDAPv3
|
||||
static final int LDAP_FILTER_EXT_TYPE = 0x82; // LDAPv3
|
||||
static final int LDAP_FILTER_EXT_VAL = 0x83; // LDAPv3
|
||||
static final int LDAP_FILTER_EXT_DN = 0x84; // LDAPv3
|
||||
|
||||
static final int LDAP_SUBSTRING_INITIAL = 0x80;
|
||||
static final int LDAP_SUBSTRING_ANY = 0x81;
|
||||
static final int LDAP_SUBSTRING_FINAL = 0x82;
|
||||
}
|
||||
212
jdkSrc/jdk8/com/sun/jndi/ldap/LdapAttribute.java
Normal file
212
jdkSrc/jdk8/com/sun/jndi/ldap/LdapAttribute.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
/**
|
||||
* This subclass is used by LDAP to implement the schema calls.
|
||||
* Basically, it keeps track of which context it is an attribute of
|
||||
* so it can get the schema for that cotnext.
|
||||
*
|
||||
* @author Jon Ruiz
|
||||
*/
|
||||
final class LdapAttribute extends BasicAttribute {
|
||||
|
||||
static final long serialVersionUID = -4288716561020779584L;
|
||||
|
||||
private transient DirContext baseCtx = null;
|
||||
private Name rdn = new CompositeName();
|
||||
|
||||
// these two are used to reconstruct the baseCtx if this attribute has
|
||||
// been serialized (
|
||||
private String baseCtxURL;
|
||||
private Hashtable<String, ? super String> baseCtxEnv;
|
||||
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
public Object clone() {
|
||||
LdapAttribute attr = new LdapAttribute(this.attrID, baseCtx, rdn);
|
||||
attr.values = (Vector<Object>)values.clone();
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new value to this attribute.
|
||||
*
|
||||
* @param attrVal The value to be added. If null, a null value is added to
|
||||
* the attribute.
|
||||
* @return true Always returns true.
|
||||
*/
|
||||
public boolean add(Object attrVal) {
|
||||
// LDAP attributes don't contain duplicate values so there's no need
|
||||
// to check if the value already exists before adding it.
|
||||
values.addElement(attrVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of an attribute.
|
||||
*
|
||||
* @param id The attribute's id. It cannot be null.
|
||||
*/
|
||||
LdapAttribute(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of an attribute.
|
||||
*
|
||||
* @param id The attribute's id. It cannot be null.
|
||||
* @param baseCtx the baseCtx object of this attribute
|
||||
* @param rdn the RDN of the entry (relative to baseCtx)
|
||||
*/
|
||||
private LdapAttribute(String id, DirContext baseCtx, Name rdn) {
|
||||
super(id);
|
||||
this.baseCtx = baseCtx;
|
||||
this.rdn = rdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the baseCtx and rdn used to find the attribute's schema
|
||||
* Used by LdapCtx.setParents().
|
||||
*/
|
||||
void setParent(DirContext baseCtx, Name rdn) {
|
||||
this.baseCtx = baseCtx;
|
||||
this.rdn = rdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the ctx this attribute came from. This call allows
|
||||
* LDAPAttribute to be serializable. 'baseCtx' is transient so if
|
||||
* it is null, the `baseCtxURL` is used to reconstruct the context
|
||||
* to which calls are made.
|
||||
*/
|
||||
private DirContext getBaseCtx() throws NamingException {
|
||||
if(baseCtx == null) {
|
||||
if (baseCtxEnv == null) {
|
||||
baseCtxEnv = new Hashtable<String, String>(3);
|
||||
}
|
||||
baseCtxEnv.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
baseCtxEnv.put(Context.PROVIDER_URL,baseCtxURL);
|
||||
baseCtx = (new InitialDirContext(baseCtxEnv));
|
||||
}
|
||||
return baseCtx;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the object is serialized. It is
|
||||
* overridden so that the appropriate class variables can be set
|
||||
* to re-construct the baseCtx when deserialized. Setting these
|
||||
* variables is costly, so it is only done if the object
|
||||
* is actually serialized.
|
||||
*/
|
||||
private void writeObject(java.io.ObjectOutputStream out)
|
||||
throws IOException {
|
||||
|
||||
// setup internal state
|
||||
this.setBaseCtxInfo();
|
||||
|
||||
// let the ObjectOutpurStream do the real work of serialization
|
||||
out.defaultWriteObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the information needed to reconstruct the baseCtx if
|
||||
* we are serialized. This must be called _before_ the object is
|
||||
* serialized!!!
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
private void setBaseCtxInfo() {
|
||||
Hashtable<String, Object> realEnv = null;
|
||||
Hashtable<String, Object> secureEnv = null;
|
||||
|
||||
if (baseCtx != null) {
|
||||
realEnv = ((LdapCtx)baseCtx).envprops;
|
||||
this.baseCtxURL = ((LdapCtx)baseCtx).getURL();
|
||||
}
|
||||
|
||||
if(realEnv != null && realEnv.size() > 0 ) {
|
||||
// remove any security credentials - otherwise the serialized form
|
||||
// would store them in the clear
|
||||
for (String key : realEnv.keySet()){
|
||||
if (key.indexOf("security") != -1 ) {
|
||||
|
||||
//if we need to remove props, we must do it to a clone
|
||||
//of the environment. cloning is expensive, so we only do
|
||||
//it if we have to.
|
||||
if(secureEnv == null) {
|
||||
secureEnv = (Hashtable<String, Object>)realEnv.clone();
|
||||
}
|
||||
secureEnv.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set baseCtxEnv depending on whether we removed props or not
|
||||
this.baseCtxEnv = (secureEnv == null ? realEnv : secureEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the syntax definition associated with this attribute.
|
||||
* @return This attribute's syntax definition.
|
||||
*/
|
||||
public DirContext getAttributeSyntaxDefinition() throws NamingException {
|
||||
// get the syntax id from the attribute def
|
||||
DirContext schema = getBaseCtx().getSchema(rdn);
|
||||
DirContext attrDef = (DirContext)schema.lookup(
|
||||
LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID());
|
||||
|
||||
Attribute syntaxAttr = attrDef.getAttributes("").get("SYNTAX");
|
||||
|
||||
if(syntaxAttr == null || syntaxAttr.size() == 0) {
|
||||
throw new NameNotFoundException(
|
||||
getID() + "does not have a syntax associated with it");
|
||||
}
|
||||
|
||||
String syntaxName = (String)syntaxAttr.get();
|
||||
|
||||
// look in the schema tree for the syntax definition
|
||||
return (DirContext)schema.lookup(
|
||||
LdapSchemaParser.SYNTAX_DEFINITION_NAME + "/" + syntaxName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this attribute's schema definition.
|
||||
*
|
||||
* @return This attribute's schema definition.
|
||||
*/
|
||||
public DirContext getAttributeDefinition() throws NamingException {
|
||||
DirContext schema = getBaseCtx().getSchema(rdn);
|
||||
|
||||
return (DirContext)schema.lookup(
|
||||
LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID());
|
||||
}
|
||||
}
|
||||
112
jdkSrc/jdk8/com/sun/jndi/ldap/LdapBindingEnumeration.java
Normal file
112
jdkSrc/jdk8/com/sun/jndi/ldap/LdapBindingEnumeration.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.spi.*;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
|
||||
final class LdapBindingEnumeration
|
||||
extends AbstractLdapNamingEnumeration<Binding> {
|
||||
|
||||
private final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
LdapBindingEnumeration(LdapCtx homeCtx, LdapResult answer, Name remain,
|
||||
Continuation cont) throws NamingException
|
||||
{
|
||||
super(homeCtx, answer, remain, cont);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Binding
|
||||
createItem(String dn, Attributes attrs, Vector<Control> respCtls)
|
||||
throws NamingException {
|
||||
|
||||
Object obj = null;
|
||||
String atom = getAtom(dn);
|
||||
|
||||
if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
|
||||
// serialized object or object reference
|
||||
try {
|
||||
obj = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
@Override
|
||||
public Object run() throws NamingException {
|
||||
return Obj.decodeObject(attrs);
|
||||
}
|
||||
}, acc);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (NamingException)e.getException();
|
||||
}
|
||||
}
|
||||
if (obj == null) {
|
||||
// DirContext object
|
||||
obj = new LdapCtx(homeCtx, dn);
|
||||
}
|
||||
|
||||
CompositeName cn = new CompositeName();
|
||||
cn.add(atom);
|
||||
|
||||
try {
|
||||
obj = DirectoryManager.getObjectInstance(obj, cn, homeCtx,
|
||||
homeCtx.envprops, attrs);
|
||||
|
||||
} catch (NamingException e) {
|
||||
throw e;
|
||||
|
||||
} catch (Exception e) {
|
||||
NamingException ne =
|
||||
new NamingException(
|
||||
"problem generating object using object factory");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
Binding binding;
|
||||
if (respCtls != null) {
|
||||
binding = new BindingWithControls(cn.toString(), obj,
|
||||
homeCtx.convertControls(respCtls));
|
||||
} else {
|
||||
binding = new Binding(cn.toString(), obj);
|
||||
}
|
||||
binding.setNameInNamespace(dn);
|
||||
return binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException{
|
||||
// repeat the original operation at the new context
|
||||
return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.listBindings(listArg);
|
||||
}
|
||||
}
|
||||
1618
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClient.java
Normal file
1618
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClient.java
Normal file
File diff suppressed because it is too large
Load Diff
71
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClientFactory.java
Normal file
71
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClientFactory.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.InterruptedNamingException;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import com.sun.jndi.ldap.pool.PoolCallback;
|
||||
import com.sun.jndi.ldap.pool.PooledConnection;
|
||||
import com.sun.jndi.ldap.pool.PooledConnectionFactory;
|
||||
|
||||
/**
|
||||
* Creates an LdapClient. Encapsulates the parameters required to create
|
||||
* an LdapClient and provides methods for returning appropriate exceptions
|
||||
* to throw when acquiring a pooled LdapClient fails.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class LdapClientFactory implements PooledConnectionFactory {
|
||||
final private String host;
|
||||
final private int port;
|
||||
final private String socketFactory;
|
||||
final private int connTimeout;
|
||||
final private int readTimeout;
|
||||
final private OutputStream trace;
|
||||
|
||||
LdapClientFactory(String host, int port, String socketFactory,
|
||||
int connTimeout, int readTimeout, OutputStream trace) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.socketFactory = socketFactory;
|
||||
this.connTimeout = connTimeout;
|
||||
this.readTimeout = readTimeout;
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public PooledConnection createPooledConnection(PoolCallback pcb)
|
||||
throws NamingException {
|
||||
return new LdapClient(host, port, socketFactory,
|
||||
connTimeout, readTimeout, trace, pcb);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return host + ":" + port;
|
||||
}
|
||||
}
|
||||
3716
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtx.java
Normal file
3716
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtx.java
Normal file
File diff suppressed because it is too large
Load Diff
303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtxFactory.java
Normal file
303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtxFactory.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
import javax.naming.spi.InitialContextFactory;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProviderResult;
|
||||
import com.sun.jndi.url.ldap.ldapURLContextFactory;
|
||||
|
||||
final public class LdapCtxFactory implements ObjectFactory, InitialContextFactory {
|
||||
/**
|
||||
* The type of each address in an LDAP reference.
|
||||
*/
|
||||
public final static String ADDRESS_TYPE = "URL";
|
||||
|
||||
// ----------------- ObjectFactory interface --------------------
|
||||
|
||||
public Object getObjectInstance(Object ref, Name name, Context nameCtx,
|
||||
Hashtable<?,?> env) throws Exception {
|
||||
|
||||
if (!isLdapRef(ref)) {
|
||||
return null;
|
||||
}
|
||||
ObjectFactory factory = new ldapURLContextFactory();
|
||||
String[] urls = getURLs((Reference)ref);
|
||||
return factory.getObjectInstance(urls, name, nameCtx, env);
|
||||
}
|
||||
|
||||
// ----------------- InitialContext interface --------------------
|
||||
|
||||
public Context getInitialContext(Hashtable<?,?> envprops)
|
||||
throws NamingException {
|
||||
|
||||
try {
|
||||
String providerUrl = (envprops != null) ?
|
||||
(String)envprops.get(Context.PROVIDER_URL) : null;
|
||||
|
||||
// If URL not in environment, use defaults
|
||||
if (providerUrl == null) {
|
||||
return new LdapCtx("", LdapCtx.DEFAULT_HOST,
|
||||
LdapCtx.DEFAULT_PORT, envprops, false);
|
||||
}
|
||||
|
||||
// Extract URL(s)
|
||||
String[] urls = LdapURL.fromList(providerUrl);
|
||||
|
||||
if (urls.length == 0) {
|
||||
throw new ConfigurationException(Context.PROVIDER_URL +
|
||||
" property does not contain a URL");
|
||||
}
|
||||
|
||||
// Generate an LDAP context
|
||||
return getLdapCtxInstance(urls, envprops);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
if (envprops != null &&
|
||||
"throw".equals(envprops.get(Context.REFERRAL))) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
Control[] bindCtls = (envprops != null)?
|
||||
(Control[])envprops.get(LdapCtx.BIND_CONTROLS) : null;
|
||||
|
||||
return (LdapCtx)e.getReferralContext(envprops, bindCtls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if argument is an LDAP reference.
|
||||
*/
|
||||
private static boolean isLdapRef(Object obj) {
|
||||
|
||||
if (!(obj instanceof Reference)) {
|
||||
return false;
|
||||
}
|
||||
String thisClassName = LdapCtxFactory.class.getName();
|
||||
Reference ref = (Reference)obj;
|
||||
|
||||
return thisClassName.equals(ref.getFactoryClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URLs contained within an LDAP reference.
|
||||
*/
|
||||
private static String[] getURLs(Reference ref) throws NamingException {
|
||||
|
||||
int size = 0; // number of URLs
|
||||
String[] urls = new String[ref.size()];
|
||||
|
||||
Enumeration<RefAddr> addrs = ref.getAll();
|
||||
while (addrs.hasMoreElements()) {
|
||||
RefAddr addr = addrs.nextElement();
|
||||
|
||||
if ((addr instanceof StringRefAddr) &&
|
||||
addr.getType().equals(ADDRESS_TYPE)) {
|
||||
|
||||
urls[size++] = (String)addr.getContent();
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
throw (new ConfigurationException(
|
||||
"Reference contains no valid addresses"));
|
||||
}
|
||||
|
||||
// Trim URL array down to size.
|
||||
if (size == ref.size()) {
|
||||
return urls;
|
||||
}
|
||||
String[] urls2 = new String[size];
|
||||
System.arraycopy(urls, 0, urls2, 0, size);
|
||||
return urls2;
|
||||
}
|
||||
|
||||
// ------------ Utilities used by other classes ----------------
|
||||
|
||||
public static DirContext getLdapCtxInstance(Object urlInfo, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
if (urlInfo instanceof String) {
|
||||
return getUsingURL((String)urlInfo, env);
|
||||
} else if (urlInfo instanceof String[]) {
|
||||
return getUsingURLs((String[])urlInfo, env);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"argument must be an LDAP URL String or array of them");
|
||||
}
|
||||
}
|
||||
|
||||
private static DirContext getUsingURL(String url, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
try {
|
||||
LdapDnsProviderResult r =
|
||||
LdapDnsProviderService.getInstance().lookupEndpoints(url, env);
|
||||
LdapCtx ctx;
|
||||
NamingException lastException = null;
|
||||
|
||||
/*
|
||||
* Prior to this change we had been assuming that the url.getDN()
|
||||
* should be converted to a domain name via
|
||||
* ServiceLocator.mapDnToDomainName(url.getDN())
|
||||
*
|
||||
* However this is incorrect as we can't assume that the supplied
|
||||
* url.getDN() is the same as the dns domain for the directory
|
||||
* server.
|
||||
*
|
||||
* This means that we depend on the dnsProvider to return both
|
||||
* the list of urls of individual hosts from which we attempt to
|
||||
* create an LdapCtx from *AND* the domain name that they serve
|
||||
*
|
||||
* In order to do this the dnsProvider must return an
|
||||
* {@link LdapDnsProviderResult}.
|
||||
*
|
||||
*/
|
||||
for (String u : r.getEndpoints()) {
|
||||
try {
|
||||
ctx = getLdapCtxFromUrl(
|
||||
r.getDomainName(), url, new LdapURL(u), env);
|
||||
return ctx;
|
||||
} catch (AuthenticationException e) {
|
||||
// do not retry on a different endpoint to avoid blocking
|
||||
// the user if authentication credentials are wrong.
|
||||
throw e;
|
||||
} catch (NamingException e) {
|
||||
// try the next element
|
||||
lastException = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
|
||||
// lookupEndpoints returned an LdapDnsProviderResult with an empty
|
||||
// list of endpoints
|
||||
throw new NamingException("Could not resolve a valid ldap host");
|
||||
} catch (NamingException e) {
|
||||
// lookupEndpoints(url, env) may throw a NamingException, which
|
||||
// there is no need to wrap.
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
NamingException ex = new NamingException();
|
||||
ex.setRootCause(e);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static LdapCtx getLdapCtxFromUrl(String domain,
|
||||
String url,
|
||||
LdapURL u,
|
||||
Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
String dn = u.getDN();
|
||||
String host = u.getHost();
|
||||
int port = u.getPort();
|
||||
LdapCtx ctx = new LdapCtx(dn, host, port, env, u.useSsl());
|
||||
ctx.setDomainName(domain);
|
||||
// Record the URL that created the context
|
||||
ctx.setProviderUrl(url);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try each URL until one of them succeeds.
|
||||
* If all URLs fail, throw one of the exceptions arbitrarily.
|
||||
* Not pretty, but potentially more informative than returning null.
|
||||
*/
|
||||
private static DirContext getUsingURLs(String[] urls, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
NamingException ex = null;
|
||||
for (String u : urls) {
|
||||
try {
|
||||
return getUsingURL(u, env);
|
||||
} catch (AuthenticationException e) {
|
||||
// do not retry on a different endpoint to avoid blocking
|
||||
// the user if authentication credentials are wrong.
|
||||
throw e;
|
||||
} catch (NamingException e) {
|
||||
ex = e;
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Obj and obj/RemoteToAttrs too so must be public
|
||||
*/
|
||||
public static Attribute createTypeNameAttr(Class<?> cl) {
|
||||
Vector<String> v = new Vector<>(10);
|
||||
String[] types = getTypeNames(cl, v);
|
||||
if (types.length > 0) {
|
||||
BasicAttribute tAttr =
|
||||
new BasicAttribute(Obj.JAVA_ATTRIBUTES[Obj.TYPENAME]);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
tAttr.add(types[i]);
|
||||
}
|
||||
return tAttr;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String[] getTypeNames(Class<?> currentClass, Vector<String> v) {
|
||||
|
||||
getClassesAux(currentClass, v);
|
||||
Class<?>[] members = currentClass.getInterfaces();
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
getClassesAux(members[i], v);
|
||||
}
|
||||
String[] ret = new String[v.size()];
|
||||
int i = 0;
|
||||
|
||||
for (String name : v) {
|
||||
ret[i++] = name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void getClassesAux(Class<?> currentClass, Vector<String> v) {
|
||||
if (!v.contains(currentClass.getName())) {
|
||||
v.addElement(currentClass.getName());
|
||||
}
|
||||
currentClass = currentClass.getSuperclass();
|
||||
|
||||
while (currentClass != null) {
|
||||
getTypeNames(currentClass, v);
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
jdkSrc/jdk8/com/sun/jndi/ldap/LdapDnsProviderService.java
Normal file
114
jdkSrc/jdk8/com/sun/jndi/ldap/LdapDnsProviderService.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import javax.naming.NamingException;
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProvider;
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProviderResult;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
/**
|
||||
* The {@code LdapDnsProviderService} is responsible for creating and providing
|
||||
* access to the registered {@code LdapDnsProvider}s. The {@link ServiceLoader}
|
||||
* is used to find and register any implementations of {@link LdapDnsProvider}.
|
||||
*
|
||||
* <p> Instances of this class are safe for use by multiple threads.
|
||||
*/
|
||||
final class LdapDnsProviderService {
|
||||
|
||||
private static volatile LdapDnsProviderService service;
|
||||
private static final Object LOCK = new int[0];
|
||||
private final ServiceLoader<LdapDnsProvider> providers;
|
||||
|
||||
/**
|
||||
* Creates a new instance of LdapDnsProviderService
|
||||
*/
|
||||
private LdapDnsProviderService() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) {
|
||||
providers = ServiceLoader.load(
|
||||
LdapDnsProvider.class,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
} else {
|
||||
final PrivilegedAction<ServiceLoader<LdapDnsProvider>> pa =
|
||||
() -> ServiceLoader.load(
|
||||
LdapDnsProvider.class,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
|
||||
providers = AccessController.doPrivileged(
|
||||
pa,
|
||||
null,
|
||||
new RuntimePermission("ldapDnsProvider"),
|
||||
SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the singleton instance of LdapDnsProviderService.
|
||||
*/
|
||||
static LdapDnsProviderService getInstance() {
|
||||
if (service != null) return service;
|
||||
synchronized (LOCK) {
|
||||
if (service != null) return service;
|
||||
service = new LdapDnsProviderService();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves result from the first provider that successfully resolves
|
||||
* the endpoints. If no results are found when calling installed
|
||||
* subclasses of {@code LdapDnsProvider} then this method will fall back
|
||||
* to the {@code DefaultLdapDnsProvider}.
|
||||
*
|
||||
* @throws NamingException if the {@code url} in not valid or an error
|
||||
* occurred while performing the lookup.
|
||||
*/
|
||||
LdapDnsProviderResult lookupEndpoints(String url, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
LdapDnsProviderResult result = null;
|
||||
Hashtable<?, ?> envCopy = new Hashtable<>(env);
|
||||
synchronized (LOCK) {
|
||||
Iterator<LdapDnsProvider> iterator = providers.iterator();
|
||||
while (result == null && iterator.hasNext()) {
|
||||
result = iterator.next().lookupEndpoints(url, envCopy)
|
||||
.filter(r -> !r.getEndpoints().isEmpty())
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
return new DefaultLdapDnsProvider().lookupEndpoints(url, env)
|
||||
.orElse(new LdapDnsProviderResult("", Collections.emptyList()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
53
jdkSrc/jdk8/com/sun/jndi/ldap/LdapEntry.java
Normal file
53
jdkSrc/jdk8/com/sun/jndi/ldap/LdapEntry.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Vector;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* A holder for an LDAP entry read from an LDAP server.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final class LdapEntry {
|
||||
String DN;
|
||||
Attributes attributes;
|
||||
Vector<Control> respCtls = null;
|
||||
|
||||
LdapEntry(String DN, Attributes attrs) {
|
||||
this.DN = DN;
|
||||
this.attributes = attrs;
|
||||
}
|
||||
|
||||
LdapEntry(String DN, Attributes attrs, Vector<Control> respCtls) {
|
||||
this.DN = DN;
|
||||
this.attributes = attrs;
|
||||
this.respCtls = respCtls;
|
||||
}
|
||||
}
|
||||
1020
jdkSrc/jdk8/com/sun/jndi/ldap/LdapName.java
Normal file
1020
jdkSrc/jdk8/com/sun/jndi/ldap/LdapName.java
Normal file
File diff suppressed because it is too large
Load Diff
41
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNameParser.java
Normal file
41
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNameParser.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.LdapName;
|
||||
|
||||
|
||||
class LdapNameParser implements NameParser {
|
||||
|
||||
public LdapNameParser() {
|
||||
}
|
||||
|
||||
public Name parse(String name) throws NamingException {
|
||||
return new LdapName(name);
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNamingEnumeration.java
Normal file
80
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNamingEnumeration.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
import java.util.Vector;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
|
||||
final class LdapNamingEnumeration
|
||||
extends AbstractLdapNamingEnumeration<NameClassPair> {
|
||||
|
||||
private static final String defaultClassName = DirContext.class.getName();
|
||||
|
||||
LdapNamingEnumeration(LdapCtx homeCtx, LdapResult answer, Name listArg,
|
||||
Continuation cont) throws NamingException {
|
||||
super(homeCtx, answer, listArg, cont);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NameClassPair createItem(String dn, Attributes attrs,
|
||||
Vector<Control> respCtls) throws NamingException {
|
||||
|
||||
Attribute attr;
|
||||
String className = null;
|
||||
|
||||
// use the Java classname if present
|
||||
if ((attr = attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME])) != null) {
|
||||
className = (String)attr.get();
|
||||
} else {
|
||||
className = defaultClassName;
|
||||
}
|
||||
CompositeName cn = new CompositeName();
|
||||
cn.add(getAtom(dn));
|
||||
|
||||
NameClassPair ncp;
|
||||
if (respCtls != null) {
|
||||
ncp = new NameClassPairWithControls(
|
||||
cn.toString(), className,
|
||||
homeCtx.convertControls(respCtls));
|
||||
} else {
|
||||
ncp = new NameClassPair(cn.toString(), className);
|
||||
}
|
||||
ncp.setNameInNamespace(dn);
|
||||
return ncp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException {
|
||||
// repeat the original operation at the new context
|
||||
return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.list(listArg);
|
||||
}
|
||||
}
|
||||
441
jdkSrc/jdk8/com/sun/jndi/ldap/LdapPoolManager.java
Normal file
441
jdkSrc/jdk8/com/sun/jndi/ldap/LdapPoolManager.java
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.CommunicationException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import com.sun.jndi.ldap.pool.PoolCleaner;
|
||||
import com.sun.jndi.ldap.pool.Pool;
|
||||
import sun.misc.InnocuousThread;
|
||||
|
||||
/**
|
||||
* Contains utilities for managing connection pools of LdapClient.
|
||||
* Contains method for
|
||||
* - checking whether attempted connection creation may be pooled
|
||||
* - creating a pooled connection
|
||||
* - closing idle connections.
|
||||
*
|
||||
* If a timeout period has been configured, then it will automatically
|
||||
* close and remove idle connections (those that have not been
|
||||
* used for the duration of the timeout period).
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
public final class LdapPoolManager {
|
||||
private static final String DEBUG =
|
||||
"com.sun.jndi.ldap.connect.pool.debug";
|
||||
|
||||
public static final boolean debug =
|
||||
"all".equalsIgnoreCase(getProperty(DEBUG, null));
|
||||
|
||||
public static final boolean trace = debug ||
|
||||
"fine".equalsIgnoreCase(getProperty(DEBUG, null));
|
||||
|
||||
// ---------- System properties for connection pooling
|
||||
|
||||
// Authentication mechanisms of connections that may be pooled
|
||||
private static final String POOL_AUTH =
|
||||
"com.sun.jndi.ldap.connect.pool.authentication";
|
||||
|
||||
// Protocol types of connections that may be pooled
|
||||
private static final String POOL_PROTOCOL =
|
||||
"com.sun.jndi.ldap.connect.pool.protocol";
|
||||
|
||||
// Maximum number of identical connections per pool
|
||||
private static final String MAX_POOL_SIZE =
|
||||
"com.sun.jndi.ldap.connect.pool.maxsize";
|
||||
|
||||
// Preferred number of identical connections per pool
|
||||
private static final String PREF_POOL_SIZE =
|
||||
"com.sun.jndi.ldap.connect.pool.prefsize";
|
||||
|
||||
// Initial number of identical connections per pool
|
||||
private static final String INIT_POOL_SIZE =
|
||||
"com.sun.jndi.ldap.connect.pool.initsize";
|
||||
|
||||
// Milliseconds to wait before closing idle connections
|
||||
private static final String POOL_TIMEOUT =
|
||||
"com.sun.jndi.ldap.connect.pool.timeout";
|
||||
|
||||
// Properties for DIGEST
|
||||
private static final String SASL_CALLBACK =
|
||||
"java.naming.security.sasl.callback";
|
||||
|
||||
// --------- Constants
|
||||
private static final int DEFAULT_MAX_POOL_SIZE = 0;
|
||||
private static final int DEFAULT_PREF_POOL_SIZE = 0;
|
||||
private static final int DEFAULT_INIT_POOL_SIZE = 1;
|
||||
private static final int DEFAULT_TIMEOUT = 0; // no timeout
|
||||
private static final String DEFAULT_AUTH_MECHS = "none simple";
|
||||
private static final String DEFAULT_PROTOCOLS = "plain";
|
||||
|
||||
private static final int NONE = 0; // indices into pools
|
||||
private static final int SIMPLE = 1;
|
||||
private static final int DIGEST = 2;
|
||||
|
||||
// --------- static fields
|
||||
private static final long idleTimeout;// ms to wait before closing idle conn
|
||||
private static final int maxSize; // max num of identical conns/pool
|
||||
private static final int prefSize; // preferred num of identical conns/pool
|
||||
private static final int initSize; // initial num of identical conns/pool
|
||||
|
||||
private static boolean supportPlainProtocol = false;
|
||||
private static boolean supportSslProtocol = false;
|
||||
|
||||
// List of pools used for different auth types
|
||||
private static final Pool[] pools = new Pool[3];
|
||||
|
||||
static {
|
||||
maxSize = getInteger(MAX_POOL_SIZE, DEFAULT_MAX_POOL_SIZE);
|
||||
|
||||
prefSize = getInteger(PREF_POOL_SIZE, DEFAULT_PREF_POOL_SIZE);
|
||||
|
||||
initSize = getInteger(INIT_POOL_SIZE, DEFAULT_INIT_POOL_SIZE);
|
||||
|
||||
idleTimeout = getLong(POOL_TIMEOUT, DEFAULT_TIMEOUT);
|
||||
|
||||
// Determine supported authentication mechanisms
|
||||
String str = getProperty(POOL_AUTH, DEFAULT_AUTH_MECHS);
|
||||
StringTokenizer parser = new StringTokenizer(str);
|
||||
int count = parser.countTokens();
|
||||
String mech;
|
||||
int p;
|
||||
for (int i = 0; i < count; i++) {
|
||||
mech = parser.nextToken().toLowerCase(Locale.ENGLISH);
|
||||
if (mech.equals("anonymous")) {
|
||||
mech = "none";
|
||||
}
|
||||
|
||||
p = findPool(mech);
|
||||
if (p >= 0 && pools[p] == null) {
|
||||
pools[p] = new Pool(initSize, prefSize, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine supported protocols
|
||||
str= getProperty(POOL_PROTOCOL, DEFAULT_PROTOCOLS);
|
||||
parser = new StringTokenizer(str);
|
||||
count = parser.countTokens();
|
||||
String proto;
|
||||
for (int i = 0; i < count; i++) {
|
||||
proto = parser.nextToken();
|
||||
if ("plain".equalsIgnoreCase(proto)) {
|
||||
supportPlainProtocol = true;
|
||||
} else if ("ssl".equalsIgnoreCase(proto)) {
|
||||
supportSslProtocol = true;
|
||||
} else {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (idleTimeout > 0) {
|
||||
// Create cleaner to expire idle connections
|
||||
PrivilegedAction<Void> pa = new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
Thread t = InnocuousThread.newSystemThread(
|
||||
"LDAP PoolCleaner",
|
||||
new PoolCleaner(idleTimeout, pools));
|
||||
assert t.getContextClassLoader() == null;
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
return null;
|
||||
}};
|
||||
AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
showStats(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot instantiate one of these
|
||||
private LdapPoolManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the pool for the specified mechanism. If not
|
||||
* one of "none", "simple", "DIGEST-MD5", or "GSSAPI",
|
||||
* return -1.
|
||||
* @param mech mechanism type
|
||||
*/
|
||||
private static int findPool(String mech) {
|
||||
if ("none".equalsIgnoreCase(mech)) {
|
||||
return NONE;
|
||||
} else if ("simple".equalsIgnoreCase(mech)) {
|
||||
return SIMPLE;
|
||||
} else if ("digest-md5".equalsIgnoreCase(mech)) {
|
||||
return DIGEST;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether pooling is allowed given information on how
|
||||
* the connection will be used.
|
||||
*
|
||||
* Non-configurable rejections:
|
||||
* - nonstandard socketFactory has been specified: the pool manager
|
||||
* cannot track input or parameters used by the socket factory and
|
||||
* thus has no way of determining whether two connection requests
|
||||
* are equivalent. Maybe in the future it might add a list of allowed
|
||||
* socket factories to be configured
|
||||
* - trace enabled (except when debugging)
|
||||
* - for Digest authentication, if a callback handler has been specified:
|
||||
* the pool manager cannot track input collected by the handler
|
||||
* and thus has no way of determining whether two connection requests are
|
||||
* equivalent. Maybe in the future it might add a list of allowed
|
||||
* callback handlers.
|
||||
*
|
||||
* Configurable tests:
|
||||
* - Pooling for the requested protocol (plain or ssl) is supported
|
||||
* - Pooling for the requested authentication mechanism is supported
|
||||
*
|
||||
*/
|
||||
static boolean isPoolingAllowed(String socketFactory, OutputStream trace,
|
||||
String authMech, String protocol, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
if (trace != null && !debug
|
||||
|
||||
// Requesting plain protocol but it is not supported
|
||||
|| (protocol == null && !supportPlainProtocol)
|
||||
|
||||
// Requesting ssl protocol but it is not supported
|
||||
|| ("ssl".equalsIgnoreCase(protocol) && !supportSslProtocol)) {
|
||||
|
||||
d("Pooling disallowed due to tracing or unsupported pooling of protocol");
|
||||
return false;
|
||||
}
|
||||
// pooling of custom socket factory is possible only if the
|
||||
// socket factory interface implements java.util.comparator
|
||||
String COMPARATOR = "java.util.Comparator";
|
||||
boolean foundSockCmp = false;
|
||||
if ((socketFactory != null) &&
|
||||
!socketFactory.equals(LdapCtx.DEFAULT_SSL_FACTORY)) {
|
||||
try {
|
||||
Class<?> socketFactoryClass = Obj.helper.loadClass(socketFactory);
|
||||
Class<?>[] interfaces = socketFactoryClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
if (interfaces[i].getCanonicalName().equals(COMPARATOR)) {
|
||||
foundSockCmp = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CommunicationException ce =
|
||||
new CommunicationException("Loading the socket factory");
|
||||
ce.setRootCause(e);
|
||||
throw ce;
|
||||
}
|
||||
if (!foundSockCmp) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Cannot use pooling if authMech is not a supported mechs
|
||||
// Cannot use pooling if authMech contains multiple mechs
|
||||
int p = findPool(authMech);
|
||||
if (p < 0 || pools[p] == null) {
|
||||
d("authmech not found: ", authMech);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
d("using authmech: ", authMech);
|
||||
|
||||
switch (p) {
|
||||
case NONE:
|
||||
case SIMPLE:
|
||||
return true;
|
||||
|
||||
case DIGEST:
|
||||
// Provider won't be able to determine connection identity
|
||||
// if an alternate callback handler is used
|
||||
return (env == null || env.get(SASL_CALLBACK) == null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a pooled connection that either already exists or is
|
||||
* newly created using the parameters supplied. If it is newly
|
||||
* created, it needs to go through the authentication checks to
|
||||
* determine whether an LDAP bind is necessary.
|
||||
*
|
||||
* Caller needs to invoke ldapClient.authenticateCalled() to
|
||||
* determine whether ldapClient.authenticate() needs to be invoked.
|
||||
* Caller has that responsibility because caller needs to deal
|
||||
* with the LDAP bind response, which might involve referrals,
|
||||
* response controls, errors, etc. This method is responsible only
|
||||
* for establishing the connection.
|
||||
*
|
||||
* @return an LdapClient that is pooled.
|
||||
*/
|
||||
static LdapClient getLdapClient(String host, int port, String socketFactory,
|
||||
int connTimeout, int readTimeout, OutputStream trace, int version,
|
||||
String authMech, Control[] ctls, String protocol, String user,
|
||||
Object passwd, Hashtable<?,?> env) throws NamingException {
|
||||
|
||||
// Create base identity for LdapClient
|
||||
ClientId id = null;
|
||||
Pool pool;
|
||||
|
||||
int p = findPool(authMech);
|
||||
if (p < 0 || (pool=pools[p]) == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Attempting to use pooling for an unsupported mechanism: " +
|
||||
authMech);
|
||||
}
|
||||
switch (p) {
|
||||
case NONE:
|
||||
id = new ClientId(version, host, port, protocol,
|
||||
ctls, trace, socketFactory);
|
||||
break;
|
||||
|
||||
case SIMPLE:
|
||||
// Add identity information used in simple authentication
|
||||
id = new SimpleClientId(version, host, port, protocol,
|
||||
ctls, trace, socketFactory, user, passwd);
|
||||
break;
|
||||
|
||||
case DIGEST:
|
||||
// Add user/passwd/realm/authzid/qop/strength/maxbuf/mutual/policy*
|
||||
id = new DigestClientId(version, host, port, protocol,
|
||||
ctls, trace, socketFactory, user, passwd, env);
|
||||
break;
|
||||
}
|
||||
|
||||
return (LdapClient) pool.getPooledConnection(id, connTimeout,
|
||||
new LdapClientFactory(host, port, socketFactory, connTimeout,
|
||||
readTimeout, trace));
|
||||
}
|
||||
|
||||
public static void showStats(PrintStream out) {
|
||||
out.println("***** start *****");
|
||||
out.println("idle timeout: " + idleTimeout);
|
||||
out.println("maximum pool size: " + maxSize);
|
||||
out.println("preferred pool size: " + prefSize);
|
||||
out.println("initial pool size: " + initSize);
|
||||
out.println("protocol types: " + (supportPlainProtocol ? "plain " : "") +
|
||||
(supportSslProtocol ? "ssl" : ""));
|
||||
out.println("authentication types: " +
|
||||
(pools[NONE] != null ? "none " : "") +
|
||||
(pools[SIMPLE] != null ? "simple " : "") +
|
||||
(pools[DIGEST] != null ? "DIGEST-MD5 " : ""));
|
||||
|
||||
for (int i = 0; i < pools.length; i++) {
|
||||
if (pools[i] != null) {
|
||||
out.println(
|
||||
(i == NONE ? "anonymous pools" :
|
||||
i == SIMPLE ? "simple auth pools" :
|
||||
i == DIGEST ? "digest pools" : "")
|
||||
+ ":");
|
||||
pools[i].showStats(out);
|
||||
}
|
||||
}
|
||||
out.println("***** end *****");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes idle connections idle since specified time.
|
||||
*
|
||||
* @param threshold Close connections idle since this time, as
|
||||
* specified in milliseconds since "the epoch".
|
||||
* @see java.util.Date
|
||||
*/
|
||||
public static void expire(long threshold) {
|
||||
for (int i = 0; i < pools.length; i++) {
|
||||
if (pools[i] != null) {
|
||||
pools[i].expire(threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void d(String msg) {
|
||||
if (debug) {
|
||||
System.err.println("LdapPoolManager: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void d(String msg, String o) {
|
||||
if (debug) {
|
||||
System.err.println("LdapPoolManager: " + msg + o);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String getProperty(final String propName,
|
||||
final String defVal) {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
try {
|
||||
return System.getProperty(propName, defVal);
|
||||
} catch (SecurityException e) {
|
||||
return defVal;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static final int getInteger(final String propName,
|
||||
final int defVal) {
|
||||
Integer val = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Integer>() {
|
||||
public Integer run() {
|
||||
try {
|
||||
return Integer.getInteger(propName, defVal);
|
||||
} catch (SecurityException e) {
|
||||
return new Integer(defVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
return val.intValue();
|
||||
}
|
||||
|
||||
private static final long getLong(final String propName,
|
||||
final long defVal) {
|
||||
Long val = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Long>() {
|
||||
public Long run() {
|
||||
try {
|
||||
return Long.getLong(propName, defVal);
|
||||
} catch (SecurityException e) {
|
||||
return new Long(defVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
return val.longValue();
|
||||
}
|
||||
}
|
||||
953
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralContext.java
Normal file
953
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralContext.java
Normal file
@@ -0,0 +1,953 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
import com.sun.jndi.toolkit.dir.SearchFilter;
|
||||
|
||||
/**
|
||||
* A context for handling referrals.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final class LdapReferralContext implements DirContext, LdapContext {
|
||||
|
||||
private DirContext refCtx = null;
|
||||
private Name urlName = null; // override the supplied name
|
||||
private String urlAttrs = null; // override attributes
|
||||
private String urlScope = null; // override scope
|
||||
private String urlFilter = null; // override filter
|
||||
|
||||
private LdapReferralException refEx = null;
|
||||
private boolean skipThisReferral = false;
|
||||
private int hopCount = 1;
|
||||
private NamingException previousEx = null;
|
||||
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
LdapReferralContext(LdapReferralException ex,
|
||||
Hashtable<?,?> env,
|
||||
Control[] connCtls,
|
||||
Control[] reqCtls,
|
||||
String nextName,
|
||||
boolean skipThisReferral,
|
||||
int handleReferrals) throws NamingException {
|
||||
|
||||
refEx = ex;
|
||||
|
||||
if (this.skipThisReferral = skipThisReferral) {
|
||||
return; // don't create a DirContext for this referral
|
||||
}
|
||||
|
||||
String referral;
|
||||
|
||||
// Make copies of environment and connect controls for our own use.
|
||||
if (env != null) {
|
||||
env = (Hashtable<?,?>) env.clone();
|
||||
// Remove old connect controls from environment, unless we have new
|
||||
// ones that will override them anyway.
|
||||
if (connCtls == null) {
|
||||
env.remove(LdapCtx.BIND_CONTROLS);
|
||||
}
|
||||
} else if (connCtls != null) {
|
||||
env = new Hashtable<String, Control[]>(5);
|
||||
}
|
||||
if (connCtls != null) {
|
||||
Control[] copiedCtls = new Control[connCtls.length];
|
||||
System.arraycopy(connCtls, 0, copiedCtls, 0, connCtls.length);
|
||||
// Add copied controls to environment, replacing any old ones.
|
||||
((Hashtable<? super String, ? super Control[]>)env)
|
||||
.put(LdapCtx.BIND_CONTROLS, copiedCtls);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
referral = refEx.getNextReferral();
|
||||
if (referral == null) {
|
||||
if (previousEx != null) {
|
||||
throw (NamingException)(previousEx.fillInStackTrace());
|
||||
} else {
|
||||
throw new NamingException(
|
||||
"Illegal encoding: referral is empty");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
if (handleReferrals == LdapClient.LDAP_REF_THROW) {
|
||||
throw e;
|
||||
} else {
|
||||
refEx = e;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Reference containing the referral URL.
|
||||
Reference ref = new Reference("javax.naming.directory.DirContext",
|
||||
new StringRefAddr("URL", referral));
|
||||
|
||||
Object obj;
|
||||
try {
|
||||
obj = NamingManager.getObjectInstance(ref, null, null, env);
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
if (handleReferrals == LdapClient.LDAP_REF_THROW) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
// mask the exception and save it for later
|
||||
previousEx = e;
|
||||
|
||||
// follow another referral
|
||||
continue;
|
||||
|
||||
} catch (Exception e) {
|
||||
NamingException e2 =
|
||||
new NamingException(
|
||||
"problem generating object using object factory");
|
||||
e2.setRootCause(e);
|
||||
throw e2;
|
||||
}
|
||||
if (obj instanceof DirContext) {
|
||||
refCtx = (DirContext)obj;
|
||||
if (refCtx instanceof LdapContext && reqCtls != null) {
|
||||
((LdapContext)refCtx).setRequestControls(reqCtls);
|
||||
}
|
||||
initDefaults(referral, nextName);
|
||||
|
||||
break;
|
||||
} else {
|
||||
NamingException ne = new NotContextException(
|
||||
"Cannot create context for: " + referral);
|
||||
ne.setRemainingName((new CompositeName()).add(nextName));
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initDefaults(String referral, String nextName)
|
||||
throws NamingException {
|
||||
String urlString;
|
||||
try {
|
||||
// parse URL
|
||||
LdapURL url = new LdapURL(referral);
|
||||
urlString = url.getDN();
|
||||
urlAttrs = url.getAttributes();
|
||||
urlScope = url.getScope();
|
||||
urlFilter = url.getFilter();
|
||||
|
||||
} catch (NamingException e) {
|
||||
// Not an LDAP URL; use original URL
|
||||
urlString = referral;
|
||||
urlAttrs = urlScope = urlFilter = null;
|
||||
}
|
||||
|
||||
// reuse original name if URL DN is absent
|
||||
if (urlString == null) {
|
||||
urlString = nextName;
|
||||
} else {
|
||||
// concatenate with remaining name if URL DN is present
|
||||
urlString = "";
|
||||
}
|
||||
|
||||
if (urlString == null) {
|
||||
urlName = null;
|
||||
} else {
|
||||
urlName = urlString.equals("") ? new CompositeName() :
|
||||
new CompositeName().add(urlString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void close() throws NamingException {
|
||||
if (refCtx != null) {
|
||||
refCtx.close();
|
||||
refCtx = null;
|
||||
}
|
||||
refEx = null;
|
||||
}
|
||||
|
||||
void setHopCount(int hopCount) {
|
||||
this.hopCount = hopCount;
|
||||
if ((refCtx != null) && (refCtx instanceof LdapCtx)) {
|
||||
((LdapCtx)refCtx).setHopCount(hopCount);
|
||||
}
|
||||
}
|
||||
|
||||
public Object lookup(String name) throws NamingException {
|
||||
return lookup(toName(name));
|
||||
}
|
||||
|
||||
public Object lookup(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.lookup(overrideName(name));
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj) throws NamingException {
|
||||
bind(toName(name), obj);
|
||||
}
|
||||
|
||||
public void bind(Name name, Object obj) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.bind(overrideName(name), obj);
|
||||
}
|
||||
|
||||
public void rebind(String name, Object obj) throws NamingException {
|
||||
rebind(toName(name), obj);
|
||||
}
|
||||
|
||||
public void rebind(Name name, Object obj) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.rebind(overrideName(name), obj);
|
||||
}
|
||||
|
||||
public void unbind(String name) throws NamingException {
|
||||
unbind(toName(name));
|
||||
}
|
||||
|
||||
public void unbind(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.unbind(overrideName(name));
|
||||
}
|
||||
|
||||
public void rename(String oldName, String newName) throws NamingException {
|
||||
rename(toName(oldName), toName(newName));
|
||||
}
|
||||
|
||||
public void rename(Name oldName, Name newName) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.rename(overrideName(oldName), toName(refEx.getNewRdn()));
|
||||
}
|
||||
|
||||
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
|
||||
return list(toName(name));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
try {
|
||||
NamingEnumeration<NameClassPair> ne = null;
|
||||
|
||||
if (urlScope != null && urlScope.equals("base")) {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningObjFlag(true);
|
||||
cons.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||
|
||||
ne = (NamingEnumeration)
|
||||
refCtx.search(overrideName(name), "(objectclass=*)", cons);
|
||||
|
||||
} else {
|
||||
ne = refCtx.list(overrideName(name));
|
||||
}
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration)ne).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (ne);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NamingEnumeration<Binding> listBindings(String name) throws
|
||||
NamingException {
|
||||
return listBindings(toName(name));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public NamingEnumeration<Binding> listBindings(Name name) throws
|
||||
NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
try {
|
||||
NamingEnumeration<Binding> be = null;
|
||||
|
||||
if (urlScope != null && urlScope.equals("base")) {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningObjFlag(true);
|
||||
cons.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||
|
||||
be = (NamingEnumeration)refCtx.search(overrideName(name),
|
||||
"(objectclass=*)", cons);
|
||||
|
||||
} else {
|
||||
be = refCtx.listBindings(overrideName(name));
|
||||
}
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration<Binding>)be).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (be);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroySubcontext(String name) throws NamingException {
|
||||
destroySubcontext(toName(name));
|
||||
}
|
||||
|
||||
public void destroySubcontext(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.destroySubcontext(overrideName(name));
|
||||
}
|
||||
|
||||
public Context createSubcontext(String name) throws NamingException {
|
||||
return createSubcontext(toName(name));
|
||||
}
|
||||
|
||||
public Context createSubcontext(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.createSubcontext(overrideName(name));
|
||||
}
|
||||
|
||||
public Object lookupLink(String name) throws NamingException {
|
||||
return lookupLink(toName(name));
|
||||
}
|
||||
|
||||
public Object lookupLink(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.lookupLink(overrideName(name));
|
||||
}
|
||||
|
||||
public NameParser getNameParser(String name) throws NamingException {
|
||||
return getNameParser(toName(name));
|
||||
}
|
||||
|
||||
public NameParser getNameParser(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getNameParser(overrideName(name));
|
||||
}
|
||||
|
||||
public String composeName(String name, String prefix)
|
||||
throws NamingException {
|
||||
return composeName(toName(name), toName(prefix)).toString();
|
||||
}
|
||||
|
||||
public Name composeName(Name name, Name prefix) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
return refCtx.composeName(name, prefix);
|
||||
}
|
||||
|
||||
public Object addToEnvironment(String propName, Object propVal)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.addToEnvironment(propName, propVal);
|
||||
}
|
||||
|
||||
public Object removeFromEnvironment(String propName)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.removeFromEnvironment(propName);
|
||||
}
|
||||
|
||||
public Hashtable<?,?> getEnvironment() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getEnvironment();
|
||||
}
|
||||
|
||||
public Attributes getAttributes(String name) throws NamingException {
|
||||
return getAttributes(toName(name));
|
||||
}
|
||||
|
||||
public Attributes getAttributes(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getAttributes(overrideName(name));
|
||||
}
|
||||
|
||||
public Attributes getAttributes(String name, String[] attrIds)
|
||||
throws NamingException {
|
||||
return getAttributes(toName(name), attrIds);
|
||||
}
|
||||
|
||||
public Attributes getAttributes(Name name, String[] attrIds)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getAttributes(overrideName(name), attrIds);
|
||||
}
|
||||
|
||||
public void modifyAttributes(String name, int mod_op, Attributes attrs)
|
||||
throws NamingException {
|
||||
modifyAttributes(toName(name), mod_op, attrs);
|
||||
}
|
||||
|
||||
public void modifyAttributes(Name name, int mod_op, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.modifyAttributes(overrideName(name), mod_op, attrs);
|
||||
}
|
||||
|
||||
public void modifyAttributes(String name, ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
modifyAttributes(toName(name), mods);
|
||||
}
|
||||
|
||||
public void modifyAttributes(Name name, ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.modifyAttributes(overrideName(name), mods);
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
bind(toName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public void bind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.bind(overrideName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public void rebind(String name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
rebind(toName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public void rebind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.rebind(overrideName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public DirContext createSubcontext(String name, Attributes attrs)
|
||||
throws NamingException {
|
||||
return createSubcontext(toName(name), attrs);
|
||||
}
|
||||
|
||||
public DirContext createSubcontext(Name name, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.createSubcontext(overrideName(name), attrs);
|
||||
}
|
||||
|
||||
public DirContext getSchema(String name) throws NamingException {
|
||||
return getSchema(toName(name));
|
||||
}
|
||||
|
||||
public DirContext getSchema(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getSchema(overrideName(name));
|
||||
}
|
||||
|
||||
public DirContext getSchemaClassDefinition(String name)
|
||||
throws NamingException {
|
||||
return getSchemaClassDefinition(toName(name));
|
||||
}
|
||||
|
||||
public DirContext getSchemaClassDefinition(Name name)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getSchemaClassDefinition(overrideName(name));
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
Attributes matchingAttributes)
|
||||
throws NamingException {
|
||||
return search(toName(name), SearchFilter.format(matchingAttributes),
|
||||
new SearchControls());
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
Attributes matchingAttributes)
|
||||
throws NamingException {
|
||||
return search(name, SearchFilter.format(matchingAttributes),
|
||||
new SearchControls());
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
Attributes matchingAttributes,
|
||||
String[] attributesToReturn)
|
||||
throws NamingException {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningAttributes(attributesToReturn);
|
||||
|
||||
return search(toName(name), SearchFilter.format(matchingAttributes),
|
||||
cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
Attributes matchingAttributes,
|
||||
String[] attributesToReturn)
|
||||
throws NamingException {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningAttributes(attributesToReturn);
|
||||
|
||||
return search(name, SearchFilter.format(matchingAttributes), cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
String filter,
|
||||
SearchControls cons)
|
||||
throws NamingException {
|
||||
return search(toName(name), filter, cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
String filter,
|
||||
SearchControls cons) throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
try {
|
||||
NamingEnumeration<SearchResult> se =
|
||||
refCtx.search(overrideName(name),
|
||||
overrideFilter(filter),
|
||||
overrideAttributesAndScope(cons));
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration)se).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (se);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// %%% VR - setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
String filterExpr,
|
||||
Object[] filterArgs,
|
||||
SearchControls cons)
|
||||
throws NamingException {
|
||||
return search(toName(name), filterExpr, filterArgs, cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
String filterExpr,
|
||||
Object[] filterArgs,
|
||||
SearchControls cons) throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
try {
|
||||
NamingEnumeration<SearchResult> se;
|
||||
|
||||
if (urlFilter != null) {
|
||||
se = refCtx.search(overrideName(name), urlFilter,
|
||||
overrideAttributesAndScope(cons));
|
||||
} else {
|
||||
se = refCtx.search(overrideName(name), filterExpr,
|
||||
filterArgs, overrideAttributesAndScope(cons));
|
||||
}
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration)se).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (se);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameInNamespace() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
return urlName != null && !urlName.isEmpty() ? urlName.get(0) : "";
|
||||
}
|
||||
|
||||
// ---------------------- LdapContext ---------------------
|
||||
|
||||
public ExtendedResponse extendedOperation(ExtendedRequest request)
|
||||
throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
return ((LdapContext)refCtx).extendedOperation(request);
|
||||
}
|
||||
|
||||
public LdapContext newInstance(Control[] requestControls)
|
||||
throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
return ((LdapContext)refCtx).newInstance(requestControls);
|
||||
}
|
||||
|
||||
public void reconnect(Control[] connCtls) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
((LdapContext)refCtx).reconnect(connCtls);
|
||||
}
|
||||
|
||||
public Control[] getConnectControls() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
return ((LdapContext)refCtx).getConnectControls();
|
||||
}
|
||||
|
||||
public void setRequestControls(Control[] requestControls)
|
||||
throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
((LdapContext)refCtx).setRequestControls(requestControls);
|
||||
}
|
||||
|
||||
public Control[] getRequestControls() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
return ((LdapContext)refCtx).getRequestControls();
|
||||
}
|
||||
|
||||
public Control[] getResponseControls() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
return ((LdapContext)refCtx).getResponseControls();
|
||||
}
|
||||
|
||||
// ---------------------- Private methods ---------------------
|
||||
private Name toName(String name) throws InvalidNameException {
|
||||
return name.equals("") ? new CompositeName() :
|
||||
new CompositeName().add(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the DN component from the LDAP URL (if present) to override the
|
||||
* supplied DN.
|
||||
*/
|
||||
private Name overrideName(Name name) throws InvalidNameException {
|
||||
return (urlName == null ? name : urlName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the attributes and scope components from the LDAP URL (if present)
|
||||
* to override the corrpesonding components supplied in SearchControls.
|
||||
*/
|
||||
private SearchControls overrideAttributesAndScope(SearchControls cons) {
|
||||
SearchControls urlCons;
|
||||
|
||||
if ((urlScope != null) || (urlAttrs != null)) {
|
||||
urlCons = new SearchControls(cons.getSearchScope(),
|
||||
cons.getCountLimit(),
|
||||
cons.getTimeLimit(),
|
||||
cons.getReturningAttributes(),
|
||||
cons.getReturningObjFlag(),
|
||||
cons.getDerefLinkFlag());
|
||||
|
||||
if (urlScope != null) {
|
||||
if (urlScope.equals("base")) {
|
||||
urlCons.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||
} else if (urlScope.equals("one")) {
|
||||
urlCons.setSearchScope(SearchControls.ONELEVEL_SCOPE);
|
||||
} else if (urlScope.equals("sub")) {
|
||||
urlCons.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlAttrs != null) {
|
||||
StringTokenizer tokens = new StringTokenizer(urlAttrs, ",");
|
||||
int count = tokens.countTokens();
|
||||
String[] attrs = new String[count];
|
||||
for (int i = 0; i < count; i ++) {
|
||||
attrs[i] = tokens.nextToken();
|
||||
}
|
||||
urlCons.setReturningAttributes(attrs);
|
||||
}
|
||||
|
||||
return urlCons;
|
||||
|
||||
} else {
|
||||
return cons;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the filter component from the LDAP URL (if present) to override the
|
||||
* supplied filter.
|
||||
*/
|
||||
private String overrideFilter(String filter) {
|
||||
return (urlFilter == null ? filter : urlFilter);
|
||||
}
|
||||
|
||||
}
|
||||
434
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralException.java
Normal file
434
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralException.java
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This exception is raised when a referral to an alternative context
|
||||
* is encountered.
|
||||
* <p>
|
||||
* An <tt>LdapReferralException</tt> object contains one or more referrals.
|
||||
* Each referral is an alternative location for the same target entry.
|
||||
* For example, a referral may be an LDAP URL.
|
||||
* The referrals are attempted in sequence until one is successful or
|
||||
* all have failed. In the case of the latter then the exception generated
|
||||
* by the final referral is recorded and presented later.
|
||||
* <p>
|
||||
* A referral may be skipped or may be retried. For example, in the case
|
||||
* of an authentication error, a referral may be retried with different
|
||||
* environment properties.
|
||||
* <p>
|
||||
* An <tt>LdapReferralException</tt> object may also contain a reference
|
||||
* to a chain of unprocessed <tt>LdapReferralException</tt> objects.
|
||||
* Once the current set of referrals have been exhausted and unprocessed
|
||||
* <tt>LdapReferralException</tt> objects remain, then the
|
||||
* <tt>LdapReferralException</tt> object referenced by the current
|
||||
* object is thrown and the cycle continues.
|
||||
* <p>
|
||||
* If new <tt>LdapReferralException</tt> objects are generated while
|
||||
* following an existing referral then these new objects are appended
|
||||
* to the end of the chain of unprocessed <tt>LdapReferralException</tt>
|
||||
* objects.
|
||||
* <p>
|
||||
* If an exception was recorded while processing a chain of
|
||||
* <tt>LdapReferralException</tt> objects then is is throw once
|
||||
* processing has completed.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class LdapReferralException extends
|
||||
javax.naming.ldap.LdapReferralException {
|
||||
private static final long serialVersionUID = 627059076356906399L;
|
||||
|
||||
// ----------- fields initialized in constructor ---------------
|
||||
private int handleReferrals;
|
||||
private Hashtable<?,?> envprops;
|
||||
private String nextName;
|
||||
private Control[] reqCtls;
|
||||
|
||||
// ----------- fields that have defaults -----------------------
|
||||
private Vector<?> referrals = null; // alternatives,set by setReferralInfo()
|
||||
private int referralIndex = 0; // index into referrals
|
||||
private int referralCount = 0; // count of referrals
|
||||
private boolean foundEntry = false; // will stop when entry is found
|
||||
private boolean skipThisReferral = false;
|
||||
private int hopCount = 1;
|
||||
private NamingException errorEx = null;
|
||||
private String newRdn = null;
|
||||
private boolean debug = false;
|
||||
LdapReferralException nextReferralEx = null; // referral ex. chain
|
||||
|
||||
/**
|
||||
* Constructs a new instance of LdapReferralException.
|
||||
* @param resolvedName The part of the name that has been successfully
|
||||
* resolved.
|
||||
* @param resolvedObj The object to which resolution was successful.
|
||||
* @param remainingName The remaining unresolved portion of the name.
|
||||
* @param explanation Additional detail about this exception.
|
||||
*/
|
||||
LdapReferralException(Name resolvedName,
|
||||
Object resolvedObj,
|
||||
Name remainingName,
|
||||
String explanation,
|
||||
Hashtable<?,?> envprops,
|
||||
String nextName,
|
||||
int handleReferrals,
|
||||
Control[] reqCtls) {
|
||||
|
||||
super(explanation);
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException constructor");
|
||||
|
||||
setResolvedName(resolvedName);
|
||||
setResolvedObj(resolvedObj);
|
||||
setRemainingName(remainingName);
|
||||
this.envprops = envprops;
|
||||
this.nextName = nextName;
|
||||
this.handleReferrals = handleReferrals;
|
||||
|
||||
// If following referral, request controls are passed to referral ctx
|
||||
this.reqCtls =
|
||||
(handleReferrals == LdapClient.LDAP_REF_FOLLOW ||
|
||||
handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME ? reqCtls : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a context at which to continue processing.
|
||||
* The current environment properties are re-used.
|
||||
*/
|
||||
public Context getReferralContext() throws NamingException {
|
||||
return getReferralContext(envprops, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a context at which to continue processing.
|
||||
* The supplied environment properties are used.
|
||||
*/
|
||||
public Context getReferralContext(Hashtable<?,?> newProps) throws
|
||||
NamingException {
|
||||
return getReferralContext(newProps, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a context at which to continue processing.
|
||||
* The supplied environment properties and connection controls are used.
|
||||
*/
|
||||
public Context getReferralContext(Hashtable<?,?> newProps, Control[] connCtls)
|
||||
throws NamingException {
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getReferralContext");
|
||||
|
||||
LdapReferralContext refCtx = new LdapReferralContext(
|
||||
this, newProps, connCtls, reqCtls,
|
||||
nextName, skipThisReferral, handleReferrals);
|
||||
|
||||
refCtx.setHopCount(hopCount + 1);
|
||||
|
||||
if (skipThisReferral) {
|
||||
skipThisReferral = false; // reset
|
||||
}
|
||||
return (Context)refCtx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets referral information.
|
||||
*/
|
||||
public Object getReferralInfo() {
|
||||
if (debug) {
|
||||
System.out.println("LdapReferralException.getReferralInfo");
|
||||
System.out.println(" referralIndex=" + referralIndex);
|
||||
}
|
||||
|
||||
if (hasMoreReferrals()) {
|
||||
return referrals.elementAt(referralIndex);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current referral as one to be retried.
|
||||
*/
|
||||
public void retryReferral() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.retryReferral");
|
||||
|
||||
if (referralIndex > 0)
|
||||
referralIndex--; // decrement index
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current referral as one to be ignored.
|
||||
* Returns false when there are no referrals remaining to be processed.
|
||||
*/
|
||||
public boolean skipReferral() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.skipReferral");
|
||||
|
||||
skipThisReferral = true;
|
||||
|
||||
// advance to next referral
|
||||
try {
|
||||
getNextReferral();
|
||||
} catch (ReferralException e) {
|
||||
// mask the referral exception
|
||||
}
|
||||
|
||||
return (hasMoreReferrals() || hasMoreReferralExceptions());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets referral information.
|
||||
*/
|
||||
void setReferralInfo(Vector<?> referrals, boolean continuationRef) {
|
||||
// %%% continuationRef is currently ignored
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setReferralInfo");
|
||||
|
||||
this.referrals = referrals;
|
||||
referralCount = (referrals == null) ? 0 : referrals.size();
|
||||
|
||||
if (debug) {
|
||||
if (referrals != null) {
|
||||
for (int i = 0; i < referralCount; i++) {
|
||||
System.out.println(" [" + i + "] " + referrals.elementAt(i));
|
||||
}
|
||||
} else {
|
||||
System.out.println("setReferralInfo : referrals == null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next referral. When the current set of referrals have
|
||||
* been exhausted then the next referral exception is thrown, if available.
|
||||
*/
|
||||
String getNextReferral() throws ReferralException {
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getNextReferral");
|
||||
|
||||
if (hasMoreReferrals()) {
|
||||
return (String)referrals.elementAt(referralIndex++);
|
||||
} else if (hasMoreReferralExceptions()) {
|
||||
throw nextReferralEx;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the supplied (chain of) referral exception onto the end of
|
||||
* the current (chain of) referral exception. Spent referral exceptions
|
||||
* are trimmed off.
|
||||
*/
|
||||
LdapReferralException
|
||||
appendUnprocessedReferrals(LdapReferralException back) {
|
||||
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"LdapReferralException.appendUnprocessedReferrals");
|
||||
dump();
|
||||
if (back != null) {
|
||||
back.dump();
|
||||
}
|
||||
}
|
||||
|
||||
LdapReferralException front = this;
|
||||
|
||||
if (! front.hasMoreReferrals()) {
|
||||
front = nextReferralEx; // trim
|
||||
|
||||
if ((errorEx != null) && (front != null)) {
|
||||
front.setNamingException(errorEx); //advance the saved exception
|
||||
}
|
||||
}
|
||||
|
||||
// don't append onto itself
|
||||
if (this == back) {
|
||||
return front;
|
||||
}
|
||||
|
||||
if ((back != null) && (! back.hasMoreReferrals())) {
|
||||
back = back.nextReferralEx; // trim
|
||||
}
|
||||
|
||||
if (back == null) {
|
||||
return front;
|
||||
}
|
||||
|
||||
// Locate the end of the current chain
|
||||
LdapReferralException ptr = front;
|
||||
while (ptr.nextReferralEx != null) {
|
||||
ptr = ptr.nextReferralEx;
|
||||
}
|
||||
ptr.nextReferralEx = back; // append
|
||||
|
||||
return front;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there are any referrals remaining to be processed.
|
||||
* If name resolution has already completed then any remaining
|
||||
* referrals (in the current referral exception) will be ignored.
|
||||
*/
|
||||
boolean hasMoreReferrals() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.hasMoreReferrals");
|
||||
|
||||
return (! foundEntry) && (referralIndex < referralCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there are any referral exceptions remaining to be processed.
|
||||
*/
|
||||
boolean hasMoreReferralExceptions() {
|
||||
if (debug)
|
||||
System.out.println(
|
||||
"LdapReferralException.hasMoreReferralExceptions");
|
||||
|
||||
return (nextReferralEx != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the counter which records the number of hops that result
|
||||
* from following a sequence of referrals.
|
||||
*/
|
||||
void setHopCount(int hopCount) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setHopCount");
|
||||
|
||||
this.hopCount = hopCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to indicate that the target name has been resolved.
|
||||
*/
|
||||
void setNameResolved(boolean resolved) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setNameResolved");
|
||||
|
||||
foundEntry = resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exception generated while processing a referral.
|
||||
* Only the first exception is recorded.
|
||||
*/
|
||||
void setNamingException(NamingException e) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setNamingException");
|
||||
|
||||
if (errorEx == null) {
|
||||
e.setRootCause(this); //record the referral exception that caused it
|
||||
errorEx = e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new RDN name.
|
||||
*/
|
||||
String getNewRdn() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getNewRdn");
|
||||
|
||||
return newRdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new RDN name so that the rename operation can be completed
|
||||
* (when a referral is being followed).
|
||||
*/
|
||||
void setNewRdn(String newRdn) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setNewRdn");
|
||||
|
||||
this.newRdn = newRdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception generated while processing a referral.
|
||||
*/
|
||||
NamingException getNamingException() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getNamingException");
|
||||
|
||||
return errorEx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the state of each element in a chain of LdapReferralException
|
||||
* objects.
|
||||
*/
|
||||
void dump() {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("LdapReferralException.dump");
|
||||
LdapReferralException ptr = this;
|
||||
while (ptr != null) {
|
||||
ptr.dumpState();
|
||||
ptr = ptr.nextReferralEx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the state of this LdapReferralException object.
|
||||
*/
|
||||
private void dumpState() {
|
||||
System.out.println("LdapReferralException.dumpState");
|
||||
System.out.println(" hashCode=" + hashCode());
|
||||
System.out.println(" foundEntry=" + foundEntry);
|
||||
System.out.println(" skipThisReferral=" + skipThisReferral);
|
||||
System.out.println(" referralIndex=" + referralIndex);
|
||||
|
||||
if (referrals != null) {
|
||||
System.out.println(" referrals:");
|
||||
for (int i = 0; i < referralCount; i++) {
|
||||
System.out.println(" [" + i + "] " + referrals.elementAt(i));
|
||||
}
|
||||
} else {
|
||||
System.out.println(" referrals=null");
|
||||
}
|
||||
|
||||
System.out.println(" errorEx=" + errorEx);
|
||||
|
||||
if (nextReferralEx == null) {
|
||||
System.out.println(" nextRefEx=null");
|
||||
} else {
|
||||
System.out.println(" nextRefEx=" + nextReferralEx.hashCode());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
141
jdkSrc/jdk8/com/sun/jndi/ldap/LdapRequest.java
Normal file
141
jdkSrc/jdk8/com/sun/jndi/ldap/LdapRequest.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
final class LdapRequest {
|
||||
|
||||
private final static BerDecoder EOF = new BerDecoder(new byte[]{}, -1, 0);
|
||||
private final static String CLOSE_MSG = "LDAP connection has been closed";
|
||||
private final static String TIMEOUT_MSG_FMT = "LDAP response read timed out, timeout used: %d ms.";
|
||||
|
||||
LdapRequest next; // Set/read in synchronized Connection methods
|
||||
final int msgId; // read-only
|
||||
|
||||
private final BlockingQueue<BerDecoder> replies;
|
||||
private volatile boolean cancelled;
|
||||
private volatile boolean closed;
|
||||
private volatile boolean completed;
|
||||
private final boolean pauseAfterReceipt;
|
||||
|
||||
LdapRequest(int msgId, boolean pause, int replyQueueCapacity) {
|
||||
this.msgId = msgId;
|
||||
this.pauseAfterReceipt = pause;
|
||||
if (replyQueueCapacity == -1) {
|
||||
this.replies = new LinkedBlockingQueue<>();
|
||||
} else {
|
||||
this.replies = new LinkedBlockingQueue<>(8 * replyQueueCapacity / 10);
|
||||
}
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
cancelled = true;
|
||||
replies.offer(EOF);
|
||||
}
|
||||
|
||||
synchronized void close() {
|
||||
closed = true;
|
||||
replies.offer(EOF);
|
||||
}
|
||||
|
||||
private boolean isClosed() {
|
||||
return closed && (replies.size() == 0 || replies.peek() == EOF);
|
||||
}
|
||||
|
||||
synchronized boolean addReplyBer(BerDecoder ber) {
|
||||
// check the closed boolean value here as we don't want anything
|
||||
// to be added to the queue after close() has been called.
|
||||
if (cancelled || closed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// peek at the BER buffer to check if it is a SearchResultDone PDU
|
||||
try {
|
||||
ber.parseSeq(null);
|
||||
ber.parseInt();
|
||||
completed = (ber.peekByte() == LdapClient.LDAP_REP_RESULT);
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
ber.reset();
|
||||
|
||||
// Add a new reply to the queue of unprocessed replies.
|
||||
try {
|
||||
replies.put(ber);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return pauseAfterReceipt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read reply BER
|
||||
* @param millis timeout, infinite if the value is negative
|
||||
* @return BerDecoder if reply was read successfully
|
||||
* @throws CommunicationException request has been canceled and request does not need to be abandoned
|
||||
* @throws NamingException request has been closed or timed out. Request does need to be abandoned
|
||||
* @throws InterruptedException LDAP operation has been interrupted
|
||||
*/
|
||||
BerDecoder getReplyBer(long millis) throws NamingException,
|
||||
InterruptedException {
|
||||
if (cancelled) {
|
||||
throw new CommunicationException("Request: " + msgId +
|
||||
" cancelled");
|
||||
}
|
||||
if (isClosed()) {
|
||||
throw new NamingException(CLOSE_MSG);
|
||||
}
|
||||
|
||||
BerDecoder result = millis > 0 ?
|
||||
replies.poll(millis, TimeUnit.MILLISECONDS) : replies.take();
|
||||
|
||||
if (cancelled) {
|
||||
throw new CommunicationException("Request: " + msgId +
|
||||
" cancelled");
|
||||
}
|
||||
|
||||
// poll from 'replies' blocking queue ended-up with timeout
|
||||
if (result == null) {
|
||||
throw new NamingException(String.format(TIMEOUT_MSG_FMT, millis));
|
||||
}
|
||||
// Unexpected EOF can be caused by connection closure or cancellation
|
||||
if (result == EOF) {
|
||||
throw new NamingException(CLOSE_MSG);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean hasSearchCompleted() {
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
82
jdkSrc/jdk8/com/sun/jndi/ldap/LdapResult.java
Normal file
82
jdkSrc/jdk8/com/sun/jndi/ldap/LdapResult.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Vector;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* %%% public for use by LdapSasl %%%
|
||||
*/
|
||||
public final class LdapResult {
|
||||
int msgId;
|
||||
public int status; // %%% public for use by LdapSasl
|
||||
String matchedDN;
|
||||
String errorMessage;
|
||||
// Vector<String | Vector<String>>
|
||||
Vector<Vector<String>> referrals = null;
|
||||
LdapReferralException refEx = null;
|
||||
Vector<LdapEntry> entries = null;
|
||||
Vector<Control> resControls = null;
|
||||
public byte[] serverCreds = null; // %%% public for use by LdapSasl
|
||||
String extensionId = null; // string OID
|
||||
byte[] extensionValue = null; // BER OCTET STRING
|
||||
|
||||
|
||||
// This function turns an LdapResult that came from a compare operation
|
||||
// into one that looks like it came from a search operation. This is
|
||||
// useful when the caller asked the context to do a search, but it was
|
||||
// carried out as a compare. In this case, the client still expects a
|
||||
// result that looks like it came from a search.
|
||||
boolean compareToSearchResult(String name) {
|
||||
boolean successful = false;
|
||||
|
||||
switch (status) {
|
||||
case LdapClient.LDAP_COMPARE_TRUE:
|
||||
status = LdapClient.LDAP_SUCCESS;
|
||||
entries = new Vector<>(1,1);
|
||||
Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
|
||||
LdapEntry entry = new LdapEntry( name, attrs );
|
||||
entries.addElement(entry);
|
||||
successful = true;
|
||||
break;
|
||||
|
||||
case LdapClient.LDAP_COMPARE_FALSE:
|
||||
status = LdapClient.LDAP_SUCCESS;
|
||||
entries = new Vector<>(0);
|
||||
successful = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
successful = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
}
|
||||
437
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaCtx.java
Normal file
437
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaCtx.java
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import java.util.Hashtable;
|
||||
import com.sun.jndi.toolkit.dir.HierMemDirCtx;
|
||||
|
||||
/**
|
||||
* This is the class used to implement LDAP's GetSchema call.
|
||||
*
|
||||
* It subclasses HierMemDirContext for most of the functionality. It
|
||||
* overrides functions that cause the schema definitions to change.
|
||||
* In such a case, it write the schema to the LdapServer and (assuming
|
||||
* there are no errors), calls it's superclass's equivalent function.
|
||||
* Thus, the schema tree and the LDAP server's schema attributes are
|
||||
* always in sync.
|
||||
*/
|
||||
|
||||
final class LdapSchemaCtx extends HierMemDirCtx {
|
||||
|
||||
static private final boolean debug = false;
|
||||
|
||||
private static final int LEAF = 0; // schema object (e.g. attribute type defn)
|
||||
private static final int SCHEMA_ROOT = 1; // schema tree root
|
||||
static final int OBJECTCLASS_ROOT = 2; // root of object class subtree
|
||||
static final int ATTRIBUTE_ROOT = 3; // root of attribute type subtree
|
||||
static final int SYNTAX_ROOT = 4; // root of syntax subtree
|
||||
static final int MATCHRULE_ROOT = 5; // root of matching rule subtree
|
||||
static final int OBJECTCLASS = 6; // an object class definition
|
||||
static final int ATTRIBUTE = 7; // an attribute type definition
|
||||
static final int SYNTAX = 8; // a syntax definition
|
||||
static final int MATCHRULE = 9; // a matching rule definition
|
||||
|
||||
private SchemaInfo info= null;
|
||||
private boolean setupMode = true;
|
||||
|
||||
private int objectType;
|
||||
|
||||
static DirContext createSchemaTree(Hashtable<String,Object> env,
|
||||
String subschemasubentry, LdapCtx schemaEntry,
|
||||
Attributes schemaAttrs, boolean netscapeBug)
|
||||
throws NamingException {
|
||||
try {
|
||||
LdapSchemaParser parser = new LdapSchemaParser(netscapeBug);
|
||||
|
||||
SchemaInfo allinfo = new SchemaInfo(subschemasubentry,
|
||||
schemaEntry, parser);
|
||||
|
||||
LdapSchemaCtx root = new LdapSchemaCtx(SCHEMA_ROOT, env, allinfo);
|
||||
LdapSchemaParser.LDAP2JNDISchema(schemaAttrs, root);
|
||||
return root;
|
||||
} catch (NamingException e) {
|
||||
schemaEntry.close(); // cleanup
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by createNewCtx
|
||||
private LdapSchemaCtx(int objectType, Hashtable<String,Object> environment,
|
||||
SchemaInfo info) {
|
||||
super(environment, LdapClient.caseIgnore);
|
||||
|
||||
this.objectType = objectType;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
// override HierMemDirCtx.close to prevent premature GC of shared data
|
||||
public void close() throws NamingException {
|
||||
info.close();
|
||||
}
|
||||
|
||||
// override to ignore obj and use attrs
|
||||
// treat same as createSubcontext
|
||||
final public void bind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (!setupMode) {
|
||||
if (obj != null) {
|
||||
throw new IllegalArgumentException("obj must be null");
|
||||
}
|
||||
|
||||
// Update server
|
||||
addServerSchema(attrs);
|
||||
}
|
||||
|
||||
// Update in-memory copy
|
||||
LdapSchemaCtx newEntry =
|
||||
(LdapSchemaCtx)super.doCreateSubcontext(name, attrs);
|
||||
}
|
||||
|
||||
final protected void doBind(Name name, Object obj, Attributes attrs,
|
||||
boolean useFactory) throws NamingException {
|
||||
if (!setupMode) {
|
||||
throw new SchemaViolationException(
|
||||
"Cannot bind arbitrary object; use createSubcontext()");
|
||||
} else {
|
||||
super.doBind(name, obj, attrs, false); // always ignore factories
|
||||
}
|
||||
}
|
||||
|
||||
// override to use bind() instead
|
||||
final public void rebind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
try {
|
||||
doLookup(name, false);
|
||||
throw new SchemaViolationException(
|
||||
"Cannot replace existing schema object");
|
||||
} catch (NameNotFoundException e) {
|
||||
bind(name, obj, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
final protected void doRebind(Name name, Object obj, Attributes attrs,
|
||||
boolean useFactory) throws NamingException {
|
||||
if (!setupMode) {
|
||||
throw new SchemaViolationException(
|
||||
"Cannot bind arbitrary object; use createSubcontext()");
|
||||
} else {
|
||||
super.doRebind(name, obj, attrs, false); // always ignore factories
|
||||
}
|
||||
}
|
||||
|
||||
final protected void doUnbind(Name name) throws NamingException {
|
||||
if (!setupMode) {
|
||||
// Update server
|
||||
try {
|
||||
// Lookup entry from memory
|
||||
LdapSchemaCtx target = (LdapSchemaCtx)doLookup(name, false);
|
||||
|
||||
deleteServerSchema(target.attrs);
|
||||
} catch (NameNotFoundException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Update in-memory copy
|
||||
super.doUnbind(name);
|
||||
}
|
||||
|
||||
final protected void doRename(Name oldname, Name newname)
|
||||
throws NamingException {
|
||||
if (!setupMode) {
|
||||
throw new SchemaViolationException("Cannot rename a schema object");
|
||||
} else {
|
||||
super.doRename(oldname, newname);
|
||||
}
|
||||
}
|
||||
|
||||
final protected void doDestroySubcontext(Name name) throws NamingException {
|
||||
if (!setupMode) {
|
||||
// Update server
|
||||
try {
|
||||
// Lookup entry from memory
|
||||
LdapSchemaCtx target = (LdapSchemaCtx)doLookup(name, false);
|
||||
|
||||
deleteServerSchema(target.attrs);
|
||||
} catch (NameNotFoundException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update in-memory copy
|
||||
super.doDestroySubcontext(name);
|
||||
}
|
||||
|
||||
// Called to create oc, attr, syntax or matching rule roots and leaf entries
|
||||
final LdapSchemaCtx setup(int objectType, String name, Attributes attrs)
|
||||
throws NamingException{
|
||||
try {
|
||||
setupMode = true;
|
||||
LdapSchemaCtx answer =
|
||||
(LdapSchemaCtx) super.doCreateSubcontext(
|
||||
new CompositeName(name), attrs);
|
||||
|
||||
answer.objectType = objectType;
|
||||
answer.setupMode = false;
|
||||
return answer;
|
||||
} finally {
|
||||
setupMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
final protected DirContext doCreateSubcontext(Name name, Attributes attrs)
|
||||
throws NamingException {
|
||||
|
||||
if (attrs == null || attrs.size() == 0) {
|
||||
throw new SchemaViolationException(
|
||||
"Must supply attributes describing schema");
|
||||
}
|
||||
|
||||
if (!setupMode) {
|
||||
// Update server
|
||||
addServerSchema(attrs);
|
||||
}
|
||||
|
||||
// Update in-memory copy
|
||||
LdapSchemaCtx newEntry =
|
||||
(LdapSchemaCtx) super.doCreateSubcontext(name, attrs);
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
final private static Attributes deepClone(Attributes orig)
|
||||
throws NamingException {
|
||||
BasicAttributes copy = new BasicAttributes(true);
|
||||
NamingEnumeration<? extends Attribute> attrs = orig.getAll();
|
||||
while (attrs.hasMore()) {
|
||||
copy.put((Attribute)attrs.next().clone());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
final protected void doModifyAttributes(ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
if (setupMode) {
|
||||
super.doModifyAttributes(mods);
|
||||
} else {
|
||||
Attributes copy = deepClone(attrs);
|
||||
|
||||
// Apply modifications to copy
|
||||
applyMods(mods, copy);
|
||||
|
||||
// Update server copy
|
||||
modifyServerSchema(attrs, copy);
|
||||
|
||||
// Update in-memory copy
|
||||
attrs = copy;
|
||||
}
|
||||
}
|
||||
|
||||
// we override this so the superclass creates the right kind of contexts
|
||||
// Default is to create LEAF objects; caller will change after creation
|
||||
// if necessary
|
||||
final protected HierMemDirCtx createNewCtx() {
|
||||
LdapSchemaCtx ctx = new LdapSchemaCtx(LEAF, myEnv, info);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
final private void addServerSchema(Attributes attrs)
|
||||
throws NamingException {
|
||||
Attribute schemaAttr;
|
||||
|
||||
switch (objectType) {
|
||||
case OBJECTCLASS_ROOT:
|
||||
schemaAttr = info.parser.stringifyObjDesc(attrs);
|
||||
break;
|
||||
|
||||
case ATTRIBUTE_ROOT:
|
||||
schemaAttr = info.parser.stringifyAttrDesc(attrs);
|
||||
break;
|
||||
|
||||
case SYNTAX_ROOT:
|
||||
schemaAttr = info.parser.stringifySyntaxDesc(attrs);
|
||||
break;
|
||||
|
||||
case MATCHRULE_ROOT:
|
||||
schemaAttr = info.parser.stringifyMatchRuleDesc(attrs);
|
||||
break;
|
||||
|
||||
case SCHEMA_ROOT:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot create new entry under schema root");
|
||||
|
||||
default:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot create child of schema object");
|
||||
}
|
||||
|
||||
Attributes holder = new BasicAttributes(true);
|
||||
holder.put(schemaAttr);
|
||||
//System.err.println((String)schemaAttr.get());
|
||||
|
||||
info.modifyAttributes(myEnv, DirContext.ADD_ATTRIBUTE, holder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When we delete an entry, we use the original to make sure that
|
||||
* any formatting inconsistencies are eliminated.
|
||||
* This is because we're just deleting a value from an attribute
|
||||
* on the server and there might not be any checks for extra spaces
|
||||
* or parens.
|
||||
*/
|
||||
final private void deleteServerSchema(Attributes origAttrs)
|
||||
throws NamingException {
|
||||
|
||||
Attribute origAttrVal;
|
||||
|
||||
switch (objectType) {
|
||||
case OBJECTCLASS_ROOT:
|
||||
origAttrVal = info.parser.stringifyObjDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case ATTRIBUTE_ROOT:
|
||||
origAttrVal = info.parser.stringifyAttrDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case SYNTAX_ROOT:
|
||||
origAttrVal = info.parser.stringifySyntaxDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case MATCHRULE_ROOT:
|
||||
origAttrVal = info.parser.stringifyMatchRuleDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case SCHEMA_ROOT:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot delete schema root");
|
||||
|
||||
default:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot delete child of schema object");
|
||||
}
|
||||
|
||||
ModificationItem[] mods = new ModificationItem[1];
|
||||
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, origAttrVal);
|
||||
|
||||
info.modifyAttributes(myEnv, mods);
|
||||
}
|
||||
|
||||
/**
|
||||
* When we modify an entry, we use the original attribute value
|
||||
* in the schema to make sure that any formatting inconsistencies
|
||||
* are eliminated. A modification is done by deleting the original
|
||||
* value and adding a new value with the modification.
|
||||
*/
|
||||
final private void modifyServerSchema(Attributes origAttrs,
|
||||
Attributes newAttrs) throws NamingException {
|
||||
|
||||
Attribute newAttrVal;
|
||||
Attribute origAttrVal;
|
||||
|
||||
switch (objectType) {
|
||||
case OBJECTCLASS:
|
||||
origAttrVal = info.parser.stringifyObjDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifyObjDesc(newAttrs);
|
||||
break;
|
||||
|
||||
case ATTRIBUTE:
|
||||
origAttrVal = info.parser.stringifyAttrDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifyAttrDesc(newAttrs);
|
||||
break;
|
||||
|
||||
case SYNTAX:
|
||||
origAttrVal = info.parser.stringifySyntaxDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifySyntaxDesc(newAttrs);
|
||||
break;
|
||||
|
||||
case MATCHRULE:
|
||||
origAttrVal = info.parser.stringifyMatchRuleDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifyMatchRuleDesc(newAttrs);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot modify schema root");
|
||||
}
|
||||
|
||||
ModificationItem[] mods = new ModificationItem[2];
|
||||
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, origAttrVal);
|
||||
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, newAttrVal);
|
||||
|
||||
info.modifyAttributes(myEnv, mods);
|
||||
}
|
||||
|
||||
final static private class SchemaInfo {
|
||||
private LdapCtx schemaEntry;
|
||||
private String schemaEntryName;
|
||||
LdapSchemaParser parser;
|
||||
private String host;
|
||||
private int port;
|
||||
private boolean hasLdapsScheme;
|
||||
|
||||
SchemaInfo(String schemaEntryName, LdapCtx schemaEntry,
|
||||
LdapSchemaParser parser) {
|
||||
this.schemaEntryName = schemaEntryName;
|
||||
this.schemaEntry = schemaEntry;
|
||||
this.parser = parser;
|
||||
this.port = schemaEntry.port_number;
|
||||
this.host = schemaEntry.hostname;
|
||||
this.hasLdapsScheme = schemaEntry.hasLdapsScheme;
|
||||
}
|
||||
|
||||
synchronized void close() throws NamingException {
|
||||
if (schemaEntry != null) {
|
||||
schemaEntry.close();
|
||||
schemaEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
private LdapCtx reopenEntry(Hashtable<?,?> env) throws NamingException {
|
||||
// Use subschemasubentry name as DN
|
||||
return new LdapCtx(schemaEntryName, host, port,
|
||||
env, hasLdapsScheme);
|
||||
}
|
||||
|
||||
synchronized void modifyAttributes(Hashtable<?,?> env,
|
||||
ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
if (schemaEntry == null) {
|
||||
schemaEntry = reopenEntry(env);
|
||||
}
|
||||
schemaEntry.modifyAttributes("", mods);
|
||||
}
|
||||
|
||||
synchronized void modifyAttributes(Hashtable<?,?> env, int mod,
|
||||
Attributes attrs) throws NamingException {
|
||||
if (schemaEntry == null) {
|
||||
schemaEntry = reopenEntry(env);
|
||||
}
|
||||
schemaEntry.modifyAttributes("", mod, attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
1303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaParser.java
Normal file
1303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaParser.java
Normal file
File diff suppressed because it is too large
Load Diff
223
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSearchEnumeration.java
Normal file
223
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSearchEnumeration.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.*;
|
||||
import javax.naming.ldap.*;
|
||||
import javax.naming.ldap.LdapName;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
|
||||
final class LdapSearchEnumeration
|
||||
extends AbstractLdapNamingEnumeration<SearchResult> {
|
||||
|
||||
private Name startName; // prefix of names of search results
|
||||
private LdapCtx.SearchArgs searchArgs = null;
|
||||
|
||||
private final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
LdapSearchEnumeration(LdapCtx homeCtx, LdapResult search_results,
|
||||
String starter, LdapCtx.SearchArgs args, Continuation cont)
|
||||
throws NamingException {
|
||||
|
||||
super(homeCtx, search_results,
|
||||
args.name, /* listArg */
|
||||
cont);
|
||||
|
||||
// fully qualified name of starting context of search
|
||||
startName = new LdapName(starter);
|
||||
searchArgs = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SearchResult createItem(String dn, Attributes attrs,
|
||||
Vector<Control> respCtls)
|
||||
throws NamingException {
|
||||
|
||||
Object obj = null;
|
||||
|
||||
String relStart; // name relative to starting search context
|
||||
String relHome; // name relative to homeCtx.currentDN
|
||||
boolean relative = true; // whether relative to currentDN
|
||||
|
||||
// need to strip off all but lowest component of dn
|
||||
// so that is relative to current context (currentDN)
|
||||
|
||||
try {
|
||||
Name parsed = new LdapName(dn);
|
||||
// System.err.println("dn string: " + dn);
|
||||
// System.err.println("dn name: " + parsed);
|
||||
|
||||
if (startName != null && parsed.startsWith(startName)) {
|
||||
relStart = parsed.getSuffix(startName.size()).toString();
|
||||
relHome = parsed.getSuffix(homeCtx.currentParsedDN.size()).toString();
|
||||
} else {
|
||||
relative = false;
|
||||
relHome = relStart =
|
||||
LdapURL.toUrlString(homeCtx.hostname, homeCtx.port_number,
|
||||
dn, homeCtx.hasLdapsScheme);
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
// could not parse name
|
||||
relative = false;
|
||||
relHome = relStart =
|
||||
LdapURL.toUrlString(homeCtx.hostname, homeCtx.port_number,
|
||||
dn, homeCtx.hasLdapsScheme);
|
||||
}
|
||||
|
||||
// Name relative to search context
|
||||
CompositeName cn = new CompositeName();
|
||||
if (!relStart.equals("")) {
|
||||
cn.add(relStart);
|
||||
}
|
||||
|
||||
// Name relative to homeCtx
|
||||
CompositeName rcn = new CompositeName();
|
||||
if (!relHome.equals("")) {
|
||||
rcn.add(relHome);
|
||||
}
|
||||
//System.err.println("relStart: " + cn);
|
||||
//System.err.println("relHome: " + rcn);
|
||||
|
||||
// Fix attributes to be able to get schema
|
||||
homeCtx.setParents(attrs, rcn);
|
||||
|
||||
// only generate object when requested
|
||||
if (searchArgs.cons.getReturningObjFlag()) {
|
||||
|
||||
if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
|
||||
// Entry contains Java-object attributes (ser/ref object)
|
||||
// serialized object or object reference
|
||||
try {
|
||||
obj = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
@Override
|
||||
public Object run() throws NamingException {
|
||||
return Obj.decodeObject(attrs);
|
||||
}
|
||||
}, acc);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (NamingException)e.getException();
|
||||
}
|
||||
}
|
||||
if (obj == null) {
|
||||
obj = new LdapCtx(homeCtx, dn);
|
||||
}
|
||||
|
||||
// Call getObjectInstance before removing unrequested attributes
|
||||
try {
|
||||
// rcn is either relative to homeCtx or a fully qualified DN
|
||||
obj = DirectoryManager.getObjectInstance(
|
||||
obj, rcn, (relative ? homeCtx : null),
|
||||
homeCtx.envprops, attrs);
|
||||
} catch (NamingException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
NamingException ne =
|
||||
new NamingException(
|
||||
"problem generating object using object factory");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// remove Java attributes from result, if necessary
|
||||
// Even if CLASSNAME attr not there, there might be some
|
||||
// residual attributes
|
||||
|
||||
String[] reqAttrs;
|
||||
if ((reqAttrs = searchArgs.reqAttrs) != null) {
|
||||
// create an attribute set for those requested
|
||||
Attributes rattrs = new BasicAttributes(true); // caseignore
|
||||
for (int i = 0; i < reqAttrs.length; i++) {
|
||||
rattrs.put(reqAttrs[i], null);
|
||||
}
|
||||
for (int i = 0; i < Obj.JAVA_ATTRIBUTES.length; i++) {
|
||||
// Remove Java-object attributes if not requested
|
||||
if (rattrs.get(Obj.JAVA_ATTRIBUTES[i]) == null) {
|
||||
attrs.remove(Obj.JAVA_ATTRIBUTES[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* name in search result is either the stringified composite name
|
||||
* relative to the search context that can be passed directly to
|
||||
* methods of the search context, or the fully qualified DN
|
||||
* which can be used with the initial context.
|
||||
*/
|
||||
SearchResult sr;
|
||||
if (respCtls != null) {
|
||||
sr = new SearchResultWithControls(
|
||||
(relative ? cn.toString() : relStart), obj, attrs,
|
||||
relative, homeCtx.convertControls(respCtls));
|
||||
} else {
|
||||
sr = new SearchResult(
|
||||
(relative ? cn.toString() : relStart),
|
||||
obj, attrs, relative);
|
||||
}
|
||||
sr.setNameInNamespace(dn);
|
||||
return sr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendUnprocessedReferrals(LdapReferralException ex) {
|
||||
|
||||
// a referral has been followed so do not create relative names
|
||||
startName = null;
|
||||
super.appendUnprocessedReferrals(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException {
|
||||
// repeat the original operation at the new context
|
||||
return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.search(
|
||||
searchArgs.name, searchArgs.filter, searchArgs.cons);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) {
|
||||
super.update(ne);
|
||||
|
||||
// Update search-specific variables
|
||||
LdapSearchEnumeration se = (LdapSearchEnumeration)ne;
|
||||
startName = se.startName;
|
||||
//VR - keep original args, don't overwite with current args
|
||||
// searchArgs = se.searchArgs;
|
||||
}
|
||||
|
||||
void setStartName(Name nm) {
|
||||
startName = nm;
|
||||
}
|
||||
}
|
||||
336
jdkSrc/jdk8/com/sun/jndi/ldap/LdapURL.java
Normal file
336
jdkSrc/jdk8/com/sun/jndi/ldap/LdapURL.java
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import com.sun.jndi.toolkit.url.Uri;
|
||||
import com.sun.jndi.toolkit.url.UrlUtil;
|
||||
|
||||
/*
|
||||
* Extract components of an LDAP URL.
|
||||
*
|
||||
* The format of an LDAP URL is defined in RFC 2255 as follows:
|
||||
*
|
||||
* ldapurl = scheme "://" [hostport] ["/"
|
||||
* [dn ["?" [attributes] ["?" [scope]
|
||||
* ["?" [filter] ["?" extensions]]]]]]
|
||||
* scheme = "ldap"
|
||||
* attributes = attrdesc *("," attrdesc)
|
||||
* scope = "base" / "one" / "sub"
|
||||
* dn = distinguishedName from Section 3 of [1]
|
||||
* hostport = hostport from Section 5 of RFC 1738 [5]
|
||||
* attrdesc = AttributeDescription from Section 4.1.5 of [2]
|
||||
* filter = filter from Section 4 of [4]
|
||||
* extensions = extension *("," extension)
|
||||
* extension = ["!"] extype ["=" exvalue]
|
||||
* extype = token / xtoken
|
||||
* exvalue = LDAPString from section 4.1.2 of [2]
|
||||
* token = oid from section 4.1 of [3]
|
||||
* xtoken = ("X-" / "x-") token
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
* ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
|
||||
* ldap://host.com:6666/o=IMC,c=US??sub?(cn=Babs%20Jensen)
|
||||
*
|
||||
* This class also supports ldaps URLs.
|
||||
*/
|
||||
|
||||
final public class LdapURL extends Uri {
|
||||
|
||||
private static final String PARSE_MODE_PROP = "com.sun.jndi.ldapURLParsing";
|
||||
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
|
||||
|
||||
public static final ParseMode PARSE_MODE;
|
||||
static {
|
||||
PrivilegedAction<String> action =
|
||||
new GetPropertyAction(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
|
||||
ParseMode parseMode = DEFAULT_PARSE_MODE;
|
||||
try {
|
||||
String mode = AccessController.doPrivileged(action);
|
||||
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
|
||||
} catch (Throwable t) {
|
||||
parseMode = DEFAULT_PARSE_MODE;
|
||||
} finally {
|
||||
PARSE_MODE = parseMode;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useSsl = false;
|
||||
private String DN = null;
|
||||
private String attributes = null;
|
||||
private String scope = null;
|
||||
private String filter = null;
|
||||
private String extensions = null;
|
||||
|
||||
/**
|
||||
* Creates an LdapURL object from an LDAP URL string.
|
||||
*/
|
||||
public LdapURL(String url) throws NamingException {
|
||||
|
||||
super();
|
||||
|
||||
try {
|
||||
init(url); // scheme, host, port, path, query
|
||||
useSsl = scheme.equalsIgnoreCase("ldaps");
|
||||
|
||||
if (! (scheme.equalsIgnoreCase("ldap") || useSsl)) {
|
||||
throw newInvalidURISchemeException(url);
|
||||
}
|
||||
|
||||
parsePathAndQuery(); // DN, attributes, scope, filter, extensions
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
NamingException ne = new NamingException("Cannot parse url: " + url);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
NamingException ne = new NamingException("Cannot parse url: " + url);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MalformedURLException newInvalidURISchemeException(String uri) {
|
||||
return new MalformedURLException("Not an LDAP URL: " + uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSchemeOnly(String uri) {
|
||||
return isLdapSchemeOnly(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParseMode parseMode() {
|
||||
return PARSE_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the URL is an LDAPS URL.
|
||||
*/
|
||||
public boolean useSsl() {
|
||||
return useSsl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's distinguished name.
|
||||
*/
|
||||
public String getDN() {
|
||||
return DN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's attributes.
|
||||
*/
|
||||
public String getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's scope.
|
||||
*/
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's filter.
|
||||
*/
|
||||
public String getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's extensions.
|
||||
*/
|
||||
public String getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a space-separated list of LDAP URLs, returns an array of strings.
|
||||
*/
|
||||
public static String[] fromList(String urlList) throws NamingException {
|
||||
|
||||
String[] urls = new String[(urlList.length() + 1) / 2];
|
||||
int i = 0; // next available index in urls
|
||||
StringTokenizer st = new StringTokenizer(urlList, " ");
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
// we don't accept scheme-only URLs here
|
||||
urls[i++] = validateURI(st.nextToken());
|
||||
}
|
||||
String[] trimmed = new String[i];
|
||||
System.arraycopy(urls, 0, trimmed, 0, i);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public static boolean isLdapSchemeOnly(String uri) {
|
||||
return "ldap:".equals(uri) || "ldaps:".equals(uri);
|
||||
}
|
||||
|
||||
public static String validateURI(String uri) {
|
||||
// no validation in legacy mode parsing
|
||||
if (PARSE_MODE == ParseMode.LEGACY) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
// special case of scheme-only URIs
|
||||
if (isLdapSchemeOnly(uri)) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
// use java.net.URI to validate the uri syntax
|
||||
return URI.create(uri).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derermines whether an LDAP URL has query components.
|
||||
*/
|
||||
public static boolean hasQueryComponents(String url) {
|
||||
return (url.lastIndexOf('?') != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assembles an LDAP or LDAPS URL string from its components.
|
||||
* If "host" is an IPv6 literal, it may optionally include delimiting
|
||||
* brackets.
|
||||
*/
|
||||
static String toUrlString(String host, int port, String dn, boolean useSsl)
|
||||
{
|
||||
|
||||
try {
|
||||
String h = (host != null) ? host : "";
|
||||
if ((h.indexOf(':') != -1) && (h.charAt(0) != '[')) {
|
||||
h = "[" + h + "]"; // IPv6 literal
|
||||
}
|
||||
String p = (port != -1) ? (":" + port) : "";
|
||||
String d = (dn != null) ? ("/" + UrlUtil.encode(dn, "UTF8")) : "";
|
||||
|
||||
String uri = useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
|
||||
return validateURI(uri);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// UTF8 should always be supported
|
||||
throw new IllegalStateException("UTF-8 encoding unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the path and query components of an URL and sets this
|
||||
* object's fields accordingly.
|
||||
*/
|
||||
private void parsePathAndQuery() throws MalformedURLException,
|
||||
UnsupportedEncodingException {
|
||||
|
||||
// path begins with a '/' or is empty
|
||||
|
||||
if (path.equals("")) {
|
||||
return;
|
||||
}
|
||||
|
||||
DN = path.startsWith("/") ? path.substring(1) : path;
|
||||
if (DN.length() > 0) {
|
||||
DN = UrlUtil.decode(DN, "UTF8");
|
||||
}
|
||||
|
||||
// query begins with a '?' or is null
|
||||
|
||||
if (query == null || query.length() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
int currentIndex = 1;
|
||||
int nextQmark;
|
||||
int endIndex;
|
||||
|
||||
// attributes:
|
||||
nextQmark = query.indexOf('?', currentIndex);
|
||||
endIndex = nextQmark == -1 ? query.length() : nextQmark;
|
||||
if (endIndex - currentIndex > 0) {
|
||||
attributes = query.substring(currentIndex, endIndex);
|
||||
}
|
||||
currentIndex = endIndex + 1;
|
||||
if (currentIndex >= query.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scope:
|
||||
nextQmark = query.indexOf('?', currentIndex);
|
||||
endIndex = nextQmark == -1 ? query.length() : nextQmark;
|
||||
if (endIndex - currentIndex > 0) {
|
||||
scope = query.substring(currentIndex, endIndex);
|
||||
}
|
||||
currentIndex = endIndex + 1;
|
||||
if (currentIndex >= query.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// filter:
|
||||
nextQmark = query.indexOf('?', currentIndex);
|
||||
endIndex = nextQmark == -1 ? query.length() : nextQmark;
|
||||
if (endIndex - currentIndex > 0) {
|
||||
filter = query.substring(currentIndex, endIndex);
|
||||
filter = UrlUtil.decode(filter, "UTF8");
|
||||
}
|
||||
currentIndex = endIndex + 1;
|
||||
if (currentIndex >= query.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// extensions:
|
||||
if (query.length() - currentIndex > 0) {
|
||||
extensions = query.substring(currentIndex);
|
||||
extensions = UrlUtil.decode(extensions, "UTF8");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
LdapURL url = new LdapURL(args[0]);
|
||||
|
||||
System.out.println("Example LDAP URL: " + url.toString());
|
||||
System.out.println(" scheme: " + url.getScheme());
|
||||
System.out.println(" host: " + url.getHost());
|
||||
System.out.println(" port: " + url.getPort());
|
||||
System.out.println(" DN: " + url.getDN());
|
||||
System.out.println(" attrs: " + url.getAttributes());
|
||||
System.out.println(" scope: " + url.getScope());
|
||||
System.out.println(" filter: " + url.getFilter());
|
||||
System.out.println(" extens: " + url.getExtensions());
|
||||
System.out.println("");
|
||||
}
|
||||
*/
|
||||
}
|
||||
66
jdkSrc/jdk8/com/sun/jndi/ldap/ManageReferralControl.java
Normal file
66
jdkSrc/jdk8/com/sun/jndi/ldap/ManageReferralControl.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Request Control for manageDsaIT as
|
||||
* defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-namedref-00.txt">draft-ietf-ldapext-namedref-00.txt</a>.
|
||||
*
|
||||
* The control has no control value.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class ManageReferralControl extends BasicControl {
|
||||
|
||||
/**
|
||||
* The manage referral control's assigned object identifier
|
||||
* is 2.16.840.1.113730.3.4.2.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
public static final String OID = "2.16.840.1.113730.3.4.2";
|
||||
|
||||
private static final long serialVersionUID = 909382692585717224L;
|
||||
|
||||
/**
|
||||
* Constructs a manage referral critical control.
|
||||
*/
|
||||
public ManageReferralControl() {
|
||||
super(OID, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a manage referral control.
|
||||
*
|
||||
* @param criticality The control's criticality setting.
|
||||
*/
|
||||
public ManageReferralControl(boolean criticality) {
|
||||
super(OID, criticality, null);
|
||||
}
|
||||
}
|
||||
45
jdkSrc/jdk8/com/sun/jndi/ldap/NameClassPairWithControls.java
Normal file
45
jdkSrc/jdk8/com/sun/jndi/ldap/NameClassPairWithControls.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
class NameClassPairWithControls extends NameClassPair implements HasControls {
|
||||
private Control[] controls;
|
||||
|
||||
public NameClassPairWithControls(String name, String className,
|
||||
Control[] controls) {
|
||||
super(name, className);
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 2010738921219112944L;
|
||||
}
|
||||
287
jdkSrc/jdk8/com/sun/jndi/ldap/NamingEventNotifier.java
Normal file
287
jdkSrc/jdk8/com/sun/jndi/ldap/NamingEventNotifier.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.event.*;
|
||||
import javax.naming.ldap.*;
|
||||
import javax.naming.ldap.LdapName;
|
||||
|
||||
import java.util.Vector;
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
|
||||
/**
|
||||
* Gathers information to generate events by using the Persistent Search
|
||||
* control.
|
||||
*<p>
|
||||
* This class maintains a list of listeners all interested in the same
|
||||
* "search" request. It creates a thread that does the persistent search
|
||||
* and blocks, collecting the results of the search.
|
||||
* For each result that it receives from the search, it fires the
|
||||
* corresponding event to its listeners. If an exception is encountered,
|
||||
* it fires a NamingExceptionEvent.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class NamingEventNotifier implements Runnable {
|
||||
private final static boolean debug = false;
|
||||
|
||||
private Vector<NamingListener> namingListeners;
|
||||
private Thread worker;
|
||||
private LdapCtx context;
|
||||
private EventContext eventSrc;
|
||||
private EventSupport support;
|
||||
private NamingEnumeration<SearchResult> results;
|
||||
|
||||
// package private; used by EventSupport to remove it
|
||||
NotifierArgs info;
|
||||
|
||||
NamingEventNotifier(EventSupport support, LdapCtx ctx, NotifierArgs info,
|
||||
NamingListener firstListener) throws NamingException {
|
||||
this.info = info;
|
||||
this.support = support;
|
||||
|
||||
Control psearch;
|
||||
try {
|
||||
psearch = new PersistentSearchControl(
|
||||
info.mask,
|
||||
true /* no info about original entry(s) */,
|
||||
true /* additional info about changes */,
|
||||
Control.CRITICAL);
|
||||
} catch (java.io.IOException e) {
|
||||
NamingException ne = new NamingException(
|
||||
"Problem creating persistent search control");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// Add psearch control to existing list
|
||||
context = (LdapCtx)ctx.newInstance(new Control[]{psearch});
|
||||
eventSrc = ctx;
|
||||
|
||||
namingListeners = new Vector<>();
|
||||
namingListeners.addElement(firstListener);
|
||||
|
||||
worker = Obj.helper.createThread(this);
|
||||
worker.setDaemon(true); // not a user thread
|
||||
worker.start();
|
||||
}
|
||||
|
||||
// package private; used by EventSupport; namingListener already synchronized
|
||||
void addNamingListener(NamingListener l) {
|
||||
namingListeners.addElement(l);
|
||||
}
|
||||
|
||||
// package private; used by EventSupport; namingListener already synchronized
|
||||
void removeNamingListener(NamingListener l) {
|
||||
namingListeners.removeElement(l);
|
||||
}
|
||||
|
||||
// package private; used by EventSupport; namingListener already synchronized
|
||||
boolean hasNamingListeners() {
|
||||
return namingListeners.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute "persistent search".
|
||||
* For each result, create the appropriate NamingEvent and
|
||||
* queue to be dispatched to listeners.
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
Continuation cont = new Continuation();
|
||||
cont.setError(this, info.name);
|
||||
Name nm = (info.name == null || info.name.equals("")) ?
|
||||
new CompositeName() : new CompositeName().add(info.name);
|
||||
|
||||
results = context.searchAux(nm, info.filter, info.controls,
|
||||
true, false, cont);
|
||||
|
||||
// Change root of search results so that it will generate
|
||||
// names relative to the event context instead of that
|
||||
// named by nm
|
||||
((LdapSearchEnumeration)(NamingEnumeration)results)
|
||||
.setStartName(context.currentParsedDN);
|
||||
|
||||
SearchResult si;
|
||||
Control[] respctls;
|
||||
EntryChangeResponseControl ec;
|
||||
long changeNum;
|
||||
|
||||
while (results.hasMore()) {
|
||||
si = results.next();
|
||||
respctls = (si instanceof HasControls) ?
|
||||
((HasControls) si).getControls() : null;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("notifier: " + si);
|
||||
System.err.println("respCtls: " + respctls);
|
||||
}
|
||||
|
||||
// Just process ECs; ignore all the rest
|
||||
if (respctls != null) {
|
||||
for (int i = 0; i < respctls.length; i++) {
|
||||
// %%% Should be checking OID instead of class
|
||||
// %%% in case using someone else's EC ctl
|
||||
if (respctls[i] instanceof EntryChangeResponseControl) {
|
||||
ec = (EntryChangeResponseControl)respctls[i];
|
||||
changeNum = ec.getChangeNumber();
|
||||
switch (ec.getChangeType()) {
|
||||
case EntryChangeResponseControl.ADD:
|
||||
fireObjectAdded(si, changeNum);
|
||||
break;
|
||||
case EntryChangeResponseControl.DELETE:
|
||||
fireObjectRemoved(si, changeNum);
|
||||
break;
|
||||
case EntryChangeResponseControl.MODIFY:
|
||||
fireObjectChanged(si, changeNum);
|
||||
break;
|
||||
case EntryChangeResponseControl.RENAME:
|
||||
fireObjectRenamed(si, ec.getPreviousDN(),
|
||||
changeNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedNamingException e) {
|
||||
if (debug) System.err.println("NamingEventNotifier Interrupted");
|
||||
} catch (NamingException e) {
|
||||
// Fire event to notify NamingExceptionEvent listeners
|
||||
fireNamingException(e);
|
||||
|
||||
// This notifier is no longer valid
|
||||
support.removeDeadNotifier(info);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
if (debug) System.err.println("NamingEventNotifier finished");
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
if (debug) System.err.println("NamingEventNotifier cleanup");
|
||||
|
||||
try {
|
||||
if (results != null) {
|
||||
if (debug) System.err.println("NamingEventNotifier enum closing");
|
||||
results.close(); // this will abandon the search
|
||||
results = null;
|
||||
}
|
||||
if (context != null) {
|
||||
if (debug) System.err.println("NamingEventNotifier ctx closing");
|
||||
context.close();
|
||||
context = null;
|
||||
}
|
||||
} catch (NamingException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the dispatcher so we can be destroyed.
|
||||
* package private; used by EventSupport
|
||||
*/
|
||||
void stop() {
|
||||
if (debug) System.err.println("NamingEventNotifier being stopping");
|
||||
if (worker != null) {
|
||||
worker.interrupt(); // kill our thread
|
||||
worker = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an "object added" event to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectAdded(Binding newBd, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
NamingEvent e = new NamingEvent(eventSrc, NamingEvent.OBJECT_ADDED,
|
||||
newBd, null, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an "object removed" event to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectRemoved(Binding oldBd, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
NamingEvent e = new NamingEvent(eventSrc, NamingEvent.OBJECT_REMOVED,
|
||||
null, oldBd, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires an "object changed" event to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectChanged(Binding newBd, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
// Name hasn't changed; construct old binding using name from new binding
|
||||
Binding oldBd = new Binding(newBd.getName(), null, newBd.isRelative());
|
||||
|
||||
NamingEvent e = new NamingEvent(
|
||||
eventSrc, NamingEvent.OBJECT_CHANGED, newBd, oldBd, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires an "object renamed" to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectRenamed(Binding newBd, String oldDN, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
Binding oldBd = null;
|
||||
try {
|
||||
LdapName dn = new LdapName(oldDN);
|
||||
if (dn.startsWith(context.currentParsedDN)) {
|
||||
String relDN = dn.getSuffix(context.currentParsedDN.size()).toString();
|
||||
oldBd = new Binding(relDN, null);
|
||||
}
|
||||
} catch (NamingException e) {}
|
||||
|
||||
if (oldBd == null) {
|
||||
oldBd = new Binding(oldDN, null, false /* not relative name */);
|
||||
}
|
||||
|
||||
NamingEvent e = new NamingEvent(
|
||||
eventSrc, NamingEvent.OBJECT_RENAMED, newBd, oldBd, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
private void fireNamingException(NamingException e) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
NamingExceptionEvent evt = new NamingExceptionEvent(eventSrc, e);
|
||||
support.queueEvent(evt, namingListeners);
|
||||
}
|
||||
}
|
||||
149
jdkSrc/jdk8/com/sun/jndi/ldap/NotifierArgs.java
Normal file
149
jdkSrc/jdk8/com/sun/jndi/ldap/NotifierArgs.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.event.*;
|
||||
|
||||
/**
|
||||
* This class holds the information in an event registration/deregistration
|
||||
* request. This includes the name, filter, search controls and
|
||||
* the different interfaces that the listener implements. This last piece
|
||||
* of information determines which event(s) the listener is interested in.
|
||||
*<p>
|
||||
* It overrides equals() and hashCode() to use all these pieces of
|
||||
* information so that it can be used correctly in a hashtable.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class NotifierArgs {
|
||||
static final int ADDED_MASK = 0x1;
|
||||
static final int REMOVED_MASK = 0x2;
|
||||
static final int CHANGED_MASK = 0x4;
|
||||
static final int RENAMED_MASK = 0x8;
|
||||
|
||||
// these fields are package private; used by NamingEventNotifier
|
||||
String name;
|
||||
String filter;
|
||||
SearchControls controls;
|
||||
int mask;
|
||||
|
||||
// package private
|
||||
NotifierArgs(String name, int scope, NamingListener l) {
|
||||
this(name, "(objectclass=*)", null, l);
|
||||
|
||||
// if scope is not default, create search ctl and set it
|
||||
if (scope != EventContext.ONELEVEL_SCOPE) {
|
||||
controls = new SearchControls();
|
||||
controls.setSearchScope(scope);
|
||||
}
|
||||
}
|
||||
|
||||
// package private
|
||||
NotifierArgs(String name, String filter, SearchControls ctls,
|
||||
NamingListener l) {
|
||||
this.name = name;
|
||||
this.filter = filter;
|
||||
this.controls = ctls;
|
||||
|
||||
if (l instanceof NamespaceChangeListener) {
|
||||
mask |= ADDED_MASK|REMOVED_MASK|RENAMED_MASK;
|
||||
}
|
||||
if (l instanceof ObjectChangeListener) {
|
||||
mask |= CHANGED_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
// checks name, filter, controls
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof NotifierArgs) {
|
||||
NotifierArgs target = (NotifierArgs)obj;
|
||||
return mask == target.mask &&
|
||||
name.equals(target.name) && filter.equals(target.filter) &&
|
||||
checkControls(target.controls);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkControls(SearchControls ctls) {
|
||||
if ((controls == null || ctls == null)) {
|
||||
return ctls == controls;
|
||||
}
|
||||
// ctls are nonempty
|
||||
|
||||
return (controls.getSearchScope() == ctls.getSearchScope()) &&
|
||||
(controls.getTimeLimit() == ctls.getTimeLimit()) &&
|
||||
(controls.getDerefLinkFlag() == ctls.getDerefLinkFlag()) &&
|
||||
(controls.getReturningObjFlag() == ctls.getReturningObjFlag()) &&
|
||||
(controls.getCountLimit() == ctls.getCountLimit()) &&
|
||||
checkStringArrays(controls.getReturningAttributes(),
|
||||
ctls.getReturningAttributes());
|
||||
}
|
||||
|
||||
private static boolean checkStringArrays(String[] s1, String[] s2) {
|
||||
if ((s1 == null) || (s2 == null)) {
|
||||
return s1 == s2;
|
||||
}
|
||||
|
||||
// both are nonnull
|
||||
if (s1.length != s2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < s1.length; i++) {
|
||||
if (!s1[i].equals(s2[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// save from having to recalculate each time
|
||||
private int sum = -1;
|
||||
public int hashCode() {
|
||||
if (sum == -1)
|
||||
sum = mask + name.hashCode() + filter.hashCode() + controlsCode();
|
||||
return sum;
|
||||
}
|
||||
|
||||
// used in calculating hash code
|
||||
private int controlsCode() {
|
||||
if (controls == null) return 0;
|
||||
|
||||
int total = controls.getTimeLimit() + (int)controls.getCountLimit() +
|
||||
(controls.getDerefLinkFlag() ? 1 : 0) +
|
||||
(controls.getReturningObjFlag() ? 1 : 0);
|
||||
|
||||
String[] attrs = controls.getReturningAttributes();
|
||||
if (attrs != null) {
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
total += attrs[i].hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
669
jdkSrc/jdk8/com/sun/jndi/ldap/Obj.java
Normal file
669
jdkSrc/jdk8/com/sun/jndi/ldap/Obj.java
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.DirectoryManager;
|
||||
import javax.naming.spi.DirStateFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import sun.misc.BASE64Encoder;
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Class containing static methods and constants for dealing with
|
||||
* encoding/decoding JNDI References and Serialized Objects
|
||||
* in LDAP.
|
||||
* @author Vincent Ryan
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class Obj {
|
||||
|
||||
private Obj () {}; // Make sure no one can create one
|
||||
|
||||
// package private; used by Connection
|
||||
static VersionHelper helper = VersionHelper.getVersionHelper();
|
||||
|
||||
// LDAP attributes used to support Java objects.
|
||||
static final String[] JAVA_ATTRIBUTES = {
|
||||
"objectClass",
|
||||
"javaSerializedData",
|
||||
"javaClassName",
|
||||
"javaFactory",
|
||||
"javaCodeBase",
|
||||
"javaReferenceAddress",
|
||||
"javaClassNames",
|
||||
"javaRemoteLocation" // Deprecated
|
||||
};
|
||||
|
||||
static final int OBJECT_CLASS = 0;
|
||||
static final int SERIALIZED_DATA = 1;
|
||||
static final int CLASSNAME = 2;
|
||||
static final int FACTORY = 3;
|
||||
static final int CODEBASE = 4;
|
||||
static final int REF_ADDR = 5;
|
||||
static final int TYPENAME = 6;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
private static final int REMOTE_LOC = 7;
|
||||
|
||||
// LDAP object classes to support Java objects
|
||||
static final String[] JAVA_OBJECT_CLASSES = {
|
||||
"javaContainer",
|
||||
"javaObject",
|
||||
"javaNamingReference",
|
||||
"javaSerializedObject",
|
||||
"javaMarshalledObject",
|
||||
};
|
||||
|
||||
static final String[] JAVA_OBJECT_CLASSES_LOWER = {
|
||||
"javacontainer",
|
||||
"javaobject",
|
||||
"javanamingreference",
|
||||
"javaserializedobject",
|
||||
"javamarshalledobject",
|
||||
};
|
||||
|
||||
static final int STRUCTURAL = 0; // structural object class
|
||||
static final int BASE_OBJECT = 1; // auxiliary java object class
|
||||
static final int REF_OBJECT = 2; // auxiliary reference object class
|
||||
static final int SER_OBJECT = 3; // auxiliary serialized object class
|
||||
static final int MAR_OBJECT = 4; // auxiliary marshalled object class
|
||||
|
||||
/**
|
||||
* Encode an object in LDAP attributes.
|
||||
* Supports binding Referenceable or Reference, Serializable,
|
||||
* and DirContext.
|
||||
*
|
||||
* If the object supports the Referenceable interface then encode
|
||||
* the reference to the object. See encodeReference() for details.
|
||||
*<p>
|
||||
* If the object is serializable, it is stored as follows:
|
||||
* javaClassName
|
||||
* value: Object.getClass();
|
||||
* javaSerializedData
|
||||
* value: serialized form of Object (in binary form).
|
||||
* javaTypeName
|
||||
* value: getTypeNames(Object.getClass());
|
||||
*/
|
||||
private static Attributes encodeObject(char separator,
|
||||
Object obj, Attributes attrs,
|
||||
Attribute objectClass, boolean cloned)
|
||||
throws NamingException {
|
||||
boolean structural =
|
||||
(objectClass.size() == 0 ||
|
||||
(objectClass.size() == 1 && objectClass.contains("top")));
|
||||
|
||||
if (structural) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[STRUCTURAL]);
|
||||
}
|
||||
|
||||
// References
|
||||
if (obj instanceof Referenceable) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
|
||||
if (!cloned) {
|
||||
attrs = (Attributes)attrs.clone();
|
||||
}
|
||||
attrs.put(objectClass);
|
||||
return (encodeReference(separator,
|
||||
((Referenceable)obj).getReference(),
|
||||
attrs, obj));
|
||||
|
||||
} else if (obj instanceof Reference) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
|
||||
if (!cloned) {
|
||||
attrs = (Attributes)attrs.clone();
|
||||
}
|
||||
attrs.put(objectClass);
|
||||
return (encodeReference(separator, (Reference)obj, attrs, null));
|
||||
|
||||
// Serializable Object
|
||||
} else if (obj instanceof java.io.Serializable) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
|
||||
if (!(objectClass.contains(JAVA_OBJECT_CLASSES[MAR_OBJECT]) ||
|
||||
objectClass.contains(JAVA_OBJECT_CLASSES_LOWER[MAR_OBJECT]))) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[SER_OBJECT]);
|
||||
}
|
||||
if (!cloned) {
|
||||
attrs = (Attributes)attrs.clone();
|
||||
}
|
||||
attrs.put(objectClass);
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[SERIALIZED_DATA],
|
||||
serializeObject(obj)));
|
||||
if (attrs.get(JAVA_ATTRIBUTES[CLASSNAME]) == null) {
|
||||
attrs.put(JAVA_ATTRIBUTES[CLASSNAME],
|
||||
obj.getClass().getName());
|
||||
}
|
||||
if (attrs.get(JAVA_ATTRIBUTES[TYPENAME]) == null) {
|
||||
Attribute tAttr =
|
||||
LdapCtxFactory.createTypeNameAttr(obj.getClass());
|
||||
if (tAttr != null) {
|
||||
attrs.put(tAttr);
|
||||
}
|
||||
}
|
||||
// DirContext Object
|
||||
} else if (obj instanceof DirContext) {
|
||||
// do nothing
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"can only bind Referenceable, Serializable, DirContext");
|
||||
}
|
||||
// System.err.println(attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each value in javaCodebase contains a list of space-separated
|
||||
* URLs. Each value is independent; we can pick any of the values
|
||||
* so we just use the first one.
|
||||
* @return an array of URL strings for the codebase
|
||||
*/
|
||||
private static String[] getCodebases(Attribute codebaseAttr) throws
|
||||
NamingException {
|
||||
if (codebaseAttr == null) {
|
||||
return null;
|
||||
} else {
|
||||
StringTokenizer parser =
|
||||
new StringTokenizer((String)codebaseAttr.get());
|
||||
Vector<String> vec = new Vector<>(10);
|
||||
while (parser.hasMoreTokens()) {
|
||||
vec.addElement(parser.nextToken());
|
||||
}
|
||||
String[] answer = new String[vec.size()];
|
||||
for (int i = 0; i < answer.length; i++) {
|
||||
answer[i] = vec.elementAt(i);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode an object from LDAP attribute(s).
|
||||
* The object may be a Reference, or a Serialized object.
|
||||
*
|
||||
* See encodeObject() and encodeReference() for details on formats
|
||||
* expected.
|
||||
*/
|
||||
static Object decodeObject(Attributes attrs)
|
||||
throws NamingException {
|
||||
|
||||
Attribute attr;
|
||||
|
||||
// Get codebase, which is used in all 3 cases.
|
||||
String[] codebases = getCodebases(attrs.get(JAVA_ATTRIBUTES[CODEBASE]));
|
||||
try {
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) {
|
||||
if (!VersionHelper12.isSerialDataAllowed()) {
|
||||
throw new NamingException("Object deserialization is not allowed");
|
||||
}
|
||||
ClassLoader cl = helper.getURLClassLoader(codebases);
|
||||
return deserializeObject((byte[])attr.get(), cl);
|
||||
} else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) {
|
||||
// javaRemoteLocation attribute (RMI stub will be created)
|
||||
if (!VersionHelper12.isSerialDataAllowed()) {
|
||||
throw new NamingException("Object deserialization is not allowed");
|
||||
}
|
||||
// For backward compatibility only
|
||||
return decodeRmiObject(
|
||||
(String)attrs.get(JAVA_ATTRIBUTES[CLASSNAME]).get(),
|
||||
(String)attr.get(), codebases);
|
||||
}
|
||||
|
||||
attr = attrs.get(JAVA_ATTRIBUTES[OBJECT_CLASS]);
|
||||
if (attr != null &&
|
||||
(attr.contains(JAVA_OBJECT_CLASSES[REF_OBJECT]) ||
|
||||
attr.contains(JAVA_OBJECT_CLASSES_LOWER[REF_OBJECT]))) {
|
||||
return decodeReference(attrs, codebases);
|
||||
}
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Reference object into several LDAP attributes.
|
||||
*
|
||||
* A Reference is stored as into the following attributes:
|
||||
* javaClassName
|
||||
* value: Reference.getClassName();
|
||||
* javaFactory
|
||||
* value: Reference.getFactoryClassName();
|
||||
* javaCodeBase
|
||||
* value: Reference.getFactoryClassLocation();
|
||||
* javaReferenceAddress
|
||||
* value: #0#typeA#valA
|
||||
* value: #1#typeB#valB
|
||||
* value: #2#typeC##[serialized RefAddr C]
|
||||
* value: #3#typeD#valD
|
||||
*
|
||||
* where
|
||||
* - the first character denotes the separator
|
||||
* - the number following the first separator denotes the position
|
||||
* of the RefAddr within the Reference
|
||||
* - "typeA" is RefAddr.getType()
|
||||
* - ## denotes that the Base64-encoded form of the non-StringRefAddr
|
||||
* is to follow; otherwise the value that follows is
|
||||
* StringRefAddr.getContents()
|
||||
*
|
||||
* The default separator is the hash character (#).
|
||||
* May provide property for this in future.
|
||||
*/
|
||||
|
||||
private static Attributes encodeReference(char separator,
|
||||
Reference ref, Attributes attrs, Object orig)
|
||||
throws NamingException {
|
||||
|
||||
if (ref == null)
|
||||
return attrs;
|
||||
|
||||
String s;
|
||||
|
||||
if ((s = ref.getClassName()) != null) {
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CLASSNAME], s));
|
||||
}
|
||||
|
||||
if ((s = ref.getFactoryClassName()) != null) {
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[FACTORY], s));
|
||||
}
|
||||
|
||||
if ((s = ref.getFactoryClassLocation()) != null) {
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CODEBASE], s));
|
||||
}
|
||||
|
||||
// Get original object's types if caller has not explicitly
|
||||
// specified other type names
|
||||
if (orig != null && attrs.get(JAVA_ATTRIBUTES[TYPENAME]) != null) {
|
||||
Attribute tAttr =
|
||||
LdapCtxFactory.createTypeNameAttr(orig.getClass());
|
||||
if (tAttr != null) {
|
||||
attrs.put(tAttr);
|
||||
}
|
||||
}
|
||||
|
||||
int count = ref.size();
|
||||
|
||||
if (count > 0) {
|
||||
|
||||
Attribute refAttr = new BasicAttribute(JAVA_ATTRIBUTES[REF_ADDR]);
|
||||
RefAddr refAddr;
|
||||
BASE64Encoder encoder = null;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
refAddr = ref.get(i);
|
||||
|
||||
if (refAddr instanceof StringRefAddr) {
|
||||
refAttr.add(""+ separator + i +
|
||||
separator + refAddr.getType() +
|
||||
separator + refAddr.getContent());
|
||||
} else {
|
||||
if (encoder == null)
|
||||
encoder = new BASE64Encoder();
|
||||
|
||||
refAttr.add(""+ separator + i +
|
||||
separator + refAddr.getType() +
|
||||
separator + separator +
|
||||
encoder.encodeBuffer(serializeObject(refAddr)));
|
||||
}
|
||||
}
|
||||
attrs.put(refAttr);
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/*
|
||||
* A RMI object is stored in the directory as
|
||||
* javaClassName
|
||||
* value: Object.getClass();
|
||||
* javaRemoteLocation
|
||||
* value: URL of RMI object (accessed through the RMI Registry)
|
||||
* javaCodebase:
|
||||
* value: URL of codebase of where to find classes for object
|
||||
*
|
||||
* Return the RMI Location URL itself. This will be turned into
|
||||
* an RMI object when getObjectInstance() is called on it.
|
||||
* %%% Ignore codebase for now. Depend on RMI registry to send code.-RL
|
||||
* @deprecated For backward compatibility only
|
||||
*/
|
||||
private static Object decodeRmiObject(String className,
|
||||
String rmiName, String[] codebases) throws NamingException {
|
||||
return new Reference(className, new StringRefAddr("URL", rmiName));
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore a Reference object from several LDAP attributes
|
||||
*/
|
||||
private static Reference decodeReference(Attributes attrs,
|
||||
String[] codebases) throws NamingException, IOException {
|
||||
|
||||
Attribute attr;
|
||||
String className;
|
||||
String factory = null;
|
||||
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[CLASSNAME])) != null) {
|
||||
className = (String)attr.get();
|
||||
} else {
|
||||
throw new InvalidAttributesException(JAVA_ATTRIBUTES[CLASSNAME] +
|
||||
" attribute is required");
|
||||
}
|
||||
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[FACTORY])) != null) {
|
||||
factory = (String)attr.get();
|
||||
}
|
||||
|
||||
Reference ref = new Reference(className, factory,
|
||||
(codebases != null? codebases[0] : null));
|
||||
|
||||
/*
|
||||
* string encoding of a RefAddr is either:
|
||||
*
|
||||
* #posn#<type>#<address>
|
||||
* or
|
||||
* #posn#<type>##<base64-encoded address>
|
||||
*/
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[REF_ADDR])) != null) {
|
||||
|
||||
String val, posnStr, type;
|
||||
char separator;
|
||||
int start, sep, posn;
|
||||
BASE64Decoder decoder = null;
|
||||
|
||||
ClassLoader cl = helper.getURLClassLoader(codebases);
|
||||
|
||||
/*
|
||||
* Temporary Vector for decoded RefAddr addresses - used to ensure
|
||||
* unordered addresses are correctly re-ordered.
|
||||
*/
|
||||
Vector<RefAddr> refAddrList = new Vector<>();
|
||||
refAddrList.setSize(attr.size());
|
||||
|
||||
for (NamingEnumeration<?> vals = attr.getAll(); vals.hasMore(); ) {
|
||||
|
||||
val = (String)vals.next();
|
||||
|
||||
if (val.length() == 0) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - "+
|
||||
"empty attribute value");
|
||||
}
|
||||
// first character denotes encoding separator
|
||||
separator = val.charAt(0);
|
||||
start = 1; // skip over separator
|
||||
|
||||
// extract position within Reference
|
||||
if ((sep = val.indexOf(separator, start)) < 0) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"separator '" + separator + "'" + "not found");
|
||||
}
|
||||
if ((posnStr = val.substring(start, sep)) == null) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"empty RefAddr position");
|
||||
}
|
||||
try {
|
||||
posn = Integer.parseInt(posnStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"RefAddr position not an integer");
|
||||
}
|
||||
start = sep + 1; // skip over position and trailing separator
|
||||
|
||||
// extract type
|
||||
if ((sep = val.indexOf(separator, start)) < 0) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"RefAddr type not found");
|
||||
}
|
||||
if ((type = val.substring(start, sep)) == null) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"empty RefAddr type");
|
||||
}
|
||||
start = sep + 1; // skip over type and trailing separator
|
||||
|
||||
// extract content
|
||||
if (start == val.length()) {
|
||||
// Empty content
|
||||
refAddrList.setElementAt(new StringRefAddr(type, null), posn);
|
||||
} else if (val.charAt(start) == separator) {
|
||||
// Check if deserialization of binary RefAddr is allowed from
|
||||
// 'javaReferenceAddress' LDAP attribute.
|
||||
if (!VersionHelper12.isSerialDataAllowed()) {
|
||||
throw new NamingException("Object deserialization is not allowed");
|
||||
}
|
||||
|
||||
// Double separators indicate a non-StringRefAddr
|
||||
// Content is a Base64-encoded serialized RefAddr
|
||||
|
||||
++start; // skip over consecutive separator
|
||||
// %%% RL: exception if empty after double separator
|
||||
|
||||
if (decoder == null)
|
||||
decoder = new BASE64Decoder();
|
||||
|
||||
RefAddr ra = (RefAddr)
|
||||
deserializeObject(
|
||||
decoder.decodeBuffer(val.substring(start)),
|
||||
cl);
|
||||
|
||||
refAddrList.setElementAt(ra, posn);
|
||||
} else {
|
||||
// Single separator indicates a StringRefAddr
|
||||
refAddrList.setElementAt(new StringRefAddr(type,
|
||||
val.substring(start)), posn);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy to real reference
|
||||
for (int i = 0; i < refAddrList.size(); i++) {
|
||||
ref.add(refAddrList.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return (ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize an object into a byte array
|
||||
*/
|
||||
private static byte[] serializeObject(Object obj) throws NamingException {
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
try (ObjectOutputStream serial = new ObjectOutputStream(bytes)) {
|
||||
serial.writeObject(obj);
|
||||
}
|
||||
|
||||
return (bytes.toByteArray());
|
||||
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserializes a byte array into an object.
|
||||
*/
|
||||
private static Object deserializeObject(byte[] obj, ClassLoader cl)
|
||||
throws NamingException {
|
||||
|
||||
try {
|
||||
// Create ObjectInputStream for deserialization
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(obj);
|
||||
try (ObjectInputStream deserial = cl == null ?
|
||||
new ObjectInputStream(bytes) :
|
||||
new LoaderInputStream(bytes, cl)) {
|
||||
return deserial.readObject();
|
||||
} catch (ClassNotFoundException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attributes to bind given an object and its attributes.
|
||||
*/
|
||||
static Attributes determineBindAttrs(
|
||||
char separator, Object obj, Attributes attrs, boolean cloned,
|
||||
Name name, Context ctx, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
// Call state factories to convert object and attrs
|
||||
DirStateFactory.Result res =
|
||||
DirectoryManager.getStateToBind(obj, name, ctx, env, attrs);
|
||||
obj = res.getObject();
|
||||
attrs = res.getAttributes();
|
||||
|
||||
// We're only storing attributes; no further processing required
|
||||
if (obj == null) {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
//if object to be bound is a DirContext extract its attributes
|
||||
if ((attrs == null) && (obj instanceof DirContext)) {
|
||||
cloned = true;
|
||||
attrs = ((DirContext)obj).getAttributes("");
|
||||
}
|
||||
|
||||
boolean ocNeedsCloning = false;
|
||||
|
||||
// Create "objectClass" attribute
|
||||
Attribute objectClass;
|
||||
if (attrs == null || attrs.size() == 0) {
|
||||
attrs = new BasicAttributes(LdapClient.caseIgnore);
|
||||
cloned = true;
|
||||
|
||||
// No objectclasses supplied, use "top" to start
|
||||
objectClass = new BasicAttribute("objectClass", "top");
|
||||
|
||||
} else {
|
||||
// Get existing objectclass attribute
|
||||
objectClass = attrs.get("objectClass");
|
||||
if (objectClass == null && !attrs.isCaseIgnored()) {
|
||||
// %%% workaround
|
||||
objectClass = attrs.get("objectclass");
|
||||
}
|
||||
|
||||
// No objectclasses supplied, use "top" to start
|
||||
if (objectClass == null) {
|
||||
objectClass = new BasicAttribute("objectClass", "top");
|
||||
} else if (ocNeedsCloning || !cloned) {
|
||||
objectClass = (Attribute)objectClass.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// convert the supplied object into LDAP attributes
|
||||
attrs = encodeObject(separator, obj, attrs, objectClass, cloned);
|
||||
|
||||
// System.err.println("Determined: " + attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* An ObjectInputStream that uses a class loader to find classes.
|
||||
*/
|
||||
private static final class LoaderInputStream extends ObjectInputStream {
|
||||
private ClassLoader classLoader;
|
||||
|
||||
LoaderInputStream(InputStream in, ClassLoader cl) throws IOException {
|
||||
super(in);
|
||||
classLoader = cl;
|
||||
}
|
||||
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws
|
||||
IOException, ClassNotFoundException {
|
||||
try {
|
||||
// %%% Should use Class.forName(desc.getName(), false, classLoader);
|
||||
// except we can't because that is only available on JDK1.2
|
||||
return classLoader.loadClass(desc.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
return super.resolveClass(desc);
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<?> resolveProxyClass(String[] interfaces) throws
|
||||
IOException, ClassNotFoundException {
|
||||
ClassLoader nonPublicLoader = null;
|
||||
boolean hasNonPublicInterface = false;
|
||||
|
||||
// define proxy in class loader of non-public interface(s), if any
|
||||
Class<?>[] classObjs = new Class<?>[interfaces.length];
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
Class<?> cl = Class.forName(interfaces[i], false, classLoader);
|
||||
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
|
||||
if (hasNonPublicInterface) {
|
||||
if (nonPublicLoader != cl.getClassLoader()) {
|
||||
throw new IllegalAccessError(
|
||||
"conflicting non-public interface class loaders");
|
||||
}
|
||||
} else {
|
||||
nonPublicLoader = cl.getClassLoader();
|
||||
hasNonPublicInterface = true;
|
||||
}
|
||||
}
|
||||
classObjs[i] = cl;
|
||||
}
|
||||
try {
|
||||
return Proxy.getProxyClass(hasNonPublicInterface ?
|
||||
nonPublicLoader : classLoader, classObjs);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ClassNotFoundException(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
161
jdkSrc/jdk8/com/sun/jndi/ldap/PersistentSearchControl.java
Normal file
161
jdkSrc/jdk8/com/sun/jndi/ldap/PersistentSearchControl.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Request Control for the persistent search
|
||||
* mechanism as defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-psearch-02.txt">draft-ietf-ldapext-psearch-02.txt</a>.
|
||||
*
|
||||
* The control's value has the following ASN.1 definition:
|
||||
* <pre>
|
||||
*
|
||||
* PersistentSearch ::= SEQUENCE {
|
||||
* changeTypes INTEGER,
|
||||
* changesOnly BOOLEAN,
|
||||
* returnECs BOOLEAN
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see EntryChangeResponseControl
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class PersistentSearchControl extends BasicControl {
|
||||
|
||||
/**
|
||||
* The persistent search control's assigned object identifier
|
||||
* is 2.16.840.1.113730.3.4.3.
|
||||
*/
|
||||
public static final String OID = "2.16.840.1.113730.3.4.3";
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been added.
|
||||
*/
|
||||
public static final int ADD = 1;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been deleted.
|
||||
*/
|
||||
public static final int DELETE = 2;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been modified.
|
||||
*/
|
||||
public static final int MODIFY = 4;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been renamed.
|
||||
*/
|
||||
public static final int RENAME = 8;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been added, deleted,
|
||||
* modified or renamed.
|
||||
*/
|
||||
public static final int ANY = ADD | DELETE | MODIFY | RENAME;
|
||||
|
||||
/**
|
||||
* The change types of interest. All changes, by default.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private int changeTypes = ANY;
|
||||
|
||||
/**
|
||||
* Return original entries and changed entries or only changed entries.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private boolean changesOnly = false;
|
||||
|
||||
/**
|
||||
* Return entry change controls.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private boolean returnControls = true;
|
||||
|
||||
private static final long serialVersionUID = 6335140491154854116L;
|
||||
|
||||
/**
|
||||
* Constructs a persistent search non-critical control.
|
||||
* The original entries, any changed entries (additions,
|
||||
* deletions, modifications or renames) and entry change
|
||||
* controls are requested.
|
||||
*
|
||||
* @exception IOException If a BER encoding error occurs.
|
||||
*/
|
||||
public PersistentSearchControl() throws IOException {
|
||||
super(OID);
|
||||
super.value = setEncodedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a persistent search control.
|
||||
*
|
||||
* @param changeTypes The change types of interest.
|
||||
* @param changesOnly Return original entries and changed entries
|
||||
* or only the changed entries.
|
||||
* @param returnControls Return entry change controls.
|
||||
* @param criticality The control's criticality.
|
||||
* @exception IOException If a BER encoding error occurs.
|
||||
*/
|
||||
public PersistentSearchControl(int changeTypes, boolean changesOnly,
|
||||
boolean returnControls, boolean criticality) throws IOException {
|
||||
|
||||
super(OID, criticality, null);
|
||||
this.changeTypes = changeTypes;
|
||||
this.changesOnly = changesOnly;
|
||||
this.returnControls = returnControls;
|
||||
super.value = setEncodedValue();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the ASN.1 BER encoded value of the persistent search control.
|
||||
* The result is the raw BER bytes including the tag and length of
|
||||
* the control's value. It does not include the controls OID or criticality.
|
||||
*
|
||||
* @return A possibly null byte array representing the ASN.1 BER encoded
|
||||
* value of the LDAP persistent search control.
|
||||
* @exception IOException If a BER encoding error occurs.
|
||||
*/
|
||||
private byte[] setEncodedValue() throws IOException {
|
||||
|
||||
// build the ASN.1 encoding
|
||||
BerEncoder ber = new BerEncoder(32);
|
||||
|
||||
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
|
||||
ber.encodeInt(changeTypes);
|
||||
ber.encodeBoolean(changesOnly);
|
||||
ber.encodeBoolean(returnControls);
|
||||
ber.endSeq();
|
||||
|
||||
return ber.getTrimmedBuf();
|
||||
}
|
||||
}
|
||||
32
jdkSrc/jdk8/com/sun/jndi/ldap/ReferralEnumeration.java
Normal file
32
jdkSrc/jdk8/com/sun/jndi/ldap/ReferralEnumeration.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
|
||||
interface ReferralEnumeration<T> extends NamingEnumeration<T> {
|
||||
void appendUnprocessedReferrals(LdapReferralException ex);
|
||||
}
|
||||
47
jdkSrc/jdk8/com/sun/jndi/ldap/SearchResultWithControls.java
Normal file
47
jdkSrc/jdk8/com/sun/jndi/ldap/SearchResultWithControls.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
class SearchResultWithControls extends SearchResult implements HasControls {
|
||||
private Control[] controls;
|
||||
|
||||
public SearchResultWithControls(String name, Object obj, Attributes attrs,
|
||||
boolean isRelative, Control[] controls) {
|
||||
|
||||
super(name, obj, attrs, isRelative);
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 8476983938747908202L;
|
||||
}
|
||||
310
jdkSrc/jdk8/com/sun/jndi/ldap/ServiceLocator.java
Normal file
310
jdkSrc/jdk8/com/sun/jndi/ldap/ServiceLocator.java
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.NamingManager;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import javax.naming.ldap.Rdn;
|
||||
|
||||
/**
|
||||
* This class discovers the location of LDAP services by querying DNS.
|
||||
* See http://www.ietf.org/internet-drafts/draft-ietf-ldapext-locate-07.txt
|
||||
*/
|
||||
|
||||
class ServiceLocator {
|
||||
|
||||
private static final String SRV_RR = "SRV";
|
||||
|
||||
private static final String[] SRV_RR_ATTR = new String[]{SRV_RR};
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
private ServiceLocator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a distinguished name (RFC 2253) to a fully qualified domain name.
|
||||
* Processes a sequence of RDNs having a DC attribute.
|
||||
* The special RDN "DC=." denotes the root of the domain tree.
|
||||
* Multi-valued RDNs, non-DC attributes, binary-valued attributes and the
|
||||
* RDN "DC=." all reset the domain name and processing continues.
|
||||
*
|
||||
* @param dn A string distinguished name (RFC 2253).
|
||||
* @return A domain name or null if none can be derived.
|
||||
* @throw InvalidNameException If the distinugished name is invalid.
|
||||
*/
|
||||
static String mapDnToDomainName(String dn) throws InvalidNameException {
|
||||
if (dn == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuffer domain = new StringBuffer();
|
||||
LdapName ldapName = new LdapName(dn);
|
||||
|
||||
// process RDNs left-to-right
|
||||
//List<Rdn> rdnList = ldapName.getRdns();
|
||||
|
||||
List<Rdn> rdnList = ldapName.getRdns();
|
||||
for (int i = rdnList.size() - 1; i >= 0; i--) {
|
||||
//Rdn rdn = rdnList.get(i);
|
||||
Rdn rdn = rdnList.get(i);
|
||||
|
||||
// single-valued RDN with a DC attribute
|
||||
if ((rdn.size() == 1) &&
|
||||
("dc".equalsIgnoreCase(rdn.getType()) )) {
|
||||
Object attrval = rdn.getValue();
|
||||
if (attrval instanceof String) {
|
||||
if (attrval.equals(".") ||
|
||||
(domain.length() == 1 && domain.charAt(0) == '.')) {
|
||||
domain.setLength(0); // reset (when current or previous
|
||||
// RDN value is "DC=.")
|
||||
}
|
||||
if (domain.length() > 0) {
|
||||
domain.append('.');
|
||||
}
|
||||
domain.append(attrval);
|
||||
} else {
|
||||
domain.setLength(0); // reset (when binary-valued attribute)
|
||||
}
|
||||
} else {
|
||||
domain.setLength(0); // reset (when multi-valued RDN or non-DC)
|
||||
}
|
||||
}
|
||||
return (domain.length() != 0) ? domain.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the LDAP service for a given domain.
|
||||
* Queries DNS for a list of LDAP Service Location Records (SRV) for a
|
||||
* given domain name.
|
||||
*
|
||||
* @param domainName A string domain name.
|
||||
* @param environment The possibly null environment of the context.
|
||||
* @return An ordered list of hostports for the LDAP service or null if
|
||||
* the service has not been located.
|
||||
*/
|
||||
static String[] getLdapService(String domainName, Map<?,?> environment) {
|
||||
if (environment instanceof Hashtable) {
|
||||
return getLdapService(domainName, (Hashtable)environment);
|
||||
}
|
||||
return getLdapService(domainName, new Hashtable<>(environment));
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the LDAP service for a given domain.
|
||||
* Queries DNS for a list of LDAP Service Location Records (SRV) for a
|
||||
* given domain name.
|
||||
*
|
||||
* @param domainName A string domain name.
|
||||
* @param environment The possibly null environment of the context.
|
||||
* @return An ordered list of hostports for the LDAP service or null if
|
||||
* the service has not been located.
|
||||
*/
|
||||
static String[] getLdapService(String domainName, Hashtable<?,?> environment) {
|
||||
|
||||
if (domainName == null || domainName.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String dnsUrl = "dns:///_ldap._tcp." + domainName;
|
||||
String[] hostports = null;
|
||||
|
||||
try {
|
||||
// Create the DNS context using NamingManager rather than using
|
||||
// the initial context constructor. This avoids having the initial
|
||||
// context constructor call itself (when processing the URL
|
||||
// argument in the getAttributes call).
|
||||
Context ctx = NamingManager.getURLContext("dns", environment);
|
||||
if (!(ctx instanceof DirContext)) {
|
||||
return null; // cannot create a DNS context
|
||||
}
|
||||
Attributes attrs =
|
||||
((DirContext)ctx).getAttributes(dnsUrl, SRV_RR_ATTR);
|
||||
Attribute attr;
|
||||
|
||||
if (attrs != null && ((attr = attrs.get(SRV_RR)) != null)) {
|
||||
int numValues = attr.size();
|
||||
int numRecords = 0;
|
||||
SrvRecord[] srvRecords = new SrvRecord[numValues];
|
||||
|
||||
// create the service records
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < numValues) {
|
||||
try {
|
||||
srvRecords[j] = new SrvRecord((String) attr.get(i));
|
||||
j++;
|
||||
} catch (Exception e) {
|
||||
// ignore bad value
|
||||
}
|
||||
i++;
|
||||
}
|
||||
numRecords = j;
|
||||
|
||||
// trim
|
||||
if (numRecords < numValues) {
|
||||
SrvRecord[] trimmed = new SrvRecord[numRecords];
|
||||
System.arraycopy(srvRecords, 0, trimmed, 0, numRecords);
|
||||
srvRecords = trimmed;
|
||||
}
|
||||
|
||||
// Sort the service records in ascending order of their
|
||||
// priority value. For records with equal priority, move
|
||||
// those with weight 0 to the top of the list.
|
||||
if (numRecords > 1) {
|
||||
Arrays.sort(srvRecords);
|
||||
}
|
||||
|
||||
// extract the host and port number from each service record
|
||||
hostports = extractHostports(srvRecords);
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
// ignore
|
||||
}
|
||||
return hostports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract hosts and port numbers from a list of SRV records.
|
||||
* An array of hostports is returned or null if none were found.
|
||||
*/
|
||||
private static String[] extractHostports(SrvRecord[] srvRecords) {
|
||||
String[] hostports = null;
|
||||
|
||||
int head = 0;
|
||||
int tail = 0;
|
||||
int sublistLength = 0;
|
||||
int k = 0;
|
||||
for (int i = 0; i < srvRecords.length; i++) {
|
||||
if (hostports == null) {
|
||||
hostports = new String[srvRecords.length];
|
||||
}
|
||||
// find the head and tail of the list of records having the same
|
||||
// priority value.
|
||||
head = i;
|
||||
while (i < srvRecords.length - 1 &&
|
||||
srvRecords[i].priority == srvRecords[i + 1].priority) {
|
||||
i++;
|
||||
}
|
||||
tail = i;
|
||||
|
||||
// select hostports from the sublist
|
||||
sublistLength = (tail - head) + 1;
|
||||
for (int j = 0; j < sublistLength; j++) {
|
||||
hostports[k++] = selectHostport(srvRecords, head, tail);
|
||||
}
|
||||
}
|
||||
return hostports;
|
||||
}
|
||||
|
||||
/*
|
||||
* Randomly select a service record in the range [head, tail] and return
|
||||
* its hostport value. Follows the algorithm in RFC 2782.
|
||||
*/
|
||||
private static String selectHostport(SrvRecord[] srvRecords, int head,
|
||||
int tail) {
|
||||
if (head == tail) {
|
||||
return srvRecords[head].hostport;
|
||||
}
|
||||
|
||||
// compute the running sum for records between head and tail
|
||||
int sum = 0;
|
||||
for (int i = head; i <= tail; i++) {
|
||||
if (srvRecords[i] != null) {
|
||||
sum += srvRecords[i].weight;
|
||||
srvRecords[i].sum = sum;
|
||||
}
|
||||
}
|
||||
String hostport = null;
|
||||
|
||||
// If all records have zero weight, select first available one;
|
||||
// otherwise, randomly select a record according to its weight
|
||||
int target = (sum == 0 ? 0 : random.nextInt(sum + 1));
|
||||
for (int i = head; i <= tail; i++) {
|
||||
if (srvRecords[i] != null && srvRecords[i].sum >= target) {
|
||||
hostport = srvRecords[i].hostport;
|
||||
srvRecords[i] = null; // make this record unavailable
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hostport;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds a DNS service (SRV) record.
|
||||
* See http://www.ietf.org/rfc/rfc2782.txt
|
||||
*/
|
||||
|
||||
static class SrvRecord implements Comparable<SrvRecord> {
|
||||
|
||||
int priority;
|
||||
int weight;
|
||||
int sum;
|
||||
String hostport;
|
||||
|
||||
/**
|
||||
* Creates a service record object from a string record.
|
||||
* DNS supplies the string record in the following format:
|
||||
* <pre>
|
||||
* <Priority> " " <Weight> " " <Port> " " <Host>
|
||||
* </pre>
|
||||
*/
|
||||
SrvRecord(String srvRecord) throws Exception {
|
||||
StringTokenizer tokenizer = new StringTokenizer(srvRecord, " ");
|
||||
String port;
|
||||
|
||||
if (tokenizer.countTokens() == 4) {
|
||||
priority = Integer.parseInt(tokenizer.nextToken());
|
||||
weight = Integer.parseInt(tokenizer.nextToken());
|
||||
port = tokenizer.nextToken();
|
||||
hostport = tokenizer.nextToken() + ":" + port;
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort records in ascending order of priority value. For records with
|
||||
* equal priority move those with weight 0 to the top of the list.
|
||||
*/
|
||||
public int compareTo(SrvRecord that) {
|
||||
if (priority > that.priority) {
|
||||
return 1; // this > that
|
||||
} else if (priority < that.priority) {
|
||||
return -1; // this < that
|
||||
} else if (weight == 0 && that.weight != 0) {
|
||||
return -1; // this < that
|
||||
} else if (weight != 0 && that.weight == 0) {
|
||||
return 1; // this > that
|
||||
} else {
|
||||
return 0; // this == that
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
jdkSrc/jdk8/com/sun/jndi/ldap/SimpleClientId.java
Normal file
100
jdkSrc/jdk8/com/sun/jndi/ldap/SimpleClientId.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.util.Arrays; // JDK1.2
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* Represents the identity of a 'simple' authenticated LDAP connection.
|
||||
* In addition to ClientId information, this class contains also the
|
||||
* username and password.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
class SimpleClientId extends ClientId {
|
||||
final private String username;
|
||||
final private Object passwd;
|
||||
final private int myHash;
|
||||
|
||||
SimpleClientId(int version, String hostname, int port,
|
||||
String protocol, Control[] bindCtls, OutputStream trace,
|
||||
String socketFactory, String username, Object passwd) {
|
||||
|
||||
super(version, hostname, port, protocol, bindCtls, trace,
|
||||
socketFactory);
|
||||
|
||||
this.username = username;
|
||||
int pwdHashCode = 0;
|
||||
if (passwd == null) {
|
||||
this.passwd = null;
|
||||
} else if (passwd instanceof byte[]) {
|
||||
this.passwd = ((byte[])passwd).clone();
|
||||
pwdHashCode = Arrays.hashCode((byte[])passwd);
|
||||
} else if (passwd instanceof char[]) {
|
||||
this.passwd = ((char[])passwd).clone();
|
||||
pwdHashCode = Arrays.hashCode((char[])passwd);
|
||||
} else {
|
||||
this.passwd = passwd;
|
||||
pwdHashCode = passwd.hashCode();
|
||||
}
|
||||
|
||||
myHash = super.hashCode()
|
||||
^ (username != null ? username.hashCode() : 0)
|
||||
^ pwdHashCode;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof SimpleClientId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SimpleClientId other = (SimpleClientId)obj;
|
||||
|
||||
return super.equals(obj)
|
||||
&& (username == other.username // null OK
|
||||
|| (username != null && username.equals(other.username)))
|
||||
&& ((passwd == other.passwd) // null OK
|
||||
|| (passwd != null && other.passwd != null
|
||||
&& (((passwd instanceof String) && passwd.equals(other.passwd))
|
||||
|| ((passwd instanceof byte[])
|
||||
&& (other.passwd instanceof byte[])
|
||||
&& Arrays.equals((byte[])passwd, (byte[])other.passwd))
|
||||
|| ((passwd instanceof char[])
|
||||
&& (other.passwd instanceof char[])
|
||||
&& Arrays.equals((char[])passwd, (char[])other.passwd)))));
|
||||
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + ":" + username; // omit password for security
|
||||
}
|
||||
}
|
||||
115
jdkSrc/jdk8/com/sun/jndi/ldap/UnsolicitedResponseImpl.java
Normal file
115
jdkSrc/jdk8/com/sun/jndi/ldap/UnsolicitedResponseImpl.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import javax.naming.ldap.UnsolicitedNotification;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.ldap.Control;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A concrete implementation of an UnsolicitedNotification.
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class UnsolicitedResponseImpl implements UnsolicitedNotification {
|
||||
private String oid;
|
||||
private String[] referrals;
|
||||
private byte[] extensionValue;
|
||||
private NamingException exception;
|
||||
private Control[] controls;
|
||||
|
||||
UnsolicitedResponseImpl(String oid, byte[] berVal, Vector<Vector<String>> ref,
|
||||
int status, String msg, String matchedDN, Control[] controls) {
|
||||
this.oid = oid;
|
||||
this.extensionValue = berVal;
|
||||
|
||||
if (ref != null && ref.size() > 0) {
|
||||
int len = ref.size();
|
||||
referrals = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
// ref is a list of single-String Vectors
|
||||
referrals[i] = ref.elementAt(i).elementAt(0);
|
||||
}
|
||||
}
|
||||
exception = LdapCtx.mapErrorCode(status, msg);
|
||||
// matchedDN ignored for now; could be used to set resolvedName
|
||||
// exception.setResolvedName(new CompositeName().add(matchedDN));
|
||||
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the object identifier of the response.
|
||||
*
|
||||
* @return A possibly null object identifier string representing the LDAP
|
||||
* <tt>ExtendedResponse.responseName</tt> component.
|
||||
*/
|
||||
public String getID() {
|
||||
return oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ASN.1 BER encoded value of the LDAP extended operation
|
||||
* response. Null is returned if the value is absent from the response
|
||||
* sent by the LDAP server.
|
||||
* The result is the raw BER bytes including the tag and length of
|
||||
* the response value. It does not include the response OID.
|
||||
*
|
||||
* @return A possibly null byte array representing the ASN.1 BER encoded
|
||||
* contents of the LDAP <tt>ExtendedResponse.response</tt>
|
||||
* component.
|
||||
*/
|
||||
public byte[] getEncodedValue() {
|
||||
return extensionValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the referral(s) sent by the server.
|
||||
*
|
||||
* @return A possibly null array of referrals, each of which is represented
|
||||
* by a URL string. If null, no referral was sent by the server.
|
||||
*/
|
||||
public String[] getReferrals() {
|
||||
return referrals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the exception as constructed using information
|
||||
* sent by the server.
|
||||
* @return A possibly null exception as constructed using information
|
||||
* sent by the server. If null, a "success" status was indicated by
|
||||
* the server.
|
||||
*/
|
||||
public NamingException getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 5913778898401784775L;
|
||||
}
|
||||
78
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper.java
Normal file
78
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
abstract class VersionHelper {
|
||||
|
||||
private static VersionHelper helper = null;
|
||||
|
||||
VersionHelper() {} // Disallow anyone from creating one of these.
|
||||
|
||||
static {
|
||||
try {
|
||||
Class.forName("java.net.URLClassLoader"); // 1.2 test
|
||||
Class.forName("java.security.PrivilegedAction"); // 1.2 test
|
||||
helper = (VersionHelper)
|
||||
Class.forName(
|
||||
"com.sun.jndi.ldap.VersionHelper12").newInstance();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
// Use 1.1 helper if 1.2 test fails, or if we cannot create 1.2 helper
|
||||
if (helper == null) {
|
||||
try {
|
||||
helper = (VersionHelper)
|
||||
Class.forName(
|
||||
"com.sun.jndi.ldap.VersionHelper11").newInstance();
|
||||
} catch (Exception e) {
|
||||
// should never happen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VersionHelper getVersionHelper() {
|
||||
return helper;
|
||||
}
|
||||
|
||||
abstract ClassLoader getURLClassLoader(String[] url)
|
||||
throws MalformedURLException;
|
||||
|
||||
|
||||
static protected URL[] getUrlArray(String[] url) throws MalformedURLException {
|
||||
URL[] urlArray = new URL[url.length];
|
||||
for (int i = 0; i < urlArray.length; i++) {
|
||||
urlArray[i] = new URL(url[i]);
|
||||
}
|
||||
return urlArray;
|
||||
}
|
||||
|
||||
abstract Class<?> loadClass(String className) throws ClassNotFoundException;
|
||||
|
||||
abstract Thread createThread(Runnable r);
|
||||
}
|
||||
128
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper12.java
Normal file
128
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper12.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.misc.SharedSecrets;
|
||||
|
||||
final class VersionHelper12 extends VersionHelper {
|
||||
|
||||
// System property to control whether classes may be loaded from an
|
||||
// arbitrary URL code base.
|
||||
private static final String TRUST_URL_CODEBASE_PROPERTY =
|
||||
"com.sun.jndi.ldap.object.trustURLCodebase";
|
||||
|
||||
// System property to control whether classes are allowed to be loaded from
|
||||
// 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' attributes.
|
||||
private static final String TRUST_SERIAL_DATA_PROPERTY =
|
||||
"com.sun.jndi.ldap.object.trustSerialData";
|
||||
|
||||
/**
|
||||
* Determines whether objects may be deserialized or reconstructed from a content of
|
||||
* 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' LDAP attributes.
|
||||
*/
|
||||
private static final boolean trustSerialData;
|
||||
|
||||
// Determine whether classes may be loaded from an arbitrary URL code base.
|
||||
private static final boolean trustURLCodebase;
|
||||
|
||||
static {
|
||||
String trust = getPrivilegedProperty(TRUST_URL_CODEBASE_PROPERTY, "false");
|
||||
trustURLCodebase = "true".equalsIgnoreCase(trust);
|
||||
String trustSDString = getPrivilegedProperty(TRUST_SERIAL_DATA_PROPERTY, "false");
|
||||
trustSerialData = "true".equalsIgnoreCase(trustSDString);
|
||||
}
|
||||
|
||||
private static String getPrivilegedProperty(String propertyName, String defaultVal) {
|
||||
PrivilegedAction<String> action = () -> System.getProperty(propertyName, defaultVal);
|
||||
if (System.getSecurityManager() == null) {
|
||||
return action.run();
|
||||
} else {
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
}
|
||||
|
||||
VersionHelper12() {} // Disallow external from creating one of these.
|
||||
|
||||
/**
|
||||
* Returns true if deserialization or reconstruction of objects from
|
||||
* 'javaSerializedData', 'javaRemoteLocation' and 'javaReferenceAddress'
|
||||
* LDAP attributes is allowed.
|
||||
*
|
||||
* @return true if deserialization is allowed; false - otherwise
|
||||
*/
|
||||
public static boolean isSerialDataAllowed() {
|
||||
return trustSerialData;
|
||||
}
|
||||
|
||||
ClassLoader getURLClassLoader(String[] url)
|
||||
throws MalformedURLException {
|
||||
ClassLoader parent = getContextClassLoader();
|
||||
/*
|
||||
* Classes may only be loaded from an arbitrary URL code base when
|
||||
* the system property com.sun.jndi.ldap.object.trustURLCodebase
|
||||
* has been set to "true".
|
||||
*/
|
||||
if (url != null && trustURLCodebase) {
|
||||
return URLClassLoader.newInstance(getUrlArray(url), parent);
|
||||
} else {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> loadClass(String className) throws ClassNotFoundException {
|
||||
ClassLoader cl = getContextClassLoader();
|
||||
return Class.forName(className, true, cl);
|
||||
}
|
||||
|
||||
private ClassLoader getContextClassLoader() {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Thread createThread(final Runnable r) {
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
// 4290486: doPrivileged is needed to create a thread in
|
||||
// an environment that restricts "modifyThreadGroup".
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<Thread>() {
|
||||
public Thread run() {
|
||||
return SharedSecrets.getJavaLangAccess()
|
||||
.newThreadWithAcc(r, acc);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
471
jdkSrc/jdk8/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java
Normal file
471
jdkSrc/jdk8/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.ext;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import sun.security.util.HostnameChecker;
|
||||
|
||||
import javax.naming.ldap.*;
|
||||
import com.sun.jndi.ldap.Connection;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Extended Response for StartTLS as
|
||||
* defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
|
||||
* Access Protocol (v3): Extension for Transport Layer Security</a>
|
||||
*
|
||||
* The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
|
||||
* and no extended response value is defined.
|
||||
*
|
||||
*<p>
|
||||
* The Start TLS extended request and response are used to establish
|
||||
* a TLS connection over the existing LDAP connection associated with
|
||||
* the JNDI context on which <tt>extendedOperation()</tt> is invoked.
|
||||
*
|
||||
* @see StartTlsRequest
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class StartTlsResponseImpl extends StartTlsResponse {
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
/*
|
||||
* The dNSName type in a subjectAltName extension of an X.509 certificate
|
||||
*/
|
||||
private static final int DNSNAME_TYPE = 2;
|
||||
|
||||
/*
|
||||
* The server's hostname.
|
||||
*/
|
||||
private transient String hostname = null;
|
||||
|
||||
/*
|
||||
* The LDAP socket.
|
||||
*/
|
||||
private transient Connection ldapConnection = null;
|
||||
|
||||
/*
|
||||
* The original input stream.
|
||||
*/
|
||||
private transient InputStream originalInputStream = null;
|
||||
|
||||
/*
|
||||
* The original output stream.
|
||||
*/
|
||||
private transient OutputStream originalOutputStream = null;
|
||||
|
||||
/*
|
||||
* The SSL socket.
|
||||
*/
|
||||
private transient SSLSocket sslSocket = null;
|
||||
|
||||
/*
|
||||
* The SSL socket factories.
|
||||
*/
|
||||
private transient SSLSocketFactory defaultFactory = null;
|
||||
private transient SSLSocketFactory currentFactory = null;
|
||||
|
||||
/*
|
||||
* The list of cipher suites to be enabled.
|
||||
*/
|
||||
private transient String[] suites = null;
|
||||
|
||||
/*
|
||||
* The hostname verifier callback.
|
||||
*/
|
||||
private transient HostnameVerifier verifier = null;
|
||||
|
||||
/*
|
||||
* The flag to indicate that the TLS connection is closed.
|
||||
*/
|
||||
private transient boolean isClosed = true;
|
||||
|
||||
private static final long serialVersionUID = -1126624615143411328L;
|
||||
|
||||
// public no-arg constructor required by JDK's Service Provider API.
|
||||
|
||||
public StartTlsResponseImpl() {}
|
||||
|
||||
/**
|
||||
* Overrides the default list of cipher suites enabled for use on the
|
||||
* TLS connection. The cipher suites must have already been listed by
|
||||
* <tt>SSLSocketFactory.getSupportedCipherSuites()</tt> as being supported.
|
||||
* Even if a suite has been enabled, it still might not be used because
|
||||
* the peer does not support it, or because the requisite certificates
|
||||
* (and private keys) are not available.
|
||||
*
|
||||
* @param suites The non-null list of names of all the cipher suites to
|
||||
* enable.
|
||||
* @see #negotiate
|
||||
*/
|
||||
public void setEnabledCipherSuites(String[] suites) {
|
||||
// The impl does accept null suites, although the spec requires
|
||||
// a non-null list.
|
||||
this.suites = suites == null ? null : suites.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default hostname verifier used by <tt>negotiate()</tt>
|
||||
* after the TLS handshake has completed. If
|
||||
* <tt>setHostnameVerifier()</tt> has not been called before
|
||||
* <tt>negotiate()</tt> is invoked, <tt>negotiate()</tt>
|
||||
* will perform a simple case ignore match. If called after
|
||||
* <tt>negotiate()</tt>, this method does not do anything.
|
||||
*
|
||||
* @param verifier The non-null hostname verifier callback.
|
||||
* @see #negotiate
|
||||
*/
|
||||
public void setHostnameVerifier(HostnameVerifier verifier) {
|
||||
this.verifier = verifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negotiates a TLS session using the default SSL socket factory.
|
||||
* <p>
|
||||
* This method is equivalent to <tt>negotiate(null)</tt>.
|
||||
*
|
||||
* @return The negotiated SSL session
|
||||
* @throw IOException If an IO error was encountered while establishing
|
||||
* the TLS session.
|
||||
* @see #setEnabledCipherSuites
|
||||
* @see #setHostnameVerifier
|
||||
*/
|
||||
public SSLSession negotiate() throws IOException {
|
||||
|
||||
return negotiate(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negotiates a TLS session using an SSL socket factory.
|
||||
* <p>
|
||||
* Creates an SSL socket using the supplied SSL socket factory and
|
||||
* attaches it to the existing connection. Performs the TLS handshake
|
||||
* and returns the negotiated session information.
|
||||
* <p>
|
||||
* If cipher suites have been set via <tt>setEnabledCipherSuites</tt>
|
||||
* then they are enabled before the TLS handshake begins.
|
||||
* <p>
|
||||
* Hostname verification is performed after the TLS handshake completes.
|
||||
* The default check performs a case insensitive match of the server's
|
||||
* hostname against that in the server's certificate. The server's
|
||||
* hostname is extracted from the subjectAltName in the server's
|
||||
* certificate (if present). Otherwise the value of the common name
|
||||
* attribute of the subject name is used. If a callback has
|
||||
* been set via <tt>setHostnameVerifier</tt> then that verifier is used if
|
||||
* the default check fails.
|
||||
* <p>
|
||||
* If an error occurs then the SSL socket is closed and an IOException
|
||||
* is thrown. The underlying connection remains intact.
|
||||
*
|
||||
* @param factory The possibly null SSL socket factory to use.
|
||||
* If null, the default SSL socket factory is used.
|
||||
* @return The negotiated SSL session
|
||||
* @throw IOException If an IO error was encountered while establishing
|
||||
* the TLS session.
|
||||
* @see #setEnabledCipherSuites
|
||||
* @see #setHostnameVerifier
|
||||
*/
|
||||
public SSLSession negotiate(SSLSocketFactory factory) throws IOException {
|
||||
|
||||
if (isClosed && sslSocket != null) {
|
||||
throw new IOException("TLS connection is closed.");
|
||||
}
|
||||
|
||||
if (factory == null) {
|
||||
factory = getDefaultFactory();
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: About to start handshake");
|
||||
}
|
||||
|
||||
SSLSession sslSession = startHandshake(factory).getSession();
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Completed handshake");
|
||||
}
|
||||
|
||||
SSLPeerUnverifiedException verifExcep = null;
|
||||
try {
|
||||
if (verify(hostname, sslSession)) {
|
||||
isClosed = false;
|
||||
return sslSession;
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// Save to return the cause
|
||||
verifExcep = e;
|
||||
}
|
||||
if ((verifier != null) &&
|
||||
verifier.verify(hostname, sslSession)) {
|
||||
isClosed = false;
|
||||
return sslSession;
|
||||
}
|
||||
|
||||
// Verification failed
|
||||
close();
|
||||
sslSession.invalidate();
|
||||
if (verifExcep == null) {
|
||||
verifExcep = new SSLPeerUnverifiedException(
|
||||
"hostname of the server '" + hostname +
|
||||
"' does not match the hostname in the " +
|
||||
"server's certificate.");
|
||||
}
|
||||
throw verifExcep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the TLS connection gracefully and reverts back to the underlying
|
||||
* connection.
|
||||
*
|
||||
* @throw IOException If an IO error was encountered while closing the
|
||||
* TLS connection
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: replacing SSL " +
|
||||
"streams with originals");
|
||||
}
|
||||
|
||||
// Replace SSL streams with the original streams
|
||||
ldapConnection.replaceStreams(
|
||||
originalInputStream, originalOutputStream, false);
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: closing SSL Socket");
|
||||
}
|
||||
sslSocket.close();
|
||||
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection for TLS to use. The TLS connection will be attached
|
||||
* to this connection.
|
||||
*
|
||||
* @param ldapConnection The non-null connection to use.
|
||||
* @param hostname The server's hostname. If null, the hostname used to
|
||||
* open the connection will be used instead.
|
||||
*/
|
||||
public void setConnection(Connection ldapConnection, String hostname) {
|
||||
this.ldapConnection = ldapConnection;
|
||||
this.hostname = (hostname == null || hostname.isEmpty())
|
||||
? ldapConnection.host : hostname;
|
||||
originalInputStream = ldapConnection.inStream;
|
||||
originalOutputStream = ldapConnection.outStream;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the default SSL socket factory.
|
||||
*
|
||||
* @return The default SSL socket factory.
|
||||
* @throw IOException If TLS is not supported.
|
||||
*/
|
||||
private SSLSocketFactory getDefaultFactory() throws IOException {
|
||||
|
||||
if (defaultFactory != null) {
|
||||
return defaultFactory;
|
||||
}
|
||||
|
||||
return (defaultFactory =
|
||||
(SSLSocketFactory) SSLSocketFactory.getDefault());
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the TLS handshake and manipulate the input and output streams.
|
||||
*
|
||||
* @param factory The SSL socket factory to use.
|
||||
* @return The SSL socket.
|
||||
* @throw IOException If an exception occurred while performing the
|
||||
* TLS handshake.
|
||||
*/
|
||||
private SSLSocket startHandshake(SSLSocketFactory factory)
|
||||
throws IOException {
|
||||
|
||||
if (ldapConnection == null) {
|
||||
throw new IllegalStateException("LDAP connection has not been set."
|
||||
+ " TLS requires an existing LDAP connection.");
|
||||
}
|
||||
|
||||
if (factory != currentFactory) {
|
||||
// Create SSL socket layered over the existing connection
|
||||
sslSocket = (SSLSocket) factory.createSocket(ldapConnection.sock,
|
||||
ldapConnection.host, ldapConnection.port, false);
|
||||
currentFactory = factory;
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Created socket : " + sslSocket);
|
||||
}
|
||||
}
|
||||
|
||||
if (suites != null) {
|
||||
sslSocket.setEnabledCipherSuites(suites);
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Enabled cipher suites");
|
||||
}
|
||||
}
|
||||
|
||||
// Connection must be quite for handshake to proceed
|
||||
|
||||
try {
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"StartTLS: Calling sslSocket.startHandshake");
|
||||
}
|
||||
sslSocket.startHandshake();
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"StartTLS: + Finished sslSocket.startHandshake");
|
||||
}
|
||||
|
||||
// Replace original streams with the new SSL streams
|
||||
ldapConnection.replaceStreams(sslSocket.getInputStream(),
|
||||
sslSocket.getOutputStream(), true);
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Replaced IO Streams");
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Got IO error during handshake");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
sslSocket.close();
|
||||
isClosed = true;
|
||||
throw e; // pass up exception
|
||||
}
|
||||
|
||||
return sslSocket;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the hostname in the server's certificate matches the
|
||||
* hostname of the server.
|
||||
* The server's first certificate is examined. If it has a subjectAltName
|
||||
* that contains a dNSName then that is used as the server's hostname.
|
||||
* The server's hostname may contain a wildcard for its left-most name part.
|
||||
* Otherwise, if the certificate has no subjectAltName then the value of
|
||||
* the common name attribute of the subject name is used.
|
||||
*
|
||||
* @param hostname The hostname of the server.
|
||||
* @param session the SSLSession used on the connection to host.
|
||||
* @return true if the hostname is verified, false otherwise.
|
||||
*/
|
||||
|
||||
private boolean verify(String hostname, SSLSession session)
|
||||
throws SSLPeerUnverifiedException {
|
||||
|
||||
java.security.cert.Certificate[] certs = null;
|
||||
|
||||
// if IPv6 strip off the "[]"
|
||||
if (hostname != null && hostname.startsWith("[") &&
|
||||
hostname.endsWith("]")) {
|
||||
hostname = hostname.substring(1, hostname.length() - 1);
|
||||
}
|
||||
try {
|
||||
HostnameChecker checker = HostnameChecker.getInstance(
|
||||
HostnameChecker.TYPE_LDAP);
|
||||
// Use ciphersuite to determine whether Kerberos is active.
|
||||
if (session.getCipherSuite().startsWith("TLS_KRB5")) {
|
||||
Principal principal = getPeerPrincipal(session);
|
||||
if (!HostnameChecker.match(hostname, principal)) {
|
||||
throw new SSLPeerUnverifiedException(
|
||||
"hostname of the kerberos principal:" + principal +
|
||||
" does not match the hostname:" + hostname);
|
||||
}
|
||||
} else { // X.509
|
||||
|
||||
// get the subject's certificate
|
||||
certs = session.getPeerCertificates();
|
||||
X509Certificate peerCert;
|
||||
if (certs[0] instanceof java.security.cert.X509Certificate) {
|
||||
peerCert = (java.security.cert.X509Certificate) certs[0];
|
||||
} else {
|
||||
throw new SSLPeerUnverifiedException(
|
||||
"Received a non X509Certificate from the server");
|
||||
}
|
||||
checker.match(hostname, peerCert);
|
||||
}
|
||||
|
||||
// no exception means verification passed
|
||||
return true;
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
|
||||
/*
|
||||
* The application may enable an anonymous SSL cipher suite, and
|
||||
* hostname verification is not done for anonymous ciphers
|
||||
*/
|
||||
String cipher = session.getCipherSuite();
|
||||
if (cipher != null && (cipher.indexOf("_anon_") != -1)) {
|
||||
return true;
|
||||
}
|
||||
throw e;
|
||||
} catch (CertificateException e) {
|
||||
|
||||
/*
|
||||
* Pass up the cause of the failure
|
||||
*/
|
||||
throw(SSLPeerUnverifiedException)
|
||||
new SSLPeerUnverifiedException("hostname of the server '" +
|
||||
hostname +
|
||||
"' does not match the hostname in the " +
|
||||
"server's certificate.").initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the peer principal from the session
|
||||
*/
|
||||
private static Principal getPeerPrincipal(SSLSession session)
|
||||
throws SSLPeerUnverifiedException {
|
||||
Principal principal;
|
||||
try {
|
||||
principal = session.getPeerPrincipal();
|
||||
} catch (AbstractMethodError e) {
|
||||
// if the JSSE provider does not support it, return null, since
|
||||
// we need it only for Kerberos.
|
||||
principal = null;
|
||||
}
|
||||
return principal;
|
||||
}
|
||||
}
|
||||
160
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionDesc.java
Normal file
160
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionDesc.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
/**
|
||||
* Represents a description of PooledConnection in Connections.
|
||||
* Contains a PooledConnection, its state (busy, idle, expired), and idle time.
|
||||
*
|
||||
* Any access or update to a descriptor's state is synchronized.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class ConnectionDesc {
|
||||
private final static boolean debug = Pool.debug;
|
||||
|
||||
// Package private because used by Pool.showStats()
|
||||
static final byte BUSY = (byte)0;
|
||||
static final byte IDLE = (byte)1;
|
||||
static final byte EXPIRED = (byte)2;
|
||||
|
||||
final private PooledConnection conn;
|
||||
|
||||
private byte state = IDLE; // initial state
|
||||
private long idleSince;
|
||||
private long useCount = 0; // for stats & debugging only
|
||||
|
||||
ConnectionDesc(PooledConnection conn) {
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
ConnectionDesc(PooledConnection conn, boolean use) {
|
||||
this.conn = conn;
|
||||
if (use) {
|
||||
state = BUSY;
|
||||
++useCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Two desc are equal if their PooledConnections are the same.
|
||||
* This is useful when searching for a ConnectionDesc using only its
|
||||
* PooledConnection.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
return obj != null
|
||||
&& obj instanceof ConnectionDesc
|
||||
&& ((ConnectionDesc)obj).conn == conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashcode is that of PooledConnection to facilitate
|
||||
* searching for a ConnectionDesc using only its PooledConnection.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return conn.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the state of a ConnectionDesc from BUSY to IDLE and
|
||||
* records the current time so that we will know how long it has been idle.
|
||||
* @return true if state change occurred.
|
||||
*/
|
||||
synchronized boolean release() {
|
||||
d("release()");
|
||||
if (state == BUSY) {
|
||||
state = IDLE;
|
||||
|
||||
idleSince = System.currentTimeMillis();
|
||||
return true; // Connection released, ready for reuse
|
||||
} else {
|
||||
return false; // Connection wasn't busy to begin with
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If ConnectionDesc is IDLE, change its state to BUSY and return
|
||||
* its connection.
|
||||
*
|
||||
* @return ConnectionDesc's PooledConnection if it was idle; null otherwise.
|
||||
*/
|
||||
synchronized PooledConnection tryUse() {
|
||||
d("tryUse()");
|
||||
|
||||
if (state == IDLE) {
|
||||
state = BUSY;
|
||||
++useCount;
|
||||
return conn;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If ConnectionDesc is IDLE and has expired, close the corresponding
|
||||
* PooledConnection.
|
||||
*
|
||||
* @param threshold a connection that has been idle before this time
|
||||
* have expired.
|
||||
*
|
||||
* @return true if entry is idle and has expired; false otherwise.
|
||||
*/
|
||||
synchronized boolean expire(long threshold) {
|
||||
if (state == IDLE && idleSince < threshold) {
|
||||
|
||||
d("expire(): expired");
|
||||
|
||||
state = EXPIRED;
|
||||
conn.closeConnection(); // Close real connection
|
||||
|
||||
return true; // Expiration successful
|
||||
} else {
|
||||
d("expire(): not expired");
|
||||
return false; // Expiration did not occur
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return conn.toString() + " " +
|
||||
(state == BUSY ? "busy" : (state == IDLE ? "idle" : "expired"));
|
||||
}
|
||||
|
||||
// Used by Pool.showStats()
|
||||
int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
// Used by Pool.showStats()
|
||||
long getUseCount() {
|
||||
return useCount;
|
||||
}
|
||||
|
||||
private void d(String msg) {
|
||||
if (debug) {
|
||||
System.err.println("ConnectionDesc." + msg + " " + toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
391
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Connections.java
Normal file
391
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Connections.java
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
import java.util.ArrayList; // JDK 1.2
|
||||
import java.util.List;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.InterruptedNamingException;
|
||||
import javax.naming.CommunicationException;
|
||||
|
||||
/**
|
||||
* Represents a list of PooledConnections (actually, ConnectionDescs) with the
|
||||
* same pool id.
|
||||
* The list starts out with an initial number of connections.
|
||||
* Additional PooledConnections are created lazily upon demand.
|
||||
* The list has a maximum size. When the number of connections
|
||||
* reaches the maximum size, a request for a PooledConnection blocks until
|
||||
* a connection is returned to the list. A maximum size of zero means that
|
||||
* there is no maximum: connection creation will be attempted when
|
||||
* no idle connection is available.
|
||||
*
|
||||
* The list may also have a preferred size. If the current list size
|
||||
* is less than the preferred size, a request for a connection will result in
|
||||
* a PooledConnection being created (even if an idle connection is available).
|
||||
* If the current list size is greater than the preferred size,
|
||||
* a connection being returned to the list will be closed and removed from
|
||||
* the list. A preferred size of zero means that there is no preferred size:
|
||||
* connections are created only when no idle connection is available and
|
||||
* a connection being returned to the list is not closed. Regardless of the
|
||||
* preferred size, connection creation always observes the maximum size:
|
||||
* a connection won't be created if the list size is at or exceeds the
|
||||
* maximum size.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
// Package private: accessed only by Pool
|
||||
final class Connections implements PoolCallback {
|
||||
private static final boolean debug = Pool.debug;
|
||||
private static final boolean trace =
|
||||
com.sun.jndi.ldap.LdapPoolManager.trace;
|
||||
private static final int DEFAULT_SIZE = 10;
|
||||
|
||||
final private int maxSize;
|
||||
final private int prefSize;
|
||||
final private List<ConnectionDesc> conns;
|
||||
|
||||
private boolean closed = false; // Closed for business
|
||||
private Reference<Object> ref; // maintains reference to id to prevent premature GC
|
||||
|
||||
/**
|
||||
* @param id the identity (connection request) of the connections in the list
|
||||
* @param initSize the number of connections to create initially
|
||||
* @param prefSize the preferred size of the pool. The pool will try
|
||||
* to maintain a pool of this size by creating and closing connections
|
||||
* as needed.
|
||||
* @param maxSize the maximum size of the pool. The pool will not exceed
|
||||
* this size. If the pool is at this size, a request for a connection
|
||||
* will block until an idle connection is released to the pool or
|
||||
* when one is removed.
|
||||
* @param factory The factory responsible for creating a connection
|
||||
*/
|
||||
Connections(Object id, int initSize, int prefSize, int maxSize,
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
|
||||
this.maxSize = maxSize;
|
||||
if (maxSize > 0) {
|
||||
// prefSize and initSize cannot exceed specified maxSize
|
||||
this.prefSize = Math.min(prefSize, maxSize);
|
||||
initSize = Math.min(initSize, maxSize);
|
||||
} else {
|
||||
this.prefSize = prefSize;
|
||||
}
|
||||
conns = new ArrayList<>(maxSize > 0 ? maxSize : DEFAULT_SIZE);
|
||||
|
||||
// Maintain soft ref to id so that this Connections' entry in
|
||||
// Pool doesn't get GC'ed prematurely
|
||||
ref = new SoftReference<>(id);
|
||||
|
||||
d("init size=", initSize);
|
||||
d("max size=", maxSize);
|
||||
d("preferred size=", prefSize);
|
||||
|
||||
// Create initial connections
|
||||
PooledConnection conn;
|
||||
for (int i = 0; i < initSize; i++) {
|
||||
conn = factory.createPooledConnection(this);
|
||||
td("Create ", conn ,factory);
|
||||
conns.add(new ConnectionDesc(conn)); // Add new idle conn to pool
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a PooledConnection from this list of connections.
|
||||
* Use an existing one if one is idle, or create one if the list's
|
||||
* max size hasn't been reached. If max size has been reached, wait
|
||||
* for a PooledConnection to be returned, or one to be removed (thus
|
||||
* not reaching the max size any longer).
|
||||
*
|
||||
* @param timeout if > 0, msec to wait until connection is available
|
||||
* @param factory creates the PooledConnection if one needs to be created
|
||||
*
|
||||
* @return A non-null PooledConnection
|
||||
* @throws NamingException PooledConnection cannot be created, because this
|
||||
* thread was interrupted while it waited for an available connection,
|
||||
* or if it timed out while waiting, or the creation of a connection
|
||||
* resulted in an error.
|
||||
*/
|
||||
synchronized PooledConnection get(long timeout,
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
PooledConnection conn;
|
||||
long start = (timeout > 0 ? System.currentTimeMillis() : 0);
|
||||
long waittime = timeout;
|
||||
|
||||
d("get(): before");
|
||||
while ((conn = getOrCreateConnection(factory)) == null) {
|
||||
if (timeout > 0 && waittime <= 0) {
|
||||
throw new CommunicationException(
|
||||
"Timeout exceeded while waiting for a connection: " +
|
||||
timeout + "ms");
|
||||
}
|
||||
try {
|
||||
d("get(): waiting");
|
||||
if (waittime > 0) {
|
||||
wait(waittime); // Wait until one is released or removed
|
||||
} else {
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedNamingException(
|
||||
"Interrupted while waiting for a connection");
|
||||
}
|
||||
// Check whether we timed out
|
||||
if (timeout > 0) {
|
||||
long now = System.currentTimeMillis();
|
||||
waittime = timeout - (now - start);
|
||||
}
|
||||
}
|
||||
|
||||
d("get(): after");
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an idle connection from this list if one is available.
|
||||
* If none is available, create a new one if maxSize hasn't been reached.
|
||||
* If maxSize has been reached, return null.
|
||||
* Always called from a synchronized method.
|
||||
*/
|
||||
private PooledConnection getOrCreateConnection(
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
|
||||
int size = conns.size(); // Current number of idle/nonidle conns
|
||||
PooledConnection conn = null;
|
||||
|
||||
if (prefSize <= 0 || size >= prefSize) {
|
||||
// If no prefSize specified, or list size already meets or
|
||||
// exceeds prefSize, then first look for an idle connection
|
||||
ConnectionDesc entry;
|
||||
for (int i = 0; i < size; i++) {
|
||||
entry = conns.get(i);
|
||||
if ((conn = entry.tryUse()) != null) {
|
||||
d("get(): use ", conn);
|
||||
td("Use ", conn);
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if list size already at maxSize specified
|
||||
if (maxSize > 0 && size >= maxSize) {
|
||||
return null; // List size is at limit; cannot create any more
|
||||
}
|
||||
|
||||
conn = factory.createPooledConnection(this);
|
||||
td("Create and use ", conn, factory);
|
||||
conns.add(new ConnectionDesc(conn, true)); // Add new conn to pool
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases connection back into list.
|
||||
* If the list size is below prefSize, the connection may be reused.
|
||||
* If the list size exceeds prefSize, then the connection is closed
|
||||
* and removed from the list.
|
||||
*
|
||||
* public because implemented as part of PoolCallback.
|
||||
*/
|
||||
public synchronized boolean releasePooledConnection(PooledConnection conn) {
|
||||
ConnectionDesc entry;
|
||||
int loc = conns.indexOf(entry=new ConnectionDesc(conn));
|
||||
|
||||
d("release(): ", conn);
|
||||
|
||||
if (loc >= 0) {
|
||||
// Found entry
|
||||
|
||||
if (closed || (prefSize > 0 && conns.size() > prefSize)) {
|
||||
// If list size exceeds prefSize, close connection
|
||||
|
||||
d("release(): closing ", conn);
|
||||
td("Close ", conn);
|
||||
|
||||
// size must be >= 2 so don't worry about empty list
|
||||
conns.remove(entry);
|
||||
conn.closeConnection();
|
||||
|
||||
} else {
|
||||
d("release(): release ", conn);
|
||||
td("Release ", conn);
|
||||
|
||||
// Get ConnectionDesc from list to get correct state info
|
||||
entry = conns.get(loc);
|
||||
// Return connection to list, ready for reuse
|
||||
entry.release();
|
||||
}
|
||||
notifyAll();
|
||||
d("release(): notify");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes PooledConnection from list of connections.
|
||||
* The closing of the connection is separate from this method.
|
||||
* This method is called usually when the caller encouters an error
|
||||
* when using the connection and wants it removed from the pool.
|
||||
*
|
||||
* @return true if conn removed; false if it was not in pool
|
||||
*
|
||||
* public because implemented as part of PoolCallback.
|
||||
*/
|
||||
public synchronized boolean removePooledConnection(PooledConnection conn) {
|
||||
if (conns.remove(new ConnectionDesc(conn))) {
|
||||
d("remove(): ", conn);
|
||||
|
||||
notifyAll();
|
||||
|
||||
d("remove(): notify");
|
||||
td("Remove ", conn);
|
||||
|
||||
if (conns.isEmpty()) {
|
||||
// Remove softref to make pool entry eligible for GC.
|
||||
// Once ref has been removed, it cannot be reinstated.
|
||||
ref = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
d("remove(): not found ", conn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through all entries in list, removes and closes ones that have been
|
||||
* idle before threshold.
|
||||
*
|
||||
* @param threshold an entry idle since this time has expired.
|
||||
* @return true if no more connections in list
|
||||
*/
|
||||
boolean expire(long threshold) {
|
||||
List<ConnectionDesc> clonedConns;
|
||||
synchronized(this) {
|
||||
clonedConns = new ArrayList<>(conns);
|
||||
}
|
||||
List<ConnectionDesc> expired = new ArrayList<>();
|
||||
|
||||
for (ConnectionDesc entry : clonedConns) {
|
||||
d("expire(): ", entry);
|
||||
if (entry.expire(threshold)) {
|
||||
expired.add(entry);
|
||||
td("expire(): Expired ", entry);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
conns.removeAll(expired);
|
||||
// Don't need to call notify() because we're
|
||||
// removing only idle connections. If there were
|
||||
// idle connections, then there should be no waiters.
|
||||
return conns.isEmpty(); // whether whole list has 'expired'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this instance of Connections has been removed from Pool.
|
||||
* This means that no one can get any pooled connections from this
|
||||
* Connections any longer. Expire all idle connections as of 'now'
|
||||
* and leave indicator so that any in-use connections will be closed upon
|
||||
* their return.
|
||||
*/
|
||||
synchronized void close() {
|
||||
expire(System.currentTimeMillis()); // Expire idle connections
|
||||
closed = true; // Close in-use connections when they are returned
|
||||
}
|
||||
|
||||
String getStats() {
|
||||
int idle = 0;
|
||||
int busy = 0;
|
||||
int expired = 0;
|
||||
long use = 0;
|
||||
int len;
|
||||
|
||||
synchronized (this) {
|
||||
len = conns.size();
|
||||
|
||||
ConnectionDesc entry;
|
||||
for (int i = 0; i < len; i++) {
|
||||
entry = conns.get(i);
|
||||
use += entry.getUseCount();
|
||||
switch (entry.getState()) {
|
||||
case ConnectionDesc.BUSY:
|
||||
++busy;
|
||||
break;
|
||||
case ConnectionDesc.IDLE:
|
||||
++idle;
|
||||
break;
|
||||
case ConnectionDesc.EXPIRED:
|
||||
++expired;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "size=" + len + "; use=" + use + "; busy=" + busy
|
||||
+ "; idle=" + idle + "; expired=" + expired;
|
||||
}
|
||||
|
||||
private void d(String msg, Object o1) {
|
||||
if (debug) {
|
||||
d(msg + o1);
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg, int i) {
|
||||
if (debug) {
|
||||
d(msg + i);
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg) {
|
||||
if (debug) {
|
||||
System.err.println(this + "." + msg + "; size: " + conns.size());
|
||||
}
|
||||
}
|
||||
|
||||
private void td(String msg, Object o1, Object o2) {
|
||||
if (trace) { // redo test to avoid object creation
|
||||
td(msg + o1 + "[" + o2 + "]");
|
||||
}
|
||||
}
|
||||
private void td(String msg, Object o1) {
|
||||
if (trace) { // redo test to avoid object creation
|
||||
td(msg + o1);
|
||||
}
|
||||
}
|
||||
private void td(String msg) {
|
||||
if (trace) {
|
||||
System.err.println(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsRef.java
Normal file
58
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsRef.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
/**
|
||||
* Is a reference to Connections that is stored in Pool.
|
||||
* This is an intermediate object that is outside of the circular
|
||||
* reference loop of
|
||||
* com.sun.jndi.ldap.Connection <-> com.sun.jndi.ldap.LdapClient
|
||||
* <-> com.sun.jndi.ldap.pool.Connections
|
||||
*
|
||||
* Because Connection is a daemon thread, it will keep LdapClient
|
||||
* alive until LdapClient closes Connection. This will in turn
|
||||
* keep Connections alive. So even when Connections is removed
|
||||
* from (the WeakHashMap of) Pool, it won't be finalized.
|
||||
* ConnectionsRef acts as Connections's finalizer.
|
||||
*
|
||||
* Without connection pooling, com.sun.jndi.ldap.LdapCtx's finalize()
|
||||
* closes LdapClient, which in turn closes Connection.
|
||||
* With connection pooling, ConnectionsRef's finalize() calls
|
||||
* Connections.close(), which in turn will close all idle connections
|
||||
* and mark Connections such that in-use connections will be closed
|
||||
* when they are returned to the pool.
|
||||
*/
|
||||
final class ConnectionsRef {
|
||||
final private Connections conns;
|
||||
|
||||
ConnectionsRef(Connections conns) {
|
||||
this.conns = conns;
|
||||
}
|
||||
|
||||
Connections getConnections() {
|
||||
return conns;
|
||||
}
|
||||
}
|
||||
71
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsWeakRef.java
Normal file
71
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsWeakRef.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
|
||||
/*
|
||||
* This class defines a WeakReference to the ConnectionRef (the referent).
|
||||
*
|
||||
* The ConnectionRef enables to break the reference
|
||||
* cycle between Connection, LdapClient, Connections and ConnectionDesc,
|
||||
* shown in the figure below.
|
||||
*
|
||||
* -------> Connections -----> ConnectionDesc
|
||||
* | ^ |
|
||||
* | | |
|
||||
* | | |
|
||||
* ConnectionsRef LdapClient <------------
|
||||
* ^ | ^
|
||||
* : | |
|
||||
* : v |
|
||||
* ConnectionsWeakRef Connection
|
||||
*
|
||||
* The ConnectionsRef is for cleaning up the resources held by the
|
||||
* Connection thread by making them available to the GC. The pool
|
||||
* uses ConnectionRef to hold the pooled resources.
|
||||
*
|
||||
* This class in turn holds a WeakReference with a ReferenceQueue to the
|
||||
* ConnectionRef to track when the ConnectionRef becomes ready
|
||||
* for getting GC'ed. It extends from WeakReference in order to hold a
|
||||
* reference to Connections used for closing (which in turn terminates
|
||||
* the Connection thread) it by monitoring the ReferenceQueue.
|
||||
*/
|
||||
class ConnectionsWeakRef extends WeakReference<ConnectionsRef> {
|
||||
|
||||
private final Connections conns;
|
||||
|
||||
ConnectionsWeakRef (ConnectionsRef connsRef,
|
||||
ReferenceQueue<? super ConnectionsRef> queue) {
|
||||
super(connsRef, queue);
|
||||
this.conns = connsRef.getConnections();
|
||||
}
|
||||
|
||||
Connections getConnections() {
|
||||
return conns;
|
||||
}
|
||||
}
|
||||
254
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Pool.java
Normal file
254
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Pool.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* A map of pool ids to Connections.
|
||||
* Key is an object that uniquely identifies a PooledConnection request
|
||||
* (typically information needed to create the connection).
|
||||
* The definitions of the key's equals() and hashCode() methods are
|
||||
* vital to its unique identification in a Pool.
|
||||
*
|
||||
* Value is a ConnectionsRef, which is a reference to Connections,
|
||||
* a list of equivalent connections.
|
||||
*
|
||||
* Supports methods that
|
||||
* - retrieves (or creates as necessary) a connection from the pool
|
||||
* - removes expired connections from the pool
|
||||
*
|
||||
* Connections cleanup:
|
||||
* A WeakHashMap is used for mapping the pool ids and Connections.
|
||||
* A SoftReference from the value to the key is kept to hold the map
|
||||
* entry as long as possible. This allows the GC to remove Connections
|
||||
* from the Pool under situations of VM running out of resources.
|
||||
* To take an appropriate action of 'closing the connections' before the GC
|
||||
* reclaims the ConnectionsRef objects, the ConnectionsRef objects are made
|
||||
* weakly reachable through a list of weak references registered with
|
||||
* a reference queue.
|
||||
* Upon an entry gets removed from the WeakHashMap, the ConnectionsRef (value
|
||||
* in the map) object is weakly reachable. When another sweep of
|
||||
* clearing the weak references is made by the GC it puts the corresponding
|
||||
* ConnectionsWeakRef object into the reference queue.
|
||||
* The reference queue is monitored lazily for reclaimable Connections
|
||||
* whenever a pooled connection is requested or a call to remove the expired
|
||||
* connections is made. The monitoring is done regularly when idle connection
|
||||
* timeout is set as the PoolCleaner removes expired connections periodically.
|
||||
* As determined by the experiements, cleanup of resources using the
|
||||
* ReferenceQueue mechanism is reliable and has immidiate effect than the
|
||||
* finalizer approach.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final public class Pool {
|
||||
|
||||
static final boolean debug = com.sun.jndi.ldap.LdapPoolManager.debug;
|
||||
|
||||
/*
|
||||
* Used for connections cleanup
|
||||
*/
|
||||
private static final ReferenceQueue<ConnectionsRef> queue =
|
||||
new ReferenceQueue<>();
|
||||
private static final Collection<Reference<ConnectionsRef>> weakRefs =
|
||||
Collections.synchronizedList(new LinkedList<Reference<ConnectionsRef>>());
|
||||
|
||||
final private int maxSize; // max num of identical conn per pool
|
||||
final private int prefSize; // preferred num of identical conn per pool
|
||||
final private int initSize; // initial number of identical conn to create
|
||||
final private Map<Object, ConnectionsRef> map;
|
||||
|
||||
public Pool(int initSize, int prefSize, int maxSize) {
|
||||
map = new WeakHashMap<>();
|
||||
this.prefSize = prefSize;
|
||||
this.maxSize = maxSize;
|
||||
this.initSize = initSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pooled connection for id. The pooled connection might be
|
||||
* newly created, as governed by the maxSize and prefSize settings.
|
||||
* If a pooled connection is unavailable and cannot be created due
|
||||
* to the maxSize constraint, this call blocks until the constraint
|
||||
* is removed or until 'timeout' ms has elapsed.
|
||||
*
|
||||
* @param id identity of the connection to get
|
||||
* @param timeout the number of milliseconds to wait before giving up
|
||||
* @param factory the factory to use for creating the connection if
|
||||
* creation is necessary
|
||||
* @return a pooled connection
|
||||
* @throws NamingException the connection could not be created due to
|
||||
* an error.
|
||||
*/
|
||||
public PooledConnection getPooledConnection(Object id, long timeout,
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
|
||||
d("get(): ", id);
|
||||
if (debug) {
|
||||
synchronized (map) {
|
||||
d("size: ", map.size());
|
||||
}
|
||||
}
|
||||
|
||||
expungeStaleConnections();
|
||||
|
||||
Connections conns;
|
||||
synchronized (map) {
|
||||
conns = getConnections(id);
|
||||
if (conns == null) {
|
||||
d("get(): creating new connections list for ", id);
|
||||
|
||||
// No connections for this id so create a new list
|
||||
conns = new Connections(id, initSize, prefSize, maxSize,
|
||||
factory);
|
||||
ConnectionsRef connsRef = new ConnectionsRef(conns);
|
||||
map.put(id, connsRef);
|
||||
|
||||
// Create a weak reference to ConnectionsRef
|
||||
Reference<ConnectionsRef> weakRef =
|
||||
new ConnectionsWeakRef(connsRef, queue);
|
||||
|
||||
// Keep the weak reference through the element of a linked list
|
||||
weakRefs.add(weakRef);
|
||||
}
|
||||
d("get(): size after: ", map.size());
|
||||
}
|
||||
|
||||
return conns.get(timeout, factory); // get one connection from list
|
||||
}
|
||||
|
||||
private Connections getConnections(Object id) {
|
||||
ConnectionsRef ref = map.get(id);
|
||||
return (ref != null) ? ref.getConnections() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through the connections in this Pool and expires ones that
|
||||
* have been idle before 'threshold'. An expired connection is closed
|
||||
* and then removed from the pool (removePooledConnection() will eventually
|
||||
* be called, and the list of pools itself removed if it becomes empty).
|
||||
*
|
||||
* @param threshold connections idle before 'threshold' should be closed
|
||||
* and removed.
|
||||
*/
|
||||
public void expire(long threshold) {
|
||||
Collection<ConnectionsRef> copy;
|
||||
synchronized (map) {
|
||||
copy = new ArrayList<>(map.values());
|
||||
}
|
||||
|
||||
ArrayList<ConnectionsRef> removed = new ArrayList<>();
|
||||
Connections conns;
|
||||
for (ConnectionsRef ref : copy) {
|
||||
conns = ref.getConnections();
|
||||
if (conns.expire(threshold)) {
|
||||
d("expire(): removing ", conns);
|
||||
removed.add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (map) {
|
||||
map.values().removeAll(removed);
|
||||
}
|
||||
|
||||
expungeStaleConnections();
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the connections contained in the ConnectionsRef object that
|
||||
* is going to be reclaimed by the GC. Called by getPooledConnection()
|
||||
* and expire() methods of this class.
|
||||
*/
|
||||
private static void expungeStaleConnections() {
|
||||
ConnectionsWeakRef releaseRef = null;
|
||||
while ((releaseRef = (ConnectionsWeakRef) queue.poll())
|
||||
!= null) {
|
||||
Connections conns = releaseRef.getConnections();
|
||||
|
||||
if (debug) {
|
||||
System.err.println(
|
||||
"weak reference cleanup: Closing Connections:" + conns);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
conns.close();
|
||||
weakRefs.remove(releaseRef);
|
||||
releaseRef.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void showStats(PrintStream out) {
|
||||
Object id;
|
||||
Connections conns;
|
||||
|
||||
out.println("===== Pool start ======================");
|
||||
out.println("maximum pool size: " + maxSize);
|
||||
out.println("preferred pool size: " + prefSize);
|
||||
out.println("initial pool size: " + initSize);
|
||||
|
||||
synchronized (map) {
|
||||
out.println("current pool size: " + map.size());
|
||||
|
||||
for (Map.Entry<Object, ConnectionsRef> entry : map.entrySet()) {
|
||||
id = entry.getKey();
|
||||
conns = entry.getValue().getConnections();
|
||||
out.println(" " + id + ":" + conns.getStats());
|
||||
}
|
||||
}
|
||||
|
||||
out.println("====== Pool end =====================");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
synchronized (map) {
|
||||
return super.toString() + " " + map.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg, int i) {
|
||||
if (debug) {
|
||||
System.err.println(this + "." + msg + i);
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg, Object obj) {
|
||||
if (debug) {
|
||||
System.err.println(this + "." + msg + obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCallback.java
Normal file
63
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCallback.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
/**
|
||||
* Represents a callback used to release or remove a PooledConnection back
|
||||
* into the pool.
|
||||
*
|
||||
* A pooled connection typically has a close method that its clients
|
||||
* use to indicate that they no longer need the connection. This close
|
||||
* method should use the methods defined in this interface to
|
||||
* interact with the connection pool to return the connection
|
||||
* to the pool.
|
||||
*
|
||||
* The methods in this interface are typically invoked by a PooledConnection.
|
||||
* The methods in this interface are typically implemented by the connection
|
||||
* pool manager.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public interface PoolCallback {
|
||||
/**
|
||||
* Releases a useable connection back to the pool.
|
||||
*
|
||||
* @param conn The connection to release.
|
||||
* @return true if the connection released; false if the connection
|
||||
* is no longer in the pool.
|
||||
*/
|
||||
public abstract boolean releasePooledConnection(PooledConnection conn);
|
||||
|
||||
/**
|
||||
* Removes a connection from the pool. The connection should not be reused.
|
||||
* The physical connection should have already been closed.
|
||||
*
|
||||
* @param conn The connection to return.
|
||||
* @return true if the connection was removed; false if the connection
|
||||
* is no longer in the pool prior to removal.
|
||||
*/
|
||||
public abstract boolean removePooledConnection(PooledConnection conn);
|
||||
}
|
||||
68
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCleaner.java
Normal file
68
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCleaner.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
/**
|
||||
* Thread that wakes up periodically and closes expired, unused connections.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final public class PoolCleaner implements Runnable {
|
||||
final private Pool[] pools;
|
||||
final private long period;
|
||||
|
||||
/**
|
||||
* @param period ms to wait between cleaning
|
||||
* @param pools non-null array of Pools to clean
|
||||
*/
|
||||
public PoolCleaner(long period, Pool[] pools) {
|
||||
super();
|
||||
this.period = period;
|
||||
this.pools = pools.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long threshold;
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
// Wait for duration of period ms
|
||||
try {
|
||||
wait(period);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
|
||||
// Connections idle since threshold have expired
|
||||
threshold = System.currentTimeMillis() - period;
|
||||
for (int i = 0; i < pools.length; i++) {
|
||||
if (pools[i] != null) {
|
||||
pools[i].expire(threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PooledConnection.java
Normal file
53
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PooledConnection.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
|
||||
/**
|
||||
* Represents a connection that is managed in a pool. The connection
|
||||
* may be reused by multiple clients.
|
||||
*
|
||||
* A pooled connection typically has a close method that its clients
|
||||
* use to indicate that they no longer need the connection. This close
|
||||
* method would interact with the connection pool to return the connection
|
||||
* to the pool (see PoolCallback).
|
||||
*<p>
|
||||
* The pooled connection also needs to provide a close method that the
|
||||
* connection pool can use to physically close the connection.
|
||||
* The pool might need to physically close the connection as determined
|
||||
* by the pool's policy (for example, to manage the pool size or idle
|
||||
* connections). This second close method should *not* use PoolCallback
|
||||
* methods. It should only do what is required to close the physical
|
||||
* connection.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public interface PooledConnection {
|
||||
|
||||
/**
|
||||
* Closes the physical connection.
|
||||
*/
|
||||
public abstract void closeConnection();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.pool;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* Represents a factory that creates PooledConnection.
|
||||
*
|
||||
* The user of the connection pool should provide an implementation of this
|
||||
* interface and pass it to the Pool.getPooledConnection() method.
|
||||
* The implementation of the factory should contain all the information
|
||||
* necessary to create a PooledConnection.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public interface PooledConnectionFactory {
|
||||
/**
|
||||
* Creates a pooled connection.
|
||||
* @param pcb callback responsible for removing and releasing the pooled
|
||||
* connection from the pool.
|
||||
*/
|
||||
public abstract PooledConnection createPooledConnection(PoolCallback pcb)
|
||||
throws NamingException;
|
||||
};
|
||||
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/DefaultCallbackHandler.java
Normal file
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/DefaultCallbackHandler.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.sasl;
|
||||
|
||||
import javax.security.auth.callback.*;
|
||||
import javax.security.sasl.RealmCallback;
|
||||
import javax.security.sasl.RealmChoiceCallback;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DefaultCallbackHandler for satisfying NameCallback and
|
||||
* PasswordCallback for an LDAP client.
|
||||
* NameCallback is used for getting the authentication ID and is
|
||||
* gotten from the java.naming.security.principal property.
|
||||
* PasswordCallback is gotten from the java.naming.security.credentials
|
||||
* property and must be of type String, char[] or byte[].
|
||||
* If byte[], it is assumed to have UTF-8 encoding.
|
||||
*
|
||||
* If the caller of getPassword() will be using the password as
|
||||
* a byte array, then it should encode the char[] array returned by
|
||||
* getPassword() into a byte[] using UTF-8.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class DefaultCallbackHandler implements CallbackHandler {
|
||||
private char[] passwd;
|
||||
private String authenticationID;
|
||||
private String authRealm;
|
||||
|
||||
DefaultCallbackHandler(String principal, Object cred, String realm)
|
||||
throws IOException {
|
||||
authenticationID = principal;
|
||||
authRealm = realm;
|
||||
if (cred instanceof String) {
|
||||
passwd = ((String)cred).toCharArray();
|
||||
} else if (cred instanceof char[]) {
|
||||
passwd = ((char[])cred).clone();
|
||||
} else if (cred != null) {
|
||||
// assume UTF-8 encoding
|
||||
String orig = new String((byte[])cred, "UTF8");
|
||||
passwd = orig.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(Callback[] callbacks)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
for (int i = 0; i < callbacks.length; i++) {
|
||||
if (callbacks[i] instanceof NameCallback) {
|
||||
((NameCallback)callbacks[i]).setName(authenticationID);
|
||||
|
||||
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||
((PasswordCallback)callbacks[i]).setPassword(passwd);
|
||||
|
||||
} else if (callbacks[i] instanceof RealmChoiceCallback) {
|
||||
/* Deals with a choice of realms */
|
||||
String[] choices =
|
||||
((RealmChoiceCallback)callbacks[i]).getChoices();
|
||||
int selected = 0;
|
||||
|
||||
if (authRealm != null && authRealm.length() > 0) {
|
||||
selected = -1; // no realm chosen
|
||||
for (int j = 0; j < choices.length; j++) {
|
||||
if (choices[j].equals(authRealm)) {
|
||||
selected = j;
|
||||
}
|
||||
}
|
||||
if (selected == -1) {
|
||||
StringBuffer allChoices = new StringBuffer();
|
||||
for (int j = 0; j < choices.length; j++) {
|
||||
allChoices.append(choices[j] + ",");
|
||||
}
|
||||
throw new IOException("Cannot match " +
|
||||
"'java.naming.security.sasl.realm' property value, '" +
|
||||
authRealm + "' with choices " + allChoices +
|
||||
"in RealmChoiceCallback");
|
||||
}
|
||||
}
|
||||
|
||||
((RealmChoiceCallback)callbacks[i]).setSelectedIndex(selected);
|
||||
|
||||
} else if (callbacks[i] instanceof RealmCallback) {
|
||||
/* 1 or 0 realms specified in challenge */
|
||||
RealmCallback rcb = (RealmCallback) callbacks[i];
|
||||
if (authRealm != null) {
|
||||
rcb.setText(authRealm); // Use what user supplied
|
||||
} else {
|
||||
String defaultRealm = rcb.getDefaultText();
|
||||
if (defaultRealm != null) {
|
||||
rcb.setText(defaultRealm); // Use what server supplied
|
||||
} else {
|
||||
rcb.setText(""); // Specify no realm
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callbacks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clearPassword() {
|
||||
if (passwd != null) {
|
||||
for (int i = 0; i < passwd.length; i++) {
|
||||
passwd[i] = '\0';
|
||||
}
|
||||
passwd = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
clearPassword();
|
||||
}
|
||||
}
|
||||
201
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/LdapSasl.java
Normal file
201
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/LdapSasl.java
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.sasl;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.naming.AuthenticationNotSupportedException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.sasl.*;
|
||||
import com.sun.jndi.ldap.Connection;
|
||||
import com.sun.jndi.ldap.LdapClient;
|
||||
import com.sun.jndi.ldap.LdapResult;
|
||||
|
||||
/**
|
||||
* Handles SASL support.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final public class LdapSasl {
|
||||
// SASL stuff
|
||||
private static final String SASL_CALLBACK = "java.naming.security.sasl.callback";
|
||||
private static final String SASL_AUTHZ_ID =
|
||||
"java.naming.security.sasl.authorizationId";
|
||||
private static final String SASL_REALM =
|
||||
"java.naming.security.sasl.realm";
|
||||
|
||||
private static final int LDAP_SUCCESS = 0;
|
||||
private static final int LDAP_SASL_BIND_IN_PROGRESS = 14; // LDAPv3
|
||||
|
||||
private LdapSasl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SASL bind.
|
||||
* Creates a SaslClient by using a default CallbackHandler
|
||||
* that uses the Context.SECURITY_PRINCIPAL and Context.SECURITY_CREDENTIALS
|
||||
* properties to satisfy the callbacks, and by using the
|
||||
* SASL_AUTHZ_ID property as the authorization id. If the SASL_AUTHZ_ID
|
||||
* property has not been set, Context.SECURITY_PRINCIPAL is used.
|
||||
* If SASL_CALLBACK has been set, use that instead of the default
|
||||
* CallbackHandler.
|
||||
*<p>
|
||||
* If bind is successful and the selected SASL mechanism has a security
|
||||
* layer, set inStream and outStream to be filter streams that use
|
||||
* the security layer. These will be used for subsequent communication
|
||||
* with the server.
|
||||
*<p>
|
||||
* @param conn The non-null connection to use for sending an LDAP BIND
|
||||
* @param server Non-null string name of host to connect to
|
||||
* @param dn Non-null DN to bind as; also used as authentication ID
|
||||
* @param pw Possibly null password; can be byte[], char[] or String
|
||||
* @param authMech A non-null space-separated list of SASL authentication
|
||||
* mechanisms.
|
||||
* @param env The possibly null environment of the context, possibly containing
|
||||
* properties for used by SASL mechanisms
|
||||
* @param bindCtls The possibly null controls to accompany the bind
|
||||
* @return LdapResult containing status of the bind
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static LdapResult saslBind(LdapClient clnt, Connection conn,
|
||||
String server, String dn, Object pw,
|
||||
String authMech, Hashtable<?,?> env, Control[] bindCtls)
|
||||
throws IOException, NamingException {
|
||||
|
||||
SaslClient saslClnt = null;
|
||||
boolean cleanupHandler = false;
|
||||
|
||||
// Use supplied callback handler or create default
|
||||
CallbackHandler cbh =
|
||||
(env != null) ? (CallbackHandler)env.get(SASL_CALLBACK) : null;
|
||||
if (cbh == null) {
|
||||
cbh = new DefaultCallbackHandler(dn, pw, (String)env.get(SASL_REALM));
|
||||
cleanupHandler = true;
|
||||
}
|
||||
|
||||
// Prepare parameters for creating SASL client
|
||||
String authzId = (env != null) ? (String)env.get(SASL_AUTHZ_ID) : null;
|
||||
String[] mechs = getSaslMechanismNames(authMech);
|
||||
|
||||
try {
|
||||
// Create SASL client to use using SASL package
|
||||
saslClnt = Sasl.createSaslClient(
|
||||
mechs, authzId, "ldap", server, (Hashtable<String, ?>)env, cbh);
|
||||
|
||||
if (saslClnt == null) {
|
||||
throw new AuthenticationNotSupportedException(authMech);
|
||||
}
|
||||
|
||||
LdapResult res;
|
||||
String mechName = saslClnt.getMechanismName();
|
||||
byte[] response = saslClnt.hasInitialResponse() ?
|
||||
saslClnt.evaluateChallenge(NO_BYTES) : null;
|
||||
|
||||
res = clnt.ldapBind(null, response, bindCtls, mechName, true);
|
||||
|
||||
while (!saslClnt.isComplete() &&
|
||||
(res.status == LDAP_SASL_BIND_IN_PROGRESS ||
|
||||
res.status == LDAP_SUCCESS)) {
|
||||
|
||||
response = saslClnt.evaluateChallenge(
|
||||
res.serverCreds != null? res.serverCreds : NO_BYTES);
|
||||
if (res.status == LDAP_SUCCESS) {
|
||||
if (response != null) {
|
||||
throw new AuthenticationException(
|
||||
"SASL client generated response after success");
|
||||
}
|
||||
break;
|
||||
}
|
||||
res = clnt.ldapBind(null, response, bindCtls, mechName, true);
|
||||
}
|
||||
|
||||
if (res.status == LDAP_SUCCESS) {
|
||||
if (!saslClnt.isComplete()) {
|
||||
throw new AuthenticationException(
|
||||
"SASL authentication not complete despite server claims");
|
||||
}
|
||||
|
||||
String qop = (String) saslClnt.getNegotiatedProperty(Sasl.QOP);
|
||||
|
||||
// If negotiated integrity or privacy,
|
||||
if (qop != null && (qop.equalsIgnoreCase("auth-int")
|
||||
|| qop.equalsIgnoreCase("auth-conf"))) {
|
||||
|
||||
InputStream newIn = new SaslInputStream(saslClnt,
|
||||
conn.inStream);
|
||||
OutputStream newOut = new SaslOutputStream(saslClnt,
|
||||
conn.outStream);
|
||||
|
||||
conn.replaceStreams(newIn, newOut);
|
||||
} else {
|
||||
saslClnt.dispose();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} catch (SaslException e) {
|
||||
NamingException ne = new AuthenticationException(
|
||||
authMech);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
} finally {
|
||||
if (cleanupHandler) {
|
||||
((DefaultCallbackHandler)cbh).clearPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of SASL mechanisms given a string of space
|
||||
* separated SASL mechanism names.
|
||||
* @param The non-null string containing the mechanism names
|
||||
* @return A non-null array of String; each element of the array
|
||||
* contains a single mechanism name.
|
||||
*/
|
||||
private static String[] getSaslMechanismNames(String str) {
|
||||
StringTokenizer parser = new StringTokenizer(str);
|
||||
Vector<String> mechs = new Vector<>(10);
|
||||
while (parser.hasMoreTokens()) {
|
||||
mechs.addElement(parser.nextToken());
|
||||
}
|
||||
String[] mechNames = new String[mechs.size()];
|
||||
for (int i = 0; i < mechs.size(); i++) {
|
||||
mechNames[i] = mechs.elementAt(i);
|
||||
}
|
||||
return mechNames;
|
||||
}
|
||||
|
||||
private static final byte[] NO_BYTES = new byte[0];
|
||||
}
|
||||
218
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslInputStream.java
Normal file
218
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslInputStream.java
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.sasl;
|
||||
|
||||
import javax.security.sasl.Sasl;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* This class is used by clients of Java SASL that need to create an input stream
|
||||
* that uses SaslClient's unwrap() method to decode the SASL buffers
|
||||
* sent by the SASL server.
|
||||
*
|
||||
* Extend from InputStream instead of FilterInputStream because
|
||||
* we need to override less methods in InputStream. That is, the
|
||||
* behavior of the default implementations in InputStream matches
|
||||
* more closely with the behavior we want in SaslInputStream.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public class SaslInputStream extends InputStream {
|
||||
private static final boolean debug = false;
|
||||
|
||||
private byte[] saslBuffer; // buffer for storing raw bytes
|
||||
private byte[] lenBuf = new byte[4]; // buffer for storing length
|
||||
|
||||
private byte[] buf = new byte[0]; // buffer for storing processed bytes
|
||||
// Initialized to empty buffer
|
||||
private int bufPos = 0; // read position in buf
|
||||
private InputStream in; // underlying input stream
|
||||
private SaslClient sc;
|
||||
private int recvMaxBufSize = 65536;
|
||||
|
||||
SaslInputStream(SaslClient sc, InputStream in) throws SaslException {
|
||||
super();
|
||||
this.in = in;
|
||||
this.sc = sc;
|
||||
|
||||
String str = (String) sc.getNegotiatedProperty(Sasl.MAX_BUFFER);
|
||||
if (str != null) {
|
||||
try {
|
||||
recvMaxBufSize = Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new SaslException(Sasl.MAX_BUFFER +
|
||||
" property must be numeric string: " + str);
|
||||
}
|
||||
}
|
||||
saslBuffer = new byte[recvMaxBufSize];
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] inBuf = new byte[1];
|
||||
int count = read(inBuf, 0, 1);
|
||||
if (count > 0) {
|
||||
return inBuf[0];
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte[] inBuf, int start, int count) throws IOException {
|
||||
|
||||
if (bufPos >= buf.length) {
|
||||
int actual = fill(); // read and unwrap next SASL buffer
|
||||
while (actual == 0) { // ignore zero length content
|
||||
actual = fill();
|
||||
}
|
||||
if (actual == -1) {
|
||||
return -1; // EOF
|
||||
}
|
||||
}
|
||||
|
||||
int avail = buf.length - bufPos;
|
||||
if (count > avail) {
|
||||
// Requesting more that we have stored
|
||||
// Return all that we have; next invocation of read() will
|
||||
// trigger fill()
|
||||
System.arraycopy(buf, bufPos, inBuf, start, avail);
|
||||
bufPos = buf.length;
|
||||
return avail;
|
||||
} else {
|
||||
// Requesting less than we have stored
|
||||
// Return all that was requested
|
||||
System.arraycopy(buf, bufPos, inBuf, start, count);
|
||||
bufPos += count;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the buf with more data by reading a SASL buffer, unwrapping it,
|
||||
* and leaving the bytes in buf for read() to return.
|
||||
* @return The number of unwrapped bytes available
|
||||
*/
|
||||
private int fill() throws IOException {
|
||||
// Read in length of buffer
|
||||
int actual = readFully(lenBuf, 4);
|
||||
if (actual != 4) {
|
||||
return -1;
|
||||
}
|
||||
int len = networkByteOrderToInt(lenBuf, 0, 4);
|
||||
|
||||
if (len > recvMaxBufSize) {
|
||||
throw new IOException(
|
||||
len + "exceeds the negotiated receive buffer size limit:" +
|
||||
recvMaxBufSize);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.err.println("reading " + len + " bytes from network");
|
||||
}
|
||||
|
||||
// Read SASL buffer
|
||||
actual = readFully(saslBuffer, len);
|
||||
if (actual != len) {
|
||||
throw new EOFException("Expecting to read " + len +
|
||||
" bytes but got " + actual + " bytes before EOF");
|
||||
}
|
||||
|
||||
// Unwrap
|
||||
buf = sc.unwrap(saslBuffer, 0, len);
|
||||
|
||||
bufPos = 0;
|
||||
|
||||
return buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read requested number of bytes before returning.
|
||||
* @return The number of bytes actually read; -1 if none read
|
||||
*/
|
||||
private int readFully(byte[] inBuf, int total) throws IOException {
|
||||
int count, pos = 0;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("readFully " + total + " from " + in);
|
||||
}
|
||||
|
||||
while (total > 0) {
|
||||
count = in.read(inBuf, pos, total);
|
||||
|
||||
if (debug) {
|
||||
System.err.println("readFully read " + count);
|
||||
}
|
||||
|
||||
if (count == -1 ) {
|
||||
return (pos == 0? -1 : pos);
|
||||
}
|
||||
pos += count;
|
||||
total -= count;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return buf.length - bufPos;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
SaslException save = null;
|
||||
try {
|
||||
sc.dispose(); // Dispose of SaslClient's state
|
||||
} catch (SaslException e) {
|
||||
// Save exception for throwing after closing 'in'
|
||||
save = e;
|
||||
}
|
||||
|
||||
in.close(); // Close underlying input stream
|
||||
|
||||
if (save != null) {
|
||||
throw save;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer represented by 4 bytes in network byte order.
|
||||
*/
|
||||
// Copied from com.sun.security.sasl.util.SaslImpl.
|
||||
private static int networkByteOrderToInt(byte[] buf, int start, int count) {
|
||||
if (count > 4) {
|
||||
throw new IllegalArgumentException("Cannot handle more than 4 bytes");
|
||||
}
|
||||
|
||||
int answer = 0;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
answer <<= 8;
|
||||
answer |= ((int)buf[start+i] & 0xff);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslOutputStream.java
Normal file
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslOutputStream.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.sasl;
|
||||
|
||||
import javax.security.sasl.Sasl;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
import java.io.IOException;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class SaslOutputStream extends FilterOutputStream {
|
||||
private static final boolean debug = false;
|
||||
|
||||
private byte[] lenBuf = new byte[4]; // buffer for storing length
|
||||
private int rawSendSize = 65536;
|
||||
private SaslClient sc;
|
||||
|
||||
SaslOutputStream(SaslClient sc, OutputStream out) throws SaslException {
|
||||
super(out);
|
||||
this.sc = sc;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("SaslOutputStream: " + out);
|
||||
}
|
||||
|
||||
String str = (String) sc.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
|
||||
if (str != null) {
|
||||
try {
|
||||
rawSendSize = Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new SaslException(Sasl.RAW_SEND_SIZE +
|
||||
" property must be numeric string: " + str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override this method to call write(byte[], int, int) counterpart
|
||||
// super.write(int) simply calls out.write(int)
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
byte[] buffer = new byte[1];
|
||||
buffer[0] = (byte)b;
|
||||
write(buffer, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to "wrap" the outgoing buffer before
|
||||
* writing it to the underlying output stream.
|
||||
*/
|
||||
public void write(byte[] buffer, int offset, int total) throws IOException {
|
||||
int count;
|
||||
byte[] wrappedToken, saslBuffer;
|
||||
|
||||
// "Packetize" buffer to be within rawSendSize
|
||||
if (debug) {
|
||||
System.err.println("Total size: " + total);
|
||||
}
|
||||
|
||||
for (int i = 0; i < total; i += rawSendSize) {
|
||||
|
||||
// Calculate length of current "packet"
|
||||
count = (total - i) < rawSendSize ? (total - i) : rawSendSize;
|
||||
|
||||
// Generate wrapped token
|
||||
wrappedToken = sc.wrap(buffer, offset+i, count);
|
||||
|
||||
// Write out length
|
||||
intToNetworkByteOrder(wrappedToken.length, lenBuf, 0, 4);
|
||||
|
||||
if (debug) {
|
||||
System.err.println("sending size: " + wrappedToken.length);
|
||||
}
|
||||
out.write(lenBuf, 0, 4);
|
||||
|
||||
// Write out wrapped token
|
||||
out.write(wrappedToken, 0, wrappedToken.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
SaslException save = null;
|
||||
try {
|
||||
sc.dispose(); // Dispose of SaslClient's state
|
||||
} catch (SaslException e) {
|
||||
// Save exception for throwing after closing 'in'
|
||||
save = e;
|
||||
}
|
||||
super.close(); // Close underlying output stream
|
||||
|
||||
if (save != null) {
|
||||
throw save;
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from com.sun.security.sasl.util.SaslImpl
|
||||
/**
|
||||
* Encodes an integer into 4 bytes in network byte order in the buffer
|
||||
* supplied.
|
||||
*/
|
||||
private static void intToNetworkByteOrder(int num, byte[] buf, int start,
|
||||
int count) {
|
||||
if (count > 4) {
|
||||
throw new IllegalArgumentException("Cannot handle more than 4 bytes");
|
||||
}
|
||||
|
||||
for (int i = count-1; i >= 0; i--) {
|
||||
buf[start+i] = (byte)(num & 0xff);
|
||||
num >>>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
109
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProvider.java
Normal file
109
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProvider.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.spi;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Service-provider class for DNS lookups when performing LDAP operations.
|
||||
*
|
||||
* <p> An LDAP DNS provider is a concrete subclass of this class that
|
||||
* has a zero-argument constructor. LDAP DNS providers are located using the
|
||||
* ServiceLoader facility, as specified by
|
||||
* {@linkplain javax.naming.directory.InitialDirContext InitialDirectContext}.
|
||||
*
|
||||
* The
|
||||
* {@link java.util.ServiceLoader ServiceLoader} is used to create and register
|
||||
* implementations of {@code LdapDnsProvider}.
|
||||
*
|
||||
* <p> An LDAP DNS provider can be used in environments where the default
|
||||
* DNS resolution mechanism is not sufficient to accurately pinpoint the
|
||||
* correct LDAP servers needed to perform LDAP operations. For example, in an
|
||||
* environment containing a mix of {@code ldap} and {@code ldaps} servers
|
||||
* you may want the {@linkplain javax.naming.ldap.LdapContext LdapContext}
|
||||
* to query {@code ldaps} servers only.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public abstract class LdapDnsProvider {
|
||||
|
||||
// The {@code RuntimePermission("ldapDnsProvider")} is
|
||||
// necessary to subclass and instantiate the {@code LdapDnsProvider} class.
|
||||
private static final RuntimePermission DNSPROVIDER_PERMISSION =
|
||||
new RuntimePermission("ldapDnsProvider");
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code LdapDnsProvider}.
|
||||
*
|
||||
* @throws SecurityException if a security manager is present and its
|
||||
* {@code checkPermission} method doesn't allow
|
||||
* the {@code RuntimePermission("ldapDnsProvider")}.
|
||||
*/
|
||||
protected LdapDnsProvider() {
|
||||
this(checkPermission());
|
||||
}
|
||||
|
||||
private LdapDnsProvider(Void unused) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
private static Void checkPermission() {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(DNSPROVIDER_PERMISSION);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the endpoints and domain name for the given {@link Context}
|
||||
* {@link Context#PROVIDER_URL provider URL} and environment. The resolved
|
||||
* endpoints and domain name are returned as an
|
||||
* {@link LdapDnsProviderResult}.
|
||||
*
|
||||
* <p> An endpoint is a {@code String} representation of an LDAP URL which
|
||||
* points to an LDAP server to be used for LDAP operations. The syntax of
|
||||
* an LDAP URL is defined by <a href="http://www.ietf.org/rfc/rfc2255.txt">
|
||||
* <i>RFC 2255: The LDAP URL Format</i></a>.
|
||||
*
|
||||
* @param url The {@link Context} {@link Context#PROVIDER_URL provider URL}
|
||||
* @param env The {@link Context} environment.
|
||||
*
|
||||
* @return an {@link LdapDnsProviderResult} or empty {@code Optional}
|
||||
* if the lookup fails.
|
||||
*
|
||||
* @throws NamingException if the {@code url} is not valid or an error
|
||||
* occurred while performing the lookup.
|
||||
* @throws NullPointerException if either {@code url} or {@code env} are
|
||||
* {@code null}.
|
||||
*/
|
||||
public abstract Optional<LdapDnsProviderResult> lookupEndpoints(
|
||||
String url, Map<?,?> env) throws NamingException;
|
||||
|
||||
}
|
||||
88
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProviderResult.java
Normal file
88
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProviderResult.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.jndi.ldap.spi;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The result of a DNS lookup for an LDAP URL.
|
||||
*
|
||||
* <p> This class is used by an {@link LdapDnsProvider} to return the result
|
||||
* of a DNS lookup for a given LDAP URL. The result consists of a domain name
|
||||
* and its associated ldap server endpoints.
|
||||
*
|
||||
* <p> A {@code null} {@code domainName} is equivalent to and represented
|
||||
* by an empty string.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public final class LdapDnsProviderResult {
|
||||
|
||||
private final String domainName;
|
||||
private final List<String> endpoints;
|
||||
|
||||
/**
|
||||
* Construct an LdapDnsProviderResult consisting of a resolved domain name
|
||||
* and the ldap server endpoints that serve the domain.
|
||||
*
|
||||
* @param domainName the resolved domain name; can be null.
|
||||
* @param endpoints the possibly empty list of resolved ldap server
|
||||
* endpoints
|
||||
*
|
||||
* @throws NullPointerException if {@code endpoints} contains {@code null}
|
||||
* elements.
|
||||
* @throws ClassCastException if {@code endpoints} contains non-
|
||||
* {@code String} elements.
|
||||
*/
|
||||
public LdapDnsProviderResult(String domainName, List<String> endpoints) {
|
||||
this.domainName = (domainName == null) ? "" : domainName;
|
||||
this.endpoints = new ArrayList<>(endpoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the domain name resolved from the ldap URL. This method returns
|
||||
* the empty string if the {@code LdapDnsProviderResult} is created with a
|
||||
* null domain name.
|
||||
*
|
||||
* @return the resolved domain name
|
||||
*/
|
||||
public String getDomainName() {
|
||||
return domainName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the possibly empty list of individual server endpoints resolved
|
||||
* from the ldap URL.
|
||||
*
|
||||
* @return a possibly empty unmodifiable {@link List} containing the
|
||||
* resolved ldap server endpoints
|
||||
*/
|
||||
public List<String> getEndpoints() {
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user