Google Apps Login - Version 3.4.5

Version Description

Updated: Plugin name. Fixed: Admin escaping

Download this release

Release Info

Developer chrisakelley
Plugin Icon 128x128 Google Apps Login
Version 3.4.5
Comparing to
See all releases

Code changes from version 3.4.4 to 3.4.5

Files changed (40) hide show
  1. autoload.php +34 -34
  2. changelog.txt +201 -0
  3. core/Google/Auth/Abstract.php +37 -36
  4. core/Google/Auth/AppIdentity.php +101 -105
  5. core/Google/Auth/AssertionCredentials.php +146 -144
  6. core/Google/Auth/Exception.php +22 -22
  7. core/Google/Auth/LoginTicket.php +71 -69
  8. core/Google/Auth/OAuth2.php +614 -629
  9. core/Google/Auth/Simple.php +62 -64
  10. core/Google/Cache/Abstract.php +52 -53
  11. core/Google/Cache/Apc.php +122 -111
  12. core/Google/Cache/Exception.php +22 -22
  13. core/Google/Cache/File.php +202 -190
  14. core/Google/Cache/Memcache.php +192 -182
  15. core/Google/Cache/Null.php +51 -55
  16. core/Google/Client.php +666 -686
  17. core/Google/Collection.php +85 -96
  18. core/Google/Config.php +403 -413
  19. core/Google/Exception.php +20 -20
  20. core/Google/Http/Batch.php +137 -141
  21. core/Google/Http/CacheParser.php +181 -184
  22. core/Google/Http/MediaFileUpload.php +297 -300
  23. core/Google/Http/REST.php +149 -147
  24. core/Google/Http/Request.php +451 -476
  25. core/Google/IO/Abstract.php +328 -329
  26. core/Google/IO/Curl.php +157 -159
  27. core/Google/IO/DebugVersionOfCurl.php +153 -155
  28. core/Google/IO/Exception.php +22 -22
  29. core/Google/IO/Stream.php +226 -230
  30. core/Google/IO/cacerts.pem +2183 -2183
  31. core/Google/Logger/Abstract.php +390 -406
  32. core/Google/Logger/Exception.php +22 -22
  33. core/Google/Logger/File.php +150 -156
  34. core/Google/Logger/Null.php +39 -41
  35. core/Google/Logger/Psr.php +86 -91
  36. core/Google/Model.php +265 -281
  37. core/Google/Service.php +38 -39
  38. core/Google/Service/AdExchangeBuyer.php +1687 -1909
  39. core/Google/Service/AdExchangeSeller.php +1544 -1712
  40. core/Google/Service/AdSense.php +2982 -3585
autoload.php CHANGED
@@ -1,34 +1,34 @@
1
- <?php
2
- /*
3
- * Copyright 2014 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- function gal_google_api_php_client_autoload($className) {
19
- $classPath = explode('_', $className);
20
- if ($classPath[0] != 'GoogleGAL') { // Was Google
21
- return;
22
- }
23
- if (count($classPath) > 3) {
24
- // Maximum class file path depth in this project is 3.
25
- $classPath = array_slice($classPath, 0, 3);
26
- }
27
- $classPath = str_replace('GoogleGAL', 'Google', $classPath); // Adjust back to Google's path
28
- $filePath = dirname(__FILE__) . '/core/' . implode('/', $classPath) . '.php'; // was src -> now core
29
- if (file_exists($filePath)) {
30
- require_once($filePath);
31
- }
32
- }
33
-
34
- spl_autoload_register('gal_google_api_php_client_autoload');
1
+ <?php
2
+ /*
3
+ * Copyright 2014 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ function gal_google_api_php_client_autoload( $className ) {
19
+ $classPath = explode( '_', $className );
20
+ if ( $classPath[0] != 'GoogleGAL' ) { // Was Google
21
+ return;
22
+ }
23
+ if ( count( $classPath ) > 3 ) {
24
+ // Maximum class file path depth in this project is 3.
25
+ $classPath = array_slice( $classPath, 0, 3 );
26
+ }
27
+ $classPath = str_replace( 'GoogleGAL', 'Google', $classPath ); // Adjust back to Google's path
28
+ $filePath = dirname( __FILE__ ) . '/core/' . implode( '/', $classPath ) . '.php'; // was src -> now core
29
+ if ( file_exists( $filePath ) ) {
30
+ require_once $filePath;
31
+ }
32
+ }
33
+
34
+ spl_autoload_register( 'gal_google_api_php_client_autoload' );
changelog.txt ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ == Changelog ==
2
+
3
+ = 3.4.5 =
4
+
5
+ Updated: Plugin name.
6
+ Fixed: Admin escaping
7
+
8
+ = 3.4.4 =
9
+
10
+ Updated compatibility with the WordPress 5.7 release.
11
+ Login with the google button removed static images generated same button using HTML code and use google svg icon
12
+ Bug fixed for header already sent
13
+
14
+ = 3.4.3 =
15
+
16
+ Updated compatibility with the WordPress 5.6 release.
17
+
18
+ = 3.4.2 =
19
+
20
+ Added missing alt attribute in image tag.
21
+ Set httponly flag in cookie.
22
+ Added custom text support for login with google button.
23
+
24
+ = 3.4.1 =
25
+
26
+ Bug fixing for PHP Notice: Undefined index: approval_prompt.
27
+ Bug Fixing for PHP Deprecated: Array and string offset access syntax with curly braces is deprecated.
28
+
29
+ = 3.4 =
30
+
31
+ Bug fixing for Invalid parameter value for approval_prompt: 'auto'.
32
+ Updated compatibility with the WordPress 5.4 release.
33
+
34
+
35
+ = 3.3 =
36
+
37
+ Added permission check functionality
38
+ Added Google Drive Embedder insufficient permission error fixes
39
+ Added Login With Google buttons branding
40
+ Updated compatibility with the WordPress 5.3.1 release
41
+
42
+ = 3.2 =
43
+
44
+ Added workaround for incompatibility with WPMU Defender plugin's new 2FA feature.
45
+ Updated compatibility with the upcoming WordPress 4.9 release.
46
+
47
+ = 3.0 =
48
+
49
+ Internal changes to Google Client library. Essential for the latest versions of some extension plugins such as Google Drive Embedder.
50
+
51
+ = 2.10.5 =
52
+
53
+ Multisite improvements: better handling of COOKIE_DOMAIN configuration and also allows login redirects straight to sub-sites even when login is handled by the root site's wp-login.php page.
54
+ Login page cookies now last for the length of the current browser session instead of for a fixed time, so this should reduce unexpected 'Session mismatch' errors.
55
+
56
+ Ensures plugin options are not loaded until 'plugins_loaded' stage. This makes it easier to use the gal_options hook more reliably.
57
+
58
+ Added language files for be_BY.
59
+ Added filters 'gal_options' and 'gal_sa_options' so you can configure settings using PHP code.
60
+
61
+ Changed the way Google client library is included to avoid conflicts with other Google-related plugins that set the include path
62
+ in a way that doesn't allow for other plugins.
63
+
64
+ = 2.9.7 =
65
+
66
+ Added gal_set_login_cookie filter so you can prevent Login for Google Apps from setting its WordPress_google_apps_login cookie under
67
+ certain circumstances. It only technically needs to be set on the wp-login.php page in most installations, and you may find
68
+ that if it sets the cookie on any page load (which it does when not already set) then this prevents caching on heavy traffic pages.
69
+
70
+ = 2.9.6 =
71
+
72
+ New 'Remember Me' in advanced options. Check to ensure users are not automatically logged out at the end of their browser session.
73
+ This applies to all users using 'Login with Google'. It has the same functionality as checking the 'Remember Me' checkbox on
74
+ the login form when using regular WordPress username/password to login.
75
+
76
+ Improved handling of errors when multiple versions of the plugin are inadvertently activated.
77
+
78
+ = 2.8.17 =
79
+
80
+ Added filter gal_login_button_text so developers can customize the 'Login with Google' button in all versions (in Premium/Enterprise,
81
+ it is possible to set the button text in settings, and that will always take priority if set).
82
+
83
+ Fixed a text injection vulnerability whereby it was possible for a third party to trick a user into viewing a version of the login page
84
+ containing an error message entirely of their own choosing - all sites should upgrade to this plugin version.
85
+
86
+ = 2.8.16 =
87
+
88
+ Updated to work correctly alongside some plugins that change the login URL from /wp-login.php to something else.
89
+
90
+ = 2.8.15 =
91
+
92
+ Removed a WordPress function that is deprecated in WP 4.4 - force_ssl_login
93
+ This could have resulted in some visible warning messages.
94
+
95
+ = 2.8.14 =
96
+
97
+ Updated some URLs pointing to information about Premium/Enterprise upgrades.
98
+ Readme updated.
99
+
100
+ = 2.8.13 =
101
+
102
+ Ready for WordPress 4.4.
103
+ New translation strings for languages.
104
+
105
+ = 2.8.12 =
106
+
107
+ Opportunity to sign up for emails on Google Apps and WordPress, from settings page.
108
+
109
+ = 2.8.11 =
110
+
111
+ Service Account Client ID is imported from JSON key file so user can copy and paste it into admin.google.com
112
+
113
+ = 2.8.10 =
114
+
115
+ Changed name of login cookie from 'google_apps_login' to 'wp_google_apps_login'.
116
+
117
+ = 2.8.3 =
118
+
119
+ Resolved conflict with some other plugins over Google-related function names.
120
+
121
+ = 2.8.1 =
122
+
123
+ 'Session mismatch' warning should be much less of a problem now.
124
+
125
+ = 2.8 =
126
+
127
+ Session mismatch (could be a problem setting cookies) should now occur less frequently. Service Account can have no admin email (for gmail.com accounts).
128
+
129
+ = 2.7 =
130
+
131
+ Accepts filter gal_client_config_ini containing filesystem path to an INI file to supply to Google's client library on instantiation, so you can override settings.
132
+ Added substitution version core/Google/IO/DebugVersionOfCurl.php to replace core/Google/IO/Curl.php temporarily to log communications to Google's server for debugging purposes.
133
+
134
+ = 2.5.2 =
135
+
136
+ Service Account settings can be uploaded by copy-and-paste of JSON file contents as well as just uploading the file directly.
137
+
138
+ = 2.5 =
139
+
140
+ Platform extended to provide Service Account settings.
141
+
142
+ = 2.4.4 =
143
+
144
+ Readme updates and tidied settings page.
145
+
146
+ = 2.4.3 =
147
+
148
+ New hooks for profile photos. Updated Google client library.
149
+
150
+ = 2.3.1 =
151
+
152
+ Fixed conflicts with some other plugins such as Google Analyticator which use similar Google client libraries.
153
+
154
+ = 2.3 =
155
+
156
+ Better organized config pages.
157
+
158
+ Uses latest Google client library.
159
+
160
+ Option to link to wp-glogin.com from login page.
161
+
162
+ = 2.2 =
163
+
164
+ Fix for an error seen on multisite admin. Added Arabic translation.
165
+
166
+ = 2.1 =
167
+
168
+ New design to support multiple languages. Includes Serbo-Croatian. Fixed some conflicts
169
+ with other plugins when used in 'auto redirect to Google' mode.
170
+
171
+ = 2.0 =
172
+
173
+ Our platform provides centralized setup and management of Google-related features in your
174
+ WordPress site and plugins.
175
+
176
+ Other developers can easily extend our Google authentication into their own plugins.
177
+
178
+ = 1.4 =
179
+
180
+ Added clearer instructions, plus new options: automatically redirect users
181
+ to Login via Google; plus force users to fully approve access to their
182
+ Google account every time they login (allowing them to switch accounts if only
183
+ logged into the wrong one, as well as making the process clearer).
184
+
185
+ = 1.3 =
186
+ Much neater support for redirecting users to most appropriate page post-login,
187
+ especially on multisite installations; Better notices guiding admins through
188
+ configuration
189
+
190
+ = 1.2 =
191
+ Upgrade to match WordPress 3.8;
192
+ More extensible code
193
+
194
+ = 1.1 =
195
+ Increased security - uses an extra authenticity check;
196
+ Better support for mal-configured Google credentials;
197
+ No longer uses PHP-based sessions - will work on even more WordPress configurations
198
+
199
+ = 1.0 =
200
+ All existing versions are functionally identical - no need to upgrade.
201
+
core/Google/Auth/Abstract.php CHANGED
@@ -1,36 +1,37 @@
1
- <?php
2
- /*
3
- * Copyright 2010 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
19
-
20
- /**
21
- * Abstract class for the Authentication in the API client
22
- * @author Chris Chabot <chabotc@google.com>
23
- *
24
- */
25
- abstract class GoogleGAL_Auth_Abstract
26
- {
27
- /**
28
- * An utility function that first calls $this->auth->sign($request) and then
29
- * executes makeRequest() on that signed request. Used for when a request
30
- * should be authenticated
31
- * @param GoogleGAL_Http_Request $request
32
- * @return GoogleGAL_Http_Request $request
33
- */
34
- abstract public function authenticatedRequest(GoogleGAL_Http_Request $request);
35
- abstract public function sign(GoogleGAL_Http_Request $request);
36
- }
 
