1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package edu.internet2.middleware.changelogconsumer.googleapps;
17
18 import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
19 import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
20 import com.google.api.client.http.HttpTransport;
21 import com.google.api.client.json.JsonFactory;
22 import com.google.api.client.json.jackson2.JacksonFactory;
23 import com.google.api.services.admin.directory.Directory;
24 import com.google.api.services.admin.directory.model.Group;
25 import com.google.api.services.admin.directory.model.Member;
26 import com.google.api.services.admin.directory.model.User;
27 import com.google.api.services.admin.directory.model.UserName;
28 import edu.internet2.middleware.changelogconsumer.googleapps.cache.GoogleCacheManager;
29 import edu.internet2.middleware.changelogconsumer.googleapps.utils.AddressFormatter;
30 import edu.internet2.middleware.grouper.changeLog.ChangeLogEntry;
31 import edu.internet2.middleware.grouper.changeLog.ChangeLogLabels;
32 import edu.internet2.middleware.grouper.changeLog.ChangeLogProcessorMetadata;
33 import edu.internet2.middleware.grouper.changeLog.ChangeLogType;
34 import edu.internet2.middleware.subject.Subject;
35 import edu.internet2.middleware.subject.provider.SubjectTypeEnum;
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.BeforeClass;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.powermock.core.classloader.annotations.PowerMockIgnore;
42 import org.powermock.core.classloader.annotations.PrepareForTest;
43 import org.powermock.modules.junit4.PowerMockRunner;
44
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.math.BigInteger;
48 import java.security.GeneralSecurityException;
49 import java.security.SecureRandom;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.List;
53 import java.util.Properties;
54
55 import static junit.framework.Assert.assertNotNull;
56 import static junit.framework.Assert.assertTrue;
57 import static org.junit.Assert.assertEquals;
58 import static org.mockito.Mockito.when;
59 import static org.powermock.api.mockito.PowerMockito.mock;
60
61 @RunWith(PowerMockRunner.class)
62 @PowerMockIgnore({"javax.net.ssl.*", "org.apache.log4j.*", " org.apache.logging.log4j.*"})
63 @PrepareForTest(value = { })
64 public class GoogleAppsChangeLogConsumerTest {
65
66 private static final String groupName = "qsuob:testStem:test";
67 private String groupDisplayName = "test";
68
69 private static final String subjectId = "fiwi";
70 private static final String sourceId = "jdbc";
71
72 private ChangeLogProcessorMetadata metadata;
73 private static AddressFormatter addressFormatter = new AddressFormatter();
74
75 private static GoogleAppsChangeLogConsumer consumer;
76 private static String googleDomain;
77
78
79 private static HttpTransport httpTransport;
80
81
82 private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
83
84 private static Directory directory = null;
85
86 @BeforeClass
87 public static void setupClass() {
88
89 consumer = new GoogleAppsChangeLogConsumer();
90
91 Properties props = new Properties();
92
93 InputStream is = ClassLoader.getSystemResourceAsStream("unit-test.properties");
94 try {
95 props.load(is);
96
97 googleDomain = props.getProperty("DOMAIN");
98 addressFormatter
99 .setDomain(googleDomain)
100 .setGroupIdentifierExpression(props.getProperty("GROUP_IDENTIFIER_EXPRESSION"))
101 .setSubjectIdentifierExpression(props.getProperty("SUBJECT_IDENTIFIER_EXPRESSION"));
102
103 httpTransport = GoogleNetHttpTransport.newTrustedTransport();
104
105 GoogleCredential googleCredential = null;
106 googleCredential = GoogleAppsSdkUtils.getGoogleDirectoryCredential(props.getProperty("SERVICE_ACCOUNT_EMAIL"),
107 props.getProperty("SERVICE_ACCOUNT_PKCS_12_FILE_PATH"), props.getProperty("SERVICE_IMPERSONATION_USER"),
108 httpTransport, JSON_FACTORY);
109
110 directory = new Directory.Builder(httpTransport, JSON_FACTORY, googleCredential)
111 .setApplicationName("Google Apps Grouper Provisioner")
112 .build();
113
114 } catch (Exception e) {
115 System.out.println("unit-test.properties configuration not found. Try again! Love, Grumpy Cat");
116 }
117
118 }
119
120 @Before
121 public void setup() throws GeneralSecurityException, IOException {
122 metadata = mock(ChangeLogProcessorMetadata.class);
123 when(metadata.getConsumerName()).thenReturn("google");
124 }
125
126 @After
127 public void tearDown() throws GeneralSecurityException, IOException {
128 try {
129 GoogleAppsSdkUtils.removeGroup(directory, addressFormatter.qualifyGroupAddress(groupName));
130 } catch (IOException e) {
131
132 }
133
134 try {
135 GoogleAppsSdkUtils.removeUser(directory, addressFormatter.qualifyGroupAddress(subjectId));
136 } catch (IOException e) {
137
138 }
139
140 GoogleCacheManager.googleGroups().clear();
141 GoogleCacheManager.googleUsers().clear();
142
143
144 pause(1000L);
145 }
146
147 @Test
148 public void testProcessGroupAdd() throws GeneralSecurityException, IOException {
149 ChangeLogEntry addEntry = mock(ChangeLogEntry.class);
150 when(addEntry.getChangeLogType()).thenReturn(new ChangeLogType("group", "addGroup", ""));
151 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_ADD.name)).thenReturn(groupName);
152 when(addEntry.getContextId()).thenReturn("123456789");
153
154 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(addEntry));
155
156 consumer.processChangeLogEntries(changeLogEntryList, metadata);
157 Group group = GoogleAppsSdkUtils.retrieveGroup(directory, addressFormatter.qualifyGroupAddress(groupName));
158 assertNotNull(group);
159 assertTrue(group.getName().equalsIgnoreCase(groupDisplayName));
160 }
161
162 @Test
163 public void testProcessGroupUpdate() throws GeneralSecurityException, IOException {
164 final String NEW_TEST = "newTest";
165
166 createTestGroup(groupDisplayName, groupName);
167
168 ChangeLogEntry addEntry = mock(ChangeLogEntry.class);
169 when(addEntry.getChangeLogType()).thenReturn(new ChangeLogType("group", "updateGroup", ""));
170 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.name)).thenReturn(groupName);
171 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyChanged)).thenReturn("displayExtension");
172 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyOldValue)).thenReturn(groupDisplayName);
173 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyNewValue)).thenReturn(NEW_TEST);
174 when(addEntry.getContextId()).thenReturn("123456789");
175
176 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(addEntry));
177
178 consumer.processChangeLogEntries(changeLogEntryList, metadata);
179 pause(1000L);
180 Group group = GoogleAppsSdkUtils.retrieveGroup(directory, addressFormatter.qualifyGroupAddress(groupName));
181
182 assertNotNull(group);
183 assertEquals(NEW_TEST, group.getName());
184
185
186
187
188 }
189
190
191 @Test
192 public void testProcessGroupMemberAddExistingUser() throws GeneralSecurityException, IOException {
193
194 createTestGroup(groupDisplayName, groupName);
195 createTestUser(buildSubjectAddress(subjectId), "Fiona", "Windsor");
196
197 ChangeLogEntry addEntry = mock(ChangeLogEntry.class);
198 when(addEntry.getChangeLogType()).thenReturn(new ChangeLogType("membership", "addMembership", ""));
199 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.groupName)).thenReturn(groupName);
200 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.subjectId)).thenReturn(subjectId);
201 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.sourceId)).thenReturn(sourceId);
202 when(addEntry.getContextId()).thenReturn("123456789");
203
204 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(addEntry));
205
206 consumer.processChangeLogEntries(changeLogEntryList, metadata);
207
208 List<Member> members = GoogleAppsSdkUtils.retrieveGroupMembers(directory, addressFormatter.qualifyGroupAddress(groupName));
209 assertNotNull(members);
210 assertTrue(members.size() == 1);
211 assertTrue(members.get(0).getEmail().equalsIgnoreCase(buildSubjectAddress(subjectId)));
212 }
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 @Test
239 public void testProcessGroupMemberAddNewUserWithProvisioning() throws GeneralSecurityException, IOException {
240
241 createTestGroup(groupDisplayName, groupName);
242
243 ChangeLogEntry addEntry = mock(ChangeLogEntry.class);
244 when(addEntry.getChangeLogType()).thenReturn(new ChangeLogType("membership", "addMembership", ""));
245 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.groupName)).thenReturn(groupName);
246 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.subjectId)).thenReturn(subjectId);
247 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_ADD.sourceId)).thenReturn(sourceId);
248 when(addEntry.getContextId()).thenReturn("123456789");
249
250 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(addEntry));
251
252 consumer.processChangeLogEntries(changeLogEntryList, metadata);
253
254 List<Member> members = GoogleAppsSdkUtils.retrieveGroupMembers(directory, addressFormatter.qualifyGroupAddress(groupName));
255 assertNotNull(members);
256 assertTrue(members.size() == 1);
257 assertTrue(members.get(0).getEmail().equalsIgnoreCase(buildSubjectAddress(subjectId)));
258 }
259
260 @Test
261 public void testProcessGroupMemberRemove() throws GeneralSecurityException, IOException {
262
263 Group group = createTestGroup(groupDisplayName, groupName);
264 createTestUser(buildSubjectAddress(subjectId), "Fiona", "Windsor");
265
266 Member member = new Member()
267 .setEmail(buildSubjectAddress(subjectId))
268 .setRole("MEMBER");
269 GoogleAppsSdkUtils.addGroupMember(directory, group.getEmail(), member);
270
271 ChangeLogEntry addEntry = mock(ChangeLogEntry.class);
272 when(addEntry.getChangeLogType()).thenReturn(new ChangeLogType("membership", "deleteMembership", ""));
273 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.groupName)).thenReturn(groupName);
274 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.subjectId)).thenReturn(subjectId);
275 when(addEntry.retrieveValueForLabel(ChangeLogLabels.MEMBERSHIP_DELETE.sourceId)).thenReturn(sourceId);
276 when(addEntry.getContextId()).thenReturn("123456789");
277
278 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(addEntry));
279
280 consumer.processChangeLogEntries(changeLogEntryList, metadata);
281
282 List<Member> members = GoogleAppsSdkUtils.retrieveGroupMembers(directory, addressFormatter.qualifyGroupAddress(groupName));
283 assertNotNull(members);
284 assertTrue(members.size() == 0);
285 }
286
287 @Test
288 public void testProcessGroupsStemChange() throws GeneralSecurityException, IOException {
289 try {
290 createTestGroup(groupDisplayName, groupName + "Change");
291 } catch (Exception ex) {}
292
293 ChangeLogEntry addEntry = mock(ChangeLogEntry.class);
294 when(addEntry.getChangeLogType()).thenReturn(new ChangeLogType("group", "updateGroup", ""));
295 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.name)).thenReturn(groupName);
296 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyChanged)).thenReturn("name");
297 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyOldValue)).thenReturn(groupName+"Change");
298 when(addEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_UPDATE.propertyNewValue)).thenReturn(groupName);
299 when(addEntry.getContextId()).thenReturn("123456789");
300
301 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(addEntry));
302
303 consumer.processChangeLogEntries(changeLogEntryList, metadata);
304 pause(2000L);
305 Group group = GoogleAppsSdkUtils.retrieveGroup(directory, addressFormatter.qualifyGroupAddress(groupName));
306
307 assertNotNull(group);
308 assertEquals(addressFormatter.qualifyGroupAddress(groupName).toLowerCase(), group.getEmail());
309 assertTrue(group.getAliases().contains(addressFormatter.qualifyGroupAddress(groupName+"Change")));
310 }
311
312 @Test
313 public void testProcessGroupDelete() throws GeneralSecurityException, IOException {
314 createTestGroup(groupDisplayName, groupName);
315
316 ChangeLogEntry deleteEntry = mock(ChangeLogEntry.class);
317 when(deleteEntry.getChangeLogType()).thenReturn(new ChangeLogType("group", "deleteGroup", ""));
318 when(deleteEntry.retrieveValueForLabel(ChangeLogLabels.GROUP_DELETE.name)).thenReturn(groupName);
319 when(deleteEntry.getContextId()).thenReturn("123456789");
320
321 ArrayList<ChangeLogEntry> changeLogEntryList = new ArrayList<ChangeLogEntry>(Arrays.asList(deleteEntry));
322
323 consumer.processChangeLogEntries(changeLogEntryList, metadata);
324 assertTrue(GoogleAppsSdkUtils.retrieveGroup(directory, addressFormatter.qualifyGroupAddress(groupName)) == null);
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366 private Group createTestGroup(String name, String mailbox) throws IOException {
367 Group group = new Group();
368 group.setName(name);
369 group.setEmail(addressFormatter.qualifyGroupAddress(mailbox));
370 return GoogleAppsSdkUtils.addGroup(directory, group);
371 }
372
373 private User createTestUser(String email, String givenName, String surname) throws IOException {
374 User user = new User();
375 user.setPrimaryEmail(email);
376 user.setName(new UserName());
377 user.getName().setFamilyName(surname);
378 user.getName().setGivenName(givenName);
379 user.setPassword(new BigInteger(130, new SecureRandom()).toString(32));
380 return GoogleAppsSdkUtils.addUser(directory, user);
381 }
382
383 private Subject getTestUserSubject() {
384 Subject subject = mock(Subject.class);
385 when(subject.getAttributeValue("givenName")).thenReturn("testgn2");
386 when(subject.getAttributeValue("sn")).thenReturn("testfn2");
387 when(subject.getAttributeValue("displayName")).thenReturn("testgn2, testfn2");
388 when(subject.getAttributeValue("mail")).thenReturn(buildSubjectAddress(subjectId));
389 when(subject.getType()).thenReturn(SubjectTypeEnum.PERSON);
390 return subject;
391 }
392
393 private Subject getTestGroupSubject() {
394 Subject subject = mock(Subject.class);
395 when(subject.getAttributeValue("givenName")).thenReturn("testgn2");
396 when(subject.getAttributeValue("sn")).thenReturn("testfn2");
397 when(subject.getAttributeValue("displayName")).thenReturn("testgn2, testfn2");
398 when(subject.getAttributeValue("mail")).thenReturn(buildSubjectAddress(subjectId));
399 when(subject.getType()).thenReturn(SubjectTypeEnum.GROUP);
400 return subject;
401 }
402
403 private void pause(long milliseconds) {
404 try {
405 Thread.sleep(milliseconds);
406 } catch (InterruptedException e) {
407 e.printStackTrace();
408 }
409 }
410
411 private String buildSubjectAddress(String subjectId) {
412 return String.format("%s@%s", subjectId, googleDomain);
413 }
414
415 }