18
18
19
19
package org .apache .hadoop .security ;
20
20
21
+ import java .util .ArrayList ;
21
22
import java .util .Arrays ;
22
23
import java .util .List ;
23
24
24
25
import javax .naming .NamingEnumeration ;
25
26
import javax .naming .NamingException ;
26
27
import javax .naming .directory .Attribute ;
28
+ import javax .naming .directory .DirContext ;
27
29
import javax .naming .directory .SearchControls ;
28
30
import javax .naming .directory .SearchResult ;
29
31
30
32
import org .apache .hadoop .conf .Configuration ;
31
33
import org .junit .Assert ;
32
- import org .junit .Before ;
33
34
import org .junit .Test ;
35
+ import org .mockito .stubbing .Stubber ;
34
36
35
37
import static org .mockito .ArgumentMatchers .any ;
36
38
import static org .mockito .ArgumentMatchers .anyString ;
49
51
public class TestLdapGroupsMappingWithOneQuery
50
52
extends TestLdapGroupsMappingBase {
51
53
52
- @ Before
53
- public void setupMocks () throws NamingException {
54
+ public void setupMocks (List <String > listOfDNs ) throws NamingException {
54
55
Attribute groupDN = mock (Attribute .class );
55
56
56
57
NamingEnumeration <SearchResult > groupNames = getGroupNames ();
57
58
doReturn (groupNames ).when (groupDN ).getAll ();
58
- String groupName1 = "CN=abc,DC=foo,DC=bar,DC=com" ;
59
- String groupName2 = "CN=xyz,DC=foo,DC=bar,DC=com" ;
60
- String groupName3 = "CN=sss,CN=foo,DC=bar,DC=com" ;
61
- doReturn (groupName1 ).doReturn (groupName2 ).doReturn (groupName3 ).
62
- when (groupNames ).next ();
63
- when (groupNames .hasMore ()).thenReturn (true ).thenReturn (true ).
64
- thenReturn (true ).thenReturn (false );
59
+ buildListOfGroupDNs (listOfDNs ).when (groupNames ).next ();
60
+ when (groupNames .hasMore ()).
61
+ thenReturn (true ).thenReturn (true ).
62
+ thenReturn (true ).thenReturn (false );
65
63
66
64
when (getAttributes ().get (eq ("memberOf" ))).thenReturn (groupDN );
67
65
}
68
66
67
+ /**
68
+ * Build and return a list of individually added group DNs such
69
+ * that calls to .next() will result in a single value each time.
70
+ *
71
+ * @param listOfDNs
72
+ * @return the stubber to use for the .when().next() call
73
+ */
74
+ private Stubber buildListOfGroupDNs (List <String > listOfDNs ) {
75
+ Stubber stubber = null ;
76
+ for (String s : listOfDNs ) {
77
+ if (stubber != null ) {
78
+ stubber .doReturn (s );
79
+ } else {
80
+ stubber = doReturn (s );
81
+ }
82
+ }
83
+ return stubber ;
84
+ }
85
+
69
86
@ Test
70
87
public void testGetGroups () throws NamingException {
71
88
// given a user whose ldap query returns a user object with three "memberOf"
72
89
// properties, return an array of strings representing its groups.
73
90
String [] testGroups = new String [] {"abc" , "xyz" , "sss" };
74
91
doTestGetGroups (Arrays .asList (testGroups ));
92
+
93
+ // test fallback triggered by NamingException
94
+ doTestGetGroupsWithFallback ();
75
95
}
76
96
77
97
private void doTestGetGroups (List <String > expectedGroups )
78
98
throws NamingException {
99
+ List <String > groupDns = new ArrayList <>();
100
+ groupDns .add ("CN=abc,DC=foo,DC=bar,DC=com" );
101
+ groupDns .add ("CN=xyz,DC=foo,DC=bar,DC=com" );
102
+ groupDns .add ("CN=sss,DC=foo,DC=bar,DC=com" );
103
+
104
+ setupMocks (groupDns );
79
105
String ldapUrl = "ldap://test" ;
80
106
Configuration conf = getBaseConf (ldapUrl );
81
107
// enable single-query lookup
82
108
conf .set (LdapGroupsMapping .MEMBEROF_ATTR_KEY , "memberOf" );
83
109
84
- LdapGroupsMapping groupsMapping = getGroupsMapping ();
110
+ TestLdapGroupsMapping groupsMapping = new TestLdapGroupsMapping ();
85
111
groupsMapping .setConf (conf );
86
112
// Username is arbitrary, since the spy is mocked to respond the same,
87
113
// regardless of input
88
114
List <String > groups = groupsMapping .getGroups ("some_user" );
89
115
90
116
Assert .assertEquals (expectedGroups , groups );
117
+ Assert .assertFalse ("Second LDAP query should NOT have been called." ,
118
+ groupsMapping .isSecondaryQueryCalled ());
91
119
92
120
// We should have only made one query because single-query lookup is enabled
93
121
verify (getContext (), times (1 )).search (anyString (), anyString (),
94
122
any (Object [].class ), any (SearchControls .class ));
95
123
}
96
- }
124
+
125
+ private void doTestGetGroupsWithFallback ()
126
+ throws NamingException {
127
+ List <String > groupDns = new ArrayList <>();
128
+ groupDns .add ("CN=abc,DC=foo,DC=bar,DC=com" );
129
+ groupDns .add ("CN=xyz,DC=foo,DC=bar,DC=com" );
130
+ groupDns .add ("ipaUniqueID=e4a9a634-bb24-11ec-aec1-06ede52b5fe1," +
131
+ "CN=sudo,DC=foo,DC=bar,DC=com" );
132
+ setupMocks (groupDns );
133
+ String ldapUrl = "ldap://test" ;
134
+ Configuration conf = getBaseConf (ldapUrl );
135
+ // enable single-query lookup
136
+ conf .set (LdapGroupsMapping .MEMBEROF_ATTR_KEY , "memberOf" );
137
+ conf .set (LdapGroupsMapping .LDAP_NUM_ATTEMPTS_KEY , "1" );
138
+
139
+ TestLdapGroupsMapping groupsMapping = new TestLdapGroupsMapping ();
140
+ groupsMapping .setConf (conf );
141
+ // Username is arbitrary, since the spy is mocked to respond the same,
142
+ // regardless of input
143
+ List <String > groups = groupsMapping .getGroups ("some_user" );
144
+
145
+ // expected to be empty due to invalid memberOf
146
+ Assert .assertEquals (0 , groups .size ());
147
+
148
+ // expect secondary query to be called: getGroups()
149
+ Assert .assertTrue ("Second LDAP query should have been called." ,
150
+ groupsMapping .isSecondaryQueryCalled ());
151
+
152
+ // We should have fallen back to the second query because first threw
153
+ // NamingException expected count is 3 since testGetGroups calls
154
+ // doTestGetGroups and doTestGetGroupsWithFallback in succession and
155
+ // the count is across both test scenarios.
156
+ verify (getContext (), times (3 )).search (anyString (), anyString (),
157
+ any (Object [].class ), any (SearchControls .class ));
158
+ }
159
+
160
+ private static final class TestLdapGroupsMapping extends LdapGroupsMapping {
161
+ private boolean secondaryQueryCalled = false ;
162
+ public boolean isSecondaryQueryCalled () {
163
+ return secondaryQueryCalled ;
164
+ }
165
+ List <String > lookupGroup (SearchResult result , DirContext c ,
166
+ int goUpHierarchy ) throws NamingException {
167
+ secondaryQueryCalled = true ;
168
+ return super .lookupGroup (result , c , goUpHierarchy );
169
+ }
170
+ }
171
+ }
0 commit comments