I needed a way to bulk add users from one group to another in Crowd this week. The problem was basically that not all members of a ‘staff’ group in Crowd were also members of a ‘jira-users’ group which was causing problems with logins in JIRA.
Since Crowd’s UI doesn’t support bulk operations yet, doing it via its Remote API was the only option. I decided to implement this in Ruby for no particular reason other than that I wanted to play with another language. Ruby turned out to be surprisingly quick to learn actually.
Read on for the full implementation details…

Ruby setup

Being a complete Ruby newbie I didn’t know that Ruby (including SOAP4R the ruby soap library) comes pre-installed on OSX (Leopard). So I went ahead and installed it (again). I found out later that this is only needed on Tiger and Leopard users should use the installed version of Ruby. So here’s the setup steps for Tiger :).
I first installed MacPorts which also required Apple’s Xcode Tools to get gcc. XCode is found as an optional package on the OSX installation DVD.
Once I’d installed this, I installed Ruby following the instructions:

% port install ruby

Finally, I also needed to install SOAP4R:

% gem install soap4r --include-dependencies

Writing the script

First I generated my client scripts using wsdl2ruby:

% wsdl2ruby --wsdl http://localhost:8095/crowd/services/SecurityServer?wsdl --type client

Then it was time to write my script. There’s two ways to do this. Interactive Mode or in a script. I found that the interactive mode was incredibly useful to learn the language and try out things. You can start the interactive shell by invoking:

% irb

Once I’d figured out how to do things in the interactive shell, I ended up putting it all together into the following script:

require "defaultDriver.rb"
# Set these for your crowd instance
crowdBaseURL = 'http://localhost:9999/crowd'
applicationName = 'demo'
applicationPassword = 'demo'
sourceGroup = 'staff'
targetGroup = 'users'
driver = SecurityServerPortType.new(crowdBaseURL + '/services/SecurityServer')
authCtx = ApplicationAuthenticationContext.new(PasswordCredential.new(applicationPassword), applicationName, [])
begin
token = driver.authenticateApplication(:in0 => authCtx)
rescue
print "Error logging in: " + $! + "\n"
raise
end
begin
group = driver.findGroupByName(:in0 => token.out, :in1 => sourceGroup)
print "Group '" + sourceGroup + "' has " + group.out.members.size.to_s + " members. Are you Sure you want to continue ? (y/n)\n"
choice = gets
if choice.chomp != 'y'
print "Goodbye!"
Process.exit
end
rescue
print "Error retrieving group '" + sourceGroup + "':" + $! + "\n"
raise
end
group.out.members.each do |member|
begin
driver.addPrincipalToGroup(:in0 => token.out, :in1 => member, :in2 => targetGroup)
print "Added '" + member + "' to group '" + targetGroup + "'.\n"
rescue
print "Error adding '" + member + "' to group '" + targetGroup + "': " + $! + "\n"
end
end

To invoke the script simply run *ruby bulkcopyusers.rb*.
I’ve attached a zip file with all the generated scripts, if you want to use it with Crowd or just play with Ruby. Given that this is my first ever Ruby script, I’d love to hear about any improvements .
Total time taken was about 1 hour, which is probably only marginally longer than it would have taken me to write a Java client to do the same thing.

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now