1
+ <?php
2
+ /*
3
+ * Copyright 2010 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
19
+
20
+ /**
21
+ * Abstract class for the Authentication in the API client
22
+ *
23
+ * @author Chris Chabot <chabotc@google.com>
24
+ */
25
+ abstract class GoogleGAL_Auth_Abstract {
26
+
27
+ /**
28
+ * An utility function that first calls $this->auth->sign($request) and then
29
+ * executes makeRequest() on that signed request. Used for when a request
30
+ * should be authenticated
31
+ *
32
+ * @param GoogleGAL_Http_Request $request
33
+ * @return GoogleGAL_Http_Request $request
34
+ */
35
+ abstract public function authenticatedRequest( GoogleGAL_Http_Request $request);
36
+ abstract public function sign( GoogleGAL_Http_Request $request);
37
+ }
core/Google/Auth/AppIdentity.php CHANGED
@@ -1,105 +1,101 @@
1
- <?php
2
- /*
3
- * Copyright 2014 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- /*
19
- * WARNING - this class depends on the Google App Engine PHP library
20
- * which is 5.3 and above only, so if you include this in a PHP 5.2
21
- * setup or one without 5.3 things will blow up.
22
- */
23
- use google\appengine\api\app_identity\AppIdentityService;
24
-
25
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
26
-
27
- /**
28
- * Authentication via the Google App Engine App Identity service.
29
- */
30
- class GoogleGAL_Auth_AppIdentity extends GoogleGAL_Auth_Abstract
31
- {
32
- const CACHE_PREFIX = "GoogleGAL_Auth_AppIdentity::";
33
- private $key = null;
34
- private $client;
35
- private $token = false;
36
- private $tokenScopes = false;
37
-
38
- public function __construct(GoogleGAL_Client $client, $config = null)
39
- {
40
- $this->client = $client;
41
- }
42
-
43
- /**
44
- * Retrieve an access token for the scopes supplied.
45
- */
46
- public function authenticateForScope($scopes)
47
- {
48
- if ($this->token && $this->tokenScopes == $scopes) {
49
- return $this->token;
50
- }
51
-
52
- $cacheKey = self::CACHE_PREFIX;
53
- if (is_string($scopes)) {
54
- $cacheKey .= $scopes;
55
- } else if (is_array($scopes)) {
56
- $cacheKey .= implode(":", $scopes);
57
- }
58
-
59
- $this->token = $this->client->getCache()->get($cacheKey);
60
- if (!$this->token) {
61
- $this->token = AppIdentityService::getAccessToken($scopes);
62
- if ($this->token) {
63
- $this->client->getCache()->set(
64
- $cacheKey,
65
- $this->token
66
- );
67
- }
68
- }
69
- $this->tokenScopes = $scopes;
70
- return $this->token;
71
- }
72
-
73
- /**
74
- * Perform an authenticated / signed apiHttpRequest.
75
- * This function takes the apiHttpRequest, calls apiAuth->sign on it
76
- * (which can modify the request in what ever way fits the auth mechanism)
77
- * and then calls apiCurlIO::makeRequest on the signed request
78
- *
79
- * @param GoogleGAL_Http_Request $request
80
- * @return GoogleGAL_Http_Request The resulting HTTP response including the
81
- * responseHttpCode, responseHeaders and responseBody.
82
- */
83
- public function authenticatedRequest(GoogleGAL_Http_Request $request)
84
- {
85
- $request = $this->sign($request);
86
- return $this->client->getIo()->makeRequest($request);
87
- }
88
-
89
- public function sign(GoogleGAL_Http_Request $request)
90
- {
91
- if (!$this->token) {
92
- // No token, so nothing to do.
93
- return $request;
94
- }
95
-
96
- $this->client->getLogger()->debug('App Identity authentication');
97
-
98
- // Add the OAuth2 header to the request
99
- $request->setRequestHeaders(
100
- array('Authorization' => 'Bearer ' . $this->token['access_token'])
101
- );
102
-
103
- return $request;
104
- }
105
- }
1
+ <?php
2
+ /*
3
+ * Copyright 2014 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /*
19
+ * WARNING - this class depends on the Google App Engine PHP library
20
+ * which is 5.3 and above only, so if you include this in a PHP 5.2
21
+ * setup or one without 5.3 things will blow up.
22
+ */
23
+ use google\appengine\api\app_identity\AppIdentityService;
24
+
25
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
26
+
27
+ /**
28
+ * Authentication via the Google App Engine App Identity service.
29
+ */
30
+ class GoogleGAL_Auth_AppIdentity extends GoogleGAL_Auth_Abstract {
31
+
32
+ const CACHE_PREFIX = 'GoogleGAL_Auth_AppIdentity::';
33
+ private $key = null;
34
+ private $client;
35
+ private $token = false;
36
+ private $tokenScopes = false;
37
+
38
+ public function __construct( GoogleGAL_Client $client, $config = null ) {
39
+ $this->client = $client;
40
+ }
41
+
42
+ /**
43
+ * Retrieve an access token for the scopes supplied.
44
+ */
45
+ public function authenticateForScope( $scopes ) {
46
+ if ( $this->token && $this->tokenScopes == $scopes ) {
47
+ return $this->token;
48
+ }
49
+
50
+ $cacheKey = self::CACHE_PREFIX;
51
+ if ( is_string( $scopes ) ) {
52
+ $cacheKey .= $scopes;
53
+ } elseif ( is_array( $scopes ) ) {
54
+ $cacheKey .= implode( ':', $scopes );
55
+ }
56
+
57
+ $this->token = $this->client->getCache()->get( $cacheKey );
58
+ if ( ! $this->token ) {
59
+ $this->token = AppIdentityService::getAccessToken( $scopes );
60
+ if ( $this->token ) {
61
+ $this->client->getCache()->set(
62
+ $cacheKey,
63
+ $this->token
64
+ );
65
+ }
66
+ }
67
+ $this->tokenScopes = $scopes;
68
+ return $this->token;
69
+ }
70
+
71
+ /**
72
+ * Perform an authenticated / signed apiHttpRequest.
73
+ * This function takes the apiHttpRequest, calls apiAuth->sign on it
74
+ * (which can modify the request in what ever way fits the auth mechanism)
75
+ * and then calls apiCurlIO::makeRequest on the signed request
76
+ *
77
+ * @param GoogleGAL_Http_Request $request
78
+ * @return GoogleGAL_Http_Request The resulting HTTP response including the
79
+ * responseHttpCode, responseHeaders and responseBody.
80
+ */
81
+ public function authenticatedRequest( GoogleGAL_Http_Request $request ) {
82
+ $request = $this->sign( $request );
83
+ return $this->client->getIo()->makeRequest( $request );
84
+ }
85
+
86
+ public function sign( GoogleGAL_Http_Request $request ) {
87
+ if ( ! $this->token ) {
88
+ // No token, so nothing to do.
89
+ return $request;
90
+ }
91
+
92
+ $this->client->getLogger()->debug( 'App Identity authentication' );
93
+
94
+ // Add the OAuth2 header to the request
95
+ $request->setRequestHeaders(
96
+ array( 'Authorization' => 'Bearer ' . $this->token['access_token'] )
97
+ );
98
+
99
+ return $request;
100
+ }
101
+ }
 
 
 
 
core/Google/Auth/AssertionCredentials.php CHANGED
@@ -1,144 +1,146 @@
1
- <?php
2
- /*
3
- * Copyright 2012 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- *
17
- * Updated by Dan Lester 2014
18
- *
19
- */
20
-
21
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
22
-
23
- /**
24
- * Credentials object used for OAuth 2.0 Signed JWT assertion grants.
25
- *
26
- * @author Chirag Shah <chirags@google.com>
27
- */
28
- class GoogleGAL_Auth_AssertionCredentials
29
- {
30
- const MAX_TOKEN_LIFETIME_SECS = 3600;
31
-
32
- public $serviceAccountName;
33
- public $scopes;
34
- public $privateKey;
35
- public $privateKeyPassword;
36
- public $assertionType;
37
- public $sub;
38
- public $signerClass = 'GoogleGAL_Signer_P12';
39
- /**
40
- * @deprecated
41
- * @link http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
42
- */
43
- public $prn;
44
- private $useCache;
45
-
46
- /**
47
- * @param $serviceAccountName
48
- * @param $scopes array List of scopes
49
- * @param $privateKey
50
- * @param string $privateKeyPassword
51
- * @param string $assertionType
52
- * @param bool|string $sub The email address of the user for which the
53
- * application is requesting delegated access.
54
- * @param bool useCache Whether to generate a cache key and allow
55
- * automatic caching of the generated token.
56
- */
57
- public function __construct(
58
- $serviceAccountName,
59
- $scopes,
60
- $privateKey,
61
- $privateKeyPassword = 'notasecret',
62
- $assertionType = 'http://oauth.net/grant_type/jwt/1.0/bearer',
63
- $sub = false,
64
- $useCache = true
65
- ) {
66
- $this->serviceAccountName = $serviceAccountName;
67
- $this->scopes = is_string($scopes) ? $scopes : implode(' ', $scopes);
68
- $this->privateKey = $privateKey;
69
- $this->privateKeyPassword = $privateKeyPassword;
70
- $this->assertionType = $assertionType;
71
- $this->sub = $sub;
72
- $this->prn = $sub;
73
- $this->useCache = $useCache;
74
- }
75
-
76
- public function setSignerClass($signerClass) {
77
- $this->signerClass = $signerClass;
78
- }
79
-
80
- /**
81
- * Generate a unique key to represent this credential.
82
- * @return string
83
- */
84
- public function getCacheKey()
85
- {
86
- if (!$this->useCache) {
87
- return false;
88
- }
89
- $h = $this->sub;
90
- $h .= $this->assertionType;
91
- $h .= $this->privateKey;
92
- $h .= $this->scopes;
93
- $h .= $this->serviceAccountName;
94
- return md5($h);
95
- }
96
-
97
- public function generateAssertion()
98
- {
99
- $now = time();
100
-
101
- $jwtParams = array(
102
- 'aud' => GoogleGAL_Auth_OAuth2::OAUTH2_TOKEN_URI,
103
- 'scope' => $this->scopes,
104
- 'iat' => $now,
105
- 'exp' => $now + self::MAX_TOKEN_LIFETIME_SECS,
106
- 'iss' => $this->serviceAccountName,
107
- );
108
-
109
- if ($this->sub !== false) {
110
- $jwtParams['sub'] = $this->sub;
111
- } else if ($this->prn !== false) {
112
- $jwtParams['prn'] = $this->prn;
113
- }
114
-
115
- return $this->makeSignedJwt($jwtParams);
116
- }
117
-
118
- /**
119
- * Creates a signed JWT.
120
- * @param array $payload
121
- * @return string The signed JWT.
122
- */
123
- private function makeSignedJwt($payload)
124
- {
125
- $header = array('typ' => 'JWT', 'alg' => 'RS256');
126
-
127
- $payload = json_encode($payload);
128
- // Handle some overzealous escaping in PHP json that seemed to cause some errors
129
- // with claimsets.
130
- $payload = str_replace('\/', '/', $payload);
131
-
132
- $segments = array(
133
- GoogleGAL_Utils::urlSafeB64Encode(json_encode($header)),
134
- GoogleGAL_Utils::urlSafeB64Encode($payload)
135
- );
136
-
137
- $signingInput = implode('.', $segments);
138
- $signer = new $this->signerClass($this->privateKey, $this->privateKeyPassword);
139
- $signature = $signer->sign($signingInput);
140
- $segments[] = GoogleGAL_Utils::urlSafeB64Encode($signature);
141
-
142
- return implode(".", $segments);
143
- }
144
- }
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2012 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ *
17
+ * Updated by Dan Lester 2014
18
+ *
19
+ */
20
+
21
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
22
+
23
+ /**
24
+ * Credentials object used for OAuth 2.0 Signed JWT assertion grants.
25
+ *
26
+ * @author Chirag Shah <chirags@google.com>
27
+ */
28
+ class GoogleGAL_Auth_AssertionCredentials {
29
+
30
+ const MAX_TOKEN_LIFETIME_SECS = 3600;
31
+
32
+ public $serviceAccountName;
33
+ public $scopes;
34
+ public $privateKey;
35
+ public $privateKeyPassword;
36
+ public $assertionType;
37
+ public $sub;
38
+ public $signerClass = 'GoogleGAL_Signer_P12';
39
+ /**
40
+ * @deprecated
41
+ * @link http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
42
+ */
43
+ public $prn;
44
+ private $useCache;
45
+
46
+ /**
47
+ * @param $serviceAccountName
48
+ * @param $scopes array List of scopes
49
+ * @param $privateKey
50
+ * @param string $privateKeyPassword
51
+ * @param string $assertionType
52
+ * @param bool|string $sub The email address of the user for which the
53
+ * application is requesting delegated access.
54
+ * @param bool useCache Whether to generate a cache key and allow
55
+ * automatic caching of the generated token.
56
+ */
57
+ public function __construct(
58
+ $serviceAccountName,
59
+ $scopes,
60
+ $privateKey,
61
+ $privateKeyPassword = 'notasecret',
62
+ $assertionType = 'http://oauth.net/grant_type/jwt/1.0/bearer',
63
+ $sub = false,
64
+ $useCache = true
65
+ ) {
66
+ $this->serviceAccountName = $serviceAccountName;
67
+ $this->scopes = is_string( $scopes ) ? $scopes : implode( ' ', $scopes );
68
+ $this->privateKey = $privateKey;
69
+ $this->privateKeyPassword = $privateKeyPassword;
70
+ $this->assertionType = $assertionType;
71
+ $this->sub = $sub;
72
+ $this->prn = $sub;
73
+ $this->useCache = $useCache;
74
+ }
75
+
76
+ public function setSignerClass( $signerClass ) {
77
+ $this->signerClass = $signerClass;
78
+ }
79
+
80
+ /**
81
+ * Generate a unique key to represent this credential.
82
+ *
83
+ * @return string
84
+ */
85
+ public function getCacheKey() {
86
+ if ( ! $this->useCache ) {
87
+ return false;
88
+ }
89
+ $h = $this->sub;
90
+ $h .= $this->assertionType;
91
+ $h .= $this->privateKey;
92
+ $h .= $this->scopes;
93
+ $h .= $this->serviceAccountName;
94
+ return md5( $h );
95
+ }
96
+
97
+ public function generateAssertion() {
98
+ $now = time();
99
+
100
+ $jwtParams = array(
101
+ 'aud' => GoogleGAL_Auth_OAuth2::OAUTH2_TOKEN_URI,
102
+ 'scope' => $this->scopes,
103
+ 'iat' => $now,
104
+ 'exp' => $now + self::MAX_TOKEN_LIFETIME_SECS,
105
+ 'iss' => $this->serviceAccountName,
106
+ );
107
+
108
+ if ( $this->sub !== false ) {
109
+ $jwtParams['sub'] = $this->sub;
110
+ } elseif ( $this->prn !== false ) {
111
+ $jwtParams['prn'] = $this->prn;
112
+ }
113
+
114
+ return $this->makeSignedJwt( $jwtParams );
115
+ }
116
+
117
+ /**
118
+ * Creates a signed JWT.
119
+ *
120
+ * @param array $payload
121
+ * @return string The signed JWT.
122
+ */
123
+ private function makeSignedJwt( $payload ) {
124
+ $header = array(
125
+ 'typ' => 'JWT',
126
+ 'alg' => 'RS256',
127
+ );
128
+
129
+ $payload = json_encode( $payload );
130
+ // Handle some overzealous escaping in PHP json that seemed to cause some errors
131
+ // with claimsets.
132
+ $payload = str_replace( '\/', '/', $payload );
133
+
134
+ $segments = array(
135
+ GoogleGAL_Utils::urlSafeB64Encode( json_encode( $header ) ),
136
+ GoogleGAL_Utils::urlSafeB64Encode( $payload ),
137
+ );
138
+
139
+ $signingInput = implode( '.', $segments );
140
+ $signer = new $this->signerClass( $this->privateKey, $this->privateKeyPassword );
141
+ $signature = $signer->sign( $signingInput );
142
+ $segments[] = GoogleGAL_Utils::urlSafeB64Encode( $signature );
143
+
144
+ return implode( '.', $segments );
145
+ }
146
+ }
core/Google/Auth/Exception.php CHANGED
@@ -1,22 +1,22 @@
1
- <?php
2
- /*
3
- * Copyright 2013 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
19
-
20
- class GoogleGAL_Auth_Exception extends GoogleGAL_Exception
21
- {
22
- }
1
+ <?php
2
+ /*
3
+ * Copyright 2013 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
19
+
20
+ class GoogleGAL_Auth_Exception extends GoogleGAL_Exception {
21
+
22
+ }
core/Google/Auth/LoginTicket.php CHANGED
@@ -1,69 +1,71 @@
1
- <?php
2
- /*
3
- * Copyright 2011 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
19
-
20
- /**
21
- * Class to hold information about an authenticated login.
22
- *
23
- * @author Brian Eaton <beaton@google.com>
24
- */
25
- class GoogleGAL_Auth_LoginTicket
26
- {
27
- const USER_ATTR = "sub";
28
-
29
- // Information from id token envelope.
30
- private $envelope;
31
-
32
- // Information from id token payload.
33
- private $payload;
34
-
35
- /**
36
- * Creates a user based on the supplied token.
37
- *
38
- * @param string $envelope Header from a verified authentication token.
39
- * @param string $payload Information from a verified authentication token.
40
- */
41
- public function __construct($envelope, $payload)
42
- {
43
- $this->envelope = $envelope;
44
- $this->payload = $payload;
45
- }
46
-
47
- /**
48
- * Returns the numeric identifier for the user.
49
- * @throws GoogleGAL_Auth_Exception
50
- * @return
51
- */
52
- public function getUserId()
53
- {
54
- if (array_key_exists(self::USER_ATTR, $this->payload)) {
55
- return $this->payload[self::USER_ATTR];
56
- }
57
- throw new GoogleGAL_Auth_Exception("No user_id in token");
58
- }
59
-
60
- /**
61
- * Returns attributes from the login ticket. This can contain
62
- * various information about the user session.
63
- * @return array
64
- */
65
- public function getAttributes()
66
- {
67
- return array("envelope" => $this->envelope, "payload" => $this->payload);
68
- }
69
- }
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2011 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
19
+
20
+ /**
21
+ * Class to hold information about an authenticated login.
22
+ *
23
+ * @author Brian Eaton <beaton@google.com>
24
+ */
25
+ class GoogleGAL_Auth_LoginTicket {
26
+
27
+ const USER_ATTR = 'sub';
28
+
29
+ // Information from id token envelope.
30
+ private $envelope;
31
+
32
+ // Information from id token payload.
33
+ private $payload;
34
+
35
+ /**
36
+ * Creates a user based on the supplied token.
37
+ *
38
+ * @param string $envelope Header from a verified authentication token.
39
+ * @param string $payload Information from a verified authentication token.
40
+ */
41
+ public function __construct( $envelope, $payload ) {
42
+ $this->envelope = $envelope;
43
+ $this->payload = $payload;
44
+ }
45
+
46
+ /**
47
+ * Returns the numeric identifier for the user.
48
+ *
49
+ * @throws GoogleGAL_Auth_Exception
50
+ * @return
51
+ */
52
+ public function getUserId() {
53
+ if ( array_key_exists( self::USER_ATTR, $this->payload ) ) {
54
+ return $this->payload[ self::USER_ATTR ];
55
+ }
56
+ throw new GoogleGAL_Auth_Exception( 'No user_id in token' );
57
+ }
58
+
59
+ /**
60
+ * Returns attributes from the login ticket. This can contain
61
+ * various information about the user session.
62
+ *
63
+ * @return array
64
+ */
65
+ public function getAttributes() {
66
+ return array(
67
+ 'envelope' => $this->envelope,
68
+ 'payload' => $this->payload,
69
+ );
70
+ }
71
+ }
core/Google/Auth/OAuth2.php CHANGED
@@ -1,629 +1,614 @@
1
- <?php
2
- /*
3
- * Copyright 2008 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
19
-
20
- /**
21
- * Authentication class that deals with the OAuth 2 web-server authentication flow
22
- *
23
- * @author Chris Chabot <chabotc@google.com>
24
- * @author Chirag Shah <chirags@google.com>
25
- *
26
- */
27
- class GoogleGAL_Auth_OAuth2 extends GoogleGAL_Auth_Abstract
28
- {
29
- const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
30
- const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token';
31
- const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
32
- const CLOCK_SKEW_SECS = 300; // five minutes in seconds
33
- const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds
34
- const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds
35
- const OAUTH2_ISSUER = 'accounts.google.com';
36
-
37
- /** @var GoogleGAL_Auth_AssertionCredentials $assertionCredentials */
38
- private $assertionCredentials;
39
-
40
- /**
41
- * @var string The state parameters for CSRF and other forgery protection.
42
- */
43
- private $state;
44
-
45
- /**
46
- * @var array The token bundle.
47
- */
48
- private $token = array();
49
-
50
- /**
51
- * @var GoogleGAL_Client the base client
52
- */
53
- private $client;
54
-
55
- /**
56
- * Instantiates the class, but does not initiate the login flow, leaving it
57
- * to the discretion of the caller.
58
- */
59
- public function __construct(GoogleGAL_Client $client)
60
- {
61
- $this->client = $client;
62
- }
63
-
64
- /**
65
- * Perform an authenticated / signed apiHttpRequest.
66
- * This function takes the apiHttpRequest, calls apiAuth->sign on it
67
- * (which can modify the request in what ever way fits the auth mechanism)
68
- * and then calls apiCurlIO::makeRequest on the signed request
69
- *
70
- * @param GoogleGAL_Http_Request $request
71
- * @return GoogleGAL_Http_Request The resulting HTTP response including the
72
- * responseHttpCode, responseHeaders and responseBody.
73
- */
74
- public function authenticatedRequest(GoogleGAL_Http_Request $request)
75
- {
76
- $request = $this->sign($request);
77
- return $this->client->getIo()->makeRequest($request);
78
- }
79
-
80
- /**
81
- * @param string $code
82
- * @throws GoogleGAL_Auth_Exception
83
- * @return string
84
- */
85
- public function authenticate($code)
86
- {
87
- if (strlen($code) == 0) {
88
- throw new GoogleGAL_Auth_Exception("Invalid code");
89
- }
90
-
91
- // We got here from the redirect from a successful authorization grant,
92
- // fetch the access token
93
- $request = new GoogleGAL_Http_Request(
94
- self::OAUTH2_TOKEN_URI,
95
- 'POST',
96
- array(),
97
- array(
98
- 'code' => $code,
99
- 'grant_type' => 'authorization_code',
100
- 'redirect_uri' => $this->client->getClassConfig($this, 'redirect_uri'),
101
- 'client_id' => $this->client->getClassConfig($this, 'client_id'),
102
- 'client_secret' => $this->client->getClassConfig($this, 'client_secret')
103
- )
104
- );
105
- $request->disableGzip();
106
- $response = $this->client->getIo()->makeRequest($request);
107
-
108
- if ($response->getResponseHttpCode() == 200) {
109
- $this->setAccessToken($response->getResponseBody());
110
- $this->token['created'] = time();
111
- return $this->getAccessToken();
112
- } else {
113
- $decodedResponse = json_decode($response->getResponseBody(), true);
114
- if ($decodedResponse != null && $decodedResponse['error']) {
115
- $errorText = $decodedResponse['error'];
116
- if (isset($decodedResponse['error_description'])) {
117
- $errorText .= ": " . $decodedResponse['error_description'];
118
- }
119
- }
120
- throw new GoogleGAL_Auth_Exception(
121
- sprintf(
122
- "Error fetching OAuth2 access token, message: '%s'",
123
- $errorText
124
- ),
125
- $response->getResponseHttpCode()
126
- );
127
- }
128
- }
129
-
130
- /**
131
- * Create a URL to obtain user authorization.
132
- * The authorization endpoint allows the user to first
133
- * authenticate, and then grant/deny the access request.
134
- * @param string $scope The scope is expressed as a list of space-delimited strings.
135
- * @return string
136
- */
137
- public function createAuthUrl($scope)
138
- {
139
- $params = array(
140
- 'response_type' => 'code',
141
- 'redirect_uri' => $this->client->getClassConfig($this, 'redirect_uri'),
142
- 'client_id' => $this->client->getClassConfig($this, 'client_id'),
143
- 'scope' => $scope,
144
- 'access_type' => $this->client->getClassConfig($this, 'access_type'),
145
- );
146
-
147
- // Prefer prompt to approval prompt.
148
- $params = $this->maybeAddParam($params, 'prompt');
149
- $params = $this->maybeAddParam($params, 'login_hint');
150
- $params = $this->maybeAddParam($params, 'hd');
151
- $params = $this->maybeAddParam($params, 'openid.realm');
152
- $params = $this->maybeAddParam($params, 'include_granted_scopes');
153
-
154
- // If the list of scopes contains plus.login, add request_visible_actions
155
- // to auth URL.
156
- $rva = $this->client->getClassConfig($this, 'request_visible_actions');
157
- if (strpos($scope, 'plus.login') && strlen($rva) > 0) {
158
- $params['request_visible_actions'] = $rva;
159
- }
160
-
161
- if (isset($this->state)) {
162
- $params['state'] = $this->state;
163
- }
164
-
165
- return self::OAUTH2_AUTH_URL . "?" . http_build_query($params, '', '&');
166
- }
167
-
168
- /**
169
- * @param string $token
170
- * @throws GoogleGAL_Auth_Exception
171
- */
172
- public function setAccessToken($token)
173
- {
174
- $token = json_decode($token, true);
175
- if ($token == null) {
176
- throw new GoogleGAL_Auth_Exception('Could not json decode the token');
177
- }
178
- if (! isset($token['access_token'])) {
179
- throw new GoogleGAL_Auth_Exception("Invalid token format");
180
- }
181
- $this->token = $token;
182
- }
183
-
184
- public function getAccessToken()
185
- {
186
- return json_encode($this->token);
187
- }
188
-
189
- public function getRefreshToken()
190
- {
191
- if (array_key_exists('refresh_token', $this->token)) {
192
- return $this->token['refresh_token'];
193
- } else {
194
- return null;
195
- }
196
- }
197
-
198
- public function setState($state)
199
- {
200
- $this->state = $state;
201
- }
202
-
203
- public function setAssertionCredentials(GoogleGAL_Auth_AssertionCredentials $creds)
204
- {
205
- $this->assertionCredentials = $creds;
206
- }
207
-
208
- /**
209
- * Include an accessToken in a given apiHttpRequest.
210
- * @param GoogleGAL_Http_Request $request
211
- * @return GoogleGAL_Http_Request
212
- * @throws GoogleGAL_Auth_Exception
213
- */
214
- public function sign(GoogleGAL_Http_Request $request)
215
- {
216
- // add the developer key to the request before signing it
217
- if ($this->client->getClassConfig($this, 'developer_key')) {
218
- $request->setQueryParam('key', $this->client->getClassConfig($this, 'developer_key'));
219
- }
220
-
221
- // Cannot sign the request without an OAuth access token.
222
- if (null == $this->token && null == $this->assertionCredentials) {
223
- return $request;
224
- }
225
-
226
- // Check if the token is set to expire in the next 30 seconds
227
- // (or has already expired).
228
- if ($this->isAccessTokenExpired()) {
229
- if ($this->assertionCredentials) {
230
- $this->refreshTokenWithAssertion();
231
- } else {
232
- $this->client->getLogger()->debug('OAuth2 access token expired');
233
- if (! array_key_exists('refresh_token', $this->token)) {
234
- $error = "The OAuth 2.0 access token has expired,"
235
- ." and a refresh token is not available. Refresh tokens"
236
- ." are not returned for responses that were auto-approved.";
237
-
238
- $this->client->getLogger()->error($error);
239
- throw new GoogleGAL_Auth_Exception($error);
240
- }
241
- $this->refreshToken($this->token['refresh_token']);
242
- }
243
- }
244
-
245
- $this->client->getLogger()->debug('OAuth2 authentication');
246
-
247
- // Add the OAuth2 header to the request
248
- $request->setRequestHeaders(
249
- array('Authorization' => 'Bearer ' . $this->token['access_token'])
250
- );
251
-
252
- return $request;
253
- }
254
-
255
- /**
256
- * Fetches a fresh access token with the given refresh token.
257
- * @param string $refreshToken
258
- * @return void
259
- */
260
- public function refreshToken($refreshToken)
261
- {
262
- $this->refreshTokenRequest(
263
- array(
264
- 'client_id' => $this->client->getClassConfig($this, 'client_id'),
265
- 'client_secret' => $this->client->getClassConfig($this, 'client_secret'),
266
- 'refresh_token' => $refreshToken,
267
- 'grant_type' => 'refresh_token'
268
- )
269
- );
270
- }
271
-
272
- /**
273
- * Fetches a fresh access token with a given assertion token.
274
- * @param GoogleGAL_Auth_AssertionCredentials $assertionCredentials optional.
275
- * @return void
276
- */
277
- public function refreshTokenWithAssertion($assertionCredentials = null)
278
- {
279
- if (!$assertionCredentials) {
280
- $assertionCredentials = $this->assertionCredentials;
281
- }
282
-
283
- $cacheKey = $assertionCredentials->getCacheKey();
284
-
285
- if ($cacheKey) {
286
- // We can check whether we have a token available in the
287
- // cache. If it is expired, we can retrieve a new one from
288
- // the assertion.
289
- $token = $this->client->getCache()->get($cacheKey);
290
- if ($token) {
291
- $this->setAccessToken($token);
292
- }
293
- if (!$this->isAccessTokenExpired()) {
294
- return;
295
- }
296
- }
297
-
298
- $this->client->getLogger()->debug('OAuth2 access token expired');
299
- $this->refreshTokenRequest(
300
- array(
301
- 'grant_type' => 'assertion',
302
- 'assertion_type' => $assertionCredentials->assertionType,
303
- 'assertion' => $assertionCredentials->generateAssertion(),
304
- )
305
- );
306
-
307
- if ($cacheKey) {
308
- // Attempt to cache the token.
309
- $this->client->getCache()->set(
310
- $cacheKey,
311
- $this->getAccessToken()
312
- );
313
- }
314
- }
315
-
316
- private function refreshTokenRequest($params)
317
- {
318
- if (isset($params['assertion'])) {
319
- $this->client->getLogger()->info(
320
- 'OAuth2 access token refresh with Signed JWT assertion grants.'
321
- );
322
- } else {
323
- $this->client->getLogger()->info('OAuth2 access token refresh');
324
- }
325
-
326
- $http = new GoogleGAL_Http_Request(
327
- self::OAUTH2_TOKEN_URI,
328
- 'POST',
329
- array(),
330
- $params
331
- );
332
- $http->disableGzip();
333
- $request = $this->client->getIo()->makeRequest($http);
334
-
335
- $code = $request->getResponseHttpCode();
336
- $body = $request->getResponseBody();
337
- if (200 == $code) {
338
- $token = json_decode($body, true);
339
- if ($token == null) {
340
- throw new GoogleGAL_Auth_Exception("Could not json decode the access token");
341
- }
342
-
343
- if (! isset($token['access_token']) || ! isset($token['expires_in'])) {
344
- throw new GoogleGAL_Auth_Exception("Invalid token format");
345
- }
346
-
347
- if (isset($token['id_token'])) {
348
- $this->token['id_token'] = $token['id_token'];
349
- }
350
- $this->token['access_token'] = $token['access_token'];
351
- $this->token['expires_in'] = $token['expires_in'];
352
- $this->token['created'] = time();
353
- } else {
354
- throw new GoogleGAL_Auth_Exception("Error refreshing the OAuth2 token, message: '$body'", $code);
355
- }
356
- }
357
-
358
- /**
359
- * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
360
- * token, if a token isn't provided.
361
- * @throws GoogleGAL_Auth_Exception
362
- * @param string|null $token The token (access token or a refresh token) that should be revoked.
363
- * @return boolean Returns True if the revocation was successful, otherwise False.
364
- */
365
- public function revokeToken($token = null)
366
- {
367
- if (!$token) {
368
- if (!$this->token) {
369
- // Not initialized, no token to actually revoke
370
- return false;
371
- } elseif (array_key_exists('refresh_token', $this->token)) {
372
- $token = $this->token['refresh_token'];
373
- } else {
374
- $token = $this->token['access_token'];
375
- }
376
- }
377
- $request = new GoogleGAL_Http_Request(
378
- self::OAUTH2_REVOKE_URI,
379
- 'POST',
380
- array(),
381
- "token=$token"
382
- );
383
- $request->disableGzip();
384
- $response = $this->client->getIo()->makeRequest($request);
385
- $code = $response->getResponseHttpCode();
386
- if ($code == 200) {
387
- $this->token = null;
388
- return true;
389
- }
390
-
391
- return false;
392
- }
393
-
394
- /**
395
- * Returns if the access_token is expired.
396
- * @return bool Returns True if the access_token is expired.
397
- */
398
- public function isAccessTokenExpired()
399
- {
400
- if (!$this->token || !isset($this->token['created'])) {
401
- return true;
402
- }
403
-
404
- // If the token is set to expire in the next 30 seconds.
405
- $expired = ($this->token['created']
406
- + ($this->token['expires_in'] - 30)) < time();
407
-
408
- return $expired;
409
- }
410
-
411
- // Gets federated sign-on certificates to use for verifying identity tokens.
412
- // Returns certs as array structure, where keys are key ids, and values
413
- // are PEM encoded certificates.
414
- private function getFederatedSignOnCerts()
415
- {
416
- return $this->retrieveCertsFromLocation(
417
- $this->client->getClassConfig($this, 'federated_signon_certs_url')
418
- );
419
- }
420
-
421
- /**
422
- * Retrieve and cache a certificates file.
423
- *
424
- * @param $url string location
425
- * @throws GoogleGAL_Auth_Exception
426
- * @return array certificates
427
- */
428
- public function retrieveCertsFromLocation($url)
429
- {
430
- // If we're retrieving a local file, just grab it.
431
- if ("http" != substr($url, 0, 4)) {
432
- $file = file_get_contents($url);
433
- if ($file) {
434
- return json_decode($file, true);
435
- } else {
436
- throw new GoogleGAL_Auth_Exception(
437
- "Failed to retrieve verification certificates: '" .
438
- $url . "'."
439
- );
440
- }
441
- }
442
-
443
- // This relies on makeRequest caching certificate responses.
444
- $request = $this->client->getIo()->makeRequest(
445
- new GoogleGAL_Http_Request(
446
- $url
447
- )
448
- );
449
- if ($request->getResponseHttpCode() == 200) {
450
- $certs = json_decode($request->getResponseBody(), true);
451
- if ($certs) {
452
- return $certs;
453
- }
454
- }
455
- throw new GoogleGAL_Auth_Exception(
456
- "Failed to retrieve verification certificates: '" .
457
- $request->getResponseBody() . "'.",
458
- $request->getResponseHttpCode()
459
- );
460
- }
461
-
462
- /**
463
- * Verifies an id token and returns the authenticated apiLoginTicket.
464
- * Throws an exception if the id token is not valid.
465
- * The audience parameter can be used to control which id tokens are
466
- * accepted. By default, the id token must have been issued to this OAuth2 client.
467
- *
468
- * @param $id_token
469
- * @param $audience
470
- * @return GoogleGAL_Auth_LoginTicket
471
- */
472
- public function verifyIdToken($id_token = null, $audience = null)
473
- {
474
- if (!$id_token) {
475
- $id_token = $this->token['id_token'];
476
- }
477
- $certs = $this->getFederatedSignonCerts();
478
- if (!$audience) {
479
- $audience = $this->client->getClassConfig($this, 'client_id');
480
- }
481
-
482
- return $this->verifySignedJwtWithCerts($id_token, $certs, $audience, self::OAUTH2_ISSUER);
483
- }
484
-
485
- /**
486
- * Verifies the id token, returns the verified token contents.
487
- *
488
- * @param $jwt string the token
489
- * @param $certs array of certificates
490
- * @param $required_audience string the expected consumer of the token
491
- * @param [$issuer] the expected issues, defaults to Google
492
- * @param [$max_expiry] the max lifetime of a token, defaults to MAX_TOKEN_LIFETIME_SECS
493
- * @throws GoogleGAL_Auth_Exception
494
- * @return mixed token information if valid, false if not
495
- */
496
- public function verifySignedJwtWithCerts(
497
- $jwt,
498
- $certs,
499
- $required_audience,
500
- $issuer = null,
501
- $max_expiry = null
502
- ) {
503
- if (!$max_expiry) {
504
- // Set the maximum time we will accept a token for.
505
- $max_expiry = self::MAX_TOKEN_LIFETIME_SECS;
506
- }
507
-
508
- $segments = explode(".", $jwt);
509
- if (count($segments) != 3) {
510
- throw new GoogleGAL_Auth_Exception("Wrong number of segments in token: $jwt");
511
- }
512
- $signed = $segments[0] . "." . $segments[1];
513
- $signature = GoogleGAL_Utils::urlSafeB64Decode($segments[2]);
514
-
515
- // Parse envelope.
516
- $envelope = json_decode(GoogleGAL_Utils::urlSafeB64Decode($segments[0]), true);
517
- if (!$envelope) {
518
- throw new GoogleGAL_Auth_Exception("Can't parse token envelope: " . $segments[0]);
519
- }
520
-
521
- // Parse token
522
- $json_body = GoogleGAL_Utils::urlSafeB64Decode($segments[1]);
523
- $payload = json_decode($json_body, true);
524
- if (!$payload) {
525
- throw new GoogleGAL_Auth_Exception("Can't parse token payload: " . $segments[1]);
526
- }
527
-
528
- // Check signature
529
- $verified = false;
530
- foreach ($certs as $keyName => $pem) {
531
- $public_key = new GoogleGAL_Verifier_Pem($pem);
532
- if ($public_key->verify($signed, $signature)) {
533
- $verified = true;
534
- break;
535
- }
536
- }
537
-
538
- if (!$verified) {
539
- throw new GoogleGAL_Auth_Exception("Invalid token signature: $jwt");
540
- }
541
-
542
- // Check issued-at timestamp
543
- $iat = 0;
544
- if (array_key_exists("iat", $payload)) {
545
- $iat = $payload["iat"];
546
- }
547
- if (!$iat) {
548
- throw new GoogleGAL_Auth_Exception("No issue time in token: $json_body");
549
- }
550
- $earliest = $iat - self::CLOCK_SKEW_SECS;
551
-
552
- // Check expiration timestamp
553
- $now = time();
554
- $exp = 0;
555
- if (array_key_exists("exp", $payload)) {
556
- $exp = $payload["exp"];
557
- }
558
- if (!$exp) {
559
- throw new GoogleGAL_Auth_Exception("No expiration time in token: $json_body");
560
- }
561
- if ($exp >= $now + $max_expiry) {
562
- throw new GoogleGAL_Auth_Exception(
563
- sprintf("Expiration time too far in future: %s", $json_body)
564
- );
565
- }
566
-
567
- $latest = $exp + self::CLOCK_SKEW_SECS;
568
- if ($now < $earliest) {
569
- throw new GoogleGAL_Auth_Exception(
570
- sprintf(
571
- "Token used too early, %s < %s: %s",
572
- $now,
573
- $earliest,
574
- $json_body
575
- )
576
- );
577
- }
578
- if ($now > $latest) {
579
- throw new GoogleGAL_Auth_Exception(
580
- sprintf(
581
- "Token used too late, %s > %s: %s",
582
- $now,
583
- $latest,
584
- $json_body
585
- )
586
- );
587
- }
588
-
589
- $iss = $payload['iss'];
590
- if ($issuer && $iss != $issuer) {
591
- throw new GoogleGAL_Auth_Exception(
592
- sprintf(
593
- "Invalid issuer, %s != %s: %s",
594
- $iss,
595
- $issuer,
596
- $json_body
597
- )
598
- );
599
- }
600
-
601
- // Check audience
602
- $aud = $payload["aud"];
603
- if ($aud != $required_audience) {
604
- throw new GoogleGAL_Auth_Exception(
605
- sprintf(
606
- "Wrong recipient, %s != %s:",
607
- $aud,
608
- $required_audience,
609
- $json_body
610
- )
611
- );
612
- }
613
-
614
- // All good.
615
- return new GoogleGAL_Auth_LoginTicket($envelope, $payload);
616
- }
617
-
618
- /**
619
- * Add a parameter to the auth params if not empty string.
620
- */
621
- private function maybeAddParam($params, $name)
622
- {
623
- $param = $this->client->getClassConfig($this, $name);
624
- if ($param != '') {
625
- $params[$name] = $param;
626
- }
627
- return $params;
628
- }
629
- }
1
+ <?php
2
+ /*
3
+ * Copyright 2008 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
19
+
20
+ /**
21
+ * Authentication class that deals with the OAuth 2 web-server authentication flow
22
+ *
23
+ * @author Chris Chabot <chabotc@google.com>
24
+ * @author Chirag Shah <chirags@google.com>
25
+ */
26
+ class GoogleGAL_Auth_OAuth2 extends GoogleGAL_Auth_Abstract {
27
+
28
+ const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
29
+ const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token';
30
+ const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
31
+ const CLOCK_SKEW_SECS = 300; // five minutes in seconds
32
+ const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds
33
+ const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds
34
+ const OAUTH2_ISSUER = 'accounts.google.com';
35
+
36
+ /** @var GoogleGAL_Auth_AssertionCredentials $assertionCredentials */
37
+ private $assertionCredentials;
38
+
39
+ /**
40
+ * @var string The state parameters for CSRF and other forgery protection.
41
+ */
42
+ private $state;
43
+
44
+ /**
45
+ * @var array The token bundle.
46
+ */
47
+ private $token = array();
48
+
49
+ /**
50
+ * @var GoogleGAL_Client the base client
51
+ */
52
+ private $client;
53
+
54
+ /**
55
+ * Instantiates the class, but does not initiate the login flow, leaving it
56
+ * to the discretion of the caller.
57
+ */
58
+ public function __construct( GoogleGAL_Client $client ) {
59
+ $this->client = $client;
60
+ }
61
+
62
+ /**
63
+ * Perform an authenticated / signed apiHttpRequest.
64
+ * This function takes the apiHttpRequest, calls apiAuth->sign on it
65
+ * (which can modify the request in what ever way fits the auth mechanism)
66
+ * and then calls apiCurlIO::makeRequest on the signed request
67
+ *
68
+ * @param GoogleGAL_Http_Request $request
69
+ * @return GoogleGAL_Http_Request The resulting HTTP response including the
70
+ * responseHttpCode, responseHeaders and responseBody.
71
+ */
72
+ public function authenticatedRequest( GoogleGAL_Http_Request $request ) {
73
+ $request = $this->sign( $request );
74
+ return $this->client->getIo()->makeRequest( $request );
75
+ }
76
+
77
+ /**
78
+ * @param string $code
79
+ * @throws GoogleGAL_Auth_Exception
80
+ * @return string
81
+ */
82
+ public function authenticate( $code ) {
83
+ if ( strlen( $code ) == 0 ) {
84
+ throw new GoogleGAL_Auth_Exception( 'Invalid code' );
85
+ }
86
+
87
+ // We got here from the redirect from a successful authorization grant,
88
+ // fetch the access token
89
+ $request = new GoogleGAL_Http_Request(
90
+ self::OAUTH2_TOKEN_URI,
91
+ 'POST',
92
+ array(),
93
+ array(
94
+ 'code' => $code,
95
+ 'grant_type' => 'authorization_code',
96
+ 'redirect_uri' => $this->client->getClassConfig( $this, 'redirect_uri' ),
97
+ 'client_id' => $this->client->getClassConfig( $this, 'client_id' ),
98
+ 'client_secret' => $this->client->getClassConfig( $this, 'client_secret' ),
99
+ )
100
+ );
101
+ $request->disableGzip();
102
+ $response = $this->client->getIo()->makeRequest( $request );
103
+
104
+ if ( $response->getResponseHttpCode() == 200 ) {
105
+ $this->setAccessToken( $response->getResponseBody() );
106
+ $this->token['created'] = time();
107
+ return $this->getAccessToken();
108
+ } else {
109
+ $decodedResponse = json_decode( $response->getResponseBody(), true );
110
+ if ( $decodedResponse != null && $decodedResponse['error'] ) {
111
+ $errorText = $decodedResponse['error'];
112
+ if ( isset( $decodedResponse['error_description'] ) ) {
113
+ $errorText .= ': ' . $decodedResponse['error_description'];
114
+ }
115
+ }
116
+ throw new GoogleGAL_Auth_Exception(
117
+ sprintf(
118
+ "Error fetching OAuth2 access token, message: '%s'",
119
+ $errorText
120
+ ),
121
+ $response->getResponseHttpCode()
122
+ );
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Create a URL to obtain user authorization.
128
+ * The authorization endpoint allows the user to first
129
+ * authenticate, and then grant/deny the access request.
130
+ *
131
+ * @param string $scope The scope is expressed as a list of space-delimited strings.
132
+ * @return string
133
+ */
134
+ public function createAuthUrl( $scope ) {
135
+ $params = array(
136
+ 'response_type' => 'code',
137
+ 'redirect_uri' => $this->client->getClassConfig( $this, 'redirect_uri' ),
138
+ 'client_id' => $this->client->getClassConfig( $this, 'client_id' ),
139
+ 'scope' => $scope,
140
+ 'access_type' => $this->client->getClassConfig( $this, 'access_type' ),
141
+ );
142
+
143
+ // Prefer prompt to approval prompt.
144
+ $params = $this->maybeAddParam( $params, 'prompt' );
145
+ $params = $this->maybeAddParam( $params, 'login_hint' );
146
+ $params = $this->maybeAddParam( $params, 'hd' );
147
+ $params = $this->maybeAddParam( $params, 'openid.realm' );
148
+ $params = $this->maybeAddParam( $params, 'include_granted_scopes' );
149
+
150
+ // If the list of scopes contains plus.login, add request_visible_actions
151
+ // to auth URL.
152
+ $rva = $this->client->getClassConfig( $this, 'request_visible_actions' );
153
+ if ( strpos( $scope, 'plus.login' ) && strlen( $rva ) > 0 ) {
154
+ $params['request_visible_actions'] = $rva;
155
+ }
156
+
157
+ if ( isset( $this->state ) ) {
158
+ $params['state'] = $this->state;
159
+ }
160
+
161
+ return self::OAUTH2_AUTH_URL . '?' . http_build_query( $params, '', '&' );
162
+ }
163
+
164
+ /**
165
+ * @param string $token
166
+ * @throws GoogleGAL_Auth_Exception
167
+ */
168
+ public function setAccessToken( $token ) {
169
+ $token = json_decode( $token, true );
170
+ if ( $token == null ) {
171
+ throw new GoogleGAL_Auth_Exception( 'Could not json decode the token' );
172
+ }
173
+ if ( ! isset( $token['access_token'] ) ) {
174
+ throw new GoogleGAL_Auth_Exception( 'Invalid token format' );
175
+ }
176
+ $this->token = $token;
177
+ }
178
+
179
+ public function getAccessToken() {
180
+ return json_encode( $this->token );
181
+ }
182
+
183
+ public function getRefreshToken() {
184
+ if ( array_key_exists( 'refresh_token', $this->token ) ) {
185
+ return $this->token['refresh_token'];
186
+ } else {
187
+ return null;
188
+ }
189
+ }
190
+
191
+ public function setState( $state ) {
192
+ $this->state = $state;
193
+ }
194
+
195
+ public function setAssertionCredentials( GoogleGAL_Auth_AssertionCredentials $creds ) {
196
+ $this->assertionCredentials = $creds;
197
+ }
198
+
199
+ /**
200
+ * Include an accessToken in a given apiHttpRequest.
201
+ *
202
+ * @param GoogleGAL_Http_Request $request
203
+ * @return GoogleGAL_Http_Request
204
+ * @throws GoogleGAL_Auth_Exception
205
+ */
206
+ public function sign( GoogleGAL_Http_Request $request ) {
207
+ // add the developer key to the request before signing it
208
+ if ( $this->client->getClassConfig( $this, 'developer_key' ) ) {
209
+ $request->setQueryParam( 'key', $this->client->getClassConfig( $this, 'developer_key' ) );
210
+ }
211
+
212
+ // Cannot sign the request without an OAuth access token.
213
+ if ( null == $this->token && null == $this->assertionCredentials ) {
214
+ return $request;
215
+ }
216
+
217
+ // Check if the token is set to expire in the next 30 seconds
218
+ // (or has already expired).
219
+ if ( $this->isAccessTokenExpired() ) {
220
+ if ( $this->assertionCredentials ) {
221
+ $this->refreshTokenWithAssertion();
222
+ } else {
223
+ $this->client->getLogger()->debug( 'OAuth2 access token expired' );
224
+ if ( ! array_key_exists( 'refresh_token', $this->token ) ) {
225
+ $error = 'The OAuth 2.0 access token has expired,'
226
+ . ' and a refresh token is not available. Refresh tokens'
227
+ . ' are not returned for responses that were auto-approved.';
228
+
229
+ $this->client->getLogger()->error( $error );
230
+ throw new GoogleGAL_Auth_Exception( $error );
231
+ }
232
+ $this->refreshToken( $this->token['refresh_token'] );
233
+ }
234
+ }
235
+
236
+ $this->client->getLogger()->debug( 'OAuth2 authentication' );
237
+
238
+ // Add the OAuth2 header to the request
239
+ $request->setRequestHeaders(
240
+ array( 'Authorization' => 'Bearer ' . $this->token['access_token'] )
241
+ );
242
+
243
+ return $request;
244
+ }
245
+
246
+ /**
247
+ * Fetches a fresh access token with the given refresh token.
248
+ *
249
+ * @param string $refreshToken
250
+ * @return void
251
+ */
252
+ public function refreshToken( $refreshToken ) {
253
+ $this->refreshTokenRequest(
254
+ array(
255
+ 'client_id' => $this->client->getClassConfig( $this, 'client_id' ),
256
+ 'client_secret' => $this->client->getClassConfig( $this, 'client_secret' ),
257
+ 'refresh_token' => $refreshToken,
258
+ 'grant_type' => 'refresh_token',
259
+ )
260
+ );
261
+ }
262
+
263
+ /**
264
+ * Fetches a fresh access token with a given assertion token.
265
+ *
266
+ * @param GoogleGAL_Auth_AssertionCredentials $assertionCredentials optional.
267
+ * @return void
268
+ */
269
+ public function refreshTokenWithAssertion( $assertionCredentials = null ) {
270
+ if ( ! $assertionCredentials ) {
271
+ $assertionCredentials = $this->assertionCredentials;
272
+ }
273
+
274
+ $cacheKey = $assertionCredentials->getCacheKey();
275
+
276
+ if ( $cacheKey ) {
277
+ // We can check whether we have a token available in the
278
+ // cache. If it is expired, we can retrieve a new one from
279
+ // the assertion.
280
+ $token = $this->client->getCache()->get( $cacheKey );
281
+ if ( $token ) {
282
+ $this->setAccessToken( $token );
283
+ }
284
+ if ( ! $this->isAccessTokenExpired() ) {
285
+ return;
286
+ }
287
+ }
288
+
289
+ $this->client->getLogger()->debug( 'OAuth2 access token expired' );
290
+ $this->refreshTokenRequest(
291
+ array(
292
+ 'grant_type' => 'assertion',
293
+ 'assertion_type' => $assertionCredentials->assertionType,
294
+ 'assertion' => $assertionCredentials->generateAssertion(),
295
+ )
296
+ );
297
+
298
+ if ( $cacheKey ) {
299
+ // Attempt to cache the token.
300
+ $this->client->getCache()->set(
301
+ $cacheKey,
302
+ $this->getAccessToken()
303
+ );
304
+ }
305
+ }
306
+
307
+ private function refreshTokenRequest( $params ) {
308
+ if ( isset( $params['assertion'] ) ) {
309
+ $this->client->getLogger()->info(
310
+ 'OAuth2 access token refresh with Signed JWT assertion grants.'
311
+ );
312
+ } else {
313
+ $this->client->getLogger()->info( 'OAuth2 access token refresh' );
314
+ }
315
+
316
+ $http = new GoogleGAL_Http_Request(
317
+ self::OAUTH2_TOKEN_URI,
318
+ 'POST',
319
+ array(),
320
+ $params
321
+ );
322
+ $http->disableGzip();
323
+ $request = $this->client->getIo()->makeRequest( $http );
324
+
325
+ $code = $request->getResponseHttpCode();
326
+ $body = $request->getResponseBody();
327
+ if ( 200 == $code ) {
328
+ $token = json_decode( $body, true );
329
+ if ( $token == null ) {
330
+ throw new GoogleGAL_Auth_Exception( 'Could not json decode the access token' );
331
+ }
332
+
333
+ if ( ! isset( $token['access_token'] ) || ! isset( $token['expires_in'] ) ) {
334
+ throw new GoogleGAL_Auth_Exception( 'Invalid token format' );
335
+ }
336
+
337
+ if ( isset( $token['id_token'] ) ) {
338
+ $this->token['id_token'] = $token['id_token'];
339
+ }
340
+ $this->token['access_token'] = $token['access_token'];
341
+ $this->token['expires_in'] = $token['expires_in'];
342
+ $this->token['created'] = time();
343
+ } else {
344
+ throw new GoogleGAL_Auth_Exception( "Error refreshing the OAuth2 token, message: '$body'", $code );
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
350
+ * token, if a token isn't provided.
351
+ *
352
+ * @throws GoogleGAL_Auth_Exception
353
+ * @param string|null $token The token (access token or a refresh token) that should be revoked.
354
+ * @return boolean Returns True if the revocation was successful, otherwise False.
355
+ */
356
+ public function revokeToken( $token = null ) {
357
+ if ( ! $token ) {
358
+ if ( ! $this->token ) {
359
+ // Not initialized, no token to actually revoke
360
+ return false;
361
+ } elseif ( array_key_exists( 'refresh_token', $this->token ) ) {
362
+ $token = $this->token['refresh_token'];
363
+ } else {
364
+ $token = $this->token['access_token'];
365
+ }
366
+ }
367
+ $request = new GoogleGAL_Http_Request(
368
+ self::OAUTH2_REVOKE_URI,
369
+ 'POST',
370
+ array(),
371
+ "token=$token"
372
+ );
373
+ $request->disableGzip();
374
+ $response = $this->client->getIo()->makeRequest( $request );
375
+ $code = $response->getResponseHttpCode();
376
+ if ( $code == 200 ) {
377
+ $this->token = null;
378
+ return true;
379
+ }
380
+
381
+ return false;
382
+ }
383
+
384
+ /**
385
+ * Returns if the access_token is expired.
386
+ *
387
+ * @return bool Returns True if the access_token is expired.
388
+ */
389
+ public function isAccessTokenExpired() {
390
+ if ( ! $this->token || ! isset( $this->token['created'] ) ) {
391
+ return true;
392
+ }
393
+
394
+ // If the token is set to expire in the next 30 seconds.
395
+ $expired = ( $this->token['created']
396
+ + ( $this->token['expires_in'] - 30 ) ) < time();
397
+
398
+ return $expired;
399
+ }
400
+
401
+ // Gets federated sign-on certificates to use for verifying identity tokens.
402
+ // Returns certs as array structure, where keys are key ids, and values
403
+ // are PEM encoded certificates.
404
+ private function getFederatedSignOnCerts() {
405
+ return $this->retrieveCertsFromLocation(
406
+ $this->client->getClassConfig( $this, 'federated_signon_certs_url' )
407
+ );
408
+ }
409
+ /**
410
+ * Retrieve and cache a certificates file.
411
+ *
412
+ * @param $url string location
413
+ * @throws GoogleGAL_Auth_Exception
414
+ * @return array certificates
415
+ */
416
+ public function retrieveCertsFromLocation( $url ) {
417
+ // If we're retrieving a local file, just grab it.
418
+ if ( 'http' != substr( $url, 0, 4 ) ) {
419
+ $file = file_get_contents( $url );
420
+ if ( $file ) {
421
+ return json_decode( $file, true );
422
+ } else {
423
+ throw new GoogleGAL_Auth_Exception(
424
+ "Failed to retrieve verification certificates: '" .
425
+ $url . "'."
426
+ );
427
+ }
428
+ }
429
+
430
+ // This relies on makeRequest caching certificate responses.
431
+ $request = $this->client->getIo()->makeRequest(
432
+ new GoogleGAL_Http_Request(
433
+ $url
434
+ )
435
+ );
436
+ if ( $request->getResponseHttpCode() == 200 ) {
437
+ $certs = json_decode( $request->getResponseBody(), true );
438
+ if ( $certs ) {
439
+ return $certs;
440
+ }
441
+ }
442
+ throw new GoogleGAL_Auth_Exception(
443
+ "Failed to retrieve verification certificates: '" .
444
+ $request->getResponseBody() . "'.",
445
+ $request->getResponseHttpCode()
446
+ );
447
+ }
448
+
449
+ /**
450
+ * Verifies an id token and returns the authenticated apiLoginTicket.
451
+ * Throws an exception if the id token is not valid.
452
+ * The audience parameter can be used to control which id tokens are
453
+ * accepted. By default, the id token must have been issued to this OAuth2 client.
454
+ *
455
+ * @param $id_token
456
+ * @param $audience
457
+ * @return GoogleGAL_Auth_LoginTicket
458
+ */
459
+ public function verifyIdToken( $id_token = null, $audience = null ) {
460
+ if ( ! $id_token ) {
461
+ $id_token = $this->token['id_token'];
462
+ }
463
+ $certs = $this->getFederatedSignonCerts();
464
+ if ( ! $audience ) {
465
+ $audience = $this->client->getClassConfig( $this, 'client_id' );
466
+ }
467
+
468
+ return $this->verifySignedJwtWithCerts( $id_token, $certs, $audience, self::OAUTH2_ISSUER );
469
+ }
470
+
471
+ /**
472
+ * Verifies the id token, returns the verified token contents.
473
+ *
474
+ * @param $jwt string the token
475
+ * @param $certs array of certificates
476
+ * @param $required_audience string the expected consumer of the token
477
+ * @param [ $issuer] the expected issues, defaults to Google
478
+ * @param [ $max_expiry] the max lifetime of a token, defaults to MAX_TOKEN_LIFETIME_SECS
479
+ * @throws GoogleGAL_Auth_Exception
480
+ * @return mixed token information if valid, false if not
481
+ */
482
+ public function verifySignedJwtWithCerts(
483
+ $jwt,
484
+ $certs,
485
+ $required_audience,
486
+ $issuer = null,
487
+ $max_expiry = null
488
+ ) {
489
+ if ( ! $max_expiry ) {
490
+ // Set the maximum time we will accept a token for.
491
+ $max_expiry = self::MAX_TOKEN_LIFETIME_SECS;
492
+ }
493
+
494
+ $segments = explode( '.', $jwt );
495
+ if ( count( $segments ) != 3 ) {
496
+ throw new GoogleGAL_Auth_Exception( "Wrong number of segments in token: $jwt" );
497
+ }
498
+ $signed = $segments[0] . '.' . $segments[1];
499
+ $signature = GoogleGAL_Utils::urlSafeB64Decode( $segments[2] );
500
+
501
+ // Parse envelope.
502
+ $envelope = json_decode( GoogleGAL_Utils::urlSafeB64Decode( $segments[0] ), true );
503
+ if ( ! $envelope ) {
504
+ throw new GoogleGAL_Auth_Exception( "Can't parse token envelope: " . $segments[0] );
505
+ }
506
+
507
+ // Parse token
508
+ $json_body = GoogleGAL_Utils::urlSafeB64Decode( $segments[1] );
509
+ $payload = json_decode( $json_body, true );
510
+ if ( ! $payload ) {
511
+ throw new GoogleGAL_Auth_Exception( "Can't parse token payload: " . $segments[1] );
512
+ }
513
+
514
+ // Check signature
515
+ $verified = false;
516
+ foreach ( $certs as $keyName => $pem ) {
517
+ $public_key = new GoogleGAL_Verifier_Pem( $pem );
518
+ if ( $public_key->verify( $signed, $signature ) ) {
519
+ $verified = true;
520
+ break;
521
+ }
522
+ }
523
+
524
+ if ( ! $verified ) {
525
+ throw new GoogleGAL_Auth_Exception( "Invalid token signature: $jwt" );
526
+ }
527
+
528
+ // Check issued-at timestamp
529
+ $iat = 0;
530
+ if ( array_key_exists( 'iat', $payload ) ) {
531
+ $iat = $payload['iat'];
532
+ }
533
+ if ( ! $iat ) {
534
+ throw new GoogleGAL_Auth_Exception( "No issue time in token: $json_body" );
535
+ }
536
+ $earliest = $iat - self::CLOCK_SKEW_SECS;
537
+
538
+ // Check expiration timestamp
539
+ $now = time();
540
+ $exp = 0;
541
+ if ( array_key_exists( 'exp', $payload ) ) {
542
+ $exp = $payload['exp'];
543
+ }
544
+ if ( ! $exp ) {
545
+ throw new GoogleGAL_Auth_Exception( "No expiration time in token: $json_body" );
546
+ }
547
+ if ( $exp >= $now + $max_expiry ) {
548
+ throw new GoogleGAL_Auth_Exception(
549
+ sprintf( 'Expiration time too far in future: %s', $json_body )
550
+ );
551
+ }
552
+
553
+ $latest = $exp + self::CLOCK_SKEW_SECS;
554
+ if ( $now < $earliest ) {
555
+ throw new GoogleGAL_Auth_Exception(
556
+ sprintf(
557
+ 'Token used too early, %s < %s: %s',
558
+ $now,
559
+ $earliest,
560
+ $json_body
561
+ )
562
+ );
563
+ }
564
+ if ( $now > $latest ) {
565
+ throw new GoogleGAL_Auth_Exception(
566
+ sprintf(
567
+ 'Token used too late, %s > %s: %s',
568
+ $now,
569
+ $latest,
570
+ $json_body
571
+ )
572
+ );
573
+ }
574
+
575
+ $iss = $payload['iss'];
576
+ if ( $issuer && $iss != $issuer ) {
577
+ throw new GoogleGAL_Auth_Exception(
578
+ sprintf(
579
+ 'Invalid issuer, %s != %s: %s',
580
+ $iss,
581
+ $issuer,
582
+ $json_body
583
+ )
584
+ );
585
+ }
586
+
587
+ // Check audience
588
+ $aud = $payload['aud'];
589
+ if ( $aud != $required_audience ) {
590
+ throw new GoogleGAL_Auth_Exception(
591
+ sprintf(
592
+ 'Wrong recipient, %s != %s:',
593
+ $aud,
594
+ $required_audience,
595
+ $json_body
596
+ )
597
+ );
598
+ }
599
+
600
+ // All good.
601
+ return new GoogleGAL_Auth_LoginTicket( $envelope, $payload );
602
+ }
603
+
604
+ /**
605
+ * Add a parameter to the auth params if not empty string.
606
+ */
607
+ private function maybeAddParam( $params, $name ) {
608
+ $param = $this->client->getClassConfig( $this, $name );
609
+ if ( $param != '' ) {
610
+ $params[ $name ] = $param;
611
+ }
612
+ return $params;
613
+ }
614
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
core/Google/Auth/Simple.php CHANGED
@@ -1,64 +1,62 @@
1
- <?php
2
- /*
3
- * Copyright 2010 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- require_once realpath(dirname(__FILE__) . '/../../../autoload.php');
19
-
20
- /**
21
- * Simple API access implementation. Can either be used to make requests
22
- * completely unauthenticated, or by using a Simple API Access developer
23
- * key.
24
- * @author Chris Chabot <chabotc@google.com>
25
- * @author Chirag Shah <chirags@google.com>
26
- */
27
- class GoogleGAL_Auth_Simple extends GoogleGAL_Auth_Abstract
28
- {
29
- private $key = null;
30
- private $client;
31
-
32
- public function __construct(GoogleGAL_Client $client, $config = null)
33
- {
34
- $this->client = $client;
35
- }
36
-
37
- /**
38
- * Perform an authenticated / signed apiHttpRequest.
39
- * This function takes the apiHttpRequest, calls apiAuth->sign on it
40
- * (which can modify the request in what ever way fits the auth mechanism)
41
- * and then calls apiCurlIO::makeRequest on the signed request
42
- *
43
- * @param GoogleGAL_Http_Request $request
44
- * @return GoogleGAL_Http_Request The resulting HTTP response including the
45
- * responseHttpCode, responseHeaders and responseBody.
46
- */
47
- public function authenticatedRequest(GoogleGAL_Http_Request $request)
48
- {
49
- $request = $this->sign($request);
50
- return $this->io->makeRequest($request);
51
- }
52
-
53
- public function sign(GoogleGAL_Http_Request $request)
54
- {
55
- $key = $this->client->getClassConfig($this, 'developer_key');
56
- if ($key) {
57
- $this->client->getLogger()->debug(
58
- 'Simple API Access developer key authentication'
59
- );
60
- $request->setQueryParam('key', $key);
61
- }
62
- return $request;
63
- }
64
- }
1
+ <?php
2
+ /*
3
+ * Copyright 2010 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ require_once realpath( dirname( __FILE__ ) . '/../../../autoload.php' );
19
+
20
+ /**
21
+ * Simple API access implementation. Can either be used to make requests
22
+ * completely unauthenticated, or by using a Simple API Access developer
23
+ * key.
24
+ *
25
+ * @author Chris Chabot <chabotc@google.com>
26
+ * @author Chirag Shah <chirags@google.com>
27
+ */
28
+ class GoogleGAL_Auth_Simple extends GoogleGAL_Auth_Abstract {
29
+
30
+ private $key = null;
31
+ private $client;
32
+
33
+ public function __construct( GoogleGAL_Client $client, $config = null ) {
34
+ $this->client = $client;
35
+ }
36
+
37
+ /**
38
+ * Perform an authenticated / signed apiHttpRequest.
39
+ * This function takes the apiHttpRequest, calls apiAuth->sign on it
40
+ * (which can modify the request in what ever way fits the auth mechanism)
41
+ * and then calls apiCurlIO::makeRequest on the signed request
42
+ *
43
+ * @param GoogleGAL_Http_Request $request
44
+ * @return GoogleGAL_Http_Request The resulting HTTP response including the
45
+ * responseHttpCode, responseHeaders and responseBody.
46
+ */
47
+ public function authenticatedRequest( GoogleGAL_Http_Request $request ) {
48
+ $request = $this->sign( $request );
49
+ return $this->io->makeRequest( $request );
50
+ }
51
+
52
+ public function sign( GoogleGAL_Http_Request $request ) {
53
+ $key = $this->client->getClassConfig( $this, 'developer_key' );
54
+ if ( $key ) {
55
+ $this->client->getLogger()->debug(
56
+ 'Simple API Access developer key authentication'
57
+ );
58
+ $request->setQueryParam( 'key', $key );
59
+ }
60
+ return $request;
61
+ }
62
+ }
 
 
core/Google/Cache/Abstract.php CHANGED
@@ -1,53 +1,52 @@
1
- <?php
2
- /*
3
- * Copyright 2008 Google Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
-
18
- /**
19
- * Abstract storage class
20
- *
21
- * @author Chris Chabot <chabotc@google.com>
22
- */
23
- abstract class GoogleGAL_Cache_Abstract
24
- {
25
-
26
- abstract public function __construct(GoogleGAL_Client $client);
27
-
28
- /**
29
- * Retrieves the data for the given key, or false if they
30
- * key is unknown or expired
31
- *
32
- * @param String $key The key who's data to retrieve
33
- * @param boolean|int $expiration Expiration time in seconds
34
- *
35
- */
36
- abstract public function get($key, $expiration = false);
37
-
38
- /**
39
- * Store the key => $value set. The $value is serialized
40
- * by this function so can be of any type
41
- *
42
- * @param string $key Key of the data
43
- * @param string $value data
44
- */
45
- abstract public function set($key, $value);
46
-
47
- /**
48
- * Removes the key/data pair for the given $key
49
- *
50
- * @param String $key
51
- */
52
- abstract public function delete($key);
53
- }
1
+ <?php
2
+ /*
3
+ * Copyright 2008 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * Abstract storage class
20
+ *
21
+ * @author Chris Chabot <chabotc@google.com>
22
+ */
23
+ abstract class GoogleGAL_Cache_Abstract {
24
+
25
+
26
+ abstract public function __construct( GoogleGAL_Client $client);
27
+
28
+ /**
29
+ * Retrieves the data for the given key, or false if they
30
+ * key is unknown or expired
31
+ *
32
+ * @param String $key The key who's data to retrieve
33
+ * @param boolean|int $expiration Expiration time in seconds
34
+