Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Created November 18, 2021 12:42
Show Gist options
  • Save salrashid123/e5fc03761f62ef6ff213ac3b29661967 to your computer and use it in GitHub Desktop.
Save salrashid123/e5fc03761f62ef6ff213ac3b29661967 to your computer and use it in GitHub Desktop.
const { GoogleAuth, OAuth2Client, Impersonated } = require('google-auth-library');
const { Storage } = require('@google-cloud/storage');
async function main() {
const scopes = 'https://www.googleapis.com/auth/cloud-platform'
// get source credentials
const auth = new GoogleAuth({
scopes: scopes
});
const client = await auth.getClient();
// First impersonate
let targetPrincipal = '[email protected]'
let targetClient = new Impersonated({
sourceClient: client,
targetPrincipal: targetPrincipal,
lifetime: 30,
delegates: [],
targetScopes: [scopes]
});
let projectId = 'fabled-ray-104117'
let bucketName = 'fabled-ray-104117-test'
// now construct workaround to use GCS client library
const oauth2Client = new OAuth2Client();
oauth2Client.refreshHandler = async () => {
const refreshedAccessToken = await targetClient.getAccessToken();
return {
access_token: refreshedAccessToken.token,
expiry_date: refreshedAccessToken.expirationTime,
};
};
// inject the oauth2client into the StorageOptions override
// for the access_token and the sign() override as well
const storageOptions = {
projectId,
authClient: {
getCredentials: async () => {
return {
client_email : targetPrincipal
}
},
request: opts => {
return oauth2Client.request(opts);
},
sign: (blobToSign) => {
return targetClient.sign(blobToSign);
},
authorizeRequest: async opts => {
opts = opts || {};
const url = opts.url || opts.uri;
const headers = await oauth2Client.getRequestHeaders(url);
opts.headers = Object.assign(opts.headers || {}, headers);
return opts;
},
},
};
const storage = new Storage(storageOptions);
// use the gcs client to get an object
const file = storage.bucket(bucketName).file('foo.txt');
await file.download(function (err, contents) {
console.log("file err: " + err);
console.log("file data: " + contents);
});
// now use the gcs client to sign a url
const options = {
version: 'v4',
action: 'read',
expires: Date.now() + 10 * 60 * 1000,
};
const [signed_url] = await storage
.bucket('fabled-ray-104117-test')
.file('foo.txt')
.getSignedUrl(options);
console.log(signed_url)
const authHeaders = await targetClient.getRequestHeaders();
const url = 'https://storage.googleapis.com/storage/v1/b/' + bucketName + '/o/foo.txt'
const resp = await targetClient.request({ url });
console.log(resp.data);
}
main().catch(console.error);
@salrashid123
Copy link
Author

note, this workaround uses a sign() interface that i added in manually here
node_modules/google-auth-library/build/src/auth/impersonated.js

    /**
     * Signs some bytes.
     * @param blobToSign Sign bytes.
     */
     async sign(blobToSign) {

        try {
            await this.sourceClient.getAccessToken();
            const name = 'projects/-/serviceAccounts/' + this.targetPrincipal;
            const u = `${this.endpoint}/v1/${name}:signBlob`;
            const body = {
                payload: Buffer.from(blobToSign).toString('base64')
            };
            const res = await this.sourceClient.request({
                url: u,
                data: body,
                method: 'POST',
            });
            const tokenResponse = res.data;
            return tokenResponse.signedBlob
        }
        catch (error) {

        }
    }    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment