|
42 | 42 | use League\OAuth2\Server\Grant\PasswordGrant;
|
43 | 43 | use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
44 | 44 | use League\OAuth2\Server\ResourceServer;
|
| 45 | +use RuntimeException; |
| 46 | +use Throwable; |
45 | 47 |
|
46 | 48 | final class Server
|
47 | 49 | {
|
| 50 | + private const PRIVATE_KEY_PATH = GLPI_CONFIG_DIR . '/oauth.pem'; |
| 51 | + private const PUBLIC_KEY_PATH = GLPI_CONFIG_DIR . '/oauth.pub'; |
| 52 | + |
48 | 53 | /**
|
49 | 54 | * @var ClientRepository
|
50 | 55 | */
|
@@ -177,43 +182,94 @@ public static function getScopeDescriptions(): array
|
177 | 182 |
|
178 | 183 | public static function generateKeys(): void
|
179 | 184 | {
|
180 |
| - $private_key_path = GLPI_CONFIG_DIR . '/oauth.pem'; |
181 |
| - $public_key_path = GLPI_CONFIG_DIR . '/oauth.pub'; |
182 |
| - if (!file_exists($private_key_path) && !file_exists($public_key_path)) { |
183 |
| - $config = [ |
184 |
| - 'digest_alg' => 'sha512', |
185 |
| - 'private_key_bits' => 2048, |
186 |
| - 'private_key_type' => OPENSSL_KEYTYPE_RSA, |
187 |
| - ]; |
188 |
| - $success = false; |
189 |
| - $error = null; |
190 |
| - $res = openssl_pkey_new($config); |
191 |
| - if ($res && openssl_pkey_export_to_file($res, $private_key_path)) { |
192 |
| - // Export public key to the public key file |
193 |
| - $pubkey = openssl_pkey_get_details($res); |
194 |
| - if ($pubkey !== false && file_put_contents($public_key_path, $pubkey['key']) === strlen($pubkey['key'])) { |
195 |
| - if (chmod($private_key_path, 0o660) && chmod($public_key_path, 0o660)) { |
196 |
| - $success = true; |
197 |
| - } else { |
198 |
| - $error = 'Unable to set permissions on the generated keys'; |
199 |
| - } |
200 |
| - } else { |
201 |
| - $error = 'Unable to export public key'; |
202 |
| - } |
203 |
| - } else { |
204 |
| - $error = 'Unable to generate keys'; |
205 |
| - } |
206 |
| - |
207 |
| - if (!$success) { |
208 |
| - // Key files didn't exist before and an error occured. We should try removing any that were created to be able to retry later |
209 |
| - if (file_exists($private_key_path)) { |
210 |
| - unlink($private_key_path); |
211 |
| - } |
212 |
| - if (file_exists($public_key_path)) { |
213 |
| - unlink($public_key_path); |
214 |
| - } |
215 |
| - throw new \RuntimeException($error); |
216 |
| - } |
| 185 | + if ( |
| 186 | + file_exists(self::PRIVATE_KEY_PATH) |
| 187 | + && file_exists(self::PUBLIC_KEY_PATH) |
| 188 | + ) { |
| 189 | + // Keys are already generated |
| 190 | + return; |
| 191 | + } |
| 192 | + |
| 193 | + // Partial data: unsure how to proceed, let the user review the files. |
| 194 | + if ( |
| 195 | + file_exists(self::PRIVATE_KEY_PATH) |
| 196 | + && !file_exists(self::PUBLIC_KEY_PATH) |
| 197 | + ) { |
| 198 | + throw new RuntimeException("Mising file: " . self::PUBLIC_KEY_PATH); |
| 199 | + } |
| 200 | + if ( |
| 201 | + file_exists(self::PUBLIC_KEY_PATH) |
| 202 | + && !file_exists(self::PRIVATE_KEY_PATH) |
| 203 | + ) { |
| 204 | + throw new RuntimeException("Mising file: " . self::PRIVATE_KEY_PATH); |
| 205 | + } |
| 206 | + |
| 207 | + // If we reach this point, both file are missing and must be generated |
| 208 | + try { |
| 209 | + // Generate keys |
| 210 | + self::doGenerateKeys(); |
| 211 | + } catch (Throwable $e) { |
| 212 | + // Make sure we don't save any partially generated data |
| 213 | + self::deleteKeys(); |
| 214 | + |
| 215 | + // Propagate exception |
| 216 | + throw $e; |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + private static function doGenerateKeys(): void |
| 221 | + { |
| 222 | + $config = [ |
| 223 | + 'digest_alg' => 'sha512', |
| 224 | + 'private_key_bits' => 2048, |
| 225 | + 'private_key_type' => OPENSSL_KEYTYPE_RSA, |
| 226 | + ]; |
| 227 | + |
| 228 | + // Generate key |
| 229 | + $key = openssl_pkey_new($config); |
| 230 | + if ($key === false) { |
| 231 | + $error = openssl_error_string(); |
| 232 | + throw new RuntimeException("Unable to generate keys: $error"); |
| 233 | + } |
| 234 | + |
| 235 | + // Export private key to file |
| 236 | + if (!openssl_pkey_export_to_file($key, self::PRIVATE_KEY_PATH)) { |
| 237 | + $error = openssl_error_string(); |
| 238 | + throw new RuntimeException("Unable to export private key: $error"); |
| 239 | + } |
| 240 | + |
| 241 | + // Get public key |
| 242 | + $pubkey = openssl_pkey_get_details($key); |
| 243 | + if ($pubkey === false) { |
| 244 | + $error = openssl_error_string(); |
| 245 | + throw new RuntimeException("Unable to get public key details: $error"); |
| 246 | + } |
| 247 | + |
| 248 | + // Export public key to file |
| 249 | + $written_bytes = file_put_contents(self::PUBLIC_KEY_PATH, $pubkey['key']); |
| 250 | + if ( |
| 251 | + $written_bytes === false |
| 252 | + || $written_bytes !== strlen($pubkey['key']) |
| 253 | + ) { |
| 254 | + throw new RuntimeException('Unable to export public key'); |
| 255 | + } |
| 256 | + |
| 257 | + // Set permisisons to both key files |
| 258 | + if ( |
| 259 | + !chmod(self::PRIVATE_KEY_PATH, 0o660) |
| 260 | + || !chmod(self::PUBLIC_KEY_PATH, 0o660) |
| 261 | + ) { |
| 262 | + throw new RuntimeException('Unable to set permissions on the generated keys'); |
| 263 | + } |
| 264 | + } |
| 265 | + |
| 266 | + private static function deleteKeys(): void |
| 267 | + { |
| 268 | + if (file_exists(self::PRIVATE_KEY_PATH)) { |
| 269 | + unlink(self::PRIVATE_KEY_PATH); |
| 270 | + } |
| 271 | + if (file_exists(self::PUBLIC_KEY_PATH)) { |
| 272 | + unlink(self::PUBLIC_KEY_PATH); |
217 | 273 | }
|
218 | 274 | }
|
219 | 275 | }
|
0 commit comments