1   package com.atlassian.user.util.migration;
2   
3   import java.util.Calendar;
4   import java.util.Date;
5   
6   import com.atlassian.user.impl.DefaultUser;
7   import com.atlassian.user.security.password.Credential;
8   import net.sf.hibernate.SessionFactory;
9   
10  import com.atlassian.ldap.server.LdapServer;
11  import com.atlassian.user.EntityException;
12  import com.atlassian.user.Group;
13  import com.atlassian.user.GroupManager;
14  import com.atlassian.user.User;
15  import com.atlassian.user.UserManager;
16  import com.atlassian.user.configuration.DefaultDelegationAccessor;
17  import com.atlassian.user.configuration.DelegationAccessor;
18  import com.atlassian.user.configuration.RepositoryAccessor;
19  import com.atlassian.user.generic.AbstractSpringTest;
20  import com.atlassian.user.generic.JdbcHelper;
21  import com.atlassian.user.properties.PropertySetFactory;
22  import com.atlassian.user.security.authentication.Authenticator;
23  import com.opensymphony.module.propertyset.PropertySet;
24  import com.opensymphony.user.provider.ProfileProvider;
25  
26  public class TestOSUserEntityMigrator extends AbstractSpringTest
27  {
28      private RepositoryAccessor osuRepositoryAccessor;
29      private RepositoryAccessor hibernateRepositoryAccessor;
30      private RepositoryAccessor ldapRepositoryAccessor;
31  
32      private ProfileProvider profileProvider;
33      private PropertySetFactory hibernatePropertySetFactory;
34  
35      private SessionFactory sessionFactory;
36      private OSUEntityMigrator migrator;
37  
38      private LdapServer ldapServer;
39      private DefaultDelegationAccessor delegationAccessor;
40  
41      protected String[] getConfigLocations()
42      {
43          return new String[]{
44              "classpath:com/atlassian/user/impl/osuser/osuserTestContext.xml",
45              "classpath:com/atlassian/user/impl/hibernate/hibernateTestContext.xml",
46              "classpath:com/atlassian/user/impl/ldap/ldapTestContext.xml",
47              "classpath:com/atlassian/user/impl/ldap/ldapTestServerContext.xml",
48              "classpath:com/atlassian/user/impl/ldap/static/flat/ldapTestStaticFlatContext.xml",
49              "classpath:com/atlassian/user/dataSourceTestContext.xml",
50          };
51      }
52  
53  
54      public void onSetUp() throws Exception
55      {
56          super.onSetUp();
57          migrator = new OSUEntityMigrator(osuRepositoryAccessor, hibernateRepositoryAccessor, sessionFactory);
58          delegationAccessor = new DefaultDelegationAccessor();
59          delegationAccessor.addRepositoryAccessor(hibernateRepositoryAccessor);
60          delegationAccessor.addRepositoryAccessor(ldapRepositoryAccessor);
61      }
62  
63      protected void onTearDown() throws Exception
64      {
65          migrator = null;
66          delegationAccessor = null;
67          // required both before and after because OSUser commits stuff in a separate transaction to the tests
68          deleteUsersAndGroups();
69          super.onTearDown();
70          deleteUsersAndGroups();
71      }
72  
73      private void deleteUsersAndGroups() throws Exception
74      {
75          deleteData(osuRepositoryAccessor);
76      }
77  
78      private void deleteData(RepositoryAccessor accessor) throws Exception
79      {
80          GroupManager osuGroupManager = accessor.getGroupManager();
81          UserManager osuUserManager = accessor.getUserManager();
82          for (Group group : osuGroupManager.getGroups())
83          {
84              osuGroupManager.removeGroup(group);
85          }
86          for (User user : osuUserManager.getUsers())
87          {
88              osuUserManager.removeUser(user);
89          }
90          // osuser does not clean up the property entry table correctly
91          // See: http://jira.atlassian.com/browse/USER-192
92          new JdbcHelper().deleteTable(jdbcTemplate, "OS_PROPERTYENTRY");
93      }
94  
95      public void testMigrateUsersAndPropertySets() throws Exception
96      {
97          final MigratorConfiguration config = new MigratorConfiguration();
98          config.setMigrateMembershipsForExistingUsers(true);
99  
100         UserManager sourceUserManager = osuRepositoryAccessor.getUserManager();
101         createUser(sourceUserManager, "user1", "password");
102         createUser(sourceUserManager, "user2", "password");
103         createUser(sourceUserManager, "user3", "password");
104         createUser(sourceUserManager, "user4", "password");
105         createUser(sourceUserManager, "user5", "password");
106 
107         addOSUProperty("user1", "foo", "bar");
108         addOSUProperty("user1", "email", "user1@atlassian.com");
109         addOSUProperty("user1", "fullName", "User One");
110 
111         final Calendar calendar = Calendar.getInstance();
112         PropertySet propertySet = profileProvider.getPropertySet("user1");
113         propertySet.setDate("date", calendar.getTime());
114 
115         migrator.migrate(config, new NoOpMigrationProgressListener());
116 
117         UserManager targetUserManager = hibernateRepositoryAccessor.getUserManager();
118         Authenticator authenticator = hibernateRepositoryAccessor.getAuthenticator();
119         assertUser(targetUserManager, authenticator, "user1", "password");
120 
121         assertUserProperty("user1", "foo", "bar");
122         assertUserProperty("user1", "email", null); // email should not be copied across
123         assertUserProperty("user1", "fullName", null); // fullName should not be copied across
124 
125         final PropertySet ps = hibernatePropertySetFactory.getPropertySet(hibernateRepositoryAccessor.getUserManager().getUser("user1"));
126         assertDatesAreEqual(calendar, ps.getDate("date"));
127 
128         assertEquals("user1@atlassian.com", targetUserManager.getUser("user1").getEmail());
129         assertEquals("User One", targetUserManager.getUser("user1").getFullName());
130 
131         assertUser(targetUserManager, authenticator, "user2", "password");
132         assertUser(targetUserManager, authenticator, "user3", "password");
133         assertUser(targetUserManager, authenticator, "user4", "password");
134         assertUser(targetUserManager, authenticator, "user5", "password");
135     }
136 
137     public void testPropertiesOfExistingUsersWithExistingPropertiesNotMigrated() throws Exception
138     {
139         final MigratorConfiguration config = new MigratorConfiguration();
140         config.setMigrateMembershipsForExistingUsers(false);
141 
142         UserManager sourceUserManager = osuRepositoryAccessor.getUserManager();
143         UserManager targetUserManager = hibernateRepositoryAccessor.getUserManager();
144         Authenticator authenticator = hibernateRepositoryAccessor.getAuthenticator();
145 
146         final String username1 = "user1";
147         // create user with properties in source repo
148         createUser(sourceUserManager, username1, "OSUpassword");
149         addOSUProperty(username1, "chocolate", "bar");
150         addOSUProperty(username1, "foo", "shouldn't copy");
151 
152         // create one user and one property in target repo (hibernate expects encrypted password)
153         createUser(targetUserManager, username1,  "HibernatePassword");
154         addHibernateUserProperty(username1, "foo", "bar");
155 
156         migrator.migrate(config, new NoOpMigrationProgressListener());
157 
158         assertUser(targetUserManager, authenticator, username1, "HibernatePassword");
159         assertUserProperty("user1", "foo", "bar");
160         assertUserProperty("user1", "chocolate", null);        
161     }
162 
163     private void assertDatesAreEqual(Calendar calendar, Date date)
164     {
165         assertEquals(calendar.getTime().getTime(), date.getTime());
166     }
167 
168     public void testGroupMembershipsAreMigratedForAllUsers() throws Exception
169     {
170         final MigratorConfiguration config = new MigratorConfiguration();
171         config.setMigrateMembershipsForExistingUsers(true);
172 
173         UserManager sourceUserManager = osuRepositoryAccessor.getUserManager();
174         GroupManager sourceGroupManager = osuRepositoryAccessor.getGroupManager();
175         UserManager targetUserManager = hibernateRepositoryAccessor.getUserManager();
176         GroupManager targetGroupManager = hibernateRepositoryAccessor.getGroupManager();
177 
178         final String username1 = "user1";
179         final String groupName1 = "group1";
180         final String username2 = "user2";
181         final String groupName2 = "group2";
182 
183         // create some users and groups in the source repo
184         createUser(sourceUserManager, username1, "password");
185         sourceGroupManager.createGroup(groupName1);
186         createUser(sourceUserManager, username2, "password");
187         sourceGroupManager.createGroup(groupName2);
188         sourceGroupManager.addMembership(sourceGroupManager.getGroup(groupName1), sourceUserManager.getUser(username1));
189         sourceGroupManager.addMembership(sourceGroupManager.getGroup(groupName2), sourceUserManager.getUser(username2));
190 
191         // create one user in the target repo
192         createUser(targetUserManager, username1, "password");
193 
194         migrator.migrate(config, new NoOpMigrationProgressListener());
195 
196         final User user = targetUserManager.getUser(username1);
197         final Group group = targetGroupManager.getGroup(groupName1);
198         final User user2 = targetUserManager.getUser(username2);
199         final Group group2 = targetGroupManager.getGroup(groupName2);
200         assertNotNull(user);
201         assertNotNull(group);
202         assertNotNull(user2);
203         assertNotNull(group2);
204         assertTrue(targetGroupManager.hasMembership(group, user));
205         assertTrue(targetGroupManager.hasMembership(group2, user2));
206     }
207 
208     public void testGroupMembershipsAreNotMigratedForExistingUsersButAreMigratedForNonExistingUsers() throws Exception
209     {
210         final MigratorConfiguration config = new MigratorConfiguration();
211         config.setMigrateMembershipsForExistingUsers(false);
212 
213         UserManager sourceUserManager = osuRepositoryAccessor.getUserManager();
214         GroupManager sourceGroupManager = osuRepositoryAccessor.getGroupManager();
215         UserManager targetUserManager = hibernateRepositoryAccessor.getUserManager();
216         GroupManager targetGroupManager = hibernateRepositoryAccessor.getGroupManager();
217 
218         final String username1 = "user1";
219         final String groupName1 = "group1";
220         final String username2 = "user2";
221         final String groupName2 = "group2";
222 
223         // create some users and groups in the source repo
224         createUser(sourceUserManager, username1, "password");
225         sourceGroupManager.createGroup(groupName1);
226         createUser(sourceUserManager, username2, "password");
227         sourceGroupManager.createGroup(groupName2);
228         sourceGroupManager.addMembership(sourceGroupManager.getGroup(groupName1), sourceUserManager.getUser(username1));
229         sourceGroupManager.addMembership(sourceGroupManager.getGroup(groupName2), sourceUserManager.getUser(username2));
230 
231         // create one user in the target repo
232         createUser(targetUserManager, username1, "password");
233 
234         migrator.migrate(config, new NoOpMigrationProgressListener());
235 
236         final User user = targetUserManager.getUser(username1);
237         final Group group = targetGroupManager.getGroup(groupName1);
238         final User user2 = targetUserManager.getUser(username2);
239         final Group group2 = targetGroupManager.getGroup(groupName2);
240         assertNotNull(user);
241         assertNotNull(group);
242         assertNotNull(user2);
243         assertNotNull(group2);
244         assertFalse(targetGroupManager.hasMembership(group, user));
245         assertTrue(targetGroupManager.hasMembership(group2, user2));
246     }
247 
248     /**
249      * Testing USER-196: UnsupportedOperationException when adding a member to an LDAP group during migration
250      */
251     public void testMigrateUsersWithExistingGroupInLdapRepository() throws Exception
252     {
253         ldapServer.start();
254         try
255         {
256             final DelegationAccessor targetRepositoryAccessor = delegationAccessor;
257             final User testUser1 = createUser(osuRepositoryAccessor.getUserManager(), "testuser1", "testpwd1");
258             final String group1name = "group1";
259             final Group group1 = osuRepositoryAccessor.getGroupManager().createGroup(group1name); // group1 is also a group in LDAP
260             osuRepositoryAccessor.getGroupManager().addMembership(group1, testUser1); // adding the user to the group
261 
262             // make sure that groupA exists in LDAP
263             assertNotNull(ldapRepositoryAccessor.getGroupManager().getGroup(group1name));
264 
265             migrator = new OSUEntityMigrator(osuRepositoryAccessor, targetRepositoryAccessor, sessionFactory);
266 
267             final MigratorConfiguration config = new MigratorConfiguration();
268             config.setMigrateMembershipsForExistingUsers(true);
269 
270             migrator.migrate(config, new NoOpMigrationProgressListener());
271 
272             // check that the user has been migrated successfuly
273             assertNotNull(targetRepositoryAccessor.getUserManager().getUser(testUser1.getName()));
274         }
275         finally
276         {
277             ldapServer.stop();
278         }
279     }
280 
281     public void testMigrateUsersWithNullPassword() throws Exception
282     {
283         final MigratorConfiguration config = new MigratorConfiguration();
284         config.setMigrateMembershipsForExistingUsers(true);
285 
286         UserManager sourceUserManager = osuRepositoryAccessor.getUserManager();
287         createUser(sourceUserManager, "user1", null);
288         createUser(sourceUserManager, "user2", "");
289         createUser(sourceUserManager, "user3", "password");
290 
291         migrator.migrate(config, new NoOpMigrationProgressListener());
292 
293         UserManager targetUserManager = hibernateRepositoryAccessor.getUserManager();
294         Authenticator authenticator = hibernateRepositoryAccessor.getAuthenticator();
295         assertUserExists(targetUserManager, "user1");
296         assertUser(targetUserManager, authenticator, "user2", "");
297         assertUser(targetUserManager, authenticator, "user3", "password");
298     }
299 
300     public void testMigratedUserExistsInLDAP() throws Exception
301     {
302         ldapServer.start();
303         try
304         {
305             // this user exists in LDAP
306             final User testUser1 = createUser(osuRepositoryAccessor.getUserManager(), "user1", "testpwd1");
307             addOSUProperty("user1", "foo", "bar");
308             final Group group = osuRepositoryAccessor.getGroupManager().createGroup("somegroup");
309             osuRepositoryAccessor.getGroupManager().addMembership(group, testUser1); // adding the user to the group
310 
311             // make sure that groupA exists in LDAP
312             assertNotNull(ldapRepositoryAccessor.getUserManager().getUser(testUser1.getName()));
313 
314             migrator = new OSUEntityMigrator(osuRepositoryAccessor, delegationAccessor, sessionFactory);
315 
316             final MigratorConfiguration config = new MigratorConfiguration();
317             config.setMigrateMembershipsForExistingUsers(true);
318 
319             migrator.migrate(config, new NoOpMigrationProgressListener());
320 
321             // check that the user has NOT been migrated
322             assertNull(hibernateRepositoryAccessor.getUserManager().getUser(testUser1.getName()));
323             //assert that the LDAP user1 is now part of "somegroup"
324             assertTrue(delegationAccessor.getGroupManager().hasMembership(
325                     delegationAccessor.getGroupManager().getGroup(group.getName()),
326                     delegationAccessor.getUserManager().getUser(testUser1.getName())));
327             assertUserProperty("user1", "foo", "bar");
328         }
329         finally
330         {
331             ldapServer.stop();
332         }
333 
334     }
335 
336     private void assertUserProperty(String username, String key, String value) throws Exception
337     {
338         final PropertySet ps = delegationAccessor.getPropertySetFactory().getPropertySet(delegationAccessor.getUserManager().getUser(username));
339         assertNotNull(ps);
340         assertEquals(value, ps.getString(key));
341     }
342 
343     private void addOSUProperty(String username, String key, String value) throws Exception
344     {
345         PropertySet propertySet = profileProvider.getPropertySet(username);
346         propertySet.setString(key, value);
347     }
348 
349     private void addHibernateUserProperty(String username, String key, String value) throws Exception
350     {
351         final PropertySet propertySet = hibernatePropertySetFactory.getPropertySet(hibernateRepositoryAccessor.getUserManager().getUser(username));
352         propertySet.setString(key, value);
353     }
354 
355     private void assertUser(UserManager userManager, Authenticator authenticator, String username, String password) throws Exception
356     {
357         assertUserExists(userManager, username);
358         assertUserAuthenticates(authenticator, username, password);
359     }
360 
361     private void assertUserAuthenticates(Authenticator authenticator, String username, String password) throws EntityException
362     {
363         assertTrue("Password not authenticated: " + username + "/" + password, authenticator.authenticate(username, password));
364     }
365 
366     private void assertUserExists(UserManager userManager, String username) throws EntityException
367     {
368         assertNotNull("expected user [ " + username + " ] not found", userManager.getUser(username));
369     }
370 
371     private User createUser(UserManager userManager, String username, String password) throws Exception
372     {
373         Credential credential = password != null ? Credential.unencrypted(password) : Credential.NONE;
374         return userManager.createUser(new DefaultUser(username), credential);
375     }
376 
377     public void setOsuRepositoryAccessor(RepositoryAccessor osuRepositoryAccessor)
378     {
379         this.osuRepositoryAccessor = osuRepositoryAccessor;
380     }
381 
382     public void setHibernateRepositoryAccessor(RepositoryAccessor hibernateRepositoryAccessor)
383     {
384         this.hibernateRepositoryAccessor = hibernateRepositoryAccessor;
385     }
386 
387     public void setLdapRepositoryAccessor(RepositoryAccessor ldapRepositoryAccessor)
388     {
389         this.ldapRepositoryAccessor = ldapRepositoryAccessor;
390     }
391 
392     public void setProfileProvider(ProfileProvider profileProvider)
393     {
394         this.profileProvider = profileProvider;
395     }
396 
397     public void setPropertySetFactory(PropertySetFactory propertySetFactory)
398     {
399         this.hibernatePropertySetFactory = propertySetFactory;
400     }
401 
402     public void setSessionFactory(SessionFactory sessionFactory)
403     {
404         this.sessionFactory = sessionFactory;
405     }
406 
407     public void setLdapServer(LdapServer ldapServer)
408     {
409         this.ldapServer = ldapServer;
410     }
411 }