}
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
env.put(Context.PROVIDER_URL, "ldap://" + ldapHost
+ ((ldapPort == null) ? "" : (":" + ldapPort)));
StartTlsResponse tlsResponse = null;
LdapContext ctx = null;
try {
ctx = new InitialLdapContext(env, null);
if (tls) {
// Requesting to start TLS on an LDAP association
tlsResponse = (StartTlsResponse) ctx.extendedOperation(
new StartTlsRequest());
// Starting TLS
tlsResponse.negotiate();
}
// A TLS/SSL secure channel has been established if you reach here.
// Assertion of client's authorization Identity -- Explicit way
ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, mechanism);
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL,
((principalTemplate == null)
? userName
: principalTemplate.replace("${username}", userName)));
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
if (saslRealm != null) {
env.put("java.naming.security.sasl.realm", saslRealm);
}
// The Context.SECURITY_* authorizations are only applied when the
// following statement executes. (Or any other remote operations done
// while the TLS connection is still open).
NamingEnumeration<SearchResult> sRess = null;
try {
sRess = ctx.search(parentDn,
new BasicAttributes(rdnAttribute, userName),
attributeUnion);
} catch (AuthenticationException ae) {
throw new DenyException();
} catch (Exception e) {
throw new RuntimeException(e);
}
if (!sRess.hasMore()) {
throw new DenyException();
}
SearchResult sRes = sRess.next();
if (sRess.hasMore()) {
throw new RuntimeException("> 1 result");
}
Attributes attrs = sRes.getAttributes();
if (accessAttribute != null) {
Attribute attribute = attrs.get(accessAttribute);
if (attribute == null) {
throw new DenyException();
}
if (attribute.size() != 1) {
throw new RuntimeException("Access attribute '"
+ accessAttribute + "' has unexpected value count: "
+ attribute.size());
}
if (accessValuePattern != null) {
Object accessValue = attribute.get(0);
if (accessValue == null) {
throw new RuntimeException(
"Access Attr. value is null");
}
if (!(accessValue instanceof String)) {
throw new RuntimeException("Access Attr. value "
+ "not a String: "
+ accessValue.getClass().getName());
}
if (!accessValuePattern.matcher(
(String) accessValue).matches()) {
throw new DenyException();
}
}
}
if (rolesSchemaAttribute == null) {
return null;
}
// If we reach here, then we definitely need to try to return a
// list of roles + schema.
List<String> returns = new ArrayList<String>();
Attribute attribute = attrs.get(rolesSchemaAttribute);
if (attribute != null) {
int valCount = attribute.size();
Matcher matcher;
Object oneVal;
for (int i = 0; i < valCount; i++) {
oneVal = attribute.get(i);
if (oneVal == null) {
throw new RuntimeException(
"R/S Attr value #" + i + " is null");
}
if (!(oneVal instanceof String)) {
throw new RuntimeException(
"R/S Attr value #" + i + " not a String: "
+ oneVal.getClass().getName());
}
if (roleSchemaValuePattern == null) {
returns.add((String) oneVal);
} else {
matcher = roleSchemaValuePattern.matcher(
(String) oneVal);
if (matcher.matches()) {
returns.add((matcher.groupCount() > 0)
? matcher.group(1)
: (String) oneVal);
}
}
}
}
if (returns.size() < 1) {
if (accessAttribute == null) {
throw new DenyException();
}
return new String[0];
}
return returns.toArray(new String[0]);
} catch (DenyException de) {
// This throws a non-runtime Exception, which is handled as an
// access denial instead of a system problem.
throw de;
} catch (RuntimeException re) {
throw re;
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} catch (NamingException ne) {
throw new RuntimeException(ne);
} finally {
if (tlsResponse != null) try {
tlsResponse.close();
} catch (IOException ioe) {
logger.error("Failed to close TLS Response", ioe);
}
if (ctx != null) try {
ctx.close();