1<?php
2/**
3 * Copyright 1999-2017 Horde LLC (http://www.horde.org/)
4 *
5 * See the enclosed file COPYING for license information (LGPL). If you did
6 * not receive this file, see http://www.horde.org/licenses/lgpl21.
7 *
8 * @author   Chuck Hagenbuch <chuck@horde.org>
9 * @category Horde
10 * @license  http://www.horde.org/licenses/lgpl21 LGPL-2.1
11 * @package  Auth
12 */
13
14/**
15 * The Horde_Auth_Ipbasic class provides access control based on CIDR masks
16 * (client IP addresses).
17 *
18 * It is not meant for user-based systems, but for times when you want a block
19 * of IPs to be able to access a site, and that access is simply on/off - no
20 * preferences, etc.
21 *
22 * @author    Chuck Hagenbuch <chuck@horde.org>
23 * @category  Horde
24 * @copyright 1999-2017 Horde LLC
25 * @license   http://www.horde.org/licenses/lgpl21 LGPL-2.1
26 * @package   Auth
27 */
28class Horde_Auth_Ipbasic extends Horde_Auth_Base
29{
30    /**
31     * An array of capabilities, so that the driver can report which
32     * operations it supports and which it doesn't.
33     *
34     * @var array
35     */
36    protected $_capabilities = array(
37        'transparent' => true
38    );
39
40    /**
41     * Constructor.
42     *
43     * @param array $params  Optional Parameters:
44     * <pre>
45     * 'blocks' - (array) CIDR masks which are allowed access.
46     * </pre>
47     */
48    public function __construct(array $params = array())
49    {
50        if (empty($params['blocks'])) {
51            $params['blocks'] = array();
52        } elseif (!is_array($params['blocks'])) {
53            $params['blocks'] = array($params['blocks']);
54        }
55
56        parent::__construct($params);
57    }
58
59    /**
60     * Automatic authentication: Find out if the client matches an allowed IP
61     * block.
62     *
63     * @return boolean  Whether or not the client is allowed.
64     */
65    public function transparent()
66    {
67        if (!isset($_SERVER['REMOTE_ADDR'])) {
68            return false;
69        }
70
71        foreach ($this->_params['blocks'] as $cidr) {
72            if ($this->_addressWithinCIDR($_SERVER['REMOTE_ADDR'], $cidr)) {
73                $this->_credentials['userId'] = $cidr;
74                return true;
75            }
76        }
77
78        return false;
79    }
80
81    /**
82     * Not implemented
83     *
84     * @param string $userId      The userID to check.
85     * @param array $credentials  An array of login credentials.
86     *
87     * @throws Horde_Auth_Exception
88     */
89    protected function _authenticate($userId, $credentials)
90    {
91        throw new Horde_Auth_Exception('Unsupported.');
92    }
93
94    /**
95     * Determine if an IP address is within a CIDR block.
96     *
97     * @param string $address  The IP address to check.
98     * @param string $cidr     The block (e.g. 192.168.0.0/16) to test against.
99     *
100     * @return boolean  Whether or not the address matches the mask.
101     */
102    protected function _addressWithinCIDR($address, $cidr)
103    {
104        $address = ip2long($address);
105        list($quad, $bits) = explode('/', $cidr);
106        $bits = intval($bits);
107        $quad = ip2long($quad);
108
109        return (($address >> (32 - $bits)) == ($quad >> (32 - $bits)));
110    }
111
112}
113