Subversion Repositories Applications.annuaire

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
42 aurelien 1
<?php
2
/**
3
 * Functions for dealing with OpenID trust roots
4
 *
5
 * PHP versions 4 and 5
6
 *
7
 * LICENSE: See the COPYING file included in this distribution.
8
 *
9
 * @package OpenID
10
 * @author JanRain, Inc. <openid@janrain.com>
11
 * @copyright 2005 Janrain, Inc.
12
 * @license http://www.gnu.org/copyleft/lesser.html LGPL
13
 */
14
 
15
/**
16
 * A regular expression that matches a domain ending in a top-level domains.
17
 * Used in checking trust roots for sanity.
18
 *
19
 * @access private
20
 */
21
define('Auth_OpenID___TLDs',
22
       '/\.(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|' .
23
       'ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|' .
24
       'bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|' .
25
       'cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|' .
26
       'fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|' .
27
       'gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|' .
28
       'ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|' .
29
       'ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|' .
30
       'nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|' .
31
       'ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|' .
32
       'so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|' .
33
       'ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$/');
34
 
35
/**
36
 * A wrapper for trust-root related functions
37
 */
38
class Auth_OpenID_TrustRoot {
39
    /**
40
     * Parse a URL into its trust_root parts.
41
     *
42
     * @static
43
     *
44
     * @access private
45
     *
46
     * @param string $trust_root The url to parse
47
     *
48
     * @return mixed $parsed Either an associative array of trust root
49
     * parts or false if parsing failed.
50
     */
51
    function _parse($trust_root)
52
    {
53
        $parts = @parse_url($trust_root);
54
        if ($parts === false) {
55
            return false;
56
        }
57
        $required_parts = array('scheme', 'host');
58
        $forbidden_parts = array('user', 'pass', 'fragment');
59
        $keys = array_keys($parts);
60
        if (array_intersect($keys, $required_parts) != $required_parts) {
61
            return false;
62
        }
63
 
64
        if (array_intersect($keys, $forbidden_parts) != array()) {
65
            return false;
66
        }
67
 
68
        // Return false if the original trust root value has more than
69
        // one port specification.
70
        if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) {
71
            return false;
72
        }
73
 
74
        $scheme = strtolower($parts['scheme']);
75
        $allowed_schemes = array('http', 'https');
76
        if (!in_array($scheme, $allowed_schemes)) {
77
            return false;
78
        }
79
        $parts['scheme'] = $scheme;
80
 
81
        $host = strtolower($parts['host']);
82
        $hostparts = explode('*', $host);
83
        switch (count($hostparts)) {
84
        case 1:
85
            $parts['wildcard'] = false;
86
            break;
87
        case 2:
88
            if ($hostparts[0] ||
89
                ($hostparts[1] && substr($hostparts[1], 0, 1) != '.')) {
90
                return false;
91
            }
92
            $host = $hostparts[1];
93
            $parts['wildcard'] = true;
94
            break;
95
        default:
96
            return false;
97
        }
98
        if (strpos($host, ':') !== false) {
99
            return false;
100
        }
101
 
102
        $parts['host'] = $host;
103
 
104
        if (isset($parts['path'])) {
105
            $path = strtolower($parts['path']);
106
            if (substr($path, -1) != '/') {
107
                $path .= '/';
108
            }
109
        } else {
110
            $path = '/';
111
        }
112
        $parts['path'] = $path;
113
        if (!isset($parts['port'])) {
114
            $parts['port'] = false;
115
        }
116
        return $parts;
117
    }
118
 
