Issues (4868)

api/src/Auth/Sql.php (1 issue)

1
<?php
2
/**
3
 * EGroupware API - Authentication from SQL
4
 *
5
 * @link http://www.egroupware.org
6
 * @author Ralf Becker <[email protected]>
7
 * @author Dan Kuykendall <[email protected]>
8
 * @author Joseph Engo <[email protected]>
9
 * Copyright (C) 2000, 2001 Dan Kuykendall
10
 * @license http://opensource.org/licenses/lgpl-license.php LGPL - GNU Lesser General Public License
11
 * @package api
12
 * @subpackage authentication
13
 * @version $Id$
14
 */
15
16
namespace EGroupware\Api\Auth;
17
18
use EGroupware\Api;
19
20
/**
21
 * eGroupWare API - Authentication based on SQL table of accounts
22
 *
23
 * Encryption types other than md5() added by Miles Lott <[email protected]>
24
 * based on code from http://www.thomas-alfeld.de/frank/
25
 *
26
 * Massive code cleanup and added password migration by Cornelius Weiss <[email protected]
27
 */
28
class Sql implements Backend
29
{
30
	/**
31
	 * Reference to the global db object
32
	 *
33
	 * @var Api\Db
34
	 */
35
	var $db;
36
	var $table = 'egw_accounts';
37
	var $previous_login = -1;
38
39
	function __construct()
40
	{
41
		$this->db = $GLOBALS['egw']->db;
42
43
		$this->type = @$GLOBALS['egw_info']['server']['sql_encryption_type'] ?
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
44
			strtolower($GLOBALS['egw_info']['server']['sql_encryption_type']) : 'md5';
45
	}
46
47
	/**
48
	 * password authentication against password stored in sql datababse
49
	 *
50
	 * @param string $username username of account to authenticate
51
	 * @param string $passwd corresponding password
52
	 * @param string $passwd_type ='text' 'text' for cleartext passwords (default)
53
	 * @return boolean true if successful authenticated, false otherwise
54
	 */
55
	function authenticate($username, $passwd, $passwd_type='text')
56
	{
57
		/* normal web form login */
58
		$where = array(
59
			'account_lid'    => $username,
60
			'account_type'   => 'u',
61
			'account_status' => 'A'
62
		);
63
		if (!$GLOBALS['egw_info']['server']['case_sensitive_username'])	// = is case sensitiv eg. on postgres, but not on mysql!
64
		{
65
			$where[] = 'account_lid '.$this->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($username);
66
			unset($where['account_lid']);
67
		}
68
		if($passwd_type == 'text')
69
		{
70
			if (!($row = $this->db->select($this->table,'account_lid,account_pwd,account_lastlogin,account_id',$where,__LINE__,__FILE__)->fetch()) ||
71
				empty($row['account_pwd']) ||
72
				$GLOBALS['egw_info']['server']['case_sensitive_username'] && $row['account_lid'] != $username)
73
			{
74
				return false;
75
			}
76
			$type = null;
77
			if(!($match = Api\Auth::compare_password($passwd, $row['account_pwd'], $this->type, strtolower($username), $type)) ||
78
				$type != $this->type && in_array($type, explode(',',strtolower($GLOBALS['egw_info']['server']['pwd_migration_types']))))
79
			{
80
				// do we have to migrate an old password ?
81
				if($GLOBALS['egw_info']['server']['pwd_migration_allowed'] && !empty($GLOBALS['egw_info']['server']['pwd_migration_types']))
82
				{
83
					if (!$match)
84
					{
85
						foreach(explode(',', $GLOBALS['egw_info']['server']['pwd_migration_types']) as $type)
86
						{
87
							if(($match = Api\Auth::compare_password($passwd,$row['account_pwd'],$type,strtolower($username))))
88
							{
89
								break;
90
							}
91
						}
92
					}
93
					if ($match && ($encrypted_passwd = Api\Auth::encrypt_sql($passwd)))
94
					{
95
						$this->_update_passwd($encrypted_passwd, $row['account_id'], false, true);
96
					}
97
				}
98
				if (!$match) return false;
99
			}
100
		}
101
		/* Auth via crypted password. NOTE: mail needs cleartext password to authenticate against mailserver! */
102
		else
103
		{
104
			$where['account_pwd'] = $passwd;
105
			if (!($row = $this->db->select($this->table,'account_lid,account_lastlogin',$where,__LINE__,__FILE__)->fetch()) ||
106
				$GLOBALS['egw_info']['server']['case_sensitive_username'] && $row['account_lid'] != $username)
107
			{
108
				return false;
109
			}
110
		}
111
		// if this point is reached, auth was successfull
112
		$this->previous_login = $row['account_lastlogin'];
113
114
		return true;
115
	}
116
117
	/**
118
	 * fetch the last pwd change for the user
119
	 *
120
	 * @param string $username username of account to authenticate
121
	 * @return mixed false or account_lastpwd_change
122
	 */
123
	function getLastPwdChange($username)
124
	{
125
		/* normal web form login */
126
		$where = array(
127
			'account_lid'    => $username,
128
			'account_type'   => 'u',
129
			'account_status' => 'A'
130
		);
131
		if (!$GLOBALS['egw_info']['server']['case_sensitive_username'])	// = is case sensitiv eg. on postgres, but not on mysql!
132
		{
133
			$where[] = 'account_lid '.$this->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($username);
134
			unset($where['account_lid']);
135
		}
136
		if (!($row = $this->db->select($this->table,'account_lid,account_lastpwd_change',$where,__LINE__,__FILE__)->fetch()) ||
137
			$GLOBALS['egw_info']['server']['case_sensitive_username'] && $row['account_lid'] != $username)
138
		{
139
			return false;
140
		}
141
		// if this point is reached, we found a user with that name and return the account_lastpwd_change
142
		$rv = $row['account_lastpwd_change'];
143
144
		return $rv;
145
	}
146
147
	/**
148
	 * changes account_lastpwd_change in sql datababse
149
	 *
150
	 * @param int $account_id account id of user whose passwd should be changed
151
	 * @param string $passwd must be cleartext, usually not used, but may be used to authenticate as user to do the change -> ldap
152
	 * @param int $_lastpwdchange =null must be a unixtimestamp
153
	 * @return boolean true if account_lastpwd_change successful changed, false otherwise
154
	 */
155
	function setLastPwdChange($account_id=0, $passwd=NULL, $_lastpwdchange=NULL)
156
	{
157
		$admin = True;
158
		// Don't allow password changes for other accounts when using XML-RPC
159
		if(!$account_id || $GLOBALS['egw_info']['flags']['currentapp'] == 'login')
160
		{
161
			$admin = False;
162
			$account_id = $GLOBALS['egw_info']['user']['account_id'];
163
			$username = $GLOBALS['egw_info']['user']['account_lid'];
164
		}
165
		else
166
		{
167
			$username = $GLOBALS['egw']->accounts->id2name($account_id);
168
		}
169
170
		if (($pw = $this->db->select($this->table,'account_pwd',array(
171
			'account_id'     => $account_id,
172
			'account_type'   => 'u',
173
			'account_status' => 'A',
174
		),__LINE__,__FILE__)->fetchColumn()) === false)
175
		{
176
			return false;	// account not found
177
		}
178
		// Check the passwd to make sure this is legal
179
		if(!$admin && !Api\Auth::compare_password($passwd,$pw,$this->type,strtolower($username)))
180
		{
181
			return false;
182
		}
183
		$lastpwdchange = (is_null($_lastpwdchange) || $_lastpwdchange < 0 ? time() : $_lastpwdchange);
184
		$this->db->update($this->table,array(
185
			'account_lastpwd_change' => $lastpwdchange,
186
		),array(
187
			'account_id' => $account_id,
188
		),__LINE__,__FILE__);
189
190
		if(!$this->db->affected_rows()) return false;
191
		if (!$admin) Api\Cache::setSession('phpgwapi', 'auth_alpwchange_val', $lastpwdchange);
192
		return true;
193
	}
194
195
	/**
196
	 * changes password in sql datababse
197
	 *
198
	 * @param string $old_passwd must be cleartext
199
	 * @param string $new_passwd must be cleartext
200
	 * @param int $account_id account id of user whose passwd should be changed
201
	 * @return boolean true if password successful changed, false otherwise
202
	 */
203
	function change_password($old_passwd, $new_passwd, $account_id=0)
204
	{
205
		$admin = True;
206
		// Don't allow password changes for other accounts when using XML-RPC
207
		if(!$account_id)
208
		{
209
			$admin = False;
210
			$account_id = $GLOBALS['egw_info']['user']['account_id'];
211
			$username = $GLOBALS['egw_info']['user']['account_lid'];
212
		}
213
		else
214
		{
215
			$username = $GLOBALS['egw']->accounts->id2name($account_id);
216
		}
217
218
		if (($pw = $this->db->select($this->table,'account_pwd',array(
219
			'account_id'     => $account_id,
220
			'account_type'   => 'u',
221
		),__LINE__,__FILE__)->fetchColumn()) === false)
222
		{
223
			return false;	// account not found
224
		}
225
		// Check the old_passwd to make sure this is legal
226
		if(!$admin && !Api\Auth::compare_password($old_passwd,$pw,$this->type,strtolower($username)))
227
		{
228
			return false;
229
		}
230
231
		if (!($encrypted_passwd = Api\Auth::encrypt_sql($new_passwd)))
232
		{
233
			return false;
234
		}
235
236
		// old password ok, or admin called the function from the admin application (no old passwd available).
237
		return $this->_update_passwd($encrypted_passwd, $account_id, $admin);
238
	}
239
240
	/**
241
	 * changes password in sql datababse
242
	 *
243
	 * @param string $encrypted_passwd
244
	 * @param string $new_passwd cleartext
245
	 * @param int $account_id account id of user whose passwd should be changed
246
	 * @param boolean $admin =false called by admin, if not update password in the session
247
	 * @param boolean $update_lastpw_change =true
248
	 * @return boolean true if password successful changed, false otherwise
249
	 */
250
	private function _update_passwd($encrypted_passwd, $account_id, $admin=false, $update_lastpw_change=true)
251
	{
252
		$update = array('account_pwd' => $encrypted_passwd);
253
		if ($update_lastpw_change) $update['account_lastpwd_change'] = time();
254
255
		if (!$this->db->update($this->table,$update,array(
256
			'account_id' => $account_id,
257
		),__LINE__,__FILE__))
258
		{
259
			return false;
260
		}
261
262
		if(!$admin)
263
		{
264
			Api\Cache::setSession('phpgwapi','auth_alpwchange_val',$update['account_lastpwd_change']);
265
		}
266
		return true;
267
	}
268
}
269