SSO.class.php
12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
<?php
/**
* @author Kieran Hardern
* @version 1.0a
*/
class SSO {
/*
* Location of the VATSIM SSO system
* Set in __construct
*/
private $base = 'http://sso.hardern.net/server/';
/*
* Location for all OAuth requests
*/
private $loc_api = 'api/';
/*
* Location for all login token requests
*/
private $loc_token = 'login_token/';
/*
* Location to query for all user data requests (upon return of user login)
*/
private $loc_return = 'login_return/';
/*
* Location to redirect the user to once we have generated a token
*/
private $loc_login = 'auth/pre_login/?oauth_token=';
/*
* Format of the data returned by SSO, default json
* Set in responseFormat method
*/
private $format = 'json';
/*
* cURL timeout (seconds) for all requests
*/
private $timeout = 10;
/*
* Holds the details of the most recent error in this class
*/
private $error = array(
'type'=>false,
'message'=>false,
'code'=>false
);
/*
* The signing method being used to encrypt your request signature.
* Set the 'signature' method
*/
private $signature = false;
/*
* A request token genereted by (or saved to) the class
*/
private $token = false;
/*
* Consumer credentials, instance of OAuthConsumer
*/
private $consumer = false;
/**
* Configures the SSO class with consumer/organisation credentials
*
* @param type $key Organisation key
* @param type $secret Secret key corresponding to this organisation (only required if using HMAC)
* @param string $signature RSA|HMAC
* @param string $private_key openssl RSA private key (only required if using RSA)
*/
public function __construct($base, $key, $secret=false, $signature=false, $private_key=false){
$this->base = $base;
// Store consumer credentials
$this->consumer = new OAuthConsumer($key, $secret);
// if signature method is defined, set the signature method now (can be set or changed later)
if ($signature){
$this->signature($signature, $private_key);
}
}
/**
* Return or change the output format (returned by VATSIM)
*
* @param string $change json|xml
* @return string current format or bool false (unable to set format)
*/
public function format($change=false){
// lower case values only
$change = strtolower($change);
// if set, attempt to change format
if ($change){
switch($change){
// allowed formats, change to new format
case "xml":
case "json":
$this->format = $change;
break;
// other formats now allowed/recognised
default:
return false;
break;
}
// return the new format (string)
return $this->format;
} else {
// get and return the current format
return $this->format;
}
}
/**
* Set the signing method to be used to encrypt request signature.
*
* @param string $signature Signature encryption method: RSA|HMAC
* @param string $private_key openssl RSA private key (only needed if using RSA)
* @return boolean true if able to use this signing type
*/
public function signature($signature, $private_key=false){
$signature = strtoupper($signature);
// RSA-SHA1 public key/private key encryption
if ($signature=='RSA' || $signature=='RSA-SHA1'){
// private key must be provided
if (!$private_key){
return false;
}
// signature method set to RSA-SHA1 using this private key (interacts with OAuth class)
$this->signature = new SSO_OAuthSignatureMethod_RSA_SHA1($private_key);
return true;
} elseif ($signature=='HMAC' || $signature=='HMAC-SHA1') {
// signature method set to HMAC-SHA1 - no private key
$this->signature = new OAuthSignatureMethod_HMAC_SHA1;
return true;
} else {
// signature method was not recognised
return false;
}
}
/**
* Request a login token from VATSIM (required to send someone for an SSO login)
*
* @param string $return_url URL for VATSIM to return memers to after login
* @param boolean $allow_sus true to allow suspended VATSIM accounts to log in
* @param boolean $allow_ina true to allow inactive VATSIM accounts to log in
* @return object|boolean
*/
public function requestToken($return_url=false, $allow_sus=false, $allow_ina=false){
// signature method must have been set
if (!$this->signature){
return false;
}
// if the return URL isn't specified, assume this file (though don't consider GET data)
if (!$return_url){
// using https or http?
$http = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) ? 'https://' : 'http://';
// the current URL
$return_url = $http.$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];
}
$tokenUrl = $this->base.$this->loc_api.$this->loc_token.$this->format.'/';
// generate a token request from the consumer details
$req = OAuthRequest::from_consumer_and_token($this->consumer, false, "POST", $tokenUrl, array(
'oauth_callback' => $return_url,
'oauth_allow_suspended' => ($allow_sus) ? true : false,
'oauth_allow_inactive' => ($allow_ina) ? true : false
));
// sign the request using the specified signature/encryption method (set in this class)
$req->sign_request($this->signature, $this->consumer, false);
$response = $this->curlRequest($tokenUrl, $req->to_postdata());
if ($response){
// convert using our response format (depending upon user preference)
$sso = $this->responseFormat($response);
// did VATSIM return a successful result?
if ($sso->request->result=='success'){
// this parameter is required by 1.0a spec
if ($sso->token->oauth_callback_confirmed=='true'){
// store the token data saved
$this->token = new OAuthConsumer($sso->token->oauth_token, $sso->token->oauth_token_secret);
// return the full object to the user
return $sso;
} else {
// no callback_confirmed parameter
$this->error = array(
'type' => 'callback_confirm',
'code' => false,
'message' => 'Callback confirm flag missing - protocol mismatch'
);
return false;
}
} else {
// oauth returned a failed request, store the error details
$this->error = array(
'type' => 'oauth_response',
'code' => false,
'message' => $sso->request->message
);
return false;
}
} else {
// cURL response failed
return false;
}
}
/**
* Redirect the user to VATSIM to log in/confirm login
*
* @return boolean false if failed
*/
public function sendToVatsim(){
// a token must have been returned to redirect this user
if (!$this->token){
return false;
}
// redirect to the SSO login location, appending the token
header("Location: ".$this->base.$this->loc_login.$this->token->key);
die();
}
/**
* Obtains a user's login details from a token key and secret
*
* @param string $tokenKey The token key provided by VATSIM
* @param secret $tokenSecret The secret associated with the token
* @return object|false false if error, otherwise returns user details
*/
public function checkLogin($tokenKey, $tokenSecret, $tokenVerifier){
$this->token = new OAuthConsumer($tokenKey, $tokenSecret);
// the location to send a cURL request to to obtain this user's details
$returnUrl = $this->base.$this->loc_api.$this->loc_return.$this->format.'/';
// generate a token request call using post data
$req = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, "POST", $returnUrl, array(
'oauth_token' => $tokenKey,
'oauth_verifier' => $tokenVerifier
));
// sign the request using the specified signature/encryption method (set in this class)
$req->sign_request($this->signature, $this->consumer, $this->token);
// post the details to VATSIM and obtain the result
$response = $this->curlRequest($returnUrl, $req->to_postdata());
if ($response){
// convert using our response format (depending upon user preference)
$sso = $this->responseFormat($response);
// did VATSIM return a successful result?
if ($sso->request->result=='success'){
// one time use of tokens only, token no longer valid
$this->token = false;
// return the full object to the user
return $sso;
} else {
// oauth returned a failed request, store the error details
$this->error = array(
'type' => 'oauth_response',
'code' => false,
'message' => $sso->request->message
);
return false;
}
} else {
// cURL response failed
return false;
}
}
/**
* Perform a (post) cURL request
*
* @param type $url Destination of request
* @param type $requestString Query string of data to be posted
* @return boolean true if able to make request
*/
private function curlRequest($url, $requestString){
// using cURL to post the request to VATSIM
$ch = curl_init();
// configure the post request to VATSIM
curl_setopt_array($ch, array(
CURLOPT_URL => $url, // the url to make the request to
CURLOPT_RETURNTRANSFER => 1, // do not output the returned data to the user
CURLOPT_TIMEOUT => $this->timeout, // time out the request after this number of seconds
CURLOPT_POST => 1, // we are sending this via post
CURLOPT_POSTFIELDS => $requestString // a query string to be posted (key1=value1&key2=value2)
));
// perform the request
$response = curl_exec($ch);
// request failed?
if (!$response){
$this->error = array(
'type' => 'curl_response',
'code' => curl_errno($ch),
'message' => curl_error($ch)
);
return false;
} else {
return $response;
}
}
/**
* Convert the response into a usable format
*
* @param string $response json|xml
* @return object Format processed into an object (Simple XML Element or json_decode)
*/
private function responseFormat($response){
if ($this->format=='xml'){
return new SimpleXMLElement($response);
} else {
return json_decode($response);
}
}
/**
* Obtain the last generated error from this class
*
* @return array Array of the latest error
*/
public function error(){
return $this->error;
}
}
?>