Skip to content

Commit

Permalink
feat: send user-agent header with auth token requests (#272)
Browse files Browse the repository at this point in the history
This commit updates our various request-based authenticators
so that the User-Agent header is included with each outbound
token request. The value of the User-Agent header will be
of the form "ibm-node-sdk-core/<authenticator-type>-<core-version> <os-info>".

Signed-off-by: Phil Adams <[email protected]>
  • Loading branch information
padamstx authored Apr 17, 2024
1 parent a69bd87 commit a558274
Show file tree
Hide file tree
Showing 19 changed files with 353 additions and 152 deletions.
32 changes: 16 additions & 16 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "package-lock.json|^.secrets.baseline$",
"lines": null
},
"generated_at": "2024-04-10T16:52:29Z",
"generated_at": "2024-04-16T16:00:48Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -200,7 +200,7 @@
"hashed_secret": "184ee1f04a018aa3b897e085516a9b657fea0f6b",
"is_secret": false,
"is_verified": false,
"line_number": 85,
"line_number": 86,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -210,31 +210,31 @@
"hashed_secret": "d5ff02fa48e492fac0a245ad63d1ae608e705c05",
"is_secret": false,
"is_verified": false,
"line_number": 97,
"line_number": 98,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "8f4bfc22c4fd7cb884f94ec175ff4a3284a174a1",
"is_secret": false,
"is_verified": false,
"line_number": 98,
"line_number": 99,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "45a15668db917c293f16e8add0f5d801889e5923",
"is_secret": false,
"is_verified": false,
"line_number": 112,
"line_number": 116,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "65e622227634e8876cfa733000233fb80c6f0473",
"is_secret": false,
"is_verified": false,
"line_number": 113,
"line_number": 117,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -270,23 +270,23 @@
"hashed_secret": "8f4bfc22c4fd7cb884f94ec175ff4a3284a174a1",
"is_secret": false,
"is_verified": false,
"line_number": 59,
"line_number": 60,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "0358c67856fb6a21c4767daf02fcb8fe4dc0a318",
"is_secret": false,
"is_verified": false,
"line_number": 62,
"line_number": 63,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "dbb19b8ae3b78f908e1467721fe4c9f0b0529d9b",
"is_secret": false,
"is_verified": false,
"line_number": 63,
"line_number": 64,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -296,15 +296,15 @@
"hashed_secret": "8f4bfc22c4fd7cb884f94ec175ff4a3284a174a1",
"is_secret": false,
"is_verified": false,
"line_number": 78,
"line_number": 79,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "65e622227634e8876cfa733000233fb80c6f0473",
"is_secret": false,
"is_verified": false,
"line_number": 91,
"line_number": 95,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -442,15 +442,15 @@
"hashed_secret": "1572bd30ac06678a82df42b5913e5e52e27f9a12",
"is_secret": false,
"is_verified": false,
"line_number": 31,
"line_number": 27,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "16856d955c788df03735a24feb2e3ffefd91f3dc",
"is_secret": false,
"is_verified": false,
"line_number": 32,
"line_number": 28,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -512,7 +512,7 @@
"hashed_secret": "43ed4c2d8375dfc89e3dc8c917f404b9481d355b",
"is_secret": false,
"is_verified": false,
"line_number": 29,
"line_number": 30,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -522,7 +522,7 @@
"hashed_secret": "a7ef1be18bb8d37af79f3d87761a203378bf26a2",
"is_secret": false,
"is_verified": false,
"line_number": 151,
"line_number": 169,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -542,7 +542,7 @@
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
"is_secret": false,
"is_verified": false,
"line_number": 30,
"line_number": 26,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
5 changes: 4 additions & 1 deletion auth/token-managers/container-token-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021, 2023 IBM Corp. All Rights Reserved.
* (C) Copyright IBM Corp. 2021, 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@

import { atLeastOne } from '../utils/helpers';
import { readCrTokenFile } from '../utils/file-reading-helpers';
import { buildUserAgent } from '../../lib/build-user-agent';
import { IamRequestBasedTokenManager, IamRequestOptions } from './iam-request-based-token-manager';

const DEFAULT_CR_TOKEN_FILEPATH1 = '/var/run/secrets/tokens/vault-token';
Expand Down Expand Up @@ -83,6 +84,8 @@ export class ContainerTokenManager extends IamRequestBasedTokenManager {

// construct form data for the cr token use case of iam token management
this.formData.grant_type = 'urn:ibm:params:oauth:grant-type:cr-token';

this.userAgent = buildUserAgent('container-authenticator');
}

/**
Expand Down
6 changes: 5 additions & 1 deletion auth/token-managers/cp4d-token-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* (C) Copyright IBM Corp. 2019, 2023.
* (C) Copyright IBM Corp. 2019, 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@

import extend from 'extend';
import { validateInput } from '../utils/helpers';
import { buildUserAgent } from '../../lib/build-user-agent';
import { JwtTokenManager, JwtTokenManagerOptions } from './jwt-token-manager';

/** Configuration options for CP4D token retrieval. */
Expand Down Expand Up @@ -96,12 +97,15 @@ export class Cp4dTokenManager extends JwtTokenManager {
this.username = options.username;
this.password = options.password;
this.apikey = options.apikey;

this.userAgent = buildUserAgent('cp4d-authenticator');
}

