Completed
Push — master ( 162a23...517658 )
by Nazar
04:24
created

authorize.php ➔ http_build_url()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 16
rs 9.2
1
<?php
2
/**
3
 * @package   OAuth2
4
 * @category  modules
5
 * @author    Nazar Mokrynskyi <[email protected]>
6
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
7
 * @license   MIT License, see license.txt
8
 */
9
/**
10
 * Provides next events:<br>
11
 *  OAuth2/custom_sign_in_page
12
 *  OAuth2/custom_allow_access_page
13
 */
14
namespace cs\modules\OAuth2;
15
use
16
	h,
17
	cs\Config,
18
	cs\Event,
19
	cs\ExitException,
20
	cs\Language\Prefix,
21
	cs\Page,
22
	cs\Response,
23
	cs\User;
24
25
if (!function_exists(__NAMESPACE__.'\\http_build_url')) {
26
	/**
27
	 * @param string   $url
0 ignored issues
show
Documentation introduced by
Should the type for parameter $url not be mixed? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
28
	 * @param string[] $parts
0 ignored issues
show
Documentation introduced by
Should the type for parameter $parts not be mixed? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
29
	 *
30
	 * @return string
31
	 */
32
	function http_build_url ($url, $parts) {
33
		$url    = explode('?', $url, 2);
34
		$params = [];
35
		if (isset($url[1])) {
36
			foreach (explode('&', $url[1]) as $u) {
37
				$params[] = $u;
38
			}
39
			unset($u, $url[1]);
40
		}
41
		$url = $url[0];
42
		foreach ($parts as $name => $value) {
43
			$params[] = $name.'='.urlencode($value);
44
		}
45
		$params = array_unique($params);
46
		return "$url?".implode('&', $params);
47
	}
48
49
	function error_redirect ($error, $description) {
50
		Response::instance()->redirect(
51
			http_build_url(
52
				urldecode($_GET['redirect_uri']),
53
				[
54
					'error'             => $error,
55
					'error_description' => $description,
56
					'state'             => isset($_GET['state']) ? $_GET['state'] : false
57
				]
58
			),
59
			302
60
		);
61
	}
62
}
63
$OAuth2 = OAuth2::instance();
64
$Config = Config::instance();
65
$L      = new Prefix('oauth2_');
66
$Page   = Page::instance();
67
/**
68
 * Errors processing
69
 */
70
if (!isset($_GET['client_id'])) {
71
	error_redirect('invalid_request', 'client_id parameter required');
72
	return;
73
}
74
$client = $OAuth2->get_client($_GET['client_id']);
75
if (!$client) {
76
	error_redirect('invalid_request', 'client_id not found');
77
	return;
78
}
79
if (!$client['domain']) {
80
	$e = new ExitException(
81
		[
82
			'unauthorized_client',
83
			'Request method is not authored'
84
		],
85
		400
86
	);
87
	$e->setJson();
88
	throw $e;
89
}
90
if (!$client['active']) {
91
	if (!isset($_GET['redirect_uri'])) {
92
		$e = new ExitException(
93
			[
94
				'invalid_request',
95
				'Inactive client_id, redirect_uri parameter required'
96
			],
97
			400
98
		);
99
		$e->setJson();
100
		throw $e;
101
	} else {
102
		if (
103
			urldecode($_GET['redirect_uri']) != $Config->base_url().'/OAuth2/blank/' &&
104
			!preg_match("#^[^/]+://$client[domain]#", urldecode($_GET['redirect_uri']))
105
		) {
106
			error_redirect('access_denied', 'Inactive client id');
107
			return;
108
		} else {
109
			$e = new ExitException(
110
				[
111
					'invalid_request',
112
					'Inactive client_id, redirect_uri parameter required'
113
				],
114
				400
115
			);
116
			$e->setJson();
117
			throw $e;
118
		}
119
	}
120
}
121
if (!isset($_GET['redirect_uri'])) {
122
	throw new ExitException(
123
		[
124
			'invalid_request',
125
			'redirect_uri parameter required'
126
		],
127
		400
128
	);
129
} elseif (
130
	urldecode($_GET['redirect_uri']) != $Config->base_url().'/OAuth2/blank/' &&
131
	!preg_match("#^[^/]+://$client[domain]#", urldecode($_GET['redirect_uri']))
132
) {
133
	throw new ExitException(
134
		[
135
			'invalid_request',
136
			'redirect_uri parameter invalid'
137
		],
138
		400
139
	);
140
}
141
$redirect_uri = urldecode($_GET['redirect_uri']);
142
if (!isset($_GET['response_type'])) {
143
	error_redirect('invalid_request', 'response_type parameter required');
144
	return;
145
}
146
$User = User::instance();
147
if (!$User->user()) {
148
	if (Event::instance()->fire('OAuth2/custom_sign_in_page')) {
149
		$Page->Content = '';
150
		$Page->warning($L->you_are_not_logged_in);
151
	}
152
	return;
153
}
154
$Response = Response::instance();
155
/**
156
 * Authorization processing
157
 */
158
if (isset($_POST['mode'])) {
159
	if ($_POST['mode'] == 'allow') {
160
		$OAuth2->add_access($client['id']);
161
	} else {
162
		error_redirect('access_denied', 'User denied access');
163
		$Page->Content = '';
164
		return;
165
	}
166
}
167
if (!$OAuth2->get_access($client['id'])) {
168
	if (Event::instance()->fire('OAuth2/custom_allow_access_page')) {
169
		$Page->success(
170
			$L->client_want_access_your_account($client['name'])
171
		);
172
		$Page->content(
173
			h::form(
174
				h::{'button[is=cs-button][type=submit][name=mode][value=allow]'}($L->allow).
175
				h::{'button[is=cs-button][type=submit][mode=mode][value=deny]'}($L->deny)
176
			)
177
		);
178
	}
179
	return;
180
}
181
$code = $OAuth2->add_code($client['id'], $_GET['response_type'], $redirect_uri);
182
if (!$code) {
183
	error_redirect('server_error', "Server can't generate code, try later");
184
	return;
185
}
186
switch ($_GET['response_type']) {
187
	case 'code':
188
		$Response->redirect(
189
			http_build_url(
190
				$redirect_uri,
191
				[
192
					'code'  => $code,
193
					'state' => isset($_GET['state']) ? $_GET['state'] : false
194
				]
195
			),
196
			302
197
		);
198
		$Page->Content = '';
199
		return;
200
	case 'token':
201
		$token_data = $OAuth2->get_code($code, $client['id'], $client['secret'], $redirect_uri);
202
		if ($token_data) {
203
			unset($token_data['refresh_token']);
204
			$url = http_build_url(
205
				$redirect_uri,
206
				array_merge(
207
					$token_data,
208
					[
209
						'state' => isset($_GET['state']) ? $_GET['state'] : false
210
					]
211
				)
212
			);
213
			$url = implode('#', explode('?', $url, 2));
214
			$Response->redirect($url, 302);
215
			$Page->Content = '';
216
			return;
217
		} else {
218
			error_redirect('server_error', "Server can't get token data, try later");
219
			return;
220
		}
221
	default:
222
		error_redirect('unsupported_response_type', 'Specified response_type is not supported, only "token" or "code" types available');
223
}
224