When I originally started using Crowd, I set it up with an internal directory… A type of directory that is proprietary to the Crowd application. Ideally, I would have set it up with an AD/LDAP directory, but at the time I did not have one setup. Now, of course, I have one setup and want to migrate away from the old (proprietary) directory to the new LDAP directory. Confluence and JIRA are both using Crowd for authentication/SSO and of course migrating from one directory to another is not as easy as I had originally thought it would be.
Atlassian Support recommended that I use the Alias feature in Crowd.. The problem with that though, is that it only provides a synchronization of passwords. The users would still have to continue using their old username to login to Confluence and JIRA. I believe the reason Atlassian chose to do this is because there are many “behind-the-scenes” references to a username. This must be so that users can freely be added and removed from Confluence/JIRA without directly affecting the integrity of Confluence pages and JIRA issues. However, this provides a problem for me, because in my scenario I no longer can afford to manage users that have two separate usernames.
I ended up creating a set of SQL scripts to migrate my users from the old (proprietary) directory, to the new (LDAP) directory. It is a very manual process and not one that I take lightly. Ultimately, I have to migrate one user at a time and it involves notifying the user that they cannot use Confluence or JIRA, restarting Confluence and JIRA a number of times and updating a number of tables in the Confluence and JIRA databases. Here I will outline the process in which I have followed to accomplish this and will also provide the SQL scripts for download. I make no guarantee that this migration process will work for anyone else, but thought I would at least share it just in case.
Notes
- Even though you update the JIRA tables, many fields are stored in memory in JIRA’s index. Even restarting JIRA doesn’t always do the trick. For example, I had to manually perform a re-index in order to get assignee’s to update.
- In JIRA, I have not been able to determine where the favorite filters are stored… So, the scripts do not update the favorite filters. That does not mean that the filters don’t exist, I just mean that they aren’t shown on the favorite filters.
- These scripts were built for JIRA 4.3.2 and Confluence 3.5.2.
- THIS IS NOT A GUARANTEED PROCESS. If you screw up your Confluence and JIRA instances, it’s not my fault.
Process
- Backup the database! Whether you are doing a migration for Confluence, or JIRA or both, backup the databases that you are working with.
- Install the procedure that I created for the appropriate application(s).
- Work on one user at a time.
- Remove all groups from the internal directory for the given user.
- Disable the user in the internal directory so that the use doesn’t count against the license count. You should only have to be worried about this if you have a limited number of users on your license. If you have an unlimited user license, you are in a better position then I.
- Activate the user in the LDAP directory and perform a Crowd authentication test for the application in question.
- Run the following MySQL command on the application’s database:
CALL MigrateUser('myOldUsername', 'mynewUsername', 1234);
- After running the MySQL command, review the returned results to make sure there are no remaining entries that did not get updated
- Re-synchronize the Crowd User Directory in the Confluence or JIRA application.
- Flush cache or re-index.
- When running the script on JIRA, re-index the application (or restart it).
- When running the script in Confluence, flush the cache (or restart it).
JIRA Script
-- JIRA
DELIMITER $$
DROP PROCEDURE IF EXISTS `MigrateUser`$$
CREATE PROCEDURE `MigrateUser` (
inOldUsername VARCHAR(255),
inNewUsername VARCHAR(255),
inDirectoryId INT
)
BEGIN
-- Update the crowd user entry
update cwd_user set
user_name = inNewUsername,
lower_user_name = inNewUsername
where
user_name = inOldUsername
and directory_id = inDirectoryId;
-- Remove crowd's old membership entries for groups (assumes groups have changed)
delete from cwd_membership where child_name = inOldUsername and directory_id = inDirectoryId;
-- Update the project roles for the new user
update projectroleactor set ROLETYPEPARAMETER = inNewUsername where ROLETYPEPARAMETER = inOldUsername;
-- Update jira issues to reflect new assigne and reporter
update jiraissue set assignee = inNewUsername where assignee = inOldUsername;
update jiraissue set reporter = inNewUsername where reporter = inOldUsername;
-- Miscellaneous updates
update columnlayout set username = inNewUsername where username = inOldUsername;
update favouriteassociations set username = inNewUsername where USERNAME = inOldUsername;
update filtersubscription set USERNAME = inNewUsername where USERNAME = inOldUsername;
update portalpage set USERNAME = inNewUsername where USERNAME = inOldUsername;
update searchrequest set authorname = inNewUsername, username = inNewUsername where username = inOldUsername;
update userhistoryitem set USERNAME = inNewUsername where USERNAME = inOldUsername;
update component set LEAD = inNewUsername where lead = inOldUsername;
update userassociation set SOURCE_NAME = inNewUsername where SOURCE_NAME = inOldUsername;
update worklog set AUTHOR = inNewUsername where AUTHOR = inOldUsername;
update worklog set UPDATEAUTHOR = inNewUsername where UPDATEAUTHOR = inOldUsername;
update project set LEAD = inNewUsername where LEAD = inOldUsername;
select * from columnlayout where username = inOldUsername;
select * from favouriteassociations where username = inOldUsername;
select * from filtersubscription where username = inOldUsername;
select * from portalpage where username = inOldUsername;
select * from searchrequest where username = inOldUsername;
select * from userhistoryitem where username = inOldUsername;
select * from userbase where username = inOldUsername;
select * from columnlayout where username = inOldUsername;
select * from projectroleactor where ROLETYPEPARAMETER = inOldUsername;
select * from cwd_user where user_name = inOldUsername and directory_id = inDirectoryId;
END
Confluence Script
-- CONFLUENCE
DELIMITER $$
DROP PROCEDURE IF EXISTS `MigrateUser`$$
CREATE PROCEDURE `MigrateUser` (
inOldUsername VARCHAR(255),
inNewUsername VARCHAR(255),
inDirectoryId INT
)
BEGIN
update ATTACHMENTS a set a.creator = inNewUsername where a.creator = inOldUsername;
update ATTACHMENTS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update CONTENT a set a.creator = inNewUsername where a.creator = inOldUsername;
update CONTENT a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update CONTENT a set a.username = inNewUsername where a.username = inOldUsername;
update CONTENTLOCK a set a.creator = inNewUsername where a.creator = inOldUsername;
update CONTENTLOCK a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update CONTENT_LABEL a set a.owner = inNewUsername where a.owner = inOldUsername;
update CONTENT_PERM a set a.creator = inNewUsername where a.creator = inOldUsername;
update CONTENT_PERM a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update CONTENT_PERM a set a.username = inNewUsername where a.username = inOldUsername;
update CWD_USER a set a.lower_user_name = LOWER(inNewUsername) where a.lower_user_name = LOWER(inOldUsername) and a.directory_id = inDirectoryId;
update CWD_USER a set a.user_name = inNewUsername where a.user_name = inOldUsername and a.directory_id = inDirectoryId;
update EXTRNLNKS a set a.creator = inNewUsername where a.creator = inOldUsername;
update EXTRNLNKS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update FOLLOW_CONNECTIONS a set a.followee = inNewUsername where a.followee = inOldUsername;
update FOLLOW_CONNECTIONS a set a.follower = inNewUsername where a.follower = inOldUsername;
update LABEL a set a.owner = inNewUsername where a.owner = inOldUsername;
update LINKS a set a.creator = inNewUsername where a.creator = inOldUsername;
update LINKS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update NOTIFICATIONS a set a.creator = inNewUsername where a.creator = inOldUsername;
update NOTIFICATIONS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update NOTIFICATIONS a set a.username = inNewUsername where a.username = inOldUsername;
update PAGETEMPLATES a set a.creator = inNewUsername where a.creator = inOldUsername;
update PAGETEMPLATES a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update REMEMBERMETOKEN a set a.username = inNewUsername where a.username = inOldUsername;
update SPACEGROUPS a set a.creator = inNewUsername where a.creator = inOldUsername;
update SPACEGROUPS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update SPACEPERMISSIONS a set a.creator = inNewUsername where a.creator = inOldUsername;
update SPACEPERMISSIONS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update SPACEPERMISSIONS a set a.permusername = inNewUsername where a.permusername = inOldUsername;
update SPACES a set a.creator = inNewUsername where a.creator = inOldUsername;
update SPACES a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
update TRACKBACKLINKS a set a.creator = inNewUsername where a.creator = inOldUsername;
update TRACKBACKLINKS a set a.lastmodifier = inNewUsername where a.lastmodifier = inOldUsername;
-- Reassign user preferences
update OS_PROPERTYENTRY a
set a.entity_name = concat('CWD_', inNewUsername)
where a.entity_name = concat('CWD_', inOldUsername);
-- Change space name
update SPACES a
set a.spacekey = concat('~', inNewUsername)
where a.spacekey = concat('~', inOldUsername);
update BANDANA a
set a.bandanacontext = concat('~', inNewUsername)
where a.bandanacontext = concat('~', inOldUsername);
select * from cwd_user where user_name = inOldUsername;
select * from NOTIFICATIONS where username = inOldUsername;
select * from SPACEPERMISSIONS where PERMUSERNAME = inOldUsername;
select * from CONTENT where username = inOldUsername;
END