protected requestToken(): Promise<any> {
// these cannot be overwritten
const requiredHeaders = {
'Content-Type': 'application/json',
'User-Agent': this.userAgent,
};

const parameters = {
Expand Down
3 changes: 2 additions & 1 deletion auth/token-managers/iam-request-based-token-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ export class IamRequestBasedTokenManager extends JwtTokenManager {
protected requestToken(): Promise<any> {
// these cannot be overwritten
const requiredHeaders = {
'Content-type': 'application/x-www-form-urlencoded',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': this.userAgent,
} as OutgoingHttpHeaders;

// If both the clientId and secret were specified by the user, then use them.
Expand Down
5 changes: 4 additions & 1 deletion auth/token-managers/iam-token-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* (C) Copyright IBM Corp. 2019, 2023.
* (C) Copyright IBM Corp. 2019, 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,6 +15,7 @@
*/

import { validateInput } from '../utils/helpers';
import { buildUserAgent } from '../../lib/build-user-agent';
import { IamRequestBasedTokenManager, IamRequestOptions } from './iam-request-based-token-manager';

/** Configuration options for IAM token retrieval. */
Expand Down Expand Up @@ -62,5 +63,7 @@ export class IamTokenManager extends IamRequestBasedTokenManager {
this.formData.apikey = this.apikey;
this.formData.grant_type = 'urn:ibm:params:oauth:grant-type:apikey';
this.formData.response_type = 'cloud_iam';

this.userAgent = buildUserAgent('iam-authenticator');
}
}
6 changes: 5 additions & 1 deletion auth/token-managers/mcsp-token-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* (C) Copyright IBM Corp. 2023.
* (C) Copyright IBM Corp. 2023, 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@

import extend from 'extend';
import { validateInput } from '../utils/helpers';
import { buildUserAgent } from '../../lib/build-user-agent';
import { JwtTokenManager, JwtTokenManagerOptions } from './jwt-token-manager';

/**
Expand Down Expand Up @@ -76,12 +77,15 @@ export class McspTokenManager extends JwtTokenManager {
validateInput(options, this.requiredOptions);

this.apikey = options.apikey;

this.userAgent = buildUserAgent('mcsp-authenticator');
}

protected requestToken(): Promise<any> {
const requiredHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
'User-Agent': this.userAgent,
};

const parameters = {
Expand Down
2 changes: 2 additions & 0 deletions auth/token-managers/token-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export type TokenManagerOptions = {
export class TokenManager {
protected url: string;

protected userAgent: string;

protected disableSslVerification: boolean;

protected headers: OutgoingHttpHeaders;
Expand Down
5 changes: 5 additions & 0 deletions auth/token-managers/vpc-instance-token-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import logger from '../../lib/logger';
import { atMostOne, getCurrentTime } from '../utils/helpers';
import { buildUserAgent } from '../../lib/build-user-agent';
import { JwtTokenManager, JwtTokenManagerOptions } from './jwt-token-manager';

const DEFAULT_IMS_ENDPOINT = 'http://169.254.169.254';
Expand Down Expand Up @@ -87,6 +88,8 @@ export class VpcInstanceTokenManager extends JwtTokenManager {
if (options.iamProfileId) {
this.iamProfileId = options.iamProfileId;
}

this.userAgent = buildUserAgent('vpc-instance-authenticator');
}

/**
Expand Down Expand Up @@ -130,6 +133,7 @@ export class VpcInstanceTokenManager extends JwtTokenManager {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': this.userAgent,
Accept: 'application/json',
Authorization: `Bearer ${instanceIdentityToken}`,
},
Expand All @@ -154,6 +158,7 @@ export class VpcInstanceTokenManager extends JwtTokenManager {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'User-Agent': this.userAgent,
Accept: 'application/json',
'Metadata-Flavor': 'ibm',
},
Expand Down
2 changes: 2 additions & 0 deletions etc/ibm-cloud-sdk-core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,8 @@ export class TokenManager {
setHeaders(headers: OutgoingHttpHeaders): void;
// (undocumented)
protected url: string;
// (undocumented)
protected userAgent: string;
}

// @public
Expand Down
19 changes: 18 additions & 1 deletion lib/base-service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* (C) Copyright IBM Corp. 2014, 2023.
* (C) Copyright IBM Corp. 2014, 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,12 +14,14 @@
* limitations under the License.
*/

import extend from 'extend';
import type { CookieJar } from 'tough-cookie';
import { OutgoingHttpHeaders } from 'http';
import { AuthenticatorInterface, checkCredentials, readExternalSources } from '../auth';
import { stripTrailingSlash } from './helper';
import logger from './logger';
import { RequestWrapper, RetryOptions } from './request-wrapper';
import { buildUserAgent } from './build-user-agent';

/**
* Configuration values for a service.
Expand Down Expand Up @@ -71,6 +73,8 @@ export class BaseService {

private requestWrapperInstance: RequestWrapper;

private defaultUserAgent;

/**
* Configuration values for a service.
*
Expand Down Expand Up @@ -131,6 +135,8 @@ export class BaseService {
}

this.authenticator = options.authenticator;

this.defaultUserAgent = buildUserAgent();
}

/**
Expand Down Expand Up @@ -271,6 +277,17 @@ export class BaseService {
return Promise.reject(new Error('The service URL is required'));
}

// make sure the outbound request contains a User-Agent header
const userAgent = {
'User-Agent': this.defaultUserAgent,
};
parameters.defaultOptions.headers = extend(
true,
{},
userAgent,
parameters.defaultOptions.headers
);

return this.authenticator.authenticate(parameters.defaultOptions).then(() =>
// resolve() handles rejection as well, so resolving the result of sendRequest should allow for proper handling later
this.requestWrapperInstance.sendRequest(parameters)
Expand Down
Loading

0 comments on commit a558274

Please sign in to comment.