Issues (209)

src/LightSaml/Helper.php (1 issue)

Severity
1
<?php
2
3
/*
4
 * This file is part of the LightSAML-Core package.
5
 *
6
 * (c) Milos Tomic <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace LightSaml;
13
14
final class Helper
15
{
16
    const TIME_FORMAT = 'Y-m-d\TH:i:s\Z';
17
18
    /**
19
     * @param string $duration
20
     */
21
    public static function validateDurationString($duration)
22
    {
23
        if ($duration) {
24
            try {
25
                new \DateInterval((string) $duration);
26
            } catch (\Exception $ex) {
27
                throw new \InvalidArgumentException(sprintf("Invalid duration '%s' format", $duration), 0, $ex);
28
            }
29
        }
30
    }
31
32
    /**
33
     * @param int $time
34
     *
35
     * @return string
36
     */
37
    public static function time2string($time)
38
    {
39
        return gmdate('Y-m-d\TH:i:s\Z', $time);
40
    }
41
42
    /**
43
     * @param int|string|\DateTime $value
44
     *
45
     * @return int
46
     *
47
     * @throws \InvalidArgumentException
48
     */
49
    public static function getTimestampFromValue($value)
50
    {
51
        if (is_string($value)) {
52
            return self::parseSAMLTime($value);
53
        } elseif ($value instanceof \DateTime) {
54
            return $value->getTimestamp();
55
        } elseif (is_int($value)) {
0 ignored issues
show
The condition is_int($value) is always true.
Loading history...
56
            return $value;
57
        } else {
58
            throw new \InvalidArgumentException();
59
        }
60
    }
61
62
    /**
63
     * @param string $time
64
     *
65
     * @return int
66
     *
67
     * @throws \InvalidArgumentException
68
     */
69
    public static function parseSAMLTime($time)
70
    {
71
        $matches = [];
72
        if (0 == preg_match(
73
                '/^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)(?:\\.\\d+)?(Z|[+-]\\d\\d:\\d\\d)$/D',
74
                $time,
75
                $matches
76
            )) {
77
            throw new \InvalidArgumentException('Invalid SAML2 timestamp: '.$time);
78
        }
79
80
        return strtotime($time);
81
    }
82
83
    /**
84
     * @param int $length
85
     *
86
     * @return string
87
     *
88
     * @throws \InvalidArgumentException
89
     */
90
    public static function generateRandomBytes($length)
91
    {
92
        $length = intval($length);
93
        if ($length <= 0) {
94
            throw new \InvalidArgumentException();
95
        }
96
97
        if (function_exists('openssl_random_pseudo_bytes')) {
98
            return openssl_random_pseudo_bytes($length);
99
        }
100
101
        $data = '';
102
        for ($i = 0; $i < $length; ++$i) {
103
            $data .= chr(mt_rand(0, 255));
104
        }
105
106
        return $data;
107
    }
108
109
    /**
110
     * @param string $bytes
111
     *
112
     * @return string
113
     */
114
    public static function stringToHex($bytes)
115
    {
116
        $result = '';
117
        $len = strlen($bytes);
118
        for ($i = 0; $i < $len; ++$i) {
119
            $result .= sprintf('%02x', ord($bytes[$i]));
120
        }
121
122
        return $result;
123
    }
124
125
    /**
126
     * @return string
127
     */
128
    public static function generateID()
129
    {
130
        return '_'.self::stringToHex(self::generateRandomBytes(21));
131
    }
132
133
    /**
134
     * Is ID element at least 128 bits in length (SAML2.0 standard section 1.3.4).
135
     *
136
     * @param string $id
137
     *
138
     * @return bool
139
     */
140
    public static function validateIdString($id)
141
    {
142
        return is_string($id) && strlen(trim($id)) >= 16;
143
    }
144
145
    /**
146
     * @param string $value
147
     *
148
     * @return bool
149
     */
150
    public static function validateRequiredString($value)
151
    {
152
        return is_string($value) && strlen(trim($value)) > 0;
153
    }
154
155
    /**
156
     * @param string $value
157
     *
158
     * @return bool
159
     */
160
    public static function validateOptionalString($value)
161
    {
162
        return null === $value || self::validateRequiredString($value);
163
    }
164
165
    /**
166
     * @param string $value
167
     *
168
     * @return bool
169
     */
170
    public static function validateWellFormedUriString($value)
171
    {
172
        $value = trim($value);
173
        if ('' == $value || strlen($value) > 65520) {
174
            return false;
175
        }
176
177
        if (preg_match('|\s|', $value)) {
178
            return false;
179
        }
180
181
        $parts = parse_url($value);
182
        if (isset($parts['scheme'])) {
183
            if ($parts['scheme'] != rawurlencode($parts['scheme'])) {
184
                return false;
185
            }
186
        } else {
187
            return false;
188
        }
189
190
        return true;
191
    }
192
193
    /**
194
     * @param int $notBefore
195
     * @param int $now
196
     * @param int $allowedSecondsSkew
197
     *
198
     * @return bool
199
     */
200
    public static function validateNotBefore($notBefore, $now, $allowedSecondsSkew)
201
    {
202
        return null == $notBefore || (($notBefore - $allowedSecondsSkew) < $now);
203
    }
204
205
    /**
206
     * @param int $notOnOrAfter
207
     * @param int $now
208
     * @param int $allowedSecondsSkew
209
     *
210
     * @return bool
211
     */
212
    public static function validateNotOnOrAfter($notOnOrAfter, $now, $allowedSecondsSkew)
213
    {
214
        return null == $notOnOrAfter || ($now < ($notOnOrAfter + $allowedSecondsSkew));
215
    }
216
}
217