119
    /**
120
     * Is this trust root sane?
121
     *
122
     * A trust root is sane if it is syntactically valid and it has a
123
     * reasonable domain name. Specifically, the domain name must be
124
     * more than one level below a standard TLD or more than two
125
     * levels below a two-letter tld.
126
     *
127
     * For example, '*.com' is not a sane trust root, but '*.foo.com'
128
     * is.  '*.co.uk' is not sane, but '*.bbc.co.uk' is.
129
     *
130
     * This check is not always correct, but it attempts to err on the
131
     * side of marking sane trust roots insane instead of marking
132
     * insane trust roots sane. For example, 'kink.fm' is marked as
133
     * insane even though it "should" (for some meaning of should) be
134
     * marked sane.
135
     *
136
     * This function should be used when creating OpenID servers to
137
     * alert the users of the server when a consumer attempts to get
138
     * the user to accept a suspicious trust root.
139
     *
140
     * @static
141
     * @param string $trust_root The trust root to check
142
     * @return bool $sanity Whether the trust root looks OK
143
     */
144
    function isSane($trust_root)
145
    {
146
        $parts = Auth_OpenID_TrustRoot::_parse($trust_root);
147
        if ($parts === false) {
148
            return false;
149
        }
150
 
151
        // Localhost is a special case
152
        if ($parts['host'] == 'localhost') {
153
            return true;
154
        }
155
 
156
        // Get the top-level domain of the host. If it is not a valid TLD,
157
        // it's not sane.
158
        preg_match(Auth_OpenID___TLDs, $parts['host'], $matches);
159
        if (!$matches) {
160
            return false;
161
        }
162
        $tld = $matches[1];
163
 
164
        // Require at least two levels of specificity for non-country
165
        // tlds and three levels for country tlds.
166
        $elements = explode('.', $parts['host']);
167
        $n = count($elements);
168
        if ($parts['wildcard']) {
169
            $n -= 1;
170
        }
171
        if (strlen($tld) == 2) {
172
            $n -= 1;
173
        }
174
        if ($n <= 1) {
175
            return false;
176
        }
177
        return true;
178
    }
179
 
180
    /**
181
     * Does this URL match the given trust root?
182
     *
183
     * Return whether the URL falls under the given trust root. This
184
     * does not check whether the trust root is sane. If the URL or
185
     * trust root do not parse, this function will return false.
186
     *
187
     * @param string $trust_root The trust root to match against
188
     *
189
     * @param string $url The URL to check
190
     *
191
     * @return bool $matches Whether the URL matches against the
192
     * trust root
193
     */
194
    function match($trust_root, $url)
195
    {
196
        $trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root);
197
        $url_parsed = Auth_OpenID_TrustRoot::_parse($url);
198
        if (!$trust_root_parsed || !$url_parsed) {
199
            return false;
200
        }
201
 
202
        // Check hosts matching
203
        if ($url_parsed['wildcard']) {
204
            return false;
205
        }
206
        if ($trust_root_parsed['wildcard']) {
207
            $host_tail = $trust_root_parsed['host'];
208
            $host = $url_parsed['host'];
209
            if ($host_tail &&
210
                substr($host, -(strlen($host_tail))) != $host_tail &&
211
                substr($host_tail, 1) != $host) {
212
                return false;
213
            }
214
        } else {
215
            if ($trust_root_parsed['host'] != $url_parsed['host']) {
216
                return false;
217
            }
218
        }
219
 
220
        // Check path and query matching
221
        $base_path = $trust_root_parsed['path'];
222
        $path = $url_parsed['path'];
223
        if (!isset($trust_root_parsed['query'])) {
224
            if (substr($path, 0, strlen($base_path)) != $base_path) {
225
                return false;
226
            }
227
        } else {
228
            $base_query = $trust_root_parsed['query'];
229
            $query = @$url_parsed['query'];
230
            $qplus = substr($query, 0, strlen($base_query) + 1);
231
            $bqplus = $base_query . '&';
232
            if ($base_path != $path ||
233
                ($base_query != $query && $qplus != $bqplus)) {
234
                return false;
235
            }
236
        }
237
 
238
        // The port and scheme need to match exactly
239
        return ($trust_root_parsed['scheme'] == $url_parsed['scheme'] &&
240
                $url_parsed['port'] === $trust_root_parsed['port']);
241
    }
242
}
243
?>