Compare commits
5 Commits
v0.9.0
...
4217ba52e0
| Author | SHA1 | Date | |
|---|---|---|---|
|
4217ba52e0
|
|||
|
de20931d30
|
|||
|
8de0a2e26e
|
|||
|
06521d1c34
|
|||
|
38b3d68fd5
|
@@ -168,21 +168,21 @@ class User < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def services_enabled
|
def services_enabled
|
||||||
ldap_entry[:service] || []
|
ldap_entry[:services_enabled] || []
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable_service(service)
|
def enable_service(service)
|
||||||
current_services = services_enabled
|
current_services = services_enabled
|
||||||
new_services = Array(service).map(&:to_s)
|
new_services = Array(service).map(&:to_s)
|
||||||
services = (current_services + new_services).uniq
|
services = (current_services + new_services).uniq
|
||||||
ldap.replace_attribute(dn, :service, services)
|
ldap.replace_attribute(dn, :serviceEnabled, services)
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_service(service)
|
def disable_service(service)
|
||||||
current_services = services_enabled
|
current_services = services_enabled
|
||||||
disabled_services = Array(service).map(&:to_s)
|
disabled_services = Array(service).map(&:to_s)
|
||||||
services = (current_services - disabled_services).uniq
|
services = (current_services - disabled_services).uniq
|
||||||
ldap.replace_attribute(dn, :service, services)
|
ldap.replace_attribute(dn, :serviceEnabled, services)
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable_all_services
|
def disable_all_services
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module LdapManager
|
|||||||
attributes = %w{ jpegPhoto }
|
attributes = %w{ jpegPhoto }
|
||||||
filter = Net::LDAP::Filter.eq("cn", @cn)
|
filter = Net::LDAP::Filter.eq("cn", @cn)
|
||||||
|
|
||||||
entry = ldap_client.search(base: treebase, filter: filter, attributes: attributes).first
|
entry = client.search(base: treebase, filter: filter, attributes: attributes).first
|
||||||
entry.try(:jpegPhoto) ? entry.jpegPhoto.first : nil
|
entry.try(:jpegPhoto) ? entry.jpegPhoto.first : nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,39 +3,49 @@ class LdapService < ApplicationService
|
|||||||
@suffix = ENV["LDAP_SUFFIX"] || "dc=kosmos,dc=org"
|
@suffix = ENV["LDAP_SUFFIX"] || "dc=kosmos,dc=org"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def modify(dn, operations=[])
|
||||||
|
client.modify dn: dn, operations: operations
|
||||||
|
client.get_operation_result.code
|
||||||
|
end
|
||||||
|
|
||||||
def add_attribute(dn, attr, values)
|
def add_attribute(dn, attr, values)
|
||||||
ldap_client.add_attribute dn, attr, values
|
client.add_attribute dn, attr, values
|
||||||
|
client.get_operation_result.code
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace_attribute(dn, attr, values)
|
def replace_attribute(dn, attr, values)
|
||||||
ldap_client.replace_attribute dn, attr, values
|
client.replace_attribute dn, attr, values
|
||||||
|
client.get_operation_result.code
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_attribute(dn, attr)
|
def delete_attribute(dn, attr)
|
||||||
ldap_client.delete_attribute dn, attr
|
client.delete_attribute dn, attr
|
||||||
|
client.get_operation_result.code
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_entry(dn, attrs, interactive=false)
|
def add_entry(dn, attrs, interactive=false)
|
||||||
puts "Adding entry: #{dn}" if interactive
|
puts "Add entry: #{dn}" if interactive
|
||||||
res = ldap_client.add dn: dn, attributes: attrs
|
client.add dn: dn, attributes: attrs
|
||||||
puts res.inspect if interactive && !res
|
client.get_operation_result.code
|
||||||
res
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_entry(dn, interactive=false)
|
def delete_entry(dn, interactive=false)
|
||||||
puts "Deleting entry: #{dn}" if interactive
|
puts "Delete entry: #{dn}" if interactive
|
||||||
res = ldap_client.delete dn: dn
|
client.delete dn: dn
|
||||||
puts res.inspect if interactive && !res
|
client.get_operation_result.code
|
||||||
res
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_all_entries!
|
def delete_all_users!
|
||||||
|
delete_all_entries!(objectclass: "person")
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_all_entries!(objectclass: "*")
|
||||||
if Rails.env.production?
|
if Rails.env.production?
|
||||||
raise "Mass deletion of entries not allowed in production"
|
raise "Mass deletion of entries not allowed in production"
|
||||||
end
|
end
|
||||||
|
|
||||||
filter = Net::LDAP::Filter.eq("objectClass", "*")
|
filter = Net::LDAP::Filter.eq("objectClass", objectclass)
|
||||||
entries = ldap_client.search(base: @suffix, filter: filter, attributes: %w{dn})
|
entries = client.search(base: @suffix, filter: filter, attributes: %w{dn})
|
||||||
entries.sort_by!{ |e| e.dn.length }.reverse!
|
entries.sort_by!{ |e| e.dn.length }.reverse!
|
||||||
|
|
||||||
entries.each do |e|
|
entries.each do |e|
|
||||||
@@ -56,7 +66,7 @@ class LdapService < ApplicationService
|
|||||||
]
|
]
|
||||||
filter = Net::LDAP::Filter.eq("uid", args[:uid] || "*")
|
filter = Net::LDAP::Filter.eq("uid", args[:uid] || "*")
|
||||||
|
|
||||||
entries = ldap_client.search(base: treebase, filter: filter, attributes: attributes)
|
entries = client.search(base: treebase, filter: filter, attributes: attributes)
|
||||||
entries.sort_by! { |e| e.cn[0] }
|
entries.sort_by! { |e| e.cn[0] }
|
||||||
entries = entries.collect do |e|
|
entries = entries.collect do |e|
|
||||||
{
|
{
|
||||||
@@ -64,9 +74,10 @@ class LdapService < ApplicationService
|
|||||||
mail: e.try(:mail) ? e.mail.first : nil,
|
mail: e.try(:mail) ? e.mail.first : nil,
|
||||||
display_name: e.try(:displayName) ? e.displayName.first : nil,
|
display_name: e.try(:displayName) ? e.displayName.first : nil,
|
||||||
admin: e.try(:admin) ? 'admin' : nil,
|
admin: e.try(:admin) ? 'admin' : nil,
|
||||||
service: e.try(:service),
|
services_enabled: e.try(:serviceEnabled),
|
||||||
email_maildrop: e.try(:mailRoutingAddress),
|
email_maildrop: e.try(:mailRoutingAddress),
|
||||||
email_password: e.try(:mailpassword)
|
email_password: e.try(:mailpassword),
|
||||||
|
nostr_key: e.try(:nostrKey)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -77,7 +88,7 @@ class LdapService < ApplicationService
|
|||||||
# filter = Net::LDAP::Filter.eq("objectClass", "*")
|
# filter = Net::LDAP::Filter.eq("objectClass", "*")
|
||||||
treebase = "cn=users,#{@suffix}"
|
treebase = "cn=users,#{@suffix}"
|
||||||
|
|
||||||
entries = ldap_client.search(base: treebase, filter: filter, attributes: attributes)
|
entries = client.search(base: treebase, filter: filter, attributes: attributes)
|
||||||
|
|
||||||
entries.sort_by! { |e| e.ou[0] }
|
entries.sort_by! { |e| e.ou[0] }
|
||||||
|
|
||||||
@@ -129,8 +140,8 @@ class LdapService < ApplicationService
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ldap_client
|
def client
|
||||||
ldap_client ||= Net::LDAP.new host: ldap_config['host'],
|
client ||= Net::LDAP.new host: ldap_config['host'],
|
||||||
port: ldap_config['port'],
|
port: ldap_config['port'],
|
||||||
# TODO has to be :simple_tls if TLS is enabled
|
# TODO has to be :simple_tls if TLS is enabled
|
||||||
# encryption: ldap_config['ssl'],
|
# encryption: ldap_config['ssl'],
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ Devise.setup do |config|
|
|||||||
config.ldap_auth_password_builder = Proc.new() { |new_password|
|
config.ldap_auth_password_builder = Proc.new() { |new_password|
|
||||||
salt = SecureRandom.hex(32)
|
salt = SecureRandom.hex(32)
|
||||||
hashed_pw = Base64.strict_encode64(Digest::SHA512.digest(new_password + salt) + salt)
|
hashed_pw = Base64.strict_encode64(Digest::SHA512.digest(new_password + salt) + salt)
|
||||||
puts '{SSHA512}' + hashed_pw
|
|
||||||
'{SSHA512}' + hashed_pw
|
'{SSHA512}' + hashed_pw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ require 'sidekiq/testing'
|
|||||||
ldap = LdapService.new
|
ldap = LdapService.new
|
||||||
|
|
||||||
Sidekiq::Testing.inline! do
|
Sidekiq::Testing.inline! do
|
||||||
|
ldap.delete_all_users!
|
||||||
|
|
||||||
|
puts "Create user: admin"
|
||||||
|
|
||||||
CreateAccount.call(account: {
|
CreateAccount.call(account: {
|
||||||
username: "admin", domain: "kosmos.org", email: "admin@example.com",
|
username: "admin", domain: "kosmos.org", email: "admin@example.com",
|
||||||
password: "admin is admin", confirmed: true
|
password: "admin is admin", confirmed: true
|
||||||
@@ -10,6 +14,7 @@ Sidekiq::Testing.inline! do
|
|||||||
|
|
||||||
ldap.add_attribute "cn=admin,ou=kosmos.org,cn=users,dc=kosmos,dc=org", :admin, "true"
|
ldap.add_attribute "cn=admin,ou=kosmos.org,cn=users,dc=kosmos,dc=org", :admin, "true"
|
||||||
|
|
||||||
|
puts "Create 35 random users"
|
||||||
35.times do |n|
|
35.times do |n|
|
||||||
username = Faker::Name.unique.first_name.downcase
|
username = Faker::Name.unique.first_name.downcase
|
||||||
email = Faker::Internet.unique.email
|
email = Faker::Internet.unique.email
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace :ldap do
|
namespace :ldap do
|
||||||
desc "Reset the LDAP directory and set up base entries and default org"
|
desc "Reset the LDAP directory and set up base entries and default org"
|
||||||
task setup: :environment do |t, args|
|
task setup: [:environment, :add_custom_attributes] do |t, args|
|
||||||
ldap = LdapService.new
|
ldap = LdapService.new
|
||||||
|
|
||||||
ldap.delete_entry "cn=admin_role,ou=kosmos.org,cn=users,dc=kosmos,dc=org", true
|
ldap.delete_entry "cn=admin_role,ou=kosmos.org,cn=users,dc=kosmos,dc=org", true
|
||||||
@@ -19,6 +19,42 @@ namespace :ldap do
|
|||||||
}, true
|
}, true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Add custom attributes to schema"
|
||||||
|
task add_custom_attributes: :environment do |t, args|
|
||||||
|
%w[ admin service_enabled nostr_key ].each do |name|
|
||||||
|
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "add")
|
||||||
|
Rake::Task['ldap:modify_ldap_schema'].reenable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Delete custom attributes from schema"
|
||||||
|
task delete_custom_attributes: :environment do |t, args|
|
||||||
|
%w[ admin service_enabled nostr_key ].each do |name|
|
||||||
|
Rake::Task["ldap:modify_ldap_schema"].invoke(name, "delete")
|
||||||
|
Rake::Task['ldap:modify_ldap_schema'].reenable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Modify LDAP schema"
|
||||||
|
task :modify_ldap_schema, [:name, :operation] => [:environment] do |t, args|
|
||||||
|
puts "Modify schema: #{args[:operation]} #{args[:name]}"
|
||||||
|
|
||||||
|
filename = "#{Rails.root}/schemas/ldap/#{args[:name]}.ldif"
|
||||||
|
ldif = YAML.safe_load(File.read(filename))
|
||||||
|
dn = ldif["dn"]
|
||||||
|
attribute = ldif["add"]
|
||||||
|
value = ldif[attribute]
|
||||||
|
operation = [ args[:operation].to_sym, attribute.to_sym, value ]
|
||||||
|
|
||||||
|
ldap = LdapService.new
|
||||||
|
res = ldap.modify dn, [ operation ]
|
||||||
|
|
||||||
|
if res != 0
|
||||||
|
puts "Result code: #{res}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc "List user domains/organizations"
|
desc "List user domains/organizations"
|
||||||
task list_organizations: :environment do |t, args|
|
task list_organizations: :environment do |t, args|
|
||||||
ldap = LdapService.new
|
ldap = LdapService.new
|
||||||
|
|||||||
9
schemas/ldap/admin.ldif
Normal file
9
schemas/ldap/admin.ldif
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
dn: cn=schema
|
||||||
|
changetype: modify
|
||||||
|
add: attributeTypes
|
||||||
|
attributeTypes: ( 1.3.6.1.4.1.61554.1.1.2.1.1
|
||||||
|
NAME 'admin'
|
||||||
|
DESC 'Admin flag'
|
||||||
|
EQUALITY booleanMatch
|
||||||
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||||
|
SINGLE-VALUE )
|
||||||
9
schemas/ldap/nostr_key.ldif
Normal file
9
schemas/ldap/nostr_key.ldif
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
dn: cn=schema
|
||||||
|
changetype: modify
|
||||||
|
add: attributeTypes
|
||||||
|
attributeTypes: ( 1.3.6.1.4.1.61554.1.1.2.1.21
|
||||||
|
NAME 'nostrKey'
|
||||||
|
DESC 'Nostr public key'
|
||||||
|
EQUALITY caseIgnoreMatch
|
||||||
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||||
|
SINGLE-VALUE )
|
||||||
8
schemas/ldap/service_enabled.ldif
Normal file
8
schemas/ldap/service_enabled.ldif
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
dn: cn=schema
|
||||||
|
changetype: modify
|
||||||
|
add: attributeTypes
|
||||||
|
attributeTypes: ( 1.3.6.1.4.1.61554.1.1.2.1.2
|
||||||
|
NAME 'serviceEnabled'
|
||||||
|
DESC 'Services enabled for account'
|
||||||
|
EQUALITY caseExactMatch
|
||||||
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||||
@@ -66,7 +66,7 @@ RSpec.describe User, type: :model do
|
|||||||
it "returns the entries from the LDAP service attribute" do
|
it "returns the entries from the LDAP service attribute" do
|
||||||
expect(user).to receive(:ldap_entry).and_return({
|
expect(user).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
service: ["discourse", "email", "gitea", "wiki", "xmpp"]
|
services_enabled: ["discourse", "email", "gitea", "wiki", "xmpp"]
|
||||||
})
|
})
|
||||||
expect(user.services_enabled).to eq(["discourse", "email", "gitea", "wiki", "xmpp"])
|
expect(user.services_enabled).to eq(["discourse", "email", "gitea", "wiki", "xmpp"])
|
||||||
end
|
end
|
||||||
@@ -76,21 +76,21 @@ RSpec.describe User, type: :model do
|
|||||||
before do
|
before do
|
||||||
allow(user).to receive(:ldap_entry).and_return({
|
allow(user).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
service: ["discourse", "gitea"]
|
services_enabled: ["discourse", "gitea"]
|
||||||
})
|
})
|
||||||
allow(user).to receive(:dn).and_return(dn)
|
allow(user).to receive(:dn).and_return(dn)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds the service to the LDAP entry" do
|
it "adds the service to the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :service, ["discourse", "gitea", "wiki"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse", "gitea", "wiki"]).and_return(true)
|
||||||
|
|
||||||
user.enable_service(:wiki)
|
user.enable_service(:wiki)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds multiple service to the LDAP entry" do
|
it "adds multiple service to the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :service, ["discourse", "gitea", "wiki", "xmpp"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse", "gitea", "wiki", "xmpp"]).and_return(true)
|
||||||
|
|
||||||
user.enable_service([:wiki, :xmpp])
|
user.enable_service([:wiki, :xmpp])
|
||||||
end
|
end
|
||||||
@@ -100,21 +100,21 @@ RSpec.describe User, type: :model do
|
|||||||
before do
|
before do
|
||||||
allow(user).to receive(:ldap_entry).and_return({
|
allow(user).to receive(:ldap_entry).and_return({
|
||||||
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
|
||||||
service: ["discourse", "gitea", "xmpp"]
|
services_enabled: ["discourse", "gitea", "xmpp"]
|
||||||
})
|
})
|
||||||
allow(user).to receive(:dn).and_return(dn)
|
allow(user).to receive(:dn).and_return(dn)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes the service from the LDAP entry" do
|
it "removes the service from the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :service, ["discourse", "gitea"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse", "gitea"]).and_return(true)
|
||||||
|
|
||||||
user.disable_service(:xmpp)
|
user.disable_service(:xmpp)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes multiple services from the LDAP entry" do
|
it "removes multiple services from the LDAP entry" do
|
||||||
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
expect_any_instance_of(LdapService).to receive(:replace_attribute)
|
||||||
.with(dn, :service, ["discourse"]).and_return(true)
|
.with(dn, :serviceEnabled, ["discourse"]).and_return(true)
|
||||||
|
|
||||||
user.disable_service([:xmpp, "gitea"])
|
user.disable_service([:xmpp, "gitea"])
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user