Subversion Repositories Web Services

Rev

Rev 118293 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
82190 hhl 1
<?php
2
/**
3
 *
4
 * This file is part of Open Library System.
5
 * Copyright © 2009, Dansk Bibliotekscenter a/s,
6
 * Tempovej 7-11, DK-2750 Ballerup, Denmark. CVR: 15149043
7
 *
8
 * Open Library System is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Open Library System is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with Open Library System.  If not, see <http://www.gnu.org/licenses/>.
118290 fvs 20
 **/
82190 hhl 21
 
22
/**
23
 * \brief AAA Authentication, Access control and Accounting
24
 *
25
 * only the first two A's are supported, since there is currently no need for accounting
26
 *
27
 * need oci_class and memcache_class to be defined
118290 fvs 28
 *
82190 hhl 29
 * if aaa_fors_right is defined, then data is fetched from the webservice defined by the parameter
30
 *
31
 * @author Finn Stausgaard - DBC
118290 fvs 32
 **/
82190 hhl 33
 
34
require_once('OLS_class_lib/oci_class.php');
35
require_once('OLS_class_lib/memcache_class.php');
36
require_once('OLS_class_lib/ip_class.php');
37
 
118290 fvs 38
/**
39
 * Class aaa
40
 */
82190 hhl 41
class aaa {
42
 
118290 fvs 43
  private $aaa_cache;        // cache object
44
  private $cache_seconds;      // number of seconds to cache
82190 hhl 45
  private $cache_key_prefix;
118290 fvs 46
  private $error_cache_seconds;  // number of seconds to cache answer after an error
47
  private $ip_rights;          // array with repeated elements: ip_list, ressource
48
  private $fors_oci;        // oci connection
49
  private $fors_credentials;    // oci login credentiales
50
  private $rights;        // the rights
51
  private $user;            // User if any
52
  private $group;            // Group if any
53
  private $password;        // Password if any
54
  private $ip;            // IP address
82190 hhl 55
  private $fors_rights_url;     // url to forsRights server
56
  public $aaa_ip_groups = array();
57
 
118290 fvs 58
  /**
59
   * aaa constructor.
60
   * @param array $aaa_setup
61
   * @param string $hash
62
   */
82190 hhl 63
  public function __construct($aaa_setup, $hash = '') {
64
    $this->fors_credentials = $aaa_setup['aaa_credentials'];
65
    if (isset($aaa_setup['aaa_cache_address']) and $aaa_setup['aaa_cache_address']) {
66
      $this->aaa_cache = new cache($aaa_setup['aaa_cache_address']);
67
      if (!$this->cache_seconds = $aaa_setup['aaa_cache_seconds'])
68
        $this->cache_seconds = 3600;
69
      $this->error_cache_seconds = 60;
70
    }
71
    $this->fors_rights_url = $aaa_setup['aaa_fors_rights'];
72
    $this->ip_rights = $aaa_setup['aaa_ip_rights'];
113143 fvs 73
    $this->cache_key_prefix = md5($hash . json_encode($aaa_setup));
82190 hhl 74
  }
75
 
76
  /**
118290 fvs 77
   * \brief sets a list of ressources and the right atributes of each
78
   *
118293 fvs 79
   * @param string $user login name
80
   * @param string $group login group
81
   * @param string $passw login password
82
   * @param integer|string $ip the users ip-address
118290 fvs 83
   *
84
   * @returns TRUE if users has some rights
85
   **/
86
  public function init_rights($user, $group, $passw, $ip = 0) {
82190 hhl 87
    $this->user = $user;
88
    $this->group = $group;
89
    $this->password = $passw;
90
    $this->ip = $ip;
91
    if ($this->aaa_cache) {
118290 fvs 92
      $cache_key = $this->cache_key_prefix . '_' . md5($this->user . '_' . $this->group . '_' . $this->password . '_' . $this->ip);
82190 hhl 93
      if ($rights = $this->aaa_cache->get($cache_key)) {
94
        $this->rights = json_decode($rights);
95
        return !empty($this->rights);
96
      }
97
    }
98
 
99
    if ($this->rights = $this->fetch_rights_from_ip_rights($this->ip, $this->ip_rights)) {
100
      return TRUE;         // do no cache when found in ip-rights (ini-file)
101
    }
102
 
103
    if ($this->fors_rights_url) {
104
      $this->rights = $this->fetch_rights_from_fors_rights_ws($this->user, $this->group, $this->password, $this->ip, $this->fors_rights_url);
105
    }
106
    elseif (strpos($this->fors_credentials, '/') && strpos($this->fors_credentials, '@')) {
107
      $this->rights = $this->fetch_rights_from_ip_fors($this->ip, $this->fors_credentials);
108
      if (empty($this->rights)) {
109
        $this->rights = $this->fetch_rights_from_auth_fors($this->user, $this->group, $this->password, $this->fors_credentials);
110
      }
111
    }
112
 
113
    if ($this->aaa_cache)
114
      $this->aaa_cache->set($cache_key, json_encode($this->rights), (isset($error) ? $this->error_cache_seconds : $this->cache_seconds));
115
    return !empty($this->rights);
116
  }
117
 
118
  /**
118290 fvs 119
   * \brief returns a list of ressources and the rights of each
120
   *
121
   * @param string $ressource
122
   *
123
   * @returns array of ressources with rights for each or the rights for a given ressource
124
   **/
125
  public function get_rights($ressource = '') {
82190 hhl 126
    if ($ressource)
127
      return $this->rights->$ressource;
128
    else
129
      return $this->rights;
130
  }
131
 
132
  /**
118290 fvs 133
   * \brief returns TRUE if user has $right to $ressource
134
   *
135
   * @param string $ressource
136
   * @param integer $right
137
   *
138
   * @returns boolean
139
   **/
82190 hhl 140
  public function has_right($ressource, $right) {
141
    return ($this->rights->$ressource->$right == TRUE);
142
  }
143
 
144
 
145
  /**
118290 fvs 146
   * \brief Register $operation on $ressource
147
   *
148
   * @param string $ressource
149
   * @param string $operation
150
   *
151
   * @returns boolean
152
   **/
82190 hhl 153
  public function accounting($ressource, $operation) {
154
    return TRUE;
155
  }
156
 
157
 
158
  /**
118290 fvs 159
   * \brief set the rights array from the forsRight webservice
160
   *
161
   * @param string $user
162
   * @param string $group
163
   * @param string $password
164
   * @param string $ip
165
   * @param string $fors_rights_url
166
   * @return mixed
167
   */
82190 hhl 168
  private function fetch_rights_from_fors_rights_ws($user, $group, $password, $ip, $fors_rights_url) {
169
    require_once('OLS_class_lib/curl_class.php');
170
    $curl = new curl();
100820 fvs 171
    $url = sprintf($fors_rights_url, urlencode($user), urlencode($group), urlencode($password), urlencode($ip));
82190 hhl 172
    $reply = unserialize($curl->get($url));
173
    if (isset($reply->forsRightsResponse->_value->ressource)) {
174
      foreach ($reply->forsRightsResponse->_value->ressource as $ressource) {
175
        $name = $ressource->_value->name->_value;
176
        foreach ($ressource->_value->right as $right) {
177
          $r = $right->_value;
94747 fvs 178
          Object::set_element($rights, $name, $r, TRUE);
82190 hhl 179
        }
180
      }
181
    }
182
    return $rights;
183
  }
184
 
185
  /**
118290 fvs 186
   * \brief set the rights array from the ini-file
187
   *
188
   * @param string $ip
189
   * @param array $ip_rights
190
   * @return mixed
191
   */
82190 hhl 192
  private function fetch_rights_from_ip_rights($ip, $ip_rights) {
193
    if ($ip && is_array($ip_rights)) {
194
      foreach ($ip_rights as $aaa_group => $aaa_par) {
195
        if (ip_func::ip_in_interval($ip, $aaa_par['ip_list'])) {
196
          $this->aaa_ip_groups[$aaa_group] = TRUE;
197
          if (isset($aaa_par['ressource'])) {
198
            foreach ($aaa_par['ressource'] as $ressource => $right_list) {
199
              $right_val = explode(',', $right_list);
200
              foreach ($right_val as $r) {
201
                $r = trim($r);
94615 fvs 202
                Object::set_element($rights, $ressource, $r, TRUE);
82190 hhl 203
              }
204
            }
205
          }
206
        }
207
      }
208
    }
209
    return $rights;
210
  }
211
 
212
 
213
  /**
118290 fvs 214
   * \brief set the rights array from FORS using the ip of the caller
215
   *
216
   * @param string $ip
217
   * @param string $fors_credentials
218
   * @return bool|mixed
219
   */
82190 hhl 220
  private function fetch_rights_from_ip_fors($ip, $fors_credentials) {
221
    if (!empty($fors_credentials) && $ip) {
222
      if (empty($this->fors_oci)) $this->fors_oci = new Oci($fors_credentials);
223
      try {
224
        $this->fors_oci->connect();
225
      }
226
      catch (ociException $e) {
120114 fvs 227
        self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI connect error: ' . $this->fors_oci->get_error_string());
82190 hhl 228
        return FALSE;
229
      }
230
      $long_ip = ip2long($ip);
231
      try {
118290 fvs 232
        $this->fors_oci->bind('bind_ipval', $long_ip, -1, SQLT_LNG);
82190 hhl 233
        $this->fors_oci->set_query('SELECT userid, ipend
234
                                   FROM domuserid
235
                                   WHERE ipstart <= :bind_ipval
236
                                   AND (:bind_ipval <= ipend OR ipend IS NULL)');
237
        $buf = $this->fors_oci->fetch_all_into_assoc();
238
        foreach ($buf as $key => $val) {
239
          if (empty($fors_userid) || $val['IPEND'])
240
            $fors_userid = $val['USERID'];
241
        }
242
      }
243
      catch (ociException $e) {
120114 fvs 244
        self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI select error: ' . $this->fors_oci->get_error_string());
82190 hhl 245
        $error = $this->fors_oci->get_error();
246
      }
247
 
248
      if (!empty($fors_userid)) {
249
        try {
250
          $this->fors_oci->bind('bind_userid', $fors_userid);
251
          $this->fors_oci->set_query('SELECT userids.userid, userids.state, logins_logingroup.groupname
252
                                     FROM logins_logingroup, userids
253
                                     WHERE userids.userid = logins_logingroup.userid
254
                                     AND userids.userid = :bind_userid');
255
          if ($buf = $this->fors_oci->fetch_into_assoc()) {
256
            $userid = $buf['USERID'];
257
            $state = $buf['STATE'];
258
            $this->group = $buf['GROUPNAME'];
259
          }
260
        }
261
        catch (ociException $e) {
120114 fvs 262
          self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI select error: ' . $this->fors_oci->get_error_string());
82190 hhl 263
          $error = $this->fors_oci->get_error();
264
        }
265
      }
266
      if ($state == 'OK')
267
        $rights = $this->fetch_rights_from_userid($userid, $this->group);
268
    }
269
    return $rights;
270
  }
271
 
272
  /**
118290 fvs 273
   * \brief set the rights array from FORS using the authentication triple of the caller
274
   *
275
   * @param string $user
276
   * @param string $group
277
   * @param string $password
278
   * @param string $fors_credentials
279
   * @return bool|mixed
280
   */
82190 hhl 281
  private function fetch_rights_from_auth_fors($user, $group, $password, $fors_credentials) {
118290 fvs 282
    if ($user && $fors_credentials) {
82190 hhl 283
      if (empty($this->fors_oci)) $this->fors_oci = new Oci($fors_credentials);
284
      try {
285
        $this->fors_oci->connect();
286
      }
287
      catch (ociException $e) {
120114 fvs 288
        self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI connect error: ' . $this->fors_oci->get_error_string());
82190 hhl 289
        return FALSE;
290
      }
291
      try {
292
        $this->fors_oci->bind('bind_username', $user);
293
        $this->fors_oci->bind('bind_usergroup', $group);
294
        $this->fors_oci->set_query('SELECT userids.userid, userids.state, crypttype, password
295
                                   FROM logins_logingroup, userids
296
                                   WHERE userids.userid = logins_logingroup.userid
297
                                   AND (administratorflag = 0 OR administratorflag IS NULL)
298
                                   AND userids.login = :bind_username
299
                                   AND groupname = :bind_usergroup');
300
        $buf = $this->fors_oci->fetch_into_assoc();
301
        $userid = &$buf['USERID'];
302
        $crypttype = &$buf['CRYPTTYPE'];
303
        $pwd = &$buf['PASSWORD'];
304
        //$pwd = md5($this->password);                  // test
305
        $state = &$buf['STATE'];
306
        if ($userid
118290 fvs 307
          && $state == 'OK'
308
          && (($crypttype == 0 && $pwd == $password)
309
            || ($crypttype == 2 && $pwd == md5($password)))
310
        )
82190 hhl 311
          $rights = $this->fetch_rights_from_userid($userid, $group);
312
      }
313
      catch (ociException $e) {
120114 fvs 314
        self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI select error: ' . $this->fors_oci->get_error_string());
82190 hhl 315
        $error = $this->fors_oci->get_error();
316
      }
317
    }
318
    return $rights;
319
  }
320
 
321
 
322
  /**
118290 fvs 323
   * \brief fecth rights from FORS given a FORS-userid and group
324
   *
325
   * @param string $userid
326
   * @param string $group
327
   * @return mixed
328
   */
82190 hhl 329
  private function fetch_rights_from_userid($userid, $group) {
330
    if (empty($this->fors_oci)) $this->fors_oci = new Oci($this->fors_credentials);
331
    try {
332
      $this->fors_oci->connect();
333
    }
334
    catch (ociException $e) {
120114 fvs 335
      self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI connect error: ' . $this->fors_oci->get_error_string());
82190 hhl 336
      return $rights;
337
    }
338
    try {
339
      $this->fors_oci->bind('bind_userid', $userid);
340
      $this->fors_oci->set_query('SELECT t.functiontypeid, objecttypename2
341
                                 FROM table(fors_pkg.fors_get_rights (:bind_userid)) t, map1
342
                                 WHERE t.objectclassid = map1.objecttypeattr1
343
                                 AND t.attr1id = map1.objecttypeattr2');
344
      $buf = $this->fors_oci->fetch_all_into_assoc();
345
      foreach ($buf as $val) {
94747 fvs 346
        Object::set_element($rights, $val['OBJECTTYPENAME2'], $val['FUNCTIONTYPEID'], TRUE);
82190 hhl 347
      }
348
      try {
349
        $this->fors_oci->bind('bind_bibnr', $group);
350
        $this->fors_oci->set_query('SELECT bib_nr FROM vip WHERE kmd_nr = :bind_bibnr');
351
        $buf = $this->fors_oci->fetch_all_into_assoc();
94747 fvs 352
        Object::set_element($rights->vipInfo, 'agencyId', $group, TRUE);
82190 hhl 353
        foreach ($buf as $val) {
94747 fvs 354
          Object::set_element($rights->vipInfo, 'subAgencyId', $val['BIB_NR'], TRUE);
82190 hhl 355
        }
356
      }
357
      catch (ociException $e) {
120114 fvs 358
        self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI select error: ' . $this->fors_oci->get_error_string());
82190 hhl 359
      }
360
    }
361
    catch (ociException $e) {
120114 fvs 362
      self::local_verbose(FATAL, 'AAA(' . __LINE__ . '):: OCI select error: ' . $this->fors_oci->get_error_string());
82190 hhl 363
    }
364
    return $rights;
365
  }
366
 
120114 fvs 367
  /** \brief -
368
   * @param string $level
369
   * @param string $msg
370
   */
371
  private function local_verbose($level, $msg) {
372
    if (method_exists('VerboseJson', 'log')) {
373
      VerboseJson::log($level, $msg);
374
    }
375
    elseif (method_exists('verbose', 'log')) {
376
      verbose::log($level, $msg);
377
    }
378
  }
379
 
82190 hhl 380
}