775 |
stephane |
1 |
<?php
|
|
|
2 |
/*
|
|
|
3 |
This class handled of ldap configuration.
|
|
|
4 |
WARNING! This class can't says if the configuration is valid or not.
|
|
|
5 |
*/
|
|
|
6 |
|
|
|
7 |
class ldapConfig
|
|
|
8 |
{
|
|
|
9 |
protected $_items = Array();
|
|
|
10 |
protected $_tls = array();
|
|
|
11 |
protected $instanceName;
|
|
|
12 |
|
|
|
13 |
public function __construct($instanceName=null) {
|
|
|
14 |
if ($instanceName!== null)
|
|
|
15 |
$this->instanceName = $instanceName;
|
|
|
16 |
// LDAP setting
|
779 |
stephane |
17 |
$this->_items['protocol'] = 'ldap';
|
775 |
stephane |
18 |
$this->_items['host'] = 'test';
|
779 |
stephane |
19 |
$this->_items['server'] = $this->_items['protocol'].'://'.$this->_items['host'];
|
775 |
stephane |
20 |
$this->_items['port'] = '389';//not use yet (689 = ldaps)
|
|
|
21 |
$this->_items['identity'] = '';
|
|
|
22 |
$this->_items['password'] = '';
|
|
|
23 |
$this->_items['basedn'] = 'dc=example,dc=com';
|
779 |
stephane |
24 |
$this->_items['uid'] = 'uid';
|
|
|
25 |
$this->_items['filter'] = "($this->_items['uid']=%{Stripped-User-Name:-%{User-Name}})";
|
775 |
stephane |
26 |
$this->_items['base_filter'] = '';
|
|
|
27 |
$this->_items['ldap_connections_number'] = '5';
|
|
|
28 |
$this->_items['timeout'] = '4';
|
|
|
29 |
$this->_items['timelimit'] = '3';
|
|
|
30 |
$this->_items['net_timeout'] = '1';
|
|
|
31 |
// TLS setting related items
|
|
|
32 |
$this->_tls['start_tls'] = 'no'; // if no all tls config are comments
|
|
|
33 |
$this->_tls['cacertfile'] = '#';
|
|
|
34 |
$this->_tls['cacertdir'] = '#';
|
|
|
35 |
$this->_tls['certfile'] = '#';
|
|
|
36 |
$this->_tls['keyfile'] = '#';
|
|
|
37 |
$this->_tls['randfile'] = '#';
|
|
|
38 |
$this->_tls['require_cert'] = '#';
|
|
|
39 |
// others ldap setting (optional)
|
|
|
40 |
$this->_items['default_profile'] = '#';
|
|
|
41 |
$this->_items['profile_attribute'] = '#';
|
|
|
42 |
$this->_items['access_attr'] = '#';
|
|
|
43 |
// Mapping of RADIUS dictionary attributes to LDAP
|
|
|
44 |
// directory attributes.
|
|
|
45 |
$this->_items['dictionary_mapping'] = '${confdir}/ldap.attrmap';
|
|
|
46 |
// for ldap like NOVEL
|
|
|
47 |
$this->_items['password_attribute'] = '#';
|
|
|
48 |
$this->_items['edir_account_policy_check'] = 'no';
|
|
|
49 |
// Group membership checking. Disabled by default.
|
|
|
50 |
$this->_items['groupname_attribute'] = '#';
|
|
|
51 |
$this->_items['groupmembership_filter'] = '#';
|
|
|
52 |
$this->_items['groupmembership_attribute'] = '#';
|
|
|
53 |
$this->_items['compare_check_items'] = '#';
|
|
|
54 |
$this->_items['do_xlat'] = '#';
|
|
|
55 |
$this->_items['access_attr_used_for_allow'] = '#';
|
|
|
56 |
// auth option
|
|
|
57 |
$this->_items['set_auth_type'] = '#';
|
|
|
58 |
// debug option
|
|
|
59 |
$this->_items['ldap_debug'] = '#';
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
public function __get($attr){ // to get an $item
|
|
|
63 |
if ($attr==='tls'){
|
|
|
64 |
return $this->_tls;
|
|
|
65 |
} elseif (array_key_exists($attr, $this->_items)){
|
|
|
66 |
return $this->_items[$attr];
|
|
|
67 |
} elseif (array_key_exists($attr, $this->_tls)){
|
|
|
68 |
return $this->_tls[$attr];
|
|
|
69 |
}
|
|
|
70 |
// nothing else!
|
|
|
71 |
}
|
|
|
72 |
public function __set($attr, $value){// to set an $item
|
|
|
73 |
if (array_key_exists($attr, $this->_items)){
|
779 |
stephane |
74 |
switch ($attr){
|
|
|
75 |
case "protocol":
|
|
|
76 |
$this->_items['protocol'] = $value;
|
|
|
77 |
$this->_items['server'] = $this->_items['protocol'].'://'.$this->_items['host'];
|
|
|
78 |
break;
|
|
|
79 |
case "host":
|
|
|
80 |
$this->_items['host'] = $value;
|
|
|
81 |
$this->_items['server'] = $this->_items['protocol'].'://'.$this->_items['host'];
|
|
|
82 |
break;
|
|
|
83 |
case "server":
|
|
|
84 |
// extract protocole & host
|
|
|
85 |
$tmp = explode("://",$value,2);
|
|
|
86 |
if (count($tmp) == 2){
|
|
|
87 |
$this->_items['protocol'] = $tmp[0];
|
|
|
88 |
$this->_items['host'] = $tmp[1];
|
|
|
89 |
} else {
|
|
|
90 |
$this->_items['protocol'] = 'ldap';
|
780 |
stephane |
91 |
$this->_items['host'] = $tmp[0];
|
779 |
stephane |
92 |
}
|
|
|
93 |
$this->_items['server'] = $this->_items['protocol'].'://'.$this->_items['host'];
|
|
|
94 |
break;
|
|
|
95 |
case "uid":
|
|
|
96 |
$this->_items['uid'] = $value;
|
780 |
stephane |
97 |
$this->_items['filter'] = "(".$this->_items['uid']."=%{Stripped-User-Name:-%{User-Name}})";
|
779 |
stephane |
98 |
break;
|
|
|
99 |
case "filter":
|
|
|
100 |
// extract uid
|
|
|
101 |
if (preg_match('`^[\(]([\sa-zA-Z0-9_-]*)=\%\{Stripped\-User\-Name:\-\%\{User-Name\}\}\)`',$value)){
|
|
|
102 |
$this->_items['uid'] = preg_replace('`^[\(]([\sa-zA-Z0-9_-]*)=\%\{Stripped\-User\-Name:\-\%\{User-Name\}\}\)`','$1',$value);
|
|
|
103 |
} else {
|
|
|
104 |
$this->_items['uid'] = 'uid';
|
|
|
105 |
}
|
|
|
106 |
$this->_items['filter'] = "($this->_items['uid']=%{Stripped-User-Name:-%{User-Name}})";
|
|
|
107 |
break;
|
|
|
108 |
default:
|
|
|
109 |
$this->_items[$attr] = $value;
|
|
|
110 |
}
|
775 |
stephane |
111 |
} elseif (array_key_exists($attr, $this->_tls)){
|
|
|
112 |
$this->_tls[$attr] = $value;
|
|
|
113 |
}
|
|
|
114 |
}
|
|
|
115 |
public function load($confFile){
|
|
|
116 |
// use here the parsing class
|
|
|
117 |
require_once("configreader.php");
|
|
|
118 |
$r = new configReader($confFile);
|
|
|
119 |
/*
|
|
|
120 |
loading only if the file containt only one ldap instance.
|
|
|
121 |
If more instance are found, we use the default values instead.
|
|
|
122 |
*/
|
|
|
123 |
if (is_object($r->ldap)){
|
|
|
124 |
$this->instanceName = $r->ldap->getInstanceName();
|
|
|
125 |
$items = $r->ldap->getpair();
|
780 |
stephane |
126 |
|
|
|
127 |
foreach ($items as $pair){
|
|
|
128 |
$pairName = $pair->getName();
|
|
|
129 |
$pairValue = $pair->getPair($pairName);
|
|
|
130 |
if (array_key_exists($pairName , $this->_items))
|
|
|
131 |
$this->$pairName = $pairValue; // we use __set() function to have all exceptions!
|
775 |
stephane |
132 |
}
|
|
|
133 |
if (is_object($r->ldap->tls)){
|
|
|
134 |
$tls = $r->ldap->tls->getpair();
|
780 |
stephane |
135 |
|
|
|
136 |
foreach ($tls as $pair){
|
|
|
137 |
$tlsPairName = $pair->getName();
|
|
|
138 |
$tlsPairValue = $pair->getPair($tlsPairName);
|
|
|
139 |
if (array_key_exists($tlsPairName , $this->_tls))
|
|
|
140 |
$this->$tlsPairName = $pairValue; // we use __set() function to have all exceptions!
|
775 |
stephane |
141 |
}
|
|
|
142 |
}
|
|
|
143 |
}
|
|
|
144 |
}
|
|
|
145 |
public function __toString() {
|
|
|
146 |
return $this->save(null, true);
|
|
|
147 |
}
|
|
|
148 |
protected function _noComment($name, $value, $quote = false){
|
|
|
149 |
if ($value !== '#'){
|
|
|
150 |
if ($quote === true){
|
|
|
151 |
return $name." = \"".$value."\"";
|
|
|
152 |
} else {
|
|
|
153 |
return $name." = ".$value;
|
|
|
154 |
}
|
|
|
155 |
}
|
|
|
156 |
}
|
|
|
157 |
public function save($savefile = null, $returnconfig = false){
|
|
|
158 |
// make config file
|
|
|
159 |
$config = "
|
|
|
160 |
# Lightweight Directory Access Protocol (LDAP)
|
|
|
161 |
#
|
|
|
162 |
# This module definition allows you to use LDAP for
|
|
|
163 |
# authorization and authentication.
|
|
|
164 |
#
|
|
|
165 |
# See raddb/sites-available/default for reference to the
|
|
|
166 |
# ldap module in the authorize and authenticate sections.
|
|
|
167 |
#
|
|
|
168 |
# However, LDAP can be used for authentication ONLY when the
|
|
|
169 |
# Access-Request packet contains a clear-text User-Password
|
|
|
170 |
# attribute. LDAP authentication will NOT work for any other
|
|
|
171 |
# authentication method.
|
|
|
172 |
#
|
|
|
173 |
# This means that LDAP servers don't understand EAP. If you
|
|
|
174 |
# force \"Auth-Type = LDAP\", and then send the server a
|
|
|
175 |
# request containing EAP authentication, then authentication
|
|
|
176 |
# WILL NOT WORK.
|
|
|
177 |
#
|
|
|
178 |
# The solution is to use the default configuration, which does
|
|
|
179 |
# work.
|
|
|
180 |
#
|
|
|
181 |
# Setting \"Auth-Type = LDAP\" is ALMOST ALWAYS WRONG. We
|
|
|
182 |
# really can't emphasize this enough.
|
|
|
183 |
#
|
|
|
184 |
ldap ".$this->instanceName."{
|
|
|
185 |
#
|
|
|
186 |
# Note that this needs to match the name in the LDAP
|
|
|
187 |
# server certificate, if you're using ldaps.
|
|
|
188 |
server = \"".$this->_items['server']."\"
|
|
|
189 |
identity = \"".$this->_items['identity']."\"
|
|
|
190 |
password = ".$this->_items['password']."
|
|
|
191 |
basedn = \"".$this->_items['basedn']."\"
|
|
|
192 |
filter = \"".$this->_items['filter']."\"
|
|
|
193 |
base_filter = \"".$this->_items['base_filter']."\"
|
|
|
194 |
|
|
|
195 |
# How many connections to keep open to the LDAP server.
|
|
|
196 |
# This saves time over opening a new LDAP socket for
|
|
|
197 |
# every authentication request.
|
|
|
198 |
ldap_connections_number = ".$this->_items['ldap_connections_number']."
|
|
|
199 |
|
|
|
200 |
# seconds to wait for LDAP query to finish. default: 20
|
|
|
201 |
timeout = ".$this->_items['timeout']."
|
|
|
202 |
|
|
|
203 |
# seconds LDAP server has to process the query (server-side
|
|
|
204 |
# time limit). default: 20
|
|
|
205 |
#
|
|
|
206 |
# LDAP_OPT_TIMELIMIT is set to this value.
|
|
|
207 |
timelimit = ".$this->_items['timelimit']."
|
|
|
208 |
|
|
|
209 |
#
|
|
|
210 |
# seconds to wait for response of the server. (network
|
|
|
211 |
# failures) default: 10
|
|
|
212 |
#
|
|
|
213 |
# LDAP_OPT_NETWORK_TIMEOUT is set to this value.
|
|
|
214 |
net_timeout = ".$this->_items['net_timeout']."
|
|
|
215 |
|
|
|
216 |
#
|
|
|
217 |
# This subsection configures the tls related items
|
|
|
218 |
# that control how FreeRADIUS connects to an LDAP
|
|
|
219 |
# server. It contains all of the \"tls_*\" configuration
|
|
|
220 |
# entries used in older versions of FreeRADIUS. Those
|
|
|
221 |
# configuration entries can still be used, but we recommend
|
|
|
222 |
# using these.
|
|
|
223 |
#
|
|
|
224 |
tls {
|
|
|
225 |
# Set this to 'yes' to use TLS encrypted connections
|
|
|
226 |
# to the LDAP database by using the StartTLS extended
|
|
|
227 |
# operation.
|
|
|
228 |
#
|
|
|
229 |
# The StartTLS operation is supposed to be
|
|
|
230 |
# used with normal ldap connections instead of
|
|
|
231 |
# using ldaps (port 689) connections
|
|
|
232 |
start_tls = ".$this->_tls['start_tls']."
|
|
|
233 |
|
|
|
234 |
# cacertfile = /path/to/cacert.pem
|
|
|
235 |
# cacertdir = /path/to/ca/dir/
|
|
|
236 |
# certfile = /path/to/radius.crt
|
|
|
237 |
# keyfile = /path/to/radius.key
|
|
|
238 |
# randfile = /path/to/rnd
|
|
|
239 |
".$this->_noComment("cacertfile", $this->_tls['cacertfile'])."
|
|
|
240 |
".$this->_noComment("cacertdir", $this->_tls['cacertdir'])."
|
|
|
241 |
".$this->_noComment("certfile", $this->_tls['certfile'])."
|
|
|
242 |
".$this->_noComment("keyfile", $this->_tls['keyfile'])."
|
|
|
243 |
".$this->_noComment("randfile", $this->_tls['randfile'])."
|
|
|
244 |
# Certificate Verification requirements. Can be:
|
|
|
245 |
# \"never\" (don't even bother trying)
|
|
|
246 |
# \"allow\" (try, but don't fail if the cerificate
|
|
|
247 |
# can't be verified)
|
|
|
248 |
# \"demand\" (fail if the certificate doesn't verify.)
|
|
|
249 |
#
|
|
|
250 |
# The default is \"allow\"
|
|
|
251 |
# require_cert = \"demand\"
|
|
|
252 |
".$this->_noComment("require_cert", $this->_tls['require_cert'], true)."
|
|
|
253 |
}
|
|
|
254 |
|
|
|
255 |
# default_profile = \"cn=radprofile,ou=dialup,o=My Org,c=UA\"
|
|
|
256 |
# profile_attribute = \"radiusProfileDn\"
|
|
|
257 |
# access_attr = \"dialupAccess\"
|
|
|
258 |
".$this->_noComment("default_profile", $this->_items['default_profile'], true)."
|
|
|
259 |
".$this->_noComment("profile_attribute", $this->_items['profile_attribute'], true)."
|
|
|
260 |
".$this->_noComment("access_attr", $this->_items['access_attr'], true)."
|
|
|
261 |
# Mapping of RADIUS dictionary attributes to LDAP
|
|
|
262 |
# directory attributes.
|
|
|
263 |
dictionary_mapping = ".$this->_items['dictionary_mapping']."
|
|
|
264 |
|
|
|
265 |
# Set password_attribute = nspmPassword to get the
|
|
|
266 |
# user's password from a Novell eDirectory
|
|
|
267 |
# backend. This will work ONLY IF FreeRADIUS has been
|
|
|
268 |
# built with the --with-edir configure option.
|
|
|
269 |
#
|
|
|
270 |
# See also the following links:
|
|
|
271 |
#
|
|
|
272 |
# http://www.novell.com/coolsolutions/appnote/16745.html
|
|
|
273 |
# https://secure-support.novell.com/KanisaPlatform/Publishing/558/3009668_f.SAL_Public.html
|
|
|
274 |
#
|
|
|
275 |
# Novell may require TLS encrypted sessions before returning
|
|
|
276 |
# the user's password.
|
|
|
277 |
#
|
|
|
278 |
# password_attribute = userPassword
|
|
|
279 |
".$this->_noComment("access_attr", $this->_items['access_attr'])."
|
|
|
280 |
# Un-comment the following to disable Novell
|
|
|
281 |
# eDirectory account policy check and intruder
|
|
|
282 |
# detection. This will work *only if* FreeRADIUS is
|
|
|
283 |
# configured to build with --with-edir option.
|
|
|
284 |
#
|
|
|
285 |
edir_account_policy_check = no
|
|
|
286 |
".$this->_noComment("access_attr", $this->_items['access_attr'])."
|
|
|
287 |
#
|
|
|
288 |
# Group membership checking. Disabled by default.
|
|
|
289 |
#
|
|
|
290 |
# groupname_attribute = cn
|
|
|
291 |
# groupmembership_filter = \"(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))\"
|
|
|
292 |
# groupmembership_attribute = radiusGroupName
|
|
|
293 |
".$this->_noComment("groupname_attribute", $this->_items['groupname_attribute'])."
|
|
|
294 |
".$this->_noComment("groupmembership_filter", $this->_items['groupmembership_filter'], true)."
|
|
|
295 |
".$this->_noComment("groupmembership_attribute", $this->_items['groupmembership_attribute'])."
|
|
|
296 |
# compare_check_items = yes
|
|
|
297 |
# do_xlat = yes
|
|
|
298 |
# access_attr_used_for_allow = yes
|
|
|
299 |
".$this->_noComment("compare_check_items", $this->_items['compare_check_items'])."
|
|
|
300 |
".$this->_noComment("do_xlat", $this->_items['do_xlat'])."
|
|
|
301 |
".$this->_noComment("access_attr_used_for_allow", $this->_items['access_attr_used_for_allow'])."
|
|
|
302 |
#
|
|
|
303 |
# By default, if the packet contains a User-Password,
|
|
|
304 |
# and no other module is configured to handle the
|
|
|
305 |
# authentication, the LDAP module sets itself to do
|
|
|
306 |
# LDAP bind for authentication.
|
|
|
307 |
#
|
|
|
308 |
# THIS WILL ONLY WORK FOR PAP AUTHENTICATION.
|
|
|
309 |
#
|
|
|
310 |
# THIS WILL NOT WORK FOR CHAP, MS-CHAP, or 802.1x (EAP).
|
|
|
311 |
#
|
|
|
312 |
# You can disable this behavior by setting the following
|
|
|
313 |
# configuration entry to \"no\".
|
|
|
314 |
#
|
|
|
315 |
# allowed values: {no, yes}
|
|
|
316 |
# set_auth_type = yes
|
|
|
317 |
# set_auth_type = no
|
|
|
318 |
".$this->_noComment("set_auth_type", $this->_items['set_auth_type'])."
|
|
|
319 |
# ldap_debug: debug flag for LDAP SDK
|
|
|
320 |
# (see OpenLDAP documentation). Set this to enable
|
|
|
321 |
# huge amounts of LDAP debugging on the screen.
|
|
|
322 |
# You should only use this if you are an LDAP expert.
|
|
|
323 |
#
|
|
|
324 |
# default: 0x0000 (no debugging messages)
|
|
|
325 |
# Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS)
|
|
|
326 |
#ldap_debug = 0x0028
|
|
|
327 |
".$this->_noComment("ldap_debug", $this->_items['ldap_debug'])."
|
|
|
328 |
}
|
|
|
329 |
";
|
|
|
330 |
if ($savefile !== null){
|
|
|
331 |
// save config file
|
|
|
332 |
if (is_file($savefile)){
|
|
|
333 |
// save the file
|
|
|
334 |
if (!is_writable($savefile))
|
|
|
335 |
return false;
|
|
|
336 |
$updatedFile = fopen( $savefile, 'w' );
|
|
|
337 |
fwrite( $updatedFile, $config );
|
|
|
338 |
fclose( $updatedFile );
|
|
|
339 |
} else {
|
|
|
340 |
// create a new file
|
|
|
341 |
$newFile = fopen($savefile, 'w') or die("can't create file");
|
|
|
342 |
fwrite( $newFile, $config );
|
|
|
343 |
fclose( $newFile );
|
|
|
344 |
}
|
|
|
345 |
}
|
|
|
346 |
// test $returnconfig
|
|
|
347 |
if (($returnconfig===true)||($returnconfig==="yes")){
|
|
|
348 |
return $config;
|
|
|
349 |
}else{
|
|
|
350 |
return true;
|
|
|
351 |
}
|
|
|
352 |
}
|
|
|
353 |
}
|
|
|
354 |
?>
|