lib.php 10.6 KB
Newer Older
Donal McMullan's avatar
Donal McMullan committed
1
2
3
4
5
<?php
/**
 *
 * @package    mahara
 * @subpackage auth-internal
6
 * @author     Catalyst IT Ltd
7
8
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
Donal McMullan's avatar
Donal McMullan committed
9
10
11
12
 *
 */

defined('INTERNAL') || die();
13
require_once(get_config('docroot') . 'auth/lib.php');
Donal McMullan's avatar
Donal McMullan committed
14
15
16
17
18
19
20
21
22

/**
 * The internal authentication method, which authenticates users against the
 * Mahara database.
 */
class AuthImap extends Auth {

    public function __construct($id = null) {
        $this->type                         = 'imap';
23
        $this->has_instance_config                   = true;
Donal McMullan's avatar
Donal McMullan committed
24
25
26
27

        $this->config['host']               = '';
        $this->config['port']               = '143';
        $this->config['protocol']           = '/imap';
28
        $this->config['domainname']  = '';
Donal McMullan's avatar
Donal McMullan committed
29
        $this->config['changepasswordurl']  = '';
30
        $this->config['weautocreateusers']  = '';
Donal McMullan's avatar
Donal McMullan committed
31

32
        if (!empty($id)) {
Donal McMullan's avatar
Donal McMullan committed
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
            return $this->init($id);
        }
        return true;
    }

    public function init($id = null) {

        $this->ready = parent::init($id);

        // Check that required fields are set
        if ( empty($this->config['host']) ||
             empty($this->config['port']) ||
             empty($this->config['protocol']) ) {
            $this->ready = false;
        }

        return $this->ready;

    }

    /**
     * Attempt to authenticate user
     *
     * @param string $username The username to authenticate with
     * @param string $password The password being used for authentication
     * @return bool            True/False based on whether the user
     *                         authenticated successfully
     * @throws AuthUnknownUserException If the user does not exist
     */
    public function authenticate_user_account($user, $password) {
        $this->must_be_ready();

        if (! function_exists('imap_open')) {
            throw new ConfigException('IMAP is not available in your PHP environment. Check that it is properly installed');
        }

69
        $connectionstring = '{'. $this->config['host'] .':'. $this->config['port'] . $this->config['protocol'] .'}';
Donal McMullan's avatar
Donal McMullan committed
70
        try {
71
72
73
74
75
76
77
78
79

            if (isset($this->config['domainname']) && $this->config['domainname'] != '') {
                // Check whether the end of the user's email address matches the specified domain name
                $domainpart = '@' . strtolower($this->config['domainname']);
                if (strtolower(substr($user->username, -1 * strlen($domainpart))) != $domainpart) {
                    return false;
                }
            }

Donal McMullan's avatar
Donal McMullan committed
80
81
82
83
84
85
86
87
88
89
90
91
            $connection = imap_open($connectionstring, $user->username, $password, OP_HALFOPEN);
            if ($connection) {
                imap_close($connection);
                return true;
            }
        } catch (Exception $e) {
            throw new ConfigException('Unable to connect to server with connection string: '.$connectionstring);
        }

        return false;  // No match
    }

92
    /**
93
94
95
96
     * Whether to auto-create users. (The only information that IMAP exports is the user's
     * email address; but this is no different from Persona/Browserid.)
     *
     * @return bool
97
98
     */
    public function can_auto_create_users() {
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
        return (bool)$this->config['weautocreateusers'];
    }


    /**
     * Get basic user info to create new users
     * Needed if can_auto_create_users comes back true
     *
     * @param string $username The username to look up information for
     * @return array           The information for the user
     * @throws AuthUnknownUserException If the user is unknown to the
     *                                  authentication method
     */
    public function get_user_info($username) {
        $userinfo = array('email' => $username);
        return (object)$userinfo;
115
116
    }

Donal McMullan's avatar
Donal McMullan committed
117
118
119
120
121
122
123
}

/**
 * Plugin configuration class
 */
class PluginAuthImap extends PluginAuth {

124
    private static $default_config = array('host'=>'', 'port'=>'143', 'protocol'=>'/imap', 'domainname'=>'', 'changepasswordurl'=>'', 'weautocreateusers'=>'');
125

Donal McMullan's avatar
Donal McMullan committed
126
    public static function has_config() {
127
128
129
130
131
132
133
134
        return false;
    }

    public static function get_config_options() {
        return array();
    }

