This repository has been archived by the owner on Nov 10, 2018. It is now read-only.
forked from WebDevStudios/aad-sso-wordpress
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AuthorizationHelper.php
133 lines (106 loc) · 5.47 KB
/
AuthorizationHelper.php
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
<?php
// A class that provides authorization token for apps that need to access Azure Active Directory Graph Service.
class AADSSO_AuthorizationHelper
{
// Currently, only RS256 is allowed and expected from AAD.
private static $allowed_algorithms = array('RS256');
// Get the authorization URL which makes the authorization request
public static function getAuthorizationURL($settings, $antiforgery_id) {
$authUrl = $settings->authorization_endpoint . '?' .
http_build_query(
array(
'response_type' => 'code',
'scope' => 'openid',
'domain_hint' => $settings->org_domain_hint,
'client_id' => $settings->client_id,
'resource' => $settings->resourceURI,
'redirect_uri' => AADSSO::redirect_uri( 'request_authorization' ),
'state' => $antiforgery_id,
'nonce' => $antiforgery_id,
)
);
return $authUrl;
}
// Takes an authorization code and obtains an gets an access token
public static function getAccessToken($code, $settings) {
// Construct the body for the access token request
$authenticationRequestBody = http_build_query(
array(
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => AADSSO::redirect_uri( 'request_access_token' ),
'resource' => $settings->resourceURI,
'client_id' => $settings->client_id,
'client_secret' => $settings->client_secret
)
);
return self::getAndProcessAccessToken($authenticationRequestBody, $settings);
}
// Takes an authorization code and obtains an gets an access token as what AAD calls a "native app"
public static function getAccessTokenAsNativeApp($code, $settings) {
// Construct the body for the access token request
$authenticationRequestBody = http_build_query(
array(
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => AADSSO::redirect_uri( 'request_access_token_as_native_app' ),
'resource' => $settings->resourceURI,
'client_id' => $settings->client_id
)
);
return self::getAndProcessAccessToken($authenticationRequestBody, $settings);
}
// Does the request for the access token and some basic processing of the access and JWT tokens
static function getAndProcessAccessToken($authenticationRequestBody, $settings) {
$response = wp_remote_post( $settings->token_endpoint, array(
'body' => $authenticationRequestBody
) );
if ( is_wp_error( $response ) ) {
return $response;
}
$output = wp_remote_retrieve_body( $response );
// Decode the JSON response from the STS. If all went well, this will contain the access token and the
// id_token (a JWT token telling us about the current user)s
$token = json_decode( $output );
if ( isset( $token->access_token ) ) {
// Add the token information to the session so that we can use it later
// TODO: these probably shouldn't be in SESSION...
$_SESSION['token_type'] = $token->token_type;
$_SESSION['access_token'] = $token->access_token;
}
return $token;
}
public static function validateIdToken($id_token, $settings, $antiforgery_id) {
$jwt = NULL;
$lastException = NULL;
// TODO: cache the keys
$discovery = json_decode(file_get_contents($settings->jwks_uri));
if ($discovery->keys == NULL) {
throw new DomainException('jwks_uri does not contain the keys attribute');
}
foreach ($discovery->keys as $key) {
try {
if ($key->x5c == NULL) {
throw new DomainException('key does not contain the x5c attribute');
}
$key_der = $key->x5c[0];
// Per section 4.7 of the current JWK draft [1], the 'x5c' property will be the DER-encoded value
// of the X.509 certificate. PHP's openssl functions all require a PEM-encoded value.
$key_pem = chunk_split($key_der, 64, "\n");
$key_pem = "-----BEGIN CERTIFICATE-----\n".$key_pem."-----END CERTIFICATE-----\n";
// This throws exception if the id_token cannot be validated.
$jwt = JWT::decode( $id_token, $key_pem, self::$allowed_algorithms);
break;
} catch (Exception $e) {
$lastException = $e;
}
}
if ($jwt == NULL) {
throw $lastException;
}
if ($jwt->nonce != $antiforgery_id) {
throw new DomainException(sprintf('Nonce mismatch. Expecting %s', $antiforgery_id));
}
return $jwt;
}
}