809
|
1 -- vim:sts=4 sw=4 |
|
2 |
|
3 -- Prosody IM |
|
4 -- Copyright (C) 2008-2010 Matthew Wild |
|
5 -- Copyright (C) 2008-2010 Waqas Hussain |
|
6 -- Copyright (C) 2012 Rob Hoelz |
|
7 -- |
|
8 -- This project is MIT/X11 licensed. Please see the |
|
9 -- COPYING file in the source package for more information. |
|
10 -- |
|
11 |
|
12 ---------------------------------------- |
|
13 -- Constants and such -- |
|
14 ---------------------------------------- |
|
15 |
|
16 local setmetatable = setmetatable; |
|
17 local ldap = module:require 'ldap'; |
|
18 local vcardlib = module:require 'ldap/vcard'; |
|
19 local st = require 'util.stanza'; |
|
20 local gettime = require 'socket'.gettime; |
|
21 |
|
22 if not ldap then |
|
23 return; |
|
24 end |
|
25 |
|
26 local CACHE_EXPIRY = 300; |
|
27 local params = module:get_option('ldap'); |
|
28 |
|
29 ---------------------------------------- |
|
30 -- Utility Functions -- |
|
31 ---------------------------------------- |
|
32 |
|
33 local function ldap_record_to_vcard(record) |
|
34 return vcardlib.create { |
|
35 record = record, |
|
36 format = params.vcard_format, |
|
37 } |
|
38 end |
|
39 |
|
40 local get_alias_for_user; |
|
41 |
|
42 do |
|
43 local user_cache; |
|
44 local last_fetch_time; |
|
45 |
|
46 local function populate_user_cache() |
|
47 local ld = ldap.getconnection(); |
|
48 |
|
49 local usernamefield = params.user.usernamefield; |
|
50 local namefield = params.user.namefield; |
|
51 |
|
52 user_cache = {}; |
|
53 |
|
54 for _, attrs in ld:search { base = params.user.basedn, scope = 'onelevel', filter = params.user.filter } do |
|
55 user_cache[attrs[usernamefield]] = attrs[namefield]; |
|
56 end |
|
57 last_fetch_time = gettime(); |
|
58 end |
|
59 |
|
60 function get_alias_for_user(user) |
|
61 if last_fetch_time and last_fetch_time + CACHE_EXPIRY < gettime() then |
|
62 user_cache = nil; |
|
63 end |
|
64 if not user_cache then |
|
65 populate_user_cache(); |
|
66 end |
|
67 return user_cache[user]; |
|
68 end |
|
69 end |
|
70 |
|
71 ---------------------------------------- |
|
72 -- General Setup -- |
|
73 ---------------------------------------- |
|
74 |
|
75 local ldap_store = {}; |
|
76 ldap_store.__index = ldap_store; |
|
77 |
|
78 local adapters = { |
|
79 roster = {}, |
|
80 vcard = {}, |
|
81 } |
|
82 |
|
83 for k, v in pairs(adapters) do |
|
84 setmetatable(v, ldap_store); |
|
85 v.__index = v; |
|
86 v.name = k; |
|
87 end |
|
88 |
|
89 function ldap_store:get(username) |
|
90 return nil, "get method unimplemented on store '" .. tostring(self.name) .. "'" |
|
91 end |
|
92 |
|
93 function ldap_store:set(username, data) |
|
94 return nil, "LDAP storage is currently read-only"; |
|
95 end |
|
96 |
|
97 ---------------------------------------- |
|
98 -- Roster Storage Implementation -- |
|
99 ---------------------------------------- |
|
100 |
|
101 function adapters.roster:get(username) |
|
102 local ld = ldap.getconnection(); |
|
103 local contacts = {}; |
|
104 |
|
105 local memberfield = params.groups.memberfield; |
|
106 local namefield = params.groups.namefield; |
|
107 local filter = memberfield .. '=' .. tostring(username); |
|
108 |
|
109 local groups = {}; |
|
110 for _, config in ipairs(params.groups) do |
|
111 groups[ config[namefield] ] = config.name; |
|
112 end |
|
113 |
|
114 -- XXX this kind of relies on the way we do groups at INOC |
|
115 for _, attrs in ld:search { base = params.groups.basedn, scope = 'onelevel', filter = filter } do |
|
116 if groups[ attrs[namefield] ] then |
|
117 local members = attrs[memberfield]; |
|
118 |
|
119 for _, user in ipairs(members) do |
|
120 if user ~= username then |
|
121 local jid = user .. '@' .. module.host; |
|
122 local record = contacts[jid]; |
|
123 |
|
124 if not record then |
|
125 record = { |
|
126 subscription = 'both', |
|
127 groups = {}, |
|
128 name = get_alias_for_user(user), |
|
129 }; |
|
130 contacts[jid] = record; |
|
131 end |
|
132 |
|
133 record.groups[ groups[ attrs[namefield] ] ] = true; |
|
134 end |
|
135 end |
|
136 end |
|
137 end |
|
138 |
|
139 return contacts; |
|
140 end |
|
141 |
|
142 ---------------------------------------- |
|
143 -- vCard Storage Implementation -- |
|
144 ---------------------------------------- |
|
145 |
|
146 function adapters.vcard:get(username) |
|
147 if not params.vcard_format then |
|
148 return nil, ''; |
|
149 end |
|
150 |
|
151 local ld = ldap.getconnection(); |
|
152 local filter = params.user.usernamefield .. '=' .. tostring(username); |
|
153 |
|
154 local match = ldap.singlematch { |
|
155 base = params.user.basedn, |
|
156 filter = filter, |
|
157 }; |
|
158 if match then |
|
159 match.jid = username .. '@' .. module.host |
|
160 return st.preserialize(ldap_record_to_vcard(match)); |
|
161 else |
|
162 return nil, 'not found'; |
|
163 end |
|
164 end |
|
165 |
|
166 ---------------------------------------- |
|
167 -- Driver Definition -- |
|
168 ---------------------------------------- |
|
169 |
|
170 local driver = { name = "ldap" }; |
|
171 |
|
172 function driver:open(store, typ) |
|
173 local adapter = adapters[store]; |
|
174 |
|
175 if adapter and not typ then |
|
176 return adapter; |
|
177 end |
|
178 return nil, "unsupported-store"; |
|
179 end |
|
180 module:add_item("data-driver", driver); |