blob: 2469b4bddb9d06786e664d5c7bc69af98733f16c [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.security;
import static org.apache.hadoop.security.LdapGroupsMapping.LDAP_CTX_FACTORY_CLASS_DEFAULT;
import static org.apache.hadoop.security.LdapGroupsMapping.LDAP_CTX_FACTORY_CLASS_KEY;
import static org.apache.hadoop.security.LdapGroupsMapping.LDAP_URL_KEY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.spi.InitialContextFactory;
import org.apache.hadoop.conf.Configuration;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.util.Hashtable;
public class TestLdapGroupsMappingBase {
@Mock
private DirContext context;
@Mock
private NamingEnumeration<SearchResult> userNames;
@Mock
private NamingEnumeration<SearchResult> groupNames;
@Mock
private NamingEnumeration<SearchResult> parentGroupNames;
@Mock
private SearchResult userSearchResult;
@Mock
private Attributes attributes;
@Spy
private LdapGroupsMapping groupsMapping = new LdapGroupsMapping();
private String[] testGroups = new String[] {"group1", "group2"};
private String[] testParentGroups =
new String[] {"group1", "group2", "group1_1"};
@Before
public void setupMocksBase() throws NamingException {
MockitoAnnotations.initMocks(this);
DirContext ctx = getContext();
when(ctx.search(Mockito.anyString(), Mockito.anyString(),
Mockito.any(Object[].class), Mockito.any(SearchControls.class))).
thenReturn(userNames);
// We only ever call hasMoreElements once for the user NamingEnum, so
// we can just have one return value
when(userNames.hasMoreElements()).thenReturn(true);
SearchResult groupSearchResult = mock(SearchResult.class);
// We're going to have to define the loop here. We want two iterations,
// to get both the groups
when(groupNames.hasMoreElements()).thenReturn(true, true, false);
when(groupNames.nextElement()).thenReturn(groupSearchResult);
// Define the attribute for the name of the first group
Attribute group1Attr = new BasicAttribute("cn");
group1Attr.add(testGroups[0]);
Attributes group1Attrs = new BasicAttributes();
group1Attrs.put(group1Attr);
// Define the attribute for the name of the second group
Attribute group2Attr = new BasicAttribute("cn");
group2Attr.add(testGroups[1]);
Attributes group2Attrs = new BasicAttributes();
group2Attrs.put(group2Attr);
// This search result gets reused, so return group1, then group2
when(groupSearchResult.getAttributes()).
thenReturn(group1Attrs, group2Attrs);
when(getUserNames().nextElement()).
thenReturn(getUserSearchResult());
when(getUserSearchResult().getAttributes()).thenReturn(getAttributes());
// Define results for groups 1 level up
SearchResult parentGroupResult = mock(SearchResult.class);
// only one parent group
when(parentGroupNames.hasMoreElements()).thenReturn(true, false);
when(parentGroupNames.nextElement()).
thenReturn(parentGroupResult);
// Define the attribute for the parent group
Attribute parentGroup1Attr = new BasicAttribute("cn");
parentGroup1Attr.add(testParentGroups[2]);
Attributes parentGroup1Attrs = new BasicAttributes();
parentGroup1Attrs.put(parentGroup1Attr);
// attach the attributes to the result
when(parentGroupResult.getAttributes()).thenReturn(parentGroup1Attrs);
when(parentGroupResult.getNameInNamespace()).
thenReturn("CN=some_group,DC=test,DC=com");
}
protected Configuration getBaseConf() {
return getBaseConf("ldap://test");
}
protected Configuration getBaseConf(String ldapUrl) {
return getBaseConf(ldapUrl, getContext());
}
protected Configuration getBaseConf(
String ldapUrl, DirContext contextToReturn) {
DummyLdapCtxFactory.setContextToReturn(contextToReturn);
DummyLdapCtxFactory.setExpectedLdapUrl(ldapUrl);
Configuration conf = new Configuration();
conf.set(LDAP_URL_KEY, ldapUrl);
conf.setClass(LDAP_CTX_FACTORY_CLASS_KEY, DummyLdapCtxFactory.class,
InitialContextFactory.class);
return conf;
}
protected DirContext getContext() {
return context;
}
protected NamingEnumeration<SearchResult> getUserNames() {
return userNames;
}
protected NamingEnumeration<SearchResult> getGroupNames() {
return groupNames;
}
protected SearchResult getUserSearchResult() {
return userSearchResult;
}
protected Attributes getAttributes() {
return attributes;
}
protected LdapGroupsMapping getGroupsMapping() {
return groupsMapping;
}
protected String[] getTestGroups() {
return testGroups;
}
protected NamingEnumeration getParentGroupNames() {
return parentGroupNames;
}
protected String[] getTestParentGroups() {
return testParentGroups;
}
/**
* Ldap Context Factory implementation to be used for testing to check
* contexts are requested for the expected LDAP server URLs etc.
*/
public static class DummyLdapCtxFactory implements InitialContextFactory {
private static DirContext contextToReturn;
private static String expectedLdapUrl;
public DummyLdapCtxFactory() {
}
protected static void setContextToReturn(DirContext ctx) {
contextToReturn = ctx;
}
protected static void setExpectedLdapUrl(String url) {
expectedLdapUrl = url;
}
@Override
public Context getInitialContext(Hashtable<?, ?> env)
throws NamingException {
if (expectedLdapUrl != null) {
String actualLdapUrl = (String) env.get(Context.PROVIDER_URL);
assertEquals(expectedLdapUrl, actualLdapUrl);
}
if (contextToReturn == null) {
InitialContextFactory defaultFactory = null;
try {
defaultFactory = LDAP_CTX_FACTORY_CLASS_DEFAULT.newInstance();
} catch (ReflectiveOperationException e) {
fail("Could not initialize the default factory");
}
return defaultFactory.getInitialContext(env);
}
return contextToReturn;
}
}
}