# SPDX-License-Identifier: Apache-2.0 # Copyright (C) 2021 OKTET Labs Ltd. All rights reserved. # # Class LdapRecord for Diary Management Application. # require_relative 'ldap_cache' require 'net/smtp' class LdapRecord @@connection = nil @@cache = {} attr_reader :id def LdapRecord.setup(args) raise "Invalid parameters" unless args.is_a? Hash raise "LDAP server is not specified" unless args[:host] @@ldap = LDAP::Conn.new(args[:host], args[:port] || LDAP::LDAP_PORT) if args[:ver] == 3 @@ldap.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3) end if args[:binddn] != "" @@ldap.bind(args[:binddn], args[:bindpw]) end #@@ldap.bind # Bind is optional for LDAPv3 raise "LDAP tree root is not specified" unless args[:root] raise "LDAP key attribute is not specified" unless args[:key] @@connection = LDAP::Cache.new(@@ldap, args[:root], LDAP::LDAP_SCOPE_SUBTREE, args[:key]) end def initialize(id) raise "LDAP connection is not established" if not @@connection @id = id @@cache[id] = self @attributes = @@connection[id] end def LdapRecord.find(id) # entry = @@cache[id] || (exists?(id) ? new(id) : nil) # entry = nil if (entry && !entry.valid?) # entry return @@cache[id] if valid?(@@cache[id]) exists?(id) ? new(id) : nil end def LdapRecord.valid?(entry) entry != nil end def LdapRecord.find_or_create(id) @@cache[id] || new(id) end def LdapRecord.exists?(id) @@connection[id] != nil end def LdapRecord.find_by_filter(filter) @@connection.list(filter, "uid").collect { |x| find(x[0]) }.find_all { |x| x } end def method_missing(method, *args) @attributes ? @attributes[method.to_s] : nil end end class Person < LdapRecord MAX_LENGTH = 30 attr_reader :organization def initialize(id) super(id) @organization = Organization.find_by_name(self.o) end def Person.exists?(id) super(id) && @@connection[id]["objectClass"] == "inetOrgPerson" end def Person.valid?(entry) super(entry) && entry.objectClass == "inetOrgPerson" end def Person.set_local(o_name, ou_name) @@local_o = o_name @@local_ou = ou_name end def to_s self.cn || @id end def to_html if not self.cn e(:span, :style => "color:red"){ @id } elsif self.mail e(:a, :href => "mailto:" + self.mail){ self.cn } else e(:span){ self.cn } end end def local? self.o == @@local_o end def employee? local? and self.ou == @@local_ou end def customer? self.o != nil and not local? end def Person.find_by_org(org_name) find_by_filter("(&(o=#{org_name})(objectClass=inetOrgPerson))") end def <=>(rhs) if self.cn rhs.cn ? self.cn <=> rhs.cn : -1 else rhs.cn ? 1 : @id <=> rhs.id end end end class Organization < LdapRecord def to_s self.o || @id end def to_html if not self.o e(:span, :style => "color:red"){ @id } else e(:span){ self.o } end end def Organization.exists?(id) super(id) && @@connection[id]["objectClass"] == "organization" end def Organization.valid?(entry) super(entry) && entry.objectClass == "organization" end def Organization.all find_by_filter("(objectClass=organization)") end def Organization.find_by_name(name) return nil unless name.is_a? String res = find_by_filter("(&(o=#{name})(objectClass=organization))") res ? res[0] : nil end def <=>(rhs) if self.o rhs.o ? self.o <=> rhs.o : -1 else rhs.o ? 1 : @id <=> rhs.id end end end class Notifier def notify(who, message) raise "No such person \"#{who.to_s}\"" if not who.is_a? Person msg = "From: Diary Management Application <#{DiaryEnv::SMTP_FROM}>\n" + "To: #{who.cn} <#{who.mail}>\n" + "Subject: Diary Management\n" + "\n" + message Net::SMTP.start(DiaryEnv::SMTP_HOST) do |smtp| smtp.send_message msg, DiaryEnv::SMTP_FROM, who.mail.untaint end end end