    public static function has_instance_config() {
Donal McMullan's avatar
Donal McMullan committed
135
136
137
        return true;
    }

138
139
140
141
    public static function is_usable() {
        return extension_loaded('imap');
    }

142
    public static function get_instance_config_options($institution, $instance = 0) {
Donal McMullan's avatar
Donal McMullan committed
143
144
145
146
147
148
        // TODO: put these strings in a lang file
        $options['/imap'] = 'IMAP';
        $options['/imap/ssl'] = 'IMAP/SSL';
        $options['/imap/ssl/novalidate-cert'] = 'IMAP/SSL (self-signed certificate)';
        $options['/imap/tls'] = 'IMAP/TLS';

149
150
        if ($instance > 0) {
            $current        = get_records_array('auth_instance',        'id',       $instance, 'priority ASC');
151
            if ($current == false) {
152
                throw new SystemException('Could not find data for auth instance '.$instance);
153
154
155
156
            }
            $default = $current[0];
            $current_config = get_records_menu('auth_instance_config', 'instance', $instance, '', 'field, value');

157
            if ($current_config == false) {
158
159
160
161
                $current_config = array();
            }

            foreach (self::$default_config as $key => $value) {
162
                if (array_key_exists($key, $current_config)) {
163
164
165
166
167
168
169
170
171
172
173
                    self::$default_config[$key] = $current_config[$key];
                }
            }
        } else {
            $default = new stdClass();
            $default->instancename = '';
        }

        $elements['instancename'] = array(
            'type' => 'text',
            'title' => get_string('authname','auth'),
Donal McMullan's avatar
Donal McMullan committed
174
175
            'rules' => array(
                'required' => true
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
            ),
            'defaultvalue' => $default->instancename
        );

        $elements['instance'] = array(
            'type' => 'hidden',
            'value' => $instance
        );

        $elements['institution'] = array(
            'type' => 'hidden',
            'value' => $institution
        );

        $elements['authname'] = array(
            'type' => 'hidden',
            'value' => 'imap'
Donal McMullan's avatar
Donal McMullan committed
193
194
195
196
        );

        $elements['host'] = array(
            'type' => 'text',
197
            'title' => get_string('host', 'auth'),
Donal McMullan's avatar
Donal McMullan committed
198
199
            'rules' => array(
                'required' => true
200
201
            ),
            'defaultvalue' => self::$default_config['host']
Donal McMullan's avatar
Donal McMullan committed
202
203
204
205
        );

        $elements['port'] = array(
            'type' => 'text',
206
            'title' => get_string('port', 'auth'),
Donal McMullan's avatar
Donal McMullan committed
207
208
209
            'rules' => array(
                'required' => true,
                'integer' => true
210
211
212
213
214
215
216
217
218
219
220
221
            ),
            'defaultvalue' => self::$default_config['port']
        );

        $elements['protocol'] = array(
            'type' => 'select',
            'title' => get_string('protocol', 'auth'),
            'options' => $options,
            'rules' => array(
                'required' => true
            ),
            'defaultvalue' => self::$default_config['protocol']
Donal McMullan's avatar
Donal McMullan committed
222
223
        );

224
225
226
227
228
229
230
231
232
233
        $elements['domainname'] = array(
            'type' => 'text',
            'title' => get_string('domainname', 'auth.imap'),
            'rules' => array(
                'required' => false
            ),
            'defaultvalue' => self::$default_config['domainname'],
            'help'  => true,
        );

Donal McMullan's avatar
Donal McMullan committed
234
235
        $elements['changepasswordurl'] = array(
            'type' => 'text',
236
            'title' => get_string('changepasswordurl', 'auth'),
Donal McMullan's avatar
Donal McMullan committed
237
238
            'rules' => array(
                'required' => false
239
240
            ),
            'defaultvalue' => self::$default_config['changepasswordurl']
Donal McMullan's avatar
Donal McMullan committed
241
242
        );

243
244
245
246
247
248
249
        $elements['weautocreateusers'] = array(
            'type'  => 'checkbox',
            'title' => get_string('weautocreateusers', 'auth'),
            'defaultvalue' => self::$default_config['weautocreateusers'],
            'help'  => true,
        );

Donal McMullan's avatar
Donal McMullan committed
250
251
        return array(
            'elements' => $elements,
252
            'renderer' => 'div'
Donal McMullan's avatar
Donal McMullan committed
253
254
255
        );
    }

256
    public static function save_instance_config_options($values, Pieform $form) {
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

        $authinstance = new stdClass();

        if ($values['instance'] > 0) {
            $values['create'] = false;
            $current = get_records_assoc('auth_instance_config', 'instance', $values['instance'], '', 'field, value');
            $authinstance->id = $values['instance'];
        } else {
            $values['create'] = true;

            // Get the auth instance with the highest priority number (which is
            // the instance with the lowest priority).
            // TODO: rethink 'priority' as a fieldname... it's backwards!!
            $lastinstance = get_records_array('auth_instance', 'institution', $values['institution'], 'priority DESC', '*', '0', '1');

            if ($lastinstance == false) {
                $authinstance->priority = 0;
            } else {
                $authinstance->priority = $lastinstance[0]->priority + 1;
            }
        }

        $authinstance->instancename = $values['instancename'];
        $authinstance->institution  = $values['institution'];
        $authinstance->authname     = $values['authname'];

        if ($values['create']) {
            $values['instance'] = insert_record('auth_instance', $authinstance, 'id', true);
        } else {
            update_record('auth_instance', $authinstance, array('id' => $values['instance']));
        }
Donal McMullan's avatar
Donal McMullan committed
288
289
290
291
292

        if (empty($current)) {
            $current = array();
        }

293
294
295
        self::$default_config =   array('host'              => $values['host'],
                                        'port'              => $values['port'],
                                        'protocol'          => $values['protocol'],
296
297
298
299
                                        'domainname'        => $values['domainname'],
                                        'changepasswordurl' => $values['changepasswordurl'],
                                        'weautocreateusers' => $values['weautocreateusers'],
                                        );
300
301

        foreach(self::$default_config as $field => $value) {
Donal McMullan's avatar
Donal McMullan committed
302
            $record = new stdClass();
303
304
            $record->instance = $values['instance'];
            $record->field    = $field;
Donal McMullan's avatar
Donal McMullan committed
305
            $record->value    = $value;
306
307

            if ($values['create'] || !array_key_exists($field, $current)) {
Donal McMullan's avatar
Donal McMullan committed
308
                insert_record('auth_instance_config', $record);
309
310
            } else {
                update_record('auth_instance_config', $record, array('instance' => $values['instance'], 'field' => $field));
Donal McMullan's avatar
Donal McMullan committed
311
312
313
            }
        }

314
        return $values;
Donal McMullan's avatar
Donal McMullan committed
315
316
    }
}