1 | var ldap = require('../lib/index');
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | function authorize(req, res, next) {
|
7 |
|
8 | var isSearch = (req instanceof ldap.SearchRequest);
|
9 | if (!req.connection.ldap.bindDN.equals('cn=root') && !isSearch)
|
10 | return next(new ldap.InsufficientAccessRightsError());
|
11 |
|
12 | return next();
|
13 | }
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | var SUFFIX = 'o=smartdc';
|
19 | var db = {};
|
20 | var server = ldap.createServer();
|
21 |
|
22 |
|
23 |
|
24 | server.bind('cn=root', function (req, res, next) {
|
25 | if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
|
26 | return next(new ldap.InvalidCredentialsError());
|
27 |
|
28 | res.end();
|
29 | return next();
|
30 | });
|
31 |
|
32 | server.add(SUFFIX, authorize, function (req, res, next) {
|
33 | var dn = req.dn.toString();
|
34 |
|
35 | if (db[dn])
|
36 | return next(new ldap.EntryAlreadyExistsError(dn));
|
37 |
|
38 | db[dn] = req.toObject().attributes;
|
39 | res.end();
|
40 | return next();
|
41 | });
|
42 |
|
43 | server.bind(SUFFIX, function (req, res, next) {
|
44 | var dn = req.dn.toString();
|
45 | if (!db[dn])
|
46 | return next(new ldap.NoSuchObjectError(dn));
|
47 |
|
48 | if (!db[dn].userpassword)
|
49 | return next(new ldap.NoSuchAttributeError('userPassword'));
|
50 |
|
51 | if (db[dn].userpassword.indexOf(req.credentials) === -1)
|
52 | return next(new ldap.InvalidCredentialsError());
|
53 |
|
54 | res.end();
|
55 | return next();
|
56 | });
|
57 |
|
58 | server.compare(SUFFIX, authorize, function (req, res, next) {
|
59 | var dn = req.dn.toString();
|
60 | if (!db[dn])
|
61 | return next(new ldap.NoSuchObjectError(dn));
|
62 |
|
63 | if (!db[dn][req.attribute])
|
64 | return next(new ldap.NoSuchAttributeError(req.attribute));
|
65 |
|
66 | var matches = false;
|
67 | var vals = db[dn][req.attribute];
|
68 | for (var i = 0; i < vals.length; i++) {
|
69 | if (vals[i] === req.value) {
|
70 | matches = true;
|
71 | break;
|
72 | }
|
73 | }
|
74 |
|
75 | res.end(matches);
|
76 | return next();
|
77 | });
|
78 |
|
79 | server.del(SUFFIX, authorize, function (req, res, next) {
|
80 | var dn = req.dn.toString();
|
81 | if (!db[dn])
|
82 | return next(new ldap.NoSuchObjectError(dn));
|
83 |
|
84 | delete db[dn];
|
85 |
|
86 | res.end();
|
87 | return next();
|
88 | });
|
89 |
|
90 | server.modify(SUFFIX, authorize, function (req, res, next) {
|
91 | var dn = req.dn.toString();
|
92 | if (!req.changes.length)
|
93 | return next(new ldap.ProtocolError('changes required'));
|
94 | if (!db[dn])
|
95 | return next(new ldap.NoSuchObjectError(dn));
|
96 |
|
97 | var entry = db[dn];
|
98 |
|
99 | for (var i = 0; i < req.changes.length; i++) {
|
100 | mod = req.changes[i].modification;
|
101 | switch (req.changes[i].operation) {
|
102 | case 'replace':
|
103 | if (!entry[mod.type])
|
104 | return next(new ldap.NoSuchAttributeError(mod.type));
|
105 |
|
106 | if (!mod.vals || !mod.vals.length) {
|
107 | delete entry[mod.type];
|
108 | } else {
|
109 | entry[mod.type] = mod.vals;
|
110 | }
|
111 |
|
112 | break;
|
113 |
|
114 | case 'add':
|
115 | if (!entry[mod.type]) {
|
116 | entry[mod.type] = mod.vals;
|
117 | } else {
|
118 | mod.vals.forEach(function (v) {
|
119 | if (entry[mod.type].indexOf(v) === -1)
|
120 | entry[mod.type].push(v);
|
121 | });
|
122 | }
|
123 |
|
124 | break;
|
125 |
|
126 | case 'delete':
|
127 | if (!entry[mod.type])
|
128 | return next(new ldap.NoSuchAttributeError(mod.type));
|
129 |
|
130 | delete entry[mod.type];
|
131 |
|
132 | break;
|
133 | }
|
134 | }
|
135 |
|
136 | res.end();
|
137 | return next();
|
138 | });
|
139 |
|
140 | server.search(SUFFIX, authorize, function (req, res, next) {
|
141 | var dn = req.dn.toString();
|
142 | if (!db[dn])
|
143 | return next(new ldap.NoSuchObjectError(dn));
|
144 |
|
145 | var scopeCheck;
|
146 |
|
147 | switch (req.scope) {
|
148 | case 'base':
|
149 | if (req.filter.matches(db[dn])) {
|
150 | res.send({
|
151 | dn: dn,
|
152 | attributes: db[dn]
|
153 | });
|
154 | }
|
155 |
|
156 | res.end();
|
157 | return next();
|
158 |
|
159 | case 'one':
|
160 | scopeCheck = function (k) {
|
161 | if (req.dn.equals(k))
|
162 | return true;
|
163 |
|
164 | var parent = ldap.parseDN(k).parent();
|
165 | return (parent ? parent.equals(req.dn) : false);
|
166 | };
|
167 | break;
|
168 |
|
169 | case 'sub':
|
170 | scopeCheck = function (k) {
|
171 | return (req.dn.equals(k) || req.dn.parentOf(k));
|
172 | };
|
173 |
|
174 | break;
|
175 | }
|
176 |
|
177 | Object.keys(db).forEach(function (key) {
|
178 | if (!scopeCheck(key))
|
179 | return;
|
180 |
|
181 | if (req.filter.matches(db[key])) {
|
182 | res.send({
|
183 | dn: key,
|
184 | attributes: db[key]
|
185 | });
|
186 | }
|
187 | });
|
188 |
|
189 | res.end();
|
190 | return next();
|
191 | });
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | server.listen(1389, function () {
|
198 | console.log('LDAP server up at: %s', server.url);
|
199 | });
|