Importing LDAP Users

The OMC includes a web service for importing users from a CSV file:

https://hostname/webservice/users/import

Using the following script, which can be found in the file doc/user_import/import_ldap_users.rb, you can – after having configured it by adapting the variable values at the beginning of the script – import users from an LDAP server. LDAP groups can be assigned to OMC roles using the LDAP_GROUP_MAPPING hash.

#!ruby

require 'rubygems'
require 'net/ldap'
require 'csv'
require 'uri'
require 'net/https'

HTTP_OMC_URL = 'https://hostname/webservice/users/import'
HTTP_OMC_API_KEY = 'keykeykeykeykeykeykeykeykeykeykeykey'
HTTP_PROXY_HOST = nil
HTTP_PROXY_PORT = nil
HTTP_PROXY_USERNAME = nil
HTTP_PROXY_PASSWORD = nil

LDAP_HOST = 'ldap.domain'
LDAP_PORT = 389
LDAP_AUTH = nil
LDAP_BASE = 'dc=company,dc=de'
LDAP_USER_LOGIN = 'uid'
LDAP_USER_EMAIL = 'mail'
LDAP_USER_FULL_NAME = 'cn'
LDAP_USER_FILTER = '(&(objectclass=posixAccount)(mail=*)(cn=*)(uid=*)(!(uid=root))(!(uid=vpn_*))(!(uid=user1))(!(uid=user32))(!(uid=otheruser))(!(uid=diradmin))(!(uid=user75))(!(uid=guest)))'
LDAP_GROUP_FILTER = '(objectClass=posixGroup)'
LDAP_GROUP_MEMBERS = 'memberUid'
LDAP_GROUP_MEMBERS_ARE_DN = false
LDAP_GROUP_MAPPING = {
  'alle' => 'cn=alle,cn=groups,dc=company,dc=de',
  'group1' => 'cn=group1,cn=groups,dc=company,dc=de',
  'admin' => 'cn=admin,cn=groups,dc=company,dc=de',
  'sales' => 'cn=sales,cn=groups,dc=company,dc=de',
}

class LdapUser

  attr_accessor :dn
  attr_accessor :login
  attr_accessor :full_name
  attr_accessor :email

  def roles
    @roles ||= []
    @roles.join(' ')
  end

  def add_role(role)
    @roles ||= []
    unless "#{role}" == ''
      @roles << role.to_s
    end
  end

end

class LdapImporter

  def make_user(ldap_entry)
    login = ldap_entry.__send__(LDAP_USER_LOGIN).to_s rescue nil
    full_name = ldap_entry.__send__(LDAP_USER_FULL_NAME).to_s rescue login
    email = ldap_entry.__send__(LDAP_USER_EMAIL).to_s rescue nil
    raise "no login for entry: #{ldap_entry.inspect}" if "#{login}" == ''
    user = LdapUser.new
    user.login = login
    user.full_name = full_name
    user.email = email
    user.dn = ldap_entry.dn.to_s
    user
  end

  def user_attributes
    [LDAP_USER_LOGIN, LDAP_USER_EMAIL, LDAP_USER_FULL_NAME, 'dn']
  end

  def user_filter
    Net::LDAP::Filter.from_rfc2254(LDAP_USER_FILTER)
  end

  def get_all_users
    users = {}
    Net::LDAP.open(
        :host => LDAP_HOST,
        :port => LDAP_PORT,
        :auth => LDAP_AUTH) do |ldap|
      ldap.search(
          :base => LDAP_BASE,
          :filter => user_filter,
          :attributes => user_attributes,
          :return_result => false
      ) do |entry|
        user = make_user(entry)
        key = LDAP_GROUP_MEMBERS_ARE_DN ? user.dn : user.login
        users[key] = user
      end
    end
    users
  end

  def group_filter(group_dn)
    Net::LDAP::Filter.from_rfc2254(LDAP_GROUP_FILTER) &
        Net::LDAP::Filter.from_rfc2254(group_dn)
  end

  def get_members_of_group(group_dn)
    members = []
    Net::LDAP.open(
        :host => LDAP_HOST,
        :port => LDAP_PORT,
        :auth => LDAP_AUTH) do |ldap|
      ldap.search(
          :base => LDAP_BASE,
          :filter => group_filter(group_dn),
          :attributes => ['dn', LDAP_GROUP_MEMBERS],
          :return_result => false
      ) do |entry|
        members = entry.__send__(LDAP_GROUP_MEMBERS)
      end
    end
    members
  end

  def add_group_assignments(users, group_mapping)
    group_mapping.each do |role, group_dn|
      get_members_of_group(group_dn).each do |member|
        user = users[member]
        user.add_role(role) if user
      end
    end
  end

  def generate_csv(users)
    csv_data = ''
    CSV::Writer.generate(csv_data, ',') do |csv|
      csv << [:login, :full_name, :email, :roles]
      users.values.each do |user|
        csv << [user.login, user.full_name, user.email, user.roles]
      end
    end
    csv_data
  end

  def post_to_webservice(csv_data)
    uri = URI.parse(HTTP_OMC_URL)
    http = Net::HTTP::Proxy(
        HTTP_PROXY_HOST, HTTP_PROXY_PORT,
        HTTP_PROXY_USERNAME, HTTP_PROXY_PASSWORD).new(uri.host, uri.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    res = http.start do |http|
      req = Net::HTTP::Post.new(uri.path)
      req.basic_auth('webservice', HTTP_OMC_API_KEY)
      req.set_form_data({'MAX_FILE_SIZE' => '1000000', 'csv' => csv_data})
      http.request(req)
    end
    case res
    when Net::HTTPSuccess, Net::HTTPRedirection
      puts "HTTP-Response: #{res.code} #{res.class.name} #{res.message}"
      puts res.body
    else
      puts "HTTP-Response: #{res.code} #{res.class.name} #{res.message}"
      puts res.body
      exit(-1)
    end
  end

  def self.run
    importer = new
    users = importer.get_all_users
    exit(-1) if users.size < 50
    importer.add_group_assignments(users, LDAP_GROUP_MAPPING)
    csv_data = importer.generate_csv(users)
    importer.post_to_webservice(csv_data)
    #puts csv_data
  end

end

LdapImporter.run