1<?php 2/* 3 * Copyright 2019 Google LLC 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 * http://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 18namespace Google\Auth; 19 20use Google\Auth\HttpHandler\HttpClientCache; 21use Google\Auth\HttpHandler\HttpHandlerFactory; 22use GuzzleHttp\Psr7; 23use GuzzleHttp\Psr7\Utils; 24 25/** 26 * Tools for using the IAM API. 27 * 28 * @see https://cloud.google.com/iam/docs IAM Documentation 29 */ 30class Iam 31{ 32 const IAM_API_ROOT = 'https://iamcredentials.googleapis.com/v1'; 33 const SIGN_BLOB_PATH = '%s:signBlob?alt=json'; 34 const SERVICE_ACCOUNT_NAME = 'projects/-/serviceAccounts/%s'; 35 36 /** 37 * @var callable 38 */ 39 private $httpHandler; 40 41 /** 42 * @param callable $httpHandler [optional] The HTTP Handler to send requests. 43 */ 44 public function __construct(callable $httpHandler = null) 45 { 46 $this->httpHandler = $httpHandler 47 ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient()); 48 } 49 50 /** 51 * Sign a string using the IAM signBlob API. 52 * 53 * Note that signing using IAM requires your service account to have the 54 * `iam.serviceAccounts.signBlob` permission, part of the "Service Account 55 * Token Creator" IAM role. 56 * 57 * @param string $email The service account email. 58 * @param string $accessToken An access token from the service account. 59 * @param string $stringToSign The string to be signed. 60 * @param array<string> $delegates [optional] A list of service account emails to 61 * add to the delegate chain. If omitted, the value of `$email` will 62 * be used. 63 * @return string The signed string, base64-encoded. 64 */ 65 public function signBlob($email, $accessToken, $stringToSign, array $delegates = []) 66 { 67 $httpHandler = $this->httpHandler; 68 $name = sprintf(self::SERVICE_ACCOUNT_NAME, $email); 69 $uri = self::IAM_API_ROOT . '/' . sprintf(self::SIGN_BLOB_PATH, $name); 70 71 if ($delegates) { 72 foreach ($delegates as &$delegate) { 73 $delegate = sprintf(self::SERVICE_ACCOUNT_NAME, $delegate); 74 } 75 } else { 76 $delegates = [$name]; 77 } 78 79 $body = [ 80 'delegates' => $delegates, 81 'payload' => base64_encode($stringToSign), 82 ]; 83 84 $headers = [ 85 'Authorization' => 'Bearer ' . $accessToken 86 ]; 87 88 $request = new Psr7\Request( 89 'POST', 90 $uri, 91 $headers, 92 Utils::streamFor(json_encode($body)) 93 ); 94 95 $res = $httpHandler($request); 96 $body = json_decode((string) $res->getBody(), true); 97 98 return $body['signedBlob']; 99 } 100} 101