Issues (29)

Lib/UniLoginUtil.php (2 issues)

1
<?php
2
/**
3
 * UniLogin Utility class.
4
 *
5
 */
6
class UniLoginUtil {
7
8
/**
9
 * The timestamp format.
10
 *
11
 * @var string
12
 */
13
	const TIMESTAMP_FORMAT = 'YmdHis';
14
15
/**
16
 * The fingerprint timeout.
17
 *
18
 *   Determines how long app -> provider -> app (plugin) may take.
19
 *
20
 * @var string
21
 */
22
	const FINGERPRINT_TIMEOUT = '-1 minute';
23
24
/**
25
 * Switch the time zone.
26
 *
27
 * @param string $timeZone The new time zone identifier
28
 * @return string The old time zone identifier
29
 * @todo Time zone should be application wide set to UTC
30
 */
31
	protected static function _switchTimeZone($timeZone = 'UTC') {
32
		$restore = date_default_timezone_get();
33
		date_default_timezone_set($timeZone);
34
35
		return $restore;
36
	}
37
38
/**
39
 * Calculate Uni Login fingerprint.
40
 *
41
 * @param string $formattedTimestamp Uni-Login formatted timestamp
42
 * @param string $user A username
43
 * @return string A fingerprint
44
 * @see https://en.wikipedia.org/wiki/Length_extension_attack
45
 */
46
	public static function calculateFingerprint($formattedTimestamp, $user) {
47
		$secret = Configure::read('UniLogin.provider.secret');
0 ignored issues
show
The type Configure was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
48
49
		return md5($formattedTimestamp . $secret . $user);
50
	}
51
52
/**
53
 * Validates Uni Login fingerprint.
54
 *
55
 * @param string $formattedTimestamp Uni-Login formatted timestamp
56
 * @param string $user A username
57
 * @param string $fingerprint Fingerprint to validate
58
 * @return bool Whether or not the fingerprint validates
59
 */
60
	public static function validateFingerprint($formattedTimestamp, $user, $fingerprint) {
61
		$restore = self::_switchTimeZone();
62
63
		$isValid = false;
64
		$now = time();
65
		$timestamp = self::parseFormattedTimestamp($formattedTimestamp);
66
67
		// Given timestamp should be between 1 minute ago and now
68
		if (($timestamp <= $now) && ($timestamp > strtotime(self::FINGERPRINT_TIMEOUT, $now))) {
69
			// Check fingerprint
70
			if (hash_equals(self::calculateFingerprint($formattedTimestamp, $user), $fingerprint)) {
71
				$isValid = true;
72
			}
73
		}
74
75
		self::_switchTimeZone($restore);
76
77
		return $isValid;
78
	}
79
80
/**
81
 * Formats given (or current) timestamp to Uni-Login formatted timestamp.
82
 *
83
 * @param string $timestamp Unix timestamp
84
 * @return string Uni-Login formatted timestamp
85
 */
86
	public static function getFormattedTimestamp($timestamp = null) {
87
		$restore = self::_switchTimeZone();
88
89
		if ($timestamp === null) {
90
			$timestamp = time();
91
		}
92
		$result = date(self::TIMESTAMP_FORMAT, $timestamp);
0 ignored issues
show
It seems like $timestamp can also be of type string; however, parameter $timestamp of date() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
		$result = date(self::TIMESTAMP_FORMAT, /** @scrutinizer ignore-type */ $timestamp);
Loading history...
93
94
		self::_switchTimeZone($restore);
95
96
		return $result;
97
	}
98
99
/**
100
 * Parses given Uni-Login timestamp.
101
 *
102
 * @param string $formattedTimestamp Uni-login formatted timestamp
103
 * @return mixed Returns a timestamp on success, false otherwise
104
 */
105
	public static function parseFormattedTimestamp($formattedTimestamp) {
106
		$restore = self::_switchTimeZone();
107
108
		$result = strtotime($formattedTimestamp);
109
110
		self::_switchTimeZone($restore);
111
112
		return $result;
113
	}
114
115
/**
116
 * Returns url of the authentication provider.
117
 *
118
 * @return string Url of the authentication provider
119
 */
120
	public static function getProviderUrl() {
121
		$url = Configure::read('UniLogin.provider.url');
122
		$applicationId = Configure::read('UniLogin.provider.applicationId');
123
124
		return sprintf($url, $applicationId);
125
	}
126
127
/**
128
 * Calculates fingerprint for given url.
129
 *
130
 * @param string $url Url to create fingerprint for
131
 * @return string A fingerprint
132
 */
133
	public static function calculateUrlFingerprint($url) {
134
		$secret = Configure::read('UniLogin.provider.secret');
135
136
		return md5($url . $secret);
137
	}
138
139
/**
140
 * Decodes given url.
141
 *
142
 * @param string $url Encoded url
143
 * @return string Decoded url
144
 */
145
	public static function decodeUrl($url) {
146
		return base64_decode(urldecode($url));
147
	}
148
149
/**
150
 * Encodes given url.
151
 *
152
 * @param string $url Decoded url
153
 * @return string Encoded url
154
 */
155
	public static function encodeUrl($url) {
156
		return base64_encode($url);
157
	}
158
159
/**
160
 * Validates Uni-Login fingerprint for given url.
161
 *
162
 * @param string $url Given url
163
 * @param string $fingerprint Fingerprint to validate
164
 * @return bool Whether or not the fingerprint validates
165
 */
166
	public static function validateUrlFingerprint($url, $fingerprint) {
167
		return hash_equals(self::calculateUrlFingerprint($url), $fingerprint);
168
	}
169
170
/**
171
 * Calculates HMAC (sha256) for data.
172
 *
173
 * @param array $data (Response) data
174
 * @return string HMAC
175
 */
176
	public static function hmac(array $data = []) {
177
		$secret = Configure::read('UniLogin.application.secret');
178
179
		return hash_hmac('sha256', implode('-', $data), $secret);
180
	}
181
}
182