Last active
November 4, 2020 15:02
-
-
Save icelander/9d45fc3a8a6836c36ec5a07db39e6965 to your computer and use it in GitHub Desktop.
Imports Mattermost users into an LDAP server from a bulk export file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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