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