Skip to content

Commit

Permalink
fix: UA string in Node no longer continuously extends (#1448)
Browse files Browse the repository at this point in the history
OKTA-641280 fix: UA string in Node no longer continuously extends
  • Loading branch information
jaredperreault-okta authored Aug 29, 2023
1 parent 92826f6 commit ae12c07
Show file tree
Hide file tree
Showing 18 changed files with 173 additions and 26 deletions.
11 changes: 9 additions & 2 deletions .bacon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,18 @@ test_suites:
criteria: MERGE
queue_name: small

- name: sample-express-embedded-auth-with-sdk
- name: sample-express-embedded-auth-with-sdk-SPEC
script_path: ../okta-auth-js/scripts/samples
sort_order: '6'
timeout: '30'
script_name: e2e-express-embedded-auth-with-sdk
script_name: e2e-express-embedded-auth-with-sdk-spec
criteria: MERGE
queue_name: small
- name: sample-express-embedded-auth-with-sdk-FEATURES
script_path: ../okta-auth-js/scripts/samples
sort_order: '6'
timeout: '30'
script_name: e2e-express-embedded-auth-with-sdk-features
criteria: MERGE
queue_name: small
- name: sample-express-web-no-oidc
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 7.4.2

### Bug Fix

- [#1448](https://github.com/okta/okta-auth-js/pull/1448) Fix: UA string in Node no longer continuously extends

## 7.4.1

### Bug Fix
Expand Down
2 changes: 1 addition & 1 deletion lib/http/OktaUserAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ export class OktaUserAgent {
constructor() {
// add base sdk env
this.environments = [`okta-auth-js/${SDK_VERSION}`];
this.maybeAddNodeEnvironment();
}

addEnvironment(env: string) {
this.environments.push(env);
}

getHttpHeader() {
this.maybeAddNodeEnvironment();
return { 'X-Okta-User-Agent-Extended': this.environments.join(' ') };
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"private": true,
"name": "@okta/okta-auth-js",
"description": "The Okta Auth SDK",
"version": "7.4.1",
"version": "7.4.2",
"homepage": "https://github.com/okta/okta-auth-js",
"license": "Apache-2.0",
"main": "build/cjs/exports/default.js",
Expand Down
2 changes: 1 addition & 1 deletion samples/test/cucumber.wdio.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export const config: WebdriverIO.Config = {
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
maxInstances: 10,
maxInstances: 2,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
Expand Down
1 change: 1 addition & 0 deletions samples/test/features/account-unlock.feature
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Feature: Account Unlock with Single factor (Email, Phone, Okta Verify Push)
When she clicks the Email magic link for unlock
Then she should see a message containing "unlocked!"

@smstest
Scenario: Mary recovers from a locked account with Phone SMS OTP
Given she has enrolled in the "SMS" factor
And Mary has entered an incorrect password to trigger an account lockout
Expand Down
2 changes: 2 additions & 0 deletions samples/test/features/mfa-password-and-sms.feature
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Feature: Multi-Factor Authentication with Password and SMS
And a user named "Mary"
And she has an account with "active" state in the org

@smstest
Scenario: Enroll in SMS Factor prompt when authenticating
When she clicks the "login" button
Then she is redirected to the "Login" page
Expand Down Expand Up @@ -58,6 +59,7 @@ Feature: Multi-Factor Authentication with Password and SMS
And she submits the form
Then she should see a message "Invalid Phone Number."

@smstest
Scenario: 2FA Login with SMS
Given she has enrolled in the "SMS" factor
When she clicks the "login" button
Expand Down
1 change: 1 addition & 0 deletions samples/test/features/self-service-registration.feature
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Scenario: Mary signs up for an account with Password, setups up required Email f
And she sees a table with her profile info
And the cell for the value of "email" is shown and contains her "email"

@smstest
Scenario: Mary signs up for an account with Password, setups up required Email factor, And sets up optional SMS
When she clicks the 'signup' button
Then she is redirected to the "Self Service Registration" page
Expand Down
1 change: 1 addition & 0 deletions samples/test/features/totp-okta-verify-signin.feature
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Feature: TOTP Support (Okta Verify) Sign In
# And the cell for the value of "email" is shown and contains her "email"
# And the cell for the value of "name" is shown and contains her "first name and last name"

@smstest
Scenario: Mary signs in to an account and enrolls in Password and Okta Verify by clicking a link in a text message
When she clicks the "login" button
Then she is redirected to the "Login" page
Expand Down
1 change: 1 addition & 0 deletions samples/test/features/totp-okta-verify-signup.feature
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Feature: TOTP Support (Okta Verify) Sign Up
# And the cell for the value of "email" is shown and contains her "email"
# And the cell for the value of "name" is shown and contains her "first name and last name"

@smstest
Scenario: Mary signs up for an account with Password, setups up required Okta Verify by clicking a link in a text message
When she clicks the 'signup' button
Then she is redirected to the "Self Service Registration" page
Expand Down
6 changes: 6 additions & 0 deletions samples/test/steps/before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
import { Before } from '@cucumber/cucumber';
import ActionContext from '../support/context';

Before('@smstest', function () {
if (process.env.SKIP_SMS === 'true') {
return 'skipped';
}
});

Before(function (this: ActionContext, scenario: any) {
this.featureName = scenario?.gherkinDocument?.feature?.name;
this.scenarioName = scenario?.pickle?.name;
Expand Down
26 changes: 26 additions & 0 deletions scripts/samples/e2e-express-embedded-auth-with-sdk-features.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

source $(dirname "${BASH_SOURCE[0]}")/../setup-e2e.sh

# NOTE: this test suite runs against a separate test org on OK14
export USE_OK_14=1
setup_sample_tests

export SAMPLE_NAME=@okta/samples.express-embedded-auth-with-sdk
export MAX_INSTANCES=2

# NOTE: the command below evaluates to the same PASSWORD retrieved in setup-e2e, leaving commented just in case
# get_vault_secret_key devex/prod-js-idx-sdk-vars password PASSWORD

# based on run_sample_tests
create_log_group "E2E Test Run"
# Run the tests
if ! yarn workspace @okta/test.e2e.samples test:features; then
echo "tests failed! Exiting..."
exit ${TEST_FAILURE}
fi

echo ${TEST_SUITE_TYPE} > ${TEST_SUITE_TYPE_FILE}
echo ${TEST_RESULT_FILE_DIR} > ${TEST_RESULT_FILE_DIR_FILE}
exit ${PUBLISH_TYPE_AND_RESULT_DIR}
finish_log_group $?
26 changes: 26 additions & 0 deletions scripts/samples/e2e-express-embedded-auth-with-sdk-spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

source $(dirname "${BASH_SOURCE[0]}")/../setup-e2e.sh

# NOTE: this test suite runs against a separate test org on OK14
export USE_OK_14=1
setup_sample_tests

export SAMPLE_NAME=@okta/samples.express-embedded-auth-with-sdk
export MAX_INSTANCES=2

# NOTE: the command below evaluates to the same PASSWORD retrieved in setup-e2e, leaving commented just in case
# get_vault_secret_key devex/prod-js-idx-sdk-vars password PASSWORD

# based on run_sample_tests
create_log_group "E2E Test Run"
# Run the tests
if ! yarn workspace @okta/test.e2e.samples test:specs; then
echo "tests failed! Exiting..."
exit ${TEST_FAILURE}
fi

echo ${TEST_SUITE_TYPE} > ${TEST_SUITE_TYPE_FILE}
echo ${TEST_RESULT_FILE_DIR} > ${TEST_RESULT_FILE_DIR_FILE}
exit ${PUBLISH_TYPE_AND_RESULT_DIR}
finish_log_group $?
2 changes: 1 addition & 1 deletion test/e2e/cucumber.wdio.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const config: Options.Testrunner = {
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
maxInstances: 10,
maxInstances: 1,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
Expand Down
3 changes: 3 additions & 0 deletions test/e2e/features/acr-values.feature
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Scenario: Mary logs in with the initial App Authentication Policy
Then she sees the default view in an AUTHENTICATED state
And she sees her ID and Access Tokens

@smstest
Scenario: Mary logs in with an ACR value in the Authorize request
Given Mary is on the default view in an UNAUTHENTICATED state
When she selects "urn:okta:loa:2fa:any:ifpossible" into "ACR values"
Expand All @@ -52,6 +53,7 @@ Scenario: Mary logs in with an ACR value in the Authorize request
Then she sees the default view in an AUTHENTICATED state
And she sees her ID and Access Tokens

@smstest
Scenario: Mary is signed in without ACR, and is challenged with an ACR value
# Authenticate using SIW
Given Mary is on the default view in an UNAUTHENTICATED state
Expand Down Expand Up @@ -85,6 +87,7 @@ Scenario: Mary is signed in without ACR, and is challenged with an ACR value
Then she sees the default view in an AUTHENTICATED state
And she sees her ID and Access Tokens

@smstest
Scenario: Mary is signed in without ACR, and is challenged with an ACR value, but has a valid ACR Token
# Authenticate using SIW with ACR values 'urn:okta:loa:2fa:any:ifpossible'
Given Mary is on the default view in an UNAUTHENTICATED state
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/features/step-definitions/before.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Before } from '@wdio/cucumber-framework';
import ActionContext from 'support/context';

Before('@smstest', function () {
if (process.env.SKIP_SMS === 'true') {
return 'skipped';
}
});

Before(function (this: ActionContext, scenario: any) {
this.featureName = scenario?.gherkinDocument?.feature?.name;
this.scenarioName = scenario?.pickle?.name;
Expand Down
92 changes: 73 additions & 19 deletions test/spec/OktaUserAgent.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,117 @@
const SDK_VERSION = (global as any).SDK_VERSION;
const NODE_VERSION = (global as any).NODE_VERSION;

import { OktaUserAgent } from '../../lib/http/OktaUserAgent';

jest.mock('../../lib/features', () => {
const mocked = {
isBrowser: jest.fn()
};
jest.mock('lib/features', () => {
return {
isBrowser: () => {}
__esModule: true,
isBrowser: () => mocked.isBrowser()
};
});

const mocked = {
features: require('../../lib/features')
};

describe('OktaUserAgent', () => {
let oktaUserAgent;
let sdkVersion;
beforeEach(async () => {
sdkVersion = (await import('../../package.json')).version;
oktaUserAgent = new OktaUserAgent();
const context: any = {};

beforeEach(() => {
context.oktaUserAgent = new OktaUserAgent();
});

describe('browser env', () => {
beforeEach(() => {
jest.spyOn(mocked.features, 'isBrowser').mockReturnValue(true);
mocked.isBrowser.mockReturnValue(true);
context.expected = `okta-auth-js/${SDK_VERSION}`;
context.oktaUserAgent = new OktaUserAgent();
});

it('gets okta-auth-js and node info in the Okta UA by default', () => {
const { oktaUserAgent, expected } = context;
const httpHeader = oktaUserAgent.getHttpHeader();
expect(httpHeader).toEqual({
'X-Okta-User-Agent-Extended': `okta-auth-js/${sdkVersion}`
'X-Okta-User-Agent-Extended': expected
});
});

it('can add extra environment', () => {
const { oktaUserAgent, expected } = context;
oktaUserAgent.addEnvironment('fake/x.y');
const httpHeader = oktaUserAgent.getHttpHeader();
expect(httpHeader).toEqual({
'X-Okta-User-Agent-Extended': `okta-auth-js/${sdkVersion} fake/x.y`
'X-Okta-User-Agent-Extended': `${expected} fake/x.y`
});
});

// Reason: OKTA-641280
it('should return same header after multiple calls', () => {
const { oktaUserAgent, expected } = context;
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
});
});

describe('node env', () => {
let nodeVersion = process.versions.node;
beforeEach(() => {
jest.spyOn(mocked.features, 'isBrowser').mockReturnValue(false);
mocked.isBrowser.mockReturnValue(false);
context.expected = `okta-auth-js/${SDK_VERSION} nodejs/${NODE_VERSION}`;
context.oktaUserAgent = new OktaUserAgent();
});

it('gets okta-auth-js and node info in the Okta UA by default', () => {
const { oktaUserAgent, expected } = context;
const httpHeader = oktaUserAgent.getHttpHeader();
expect(httpHeader).toEqual({
'X-Okta-User-Agent-Extended': `okta-auth-js/${sdkVersion} nodejs/${nodeVersion}`
'X-Okta-User-Agent-Extended': expected
});
});

it('can add extra environment', () => {
const { oktaUserAgent, expected } = context;
oktaUserAgent.addEnvironment('fake/x.y');
const httpHeader = oktaUserAgent.getHttpHeader();
expect(httpHeader).toEqual({
'X-Okta-User-Agent-Extended': `okta-auth-js/${sdkVersion} fake/x.y nodejs/${nodeVersion}`
'X-Okta-User-Agent-Extended': `${expected} fake/x.y`
});
});

// Reason: OKTA-641280
it('should return same header after multiple calls', () => {
const { oktaUserAgent, expected } = context;
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
expect(oktaUserAgent.getHttpHeader()).toEqual({
'X-Okta-User-Agent-Extended': expected
});
});
});

it('can get sdk version', () => {
expect(oktaUserAgent.getVersion()).toBe(sdkVersion);
const { oktaUserAgent } = context;
expect(oktaUserAgent.getVersion()).toBe(SDK_VERSION);
});
});
9 changes: 8 additions & 1 deletion test/support/jest/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@
var OktaAuth = '<rootDir>/lib/exports/default';
var SDK_VERSION = require('../../../package.json').version;

const { node: NODE_VERSION } = process.versions;

module.exports = {
'coverageDirectory': '<rootDir>/build2/reports/coverage-browser',
'collectCoverage': true,
'collectCoverageFrom': ['./lib/**','!./test/**'],
'globals': {
SDK_VERSION
SDK_VERSION,
NODE_VERSION,
'ts-jest': {
SDK_VERSION,
NODE_VERSION
}
},
'transform': {
'^.+\\.(js)$': 'babel-jest',
Expand Down

0 comments on commit ae12c07

Please sign in to comment.