Skip to content

Instantly share code, notes, and snippets.

@icelander
Last active November 4, 2020 15:02
Show Gist options
  • Save icelander/9d45fc3a8a6836c36ec5a07db39e6965 to your computer and use it in GitHub Desktop.
Save icelander/9d45fc3a8a6836c36ec5a07db39e6965 to your computer and use it in GitHub Desktop.
Imports Mattermost users into an LDAP server from a bulk export file
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
require 'net-ldap'
###
## make_ldap_users.rb
#
# This script automates the process of importing users from a Mattermost bulk
# import file into an LDAP server
#
## How to use
#
# 0. Install the required Ruby gems:
# 1. Modify the ldap authentication information in this script to match your LDAP configuration
# - Default values work with https://hub.docker.com/r/rroemhild/test-openldap/
ldap = Net::LDAP.new
ldap.host = '127.0.0.1'
ldap.port = '389'
ldap.base = 'dc=planetexpress,dc=com'
ldap.auth 'cn=admin,dc=planetexpress,dc=com', 'GoodNewsEveryone'
# 2. Generate a Mattermost bulk import file and replace the filename on this line:
jsonl_filename = 'bulk-import.jsonl'
# 3. Customize the groups to randomly assign the users to
groups = [
['admin_staff', 'Office Management'],
['ship_crew', 'Delivering Crew']
]
# 4. Run the script and wait for it to run. It does about 1k users per minute
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
if ldap.bind
puts "Authenticated with LDAP server at #{ldap.host}"
else
puts "Could not authenticate with LDAP server at #{ldap.host}"
exit 1
end
##
# This shows how to do an LDAP query so you can verify that LDAP is working.
# Adjust the filter and treebase as necessary.
#
# filter = Net::LDAP::Filter.eq( "uid", "professor")
# treebase = "dc=planetexpress,dc=com"
# ldap.search( :base => treebase, :filter => filter ) do |entry|
# puts "DN: #{entry.dn}"
# entry.each do |attribute, values|
# puts " #{attribute}:"
# values.each do |value|
# if attribute.to_s != "jpegphoto"
# puts " --->#{value}"
# end
# end
# end
# end
# exit
file = File.open(jsonl_filename)
total_lines = File.foreach(file).count
file.close()
# Open jsonl file
users_jsonl = File.open(jsonl_filename, 'r')
line_count = 0
ldap_count = 0
existing_ldap_count = 0
group_count = {}
auth_count = 0
auth_array = []
# For each line
users_jsonl.each_line do |line|
# Make sure it's JSON and is a user
data = JSON.parse(line)
if data['type'] == 'user'
line_count += 1
puts "===== LINE #{line_count}/#{total_lines} ==="
user = data['user']
# Randomly assign to a group
group_id = rand(groups.length)
group = groups[group_id]
if ! group_count.key? group[0]
group_count[group[0]] = 0
end
# Check to see if the user exists in LDAP
search_filter = Net::LDAP::Filter.eq("mail", user['email'])
group_filter = Net::LDAP::Filter.eq("objectClass", 'inetOrgPerson')
composite_filter = Net::LDAP::Filter.join(search_filter, group_filter)
results = ldap.search(:filter => composite_filter)
if results.length == 0
###
# Add the user to the LDAP server
user_dn = sprintf("cn=%s,ou=people,dc=planetexpress,dc=com", user['email'])
password = Net::LDAP::Password.generate(:md5, user['password'])
if user['position'].nil?
employeeType = "Desk Jockey"
else
employeeType = user['position']
end
ldap_record = {
:objectClass => ['inetOrgPerson', 'organizationalPerson', 'person', 'top'],
:cn => user['first_name'],
:sn => user['last_name'],
:description => 'Human',
:employeeType => employeeType,
:givenName => user['first_name'],
:mail => user['email'],
:ou => group[1],
:uid => user['username'],
:userPassword => password
}
# pp user_dn
# pp ldap_record
add_result = ldap.add(:dn => user_dn, :attributes => ldap_record)
else
puts "User already exists"
existing_ldap_count += 1
auth_array << [user['username'], user['password']]
add_result = false
end
if add_result
ldap_count += 1
###
# Put the user into one of the two groups in LDAP
# Check if the user is in the group
# To do this I need to modify the group they're in
group_dn = "cn=#{group[0]},ou=people,dc=planetexpress,dc=com"
operations = [[:add, :member, user_dn]]
modify_result = ldap.modify :dn => group_dn, :operations => operations
###
# Authenticate the user against the Mattermost server to activate them
if modify_result
group_count[group[0]] += 1
puts "Added #{user['username']} to #{group[0]}"
# pp operations
auth_array << [user['username'], user['password']]
else
p ldap.get_operation_result
puts "Could not add #{user['username']} to group #{group[0]}"
end
else
p ldap.get_operation_result
puts "Could not add #{user['username']} to LDAP server"
end
end
end
users_jsonl.close
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
elapsed = ending - starting
puts "Processing complete! Took #{elapsed.round(2)} seconds - #{total_lines/elapsed.round(2) users per second}"
puts " - Processed #{line_count} users from #{jsonl_filename}"
puts " - Added #{ldap_count} users to #{ldap.host}"
puts " - Found #{existing_ldap_count} users in LDAP"
group_count.each do |gn,c|
puts " - Added #{c} users to group #{gn}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment