169 lines
4.9 KiB
Ruby
169 lines
4.9 KiB
Ruby
class LdapService < ApplicationService
|
|
def modify(dn, operations=[])
|
|
client.modify dn: dn, operations: operations
|
|
client.get_operation_result.code
|
|
end
|
|
|
|
def add_attribute(dn, attr, values)
|
|
client.add_attribute dn, attr, values
|
|
client.get_operation_result.code
|
|
end
|
|
|
|
def replace_attribute(dn, attr, values)
|
|
client.replace_attribute dn, attr, values
|
|
client.get_operation_result.code
|
|
end
|
|
|
|
def delete_attribute(dn, attr)
|
|
client.delete_attribute dn, attr
|
|
client.get_operation_result.code
|
|
end
|
|
|
|
def add_entry(dn, attrs, interactive=false)
|
|
puts "Add entry: #{dn}" if interactive
|
|
client.add dn: dn, attributes: attrs
|
|
client.get_operation_result.code
|
|
end
|
|
|
|
def delete_entry(dn, interactive=false)
|
|
puts "Delete entry: #{dn}" if interactive
|
|
client.delete dn: dn
|
|
client.get_operation_result.code
|
|
end
|
|
|
|
def delete_all_users!
|
|
delete_all_entries!(objectclass: "person")
|
|
end
|
|
|
|
def delete_all_entries!(objectclass: "*")
|
|
if Rails.env.production?
|
|
raise "Mass deletion of entries not allowed in production"
|
|
end
|
|
|
|
filter = Net::LDAP::Filter.eq("objectClass", objectclass)
|
|
entries = client.search(base: ldap_suffix, filter: filter, attributes: %w{dn})
|
|
entries.sort_by!{ |e| e.dn.length }.reverse!
|
|
|
|
entries.each do |e|
|
|
delete_entry e.dn, true
|
|
end
|
|
end
|
|
|
|
def fetch_users(args={})
|
|
attributes = %w[
|
|
dn cn uid mail displayName admin serviceEnabled memberStatus
|
|
mailRoutingAddress mailpassword nostrKey pgpKey
|
|
]
|
|
filter = Net::LDAP::Filter.eq('objectClass', 'person') &
|
|
Net::LDAP::Filter.eq("cn", args[:cn] || "*")
|
|
|
|
entries = client.search(
|
|
base: ldap_config["base"], filter: filter,
|
|
attributes: attributes
|
|
)
|
|
entries.sort_by! { |e| e.cn[0] }
|
|
entries = entries.collect do |e|
|
|
{
|
|
uid: e.uid.first,
|
|
mail: e.try(:mail) ? e.mail.first : nil,
|
|
display_name: e.try(:displayName) ? e.displayName.first : nil,
|
|
admin: e.try(:admin) ? 'admin' : nil,
|
|
services_enabled: e.try(:serviceEnabled),
|
|
member_status: e.try(:memberStatus),
|
|
email_maildrop: e.try(:mailRoutingAddress),
|
|
email_password: e.try(:mailpassword),
|
|
nostr_key: e.try(:nostrKey) ? e.nostrKey.first : nil,
|
|
pgp_key: e.try(:pgpKey) ? e.pgpKey.first : nil
|
|
}
|
|
end
|
|
end
|
|
|
|
def search_users(search_attr, value, return_attr)
|
|
filter = Net::LDAP::Filter.eq('objectClass', 'person') &
|
|
Net::LDAP::Filter.eq(search_attr.to_s, value.to_s) &
|
|
Net::LDAP::Filter.present('cn')
|
|
entries = client.search(
|
|
base: ldap_config["base"], filter: filter,
|
|
attributes: [return_attr]
|
|
)
|
|
entries.map { |entry| entry[return_attr].first }.compact
|
|
end
|
|
|
|
def fetch_organizations
|
|
attributes = %w{dn ou description}
|
|
filter = Net::LDAP::Filter.eq("objectClass", "organizationalUnit")
|
|
treebase = "cn=users,#{ldap_suffix}"
|
|
|
|
entries = client.search(base: treebase, filter: filter, attributes: attributes)
|
|
|
|
entries.sort_by! { |e| e.ou[0] }
|
|
|
|
entries = entries.collect do |e|
|
|
{
|
|
dn: e.dn,
|
|
ou: e.ou.first,
|
|
description: e.try(:description) ? e.description.first : nil,
|
|
}
|
|
end
|
|
end
|
|
|
|
def add_organization(ou, description, interactive=false)
|
|
dn = "ou=#{ou},cn=users,#{ldap_suffix}"
|
|
|
|
aci = <<-EOS
|
|
(target="ldap:///cn=*,ou=#{ou},cn=users,#{ldap_suffix}")(targetattr="cn || sn || uid || userPassword || mail || mailRoutingAddress || serviceEnabled || nostrKey || pgpKey || nsRole || objectClass") (version 3.0; acl "service-#{ou.gsub(".", "-")}-read-search"; allow (read,search) userdn="ldap:///uid=service,ou=#{ou},cn=applications,#{ldap_suffix}";)
|
|
EOS
|
|
|
|
attrs = {
|
|
objectClass: ["top", "organizationalUnit"],
|
|
description: description,
|
|
ou: ou,
|
|
aci: aci
|
|
}
|
|
|
|
add_entry dn, attrs, interactive
|
|
end
|
|
|
|
def reset_directory!
|
|
if Rails.env.production?
|
|
raise "Resetting the directory not allowed in production"
|
|
end
|
|
|
|
delete_all_entries!
|
|
|
|
user_read_aci = <<-EOS
|
|
(target="ldap:///#{ldap_suffix}")(targetattr="*") (version 3.0; acl "user-read-search-own-attributes"; allow (read,search) userdn="ldap:///self";)
|
|
EOS
|
|
|
|
add_entry ldap_suffix, {
|
|
dc: "kosmos", objectClass: ["top", "domain"], aci: user_read_aci
|
|
}, true
|
|
|
|
add_entry "cn=users,#{ldap_suffix}", {
|
|
cn: "users", objectClass: ["top", "organizationalRole"]
|
|
}, true
|
|
end
|
|
|
|
private
|
|
|
|
def client
|
|
client ||= Net::LDAP.new host: ldap_config['host'],
|
|
port: ldap_config['port'],
|
|
# TODO has to be :simple_tls if TLS is enabled
|
|
# encryption: ldap_config['ssl'],
|
|
auth: {
|
|
method: :simple,
|
|
username: ldap_config['admin_user'],
|
|
password: ldap_config['admin_password']
|
|
}
|
|
end
|
|
|
|
def ldap_config
|
|
ldap_config ||= YAML.load(ERB.new(File.read("#{Rails.root}/config/ldap.yml")).result)[Rails.env]
|
|
end
|
|
|
|
def ldap_suffix
|
|
@ldap_suffix ||= ENV["LDAP_SUFFIX"] || "dc=kosmos,dc=org"
|
|
end
|
|
end
|