Skip to content

Commit

Permalink
Merge pull request #18 from fbelzunc/JENKINS-16257
Browse files Browse the repository at this point in the history
[FIXED JENKINS 16257] Active Directory Plugin - Credential exception tying to authenticate with special characters like / or #
  • Loading branch information
fbelzunc committed Mar 1, 2016
2 parents 663ae60 + f01ee30 commit 96a21ce
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 6 deletions.
Expand Up @@ -83,6 +83,8 @@ public class ActiveDirectoryUnixAuthenticationProvider extends AbstractActiveDir

private GroupLookupStrategy groupLookupStrategy;

protected static final String DN_FORMATTED = "distinguishedNameFormatted";

/**
* {@link ActiveDirectoryGroupDetails} cache.
*/
Expand Down Expand Up @@ -300,25 +302,29 @@ public UserDetails retrieveUser(String username, String password, String domainN
}
LOGGER.fine("Found user "+username+" : "+user);

Object dn = user.get("distinguishedName").get();
if (dn==null)
Object dnObject = user.get(DN_FORMATTED).get();
if (dnObject==null)
throw new AuthenticationServiceException("No distinguished name for "+username);

String dn = dnObject.toString();
LdapName ldapName = new LdapName(dn);
String dnFormatted = ldapName.toString();

if (bindName!=null && password!=NO_AUTHENTICATION) {
// if we've used the credential specifically for the bind, we
// need to verify the provided password to do authentication
LOGGER.fine("Attempting to validate password for DN="+dn);
DirContext test = descriptor.bind(dn.toString(), password, ldapServers);
DirContext test = descriptor.bind(dnFormatted, password,ldapServers);
// Binding alone is not enough to test the credential. Need to actually perform some query operation.
// but if the authentication fails this throws an exception
try {
new LDAPSearchBuilder(test,domainDN).searchOne("(& (userPrincipalName={0})(objectCategory=user))",userPrincipalName);
new LDAPSearchBuilder(test,domainDN).searchOne("(& (userPrincipalName={0})(objectCategory=user))", userPrincipalName);
} finally {
closeQuietly(test);
}
}

Set<GrantedAuthority> groups = resolveGroups(domainDN, dn.toString(), context);
Set<GrantedAuthority> groups = resolveGroups(domainDN, dnFormatted, context);
groups.add(SecurityRealm.AUTHENTICATED_AUTHORITY);

return new ActiveDirectoryUserDetail(username, password, true, true, true, true, groups.toArray(new GrantedAuthority[groups.size()]),
Expand Down Expand Up @@ -397,6 +403,9 @@ private String getPrincipalName(String username, String domainName) {
* @param context Used for making queries.
*/
private Set<GrantedAuthority> resolveGroups(String domainDN, String userDN, DirContext context) throws NamingException {
if (userDN.contains("/")) {
userDN = userDN.replace("/","\\/");
}
LOGGER.finer("Looking up group of "+userDN);
Attributes id = context.getAttributes(userDN,new String[]{"tokenGroups","memberOf","CN"});
Attribute tga = id.get("tokenGroups");
Expand Down
Expand Up @@ -70,11 +70,26 @@ public LDAPSearchBuilder returns(String... attributes) {
return this;
}

/**
* Add all the attributes returned by the search
*
* @param filter
* The filter to be used for the search
* @param args
* Arguments to be used for the search
*
* @return Return all the attributes of the search and adds the DN correctly formatted per RFC 2253
*/
public Attributes searchOne(String filter, Object... args) throws NamingException {
NamingEnumeration<SearchResult> r = search(filter,args);
try {
if (r.hasMore()) {
Attributes attrs = r.next().getAttributes();
SearchResult searchResult = r.next();
Attributes attrs = searchResult.getAttributes();
//We need to use getNameInNamespace in order to correctly format everything
//to be able to use LdapName later and get the DN correctly formatted with escaped
//characters like slash
attrs.put(ActiveDirectoryUnixAuthenticationProvider.DN_FORMATTED, searchResult.getNameInNamespace());
LOG.log(Level.FINER, "found {0}", attrs);
return attrs;
} else {
Expand Down
Expand Up @@ -10,4 +10,8 @@
<p>
This field must be the full user principal name with domain name, like "joe@europe.contoso.com", or
a LDAP-style distinguished name, such as "CN=Joe Chin,OU=europe,DC=contoso,DC=com".

<p>
In case you are using DN in the bind, Active Directory requires that the <a href="http://social.technet.microsoft.com/wiki/contents/articles/5312.active-directory-characters-to-escape.aspx">following ten characters</a>
are escaped with the backslash "\" escape character if they appear in any of the individual components of a distinguished name.
</div>

0 comments on commit 96a21ce

Please sign in to comment.