Subversion Repositories ALCASAR

Rev

Rev 779 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
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
?>