Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS SDK v3 support #13

Open
trangvu9 opened this issue Apr 13, 2023 · 5 comments
Open

AWS SDK v3 support #13

trangvu9 opened this issue Apr 13, 2023 · 5 comments

Comments

@trangvu9
Copy link

trangvu9 commented Apr 13, 2023

Any roadmap to migrate to AWS SDK V3?

Please migrate your code to use AWS SDK for JavaScript (v3).                                                  
For more information, check the migration guide at https://a.co/7PzMCcy                                       
     at emitWarning (/data/.../node_modules/aws-sdk/lib/maintenance_mode_message.js:37:13)                
     at Timeout._onTimeout (/data/.../node_modules/aws-sdk/lib/maintenance_mode_message.js:45:5)
@bernd-yomali
Copy link

I am also facing this issue

@higherorderfunctor
Copy link

higherorderfunctor commented Oct 8, 2023

I was able to hack one up in typescript for non-temporary access keys (no tokens) using only v3 APIs. Needs additional work, but might start as a base.

/* eslint-disable max-classes-per-file */
import { Sha256 } from '@aws-crypto/sha256-js';
import { createScope, SignatureV4 } from '@smithy/signature-v4';
import { auth, Client as Cassandra } from 'cassandra-driver';
import { createHash } from 'crypto';
import fs from 'fs';
import _ from 'lodash';


class SigV4Authenticator implements auth.Authenticator {
    private readonly region: string;

    private readonly accessKeyId: string;

    private readonly secretAccessKey: string;

    public static readonly AWS4_SIGNING_ALGORITHM = 'AWS4-HMAC-SHA256';

    constructor(props: { region: string; accessKeyId: string; secretAccessKey: string }) {
        this.region = props.region;
        this.accessKeyId = props.accessKeyId;
        this.secretAccessKey = props.secretAccessKey;
    }

    /* Calling class expects to be a method, so cannot make static even though it is a static function */
    /* eslint-disable-next-line class-methods-use-this */
    initialResponse = (callback: (error: Error | null, buffer: Buffer | null) => void): void => {
        callback(null, Buffer.from('SigV4\0\0', 'utf8'));
    };

    private static handleError =
        (callback: (error: Error | null, buffer: Buffer | null) => void) =>
        (err: unknown): void => {
            callback(_.isError(err) ? err : new Error(JSON.stringify(err)), null);
        };

    private handleSignature =
        (timestamp: string, callback: (error: Error | null, buffer: Buffer | null) => void) =>
        (signature: string): void => {
            const payload = `signature=${signature},access_key=${this.accessKeyId},amzdate=${timestamp}`;
            callback(null, Buffer.from(payload, 'utf-8'));
        };

    evaluateChallenge = (challenge: Buffer, callback: (error: Error | null, buffer: Buffer | null) => void) => {
        const res = challenge.toString().split('nonce=');
        if (res.length < 2) {
            callback(new Error(`could not parse nonce: ${challenge.toString()}`), null);
            return;
        }
        const nonce = res[1].split(',')[0];
        const timestamp = new Date().toISOString();
        /* eslint-disable-next-line no-useless-escape */
        const timestampDate = timestamp.replace(/[:\-]|\.\d{3}/g, '').slice(0, 8);
        const nonceHash = Buffer.from(createHash('sha256').update(nonce, 'utf-8').digest()).toString('hex');
        const scope = createScope(timestampDate, this.region, 'cassandra');
        const headers = [
            `X-Amz-Algorithm=${SigV4Authenticator.AWS4_SIGNING_ALGORITHM}`,
            `X-Amz-Credential=${this.accessKeyId}%2F${encodeURIComponent(scope)}`,
            `X-Amz-Date=${encodeURIComponent(timestamp)}`,
            'X-Amz-Expires=900',
        ].sort();
        const canonicalRequest = `PUT\n/authenticate\n${headers.join('&')}\nhost:cassandra\n\nhost\n${nonceHash}`;
        const digest = Buffer.from(createHash('sha256').update(canonicalRequest, 'utf-8').digest()).toString('hex');
        const stringToSign = `${SigV4Authenticator.AWS4_SIGNING_ALGORITHM}\n${timestamp}\n${scope}\n${digest}`;
        const signer = new SignatureV4({
            service: 'cassandra',
            region: this.region,
            credentials: {
                accessKeyId: this.accessKeyId,
                secretAccessKey: this.secretAccessKey,
            },
            sha256: Sha256,
        });
        signer
            .sign(stringToSign)
            .then(this.handleSignature(timestamp, callback))
            .catch(SigV4Authenticator.handleError(callback));
    };

    /* Calling class expects to be a method, so cannot make static even though it is a static function */
    /* eslint-disable-next-line class-methods-use-this */
    onAuthenticationSuccess = (): void => {};
}

class SigV4AuthProvider implements auth.AuthProvider {
    private readonly region: string;

    private readonly accessKeyId: string;

    private readonly secretAccessKey: string;

    constructor(props: { region?: string; accessKeyId: string; secretAccessKey: string }) {
        Object.setPrototypeOf(this, auth.PlainTextAuthProvider.prototype);
        const region = props.region || process.env.AWS_REGION;
        if (_.isNil(region)) throw new Error('no AWS region specified');
        this.region = region;
        this.accessKeyId = props.accessKeyId;
        this.secretAccessKey = props.secretAccessKey;
    }

    newAuthenticator = (): auth.Authenticator =>
        new SigV4Authenticator({
            region: this.region,
            accessKeyId: this.accessKeyId,
            secretAccessKey: this.secretAccessKey,
        });
}

const client = new Cassandra({
    contactPoints: ['cassandra.us-east-1.amazonaws.com'],
    localDataCenter: 'us-east-1',
    authProvider: new SigV4AuthProvider({
        region: 'us-east-1',
        accessKeyId: '<REDACTED>',
        secretAccessKey: '<REDACTED>',
    }),
    sslOptions: {
        ca: [fs.readFileSync('/home/<REDACTED>/.cassandra/sf-class2-root.crt', 'utf-8')],
        host: 'cassandra.us-east-1.amazonaws.com',
        rejectUnauthorized: true,
    },
    protocolOptions: { port: 9142 },
});

const query = 'SELECT * FROM system_schema.keyspaces';

client.execute(query).then((result) => console.log('Row from Keyspaces:', result));

@fredarend
Copy link

2024 and this issue is still open.

@bhoudu
Copy link

bhoudu commented Mar 21, 2024

is there any news about that?

@bhoudu
Copy link

bhoudu commented Feb 4, 2025

2025 no update at all, is it dead AWS?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants