|
|
a0be74a |
--- activemq-5.6.0/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java 2012-09-11 01:12:25.000000000 +0200
|
|
|
a0be74a |
+++ activemq-5.6.0/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java.CVE-2015-6524 2015-01-15 08:57:10.000000000 +0100
|
|
|
a0be74a |
@@ -17,22 +17,13 @@
|
|
|
a0be74a |
package org.apache.activemq.jaas;
|
|
|
a0be74a |
|
|
|
a0be74a |
import java.io.IOException;
|
|
|
a0be74a |
+import java.net.URI;
|
|
|
a0be74a |
+import java.net.URISyntaxException;
|
|
|
a0be74a |
import java.security.Principal;
|
|
|
a0be74a |
import java.text.MessageFormat;
|
|
|
a0be74a |
-import java.util.ArrayList;
|
|
|
a0be74a |
-import java.util.HashSet;
|
|
|
a0be74a |
-import java.util.Hashtable;
|
|
|
a0be74a |
-import java.util.List;
|
|
|
a0be74a |
-import java.util.Map;
|
|
|
a0be74a |
-import java.util.Set;
|
|
|
a0be74a |
-
|
|
|
a0be74a |
-import javax.naming.AuthenticationException;
|
|
|
a0be74a |
-import javax.naming.CommunicationException;
|
|
|
a0be74a |
-import javax.naming.Context;
|
|
|
a0be74a |
-import javax.naming.Name;
|
|
|
a0be74a |
-import javax.naming.NameParser;
|
|
|
a0be74a |
-import javax.naming.NamingEnumeration;
|
|
|
a0be74a |
-import javax.naming.NamingException;
|
|
|
a0be74a |
+import java.util.*;
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+import javax.naming.*;
|
|
|
a0be74a |
import javax.naming.directory.Attribute;
|
|
|
a0be74a |
import javax.naming.directory.Attributes;
|
|
|
a0be74a |
import javax.naming.directory.DirContext;
|
|
|
a0be74a |
@@ -71,6 +62,8 @@
|
|
|
a0be74a |
private static final String ROLE_SEARCH_MATCHING = "roleSearchMatching";
|
|
|
a0be74a |
private static final String ROLE_SEARCH_SUBTREE = "roleSearchSubtree";
|
|
|
a0be74a |
private static final String USER_ROLE_NAME = "userRoleName";
|
|
|
a0be74a |
+ private static final String EXPAND_ROLES = "expandRoles";
|
|
|
a0be74a |
+ private static final String EXPAND_ROLES_MATCHING = "expandRolesMatching";
|
|
|
a0be74a |
|
|
|
a0be74a |
private static Logger log = LoggerFactory.getLogger(LDAPLoginModule.class);
|
|
|
a0be74a |
|
|
|
a0be74a |
@@ -102,7 +95,10 @@
|
|
|
a0be74a |
new LDAPLoginProperty (ROLE_SEARCH_MATCHING, (String)options.get(ROLE_SEARCH_MATCHING)),
|
|
|
a0be74a |
new LDAPLoginProperty (ROLE_SEARCH_SUBTREE, (String)options.get(ROLE_SEARCH_SUBTREE)),
|
|
|
a0be74a |
new LDAPLoginProperty (USER_ROLE_NAME, (String)options.get(USER_ROLE_NAME)),
|
|
|
a0be74a |
- };
|
|
|
a0be74a |
+ new LDAPLoginProperty (EXPAND_ROLES, (String) options.get(EXPAND_ROLES)),
|
|
|
a0be74a |
+ new LDAPLoginProperty (EXPAND_ROLES_MATCHING, (String) options.get(EXPAND_ROLES_MATCHING)),
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+ };
|
|
|
a0be74a |
}
|
|
|
a0be74a |
|
|
|
a0be74a |
@Override
|
|
|
a0be74a |
@@ -194,7 +190,7 @@
|
|
|
a0be74a |
try {
|
|
|
a0be74a |
|
|
|
a0be74a |
String filter = userSearchMatchingFormat.format(new String[] {
|
|
|
a0be74a |
- username
|
|
|
a0be74a |
+ doRFC2254Encoding(username)
|
|
|
a0be74a |
});
|
|
|
a0be74a |
SearchControls constraints = new SearchControls();
|
|
|
a0be74a |
if (userSearchSubtreeBool) {
|
|
|
a0be74a |
@@ -231,13 +227,43 @@
|
|
|
a0be74a |
if (results.hasMore()) {
|
|
|
a0be74a |
// ignore for now
|
|
|
a0be74a |
}
|
|
|
a0be74a |
- NameParser parser = context.getNameParser("");
|
|
|
a0be74a |
- Name contextName = parser.parse(context.getNameInNamespace());
|
|
|
a0be74a |
- Name baseName = parser.parse(getLDAPPropertyValue(USER_BASE));
|
|
|
a0be74a |
- Name entryName = parser.parse(result.getName());
|
|
|
a0be74a |
- Name name = contextName.addAll(baseName);
|
|
|
a0be74a |
- name = name.addAll(entryName);
|
|
|
a0be74a |
- String dn = name.toString();
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+ String dn;
|
|
|
a0be74a |
+ if (result.isRelative()) {
|
|
|
a0be74a |
+ log.debug("LDAP returned a relative name: {}", result.getName());
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+ NameParser parser = context.getNameParser("");
|
|
|
a0be74a |
+ Name contextName = parser.parse(context.getNameInNamespace());
|
|
|
a0be74a |
+ Name baseName = parser.parse(getLDAPPropertyValue(USER_BASE));
|
|
|
a0be74a |
+ Name entryName = parser.parse(result.getName());
|
|
|
a0be74a |
+ Name name = contextName.addAll(baseName);
|
|
|
a0be74a |
+ name = name.addAll(entryName);
|
|
|
a0be74a |
+ dn = name.toString();
|
|
|
a0be74a |
+ } else {
|
|
|
a0be74a |
+ log.debug("LDAP returned an absolute name: {}", result.getName());
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+ try {
|
|
|
a0be74a |
+ URI uri = new URI(result.getName());
|
|
|
a0be74a |
+ String path = uri.getPath();
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+ if (path.startsWith("/")) {
|
|
|
a0be74a |
+ dn = path.substring(1);
|
|
|
a0be74a |
+ } else {
|
|
|
a0be74a |
+ dn = path;
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+ } catch (URISyntaxException e) {
|
|
|
a0be74a |
+ if (context != null) {
|
|
|
a0be74a |
+ close(context);
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+ FailedLoginException ex = new FailedLoginException("Error parsing absolute name as URI.");
|
|
|
a0be74a |
+ ex.initCause(e);
|
|
|
a0be74a |
+ throw ex;
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+
|
|
|
a0be74a |
+ if (log.isDebugEnabled()) {
|
|
|
a0be74a |
+ log.debug("Using DN [" + dn + "] for binding.");
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
|
|
|
a0be74a |
Attributes attrs = result.getAttributes();
|
|
|
a0be74a |
if (attrs == null) {
|
|
|
a0be74a |
@@ -281,8 +307,10 @@
|
|
|
a0be74a |
List<String> list = currentRoles;
|
|
|
a0be74a |
MessageFormat roleSearchMatchingFormat;
|
|
|
a0be74a |
boolean roleSearchSubtreeBool;
|
|
|
a0be74a |
+ boolean expandRolesBool;
|
|
|
a0be74a |
roleSearchMatchingFormat = new MessageFormat(getLDAPPropertyValue(ROLE_SEARCH_MATCHING));
|
|
|
a0be74a |
roleSearchSubtreeBool = Boolean.valueOf(getLDAPPropertyValue(ROLE_SEARCH_SUBTREE)).booleanValue();
|
|
|
a0be74a |
+ expandRolesBool = Boolean.valueOf(getLDAPPropertyValue(EXPAND_ROLES)).booleanValue();
|
|
|
a0be74a |
|
|
|
a0be74a |
if (list == null) {
|
|
|
a0be74a |
list = new ArrayList<String>();
|
|
|
a0be74a |
@@ -291,7 +319,7 @@
|
|
|
a0be74a |
return list;
|
|
|
a0be74a |
}
|
|
|
a0be74a |
String filter = roleSearchMatchingFormat.format(new String[] {
|
|
|
a0be74a |
- doRFC2254Encoding(dn), username
|
|
|
a0be74a |
+ doRFC2254Encoding(dn), doRFC2254Encoding(username)
|
|
|
a0be74a |
});
|
|
|
a0be74a |
|
|
|
a0be74a |
SearchControls constraints = new SearchControls();
|
|
|
a0be74a |
@@ -306,17 +334,40 @@
|
|
|
a0be74a |
log.debug(" base DN: " + getLDAPPropertyValue(ROLE_BASE));
|
|
|
a0be74a |
log.debug(" filter: " + filter);
|
|
|
a0be74a |
}
|
|
|
a0be74a |
+ HashSet<String> haveSeenNames = new HashSet<String>();
|
|
|
a0be74a |
+ Queue<String> pendingNameExpansion = new LinkedList<String>();
|
|
|
a0be74a |
NamingEnumeration<SearchResult> results = context.search(getLDAPPropertyValue(ROLE_BASE), filter, constraints);
|
|
|
a0be74a |
while (results.hasMore()) {
|
|
|
a0be74a |
SearchResult result = results.next();
|
|
|
a0be74a |
Attributes attrs = result.getAttributes();
|
|
|
a0be74a |
+ if (expandRolesBool) {
|
|
|
a0be74a |
+ haveSeenNames.add(result.getNameInNamespace());
|
|
|
a0be74a |
+ pendingNameExpansion.add(result.getNameInNamespace());
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
if (attrs == null) {
|
|
|
a0be74a |
continue;
|
|
|
a0be74a |
}
|
|
|
a0be74a |
list = addAttributeValues(getLDAPPropertyValue(ROLE_NAME), attrs, list);
|
|
|
a0be74a |
}
|
|
|
a0be74a |
+ if (expandRolesBool) {
|
|
|
a0be74a |
+ MessageFormat expandRolesMatchingFormat = new MessageFormat(getLDAPPropertyValue(EXPAND_ROLES_MATCHING));
|
|
|
a0be74a |
+ while (!pendingNameExpansion.isEmpty()) {
|
|
|
a0be74a |
+ String name = pendingNameExpansion.remove();
|
|
|
a0be74a |
+ filter = expandRolesMatchingFormat.format(new String[]{name});
|
|
|
a0be74a |
+ results = context.search(getLDAPPropertyValue(ROLE_BASE), filter, constraints);
|
|
|
a0be74a |
+ while (results.hasMore()) {
|
|
|
a0be74a |
+ SearchResult result = results.next();
|
|
|
a0be74a |
+ name = result.getNameInNamespace();
|
|
|
a0be74a |
+ if (!haveSeenNames.contains(name)) {
|
|
|
a0be74a |
+ Attributes attrs = result.getAttributes();
|
|
|
a0be74a |
+ list = addAttributeValues(getLDAPPropertyValue(ROLE_NAME), attrs, list);
|
|
|
a0be74a |
+ haveSeenNames.add(name);
|
|
|
a0be74a |
+ pendingNameExpansion.add(name);
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
+ }
|
|
|
a0be74a |
return list;
|
|
|
a0be74a |
-
|
|
|
a0be74a |
}
|
|
|
a0be74a |
|
|
|
a0be74a |
protected String doRFC2254Encoding(String inputString) {
|
|
|
a0be74a |
@@ -408,9 +459,14 @@
|
|
|
a0be74a |
env.put(Context.INITIAL_CONTEXT_FACTORY, getLDAPPropertyValue(INITIAL_CONTEXT_FACTORY));
|
|
|
a0be74a |
if (isLoginPropertySet(CONNECTION_USERNAME)) {
|
|
|
a0be74a |
env.put(Context.SECURITY_PRINCIPAL, getLDAPPropertyValue(CONNECTION_USERNAME));
|
|
|
a0be74a |
+ } else {
|
|
|
a0be74a |
+ throw new NamingException("Empty username is not allowed");
|
|
|
a0be74a |
}
|
|
|
a0be74a |
+
|
|
|
a0be74a |
if (isLoginPropertySet(CONNECTION_PASSWORD)) {
|
|
|
a0be74a |
env.put(Context.SECURITY_CREDENTIALS, getLDAPPropertyValue(CONNECTION_PASSWORD));
|
|
|
a0be74a |
+ } else {
|
|
|
a0be74a |
+ throw new NamingException("Empty password is not allowed");
|
|
|
a0be74a |
}
|
|
|
a0be74a |
env.put(Context.SECURITY_PROTOCOL, getLDAPPropertyValue(CONNECTION_PROTOCOL));
|
|
|
a0be74a |
env.put(Context.PROVIDER_URL, getLDAPPropertyValue(CONNECTION_URL));
|
|
|
a0be74a |
@@ -433,7 +489,7 @@
|
|
|
a0be74a |
|
|
|
a0be74a |
private boolean isLoginPropertySet(String propertyName) {
|
|
|
a0be74a |
for (int i=0; i < config.length; i++ ) {
|
|
|
a0be74a |
- if (config[i].getPropertyName() == propertyName && config[i].getPropertyValue() != null)
|
|
|
a0be74a |
+ if (config[i].getPropertyName() == propertyName && (config[i].getPropertyValue() != null && !"".equals(config[i].getPropertyValue())))
|
|
|
a0be74a |
return true;
|
|
|
a0be74a |
}
|
|
|
a0be74a |
return false;
|