comparison mod_storage_ldap/mod_storage_ldap.lua @ 809:1d51c5e38faa

Add LDAP plugin suite
author rob@hoelz.ro
date Sun, 02 Sep 2012 15:35:50 +0200
parents
children 2469f779b3f7
comparison
equal deleted inserted replaced
808:ba2e207e1fb7 809:1d51c5e38faa
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);