Skip to content

Commit

Permalink
JWT auth support (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
slvrtrn authored Dec 13, 2024
1 parent ad54291 commit 862b552
Show file tree
Hide file tree
Showing 27 changed files with 555 additions and 118 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ jobs:
env:
CLICKHOUSE_CLOUD_HOST: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_HOST_SMT }}
CLICKHOUSE_CLOUD_PASSWORD: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_PASSWORD_SMT }}
CLICKHOUSE_CLOUD_JWT_SECRET: ${{ secrets.CI_JWT_SIGNING_PRIVATE_KEY }}
run: |
npm run test:node:integration:cloud_smt
Expand All @@ -242,6 +243,14 @@ jobs:
run: |
npm run test:web:integration:cloud_smt
- name: Run JWT auth integration tests
env:
CLICKHOUSE_CLOUD_HOST: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_HOST_SMT }}
CLICKHOUSE_CLOUD_PASSWORD: ${{ secrets.INTEGRATIONS_TEAM_TESTS_CLOUD_PASSWORD_SMT }}
CLICKHOUSE_CLOUD_JWT_SECRET: ${{ secrets.CI_JWT_SIGNING_PRIVATE_KEY }}
run: |
npm run test:web:integration:cloud_smt:jwt
# With unit + integration + TLS tests + coverage + SonarCloud report, after the rest of the tests.
# Needs all integration tests on all environments to pass.
# Should use only the current LTS version of Node.js.
Expand Down
7 changes: 7 additions & 0 deletions .scripts/generate_cloud_jwt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { makeJWT } from '../packages/client-node/__tests__/utils/jwt'

/** Used to generate a JWT token for web testing (can't use `jsonwebtoken` library directly there)
* See `package.json` -> `scripts` -> `test:web:integration:cloud_smt:jwt` */
;(() => {
console.log(makeJWT())
})()
40 changes: 40 additions & 0 deletions karma.config.jwt.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const webpackConfig = require('./webpack.dev.js')

const TEST_TIMEOUT_MS = 400_000

module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (e.g. files, exclude)
basePath: '',
frameworks: ['webpack', 'jasmine'],
// list of files / patterns to load in the browser
files: ['packages/client-web/__tests__/jwt/*.test.ts'],
exclude: [],
webpack: webpackConfig,
preprocessors: {
'packages/client-common/**/*.ts': ['webpack', 'sourcemap'],
'packages/client-web/**/*.ts': ['webpack', 'sourcemap'],
'packages/client-common/__tests__/jwt/*.ts': ['webpack', 'sourcemap'],
'packages/client-common/__tests__/utils/*.ts': ['webpack', 'sourcemap'],
},
reporters: ['mocha'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['ChromeHeadless', 'FirefoxHeadless'],
browserNoActivityTimeout: TEST_TIMEOUT_MS,
browserDisconnectTimeout: TEST_TIMEOUT_MS,
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
client: {
jasmine: {
random: false,
stopOnSpecFailure: false,
stopSpecOnExpectationFailure: true,
timeoutInterval: TEST_TIMEOUT_MS,
},
},
})
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@
"test:web:integration:local_cluster": "CLICKHOUSE_TEST_ENVIRONMENT=local_cluster npm run test:web",
"test:web:integration:cloud": "CLICKHOUSE_TEST_ENVIRONMENT=cloud npm run test:web",
"test:web:integration:cloud_smt": "CLICKHOUSE_TEST_ENVIRONMENT=cloud_smt npm run test:web",
"test:web:integration:cloud_smt:jwt": "CLICKHOUSE_CLOUD_JWT_ACCESS_TOKEN=`ts-node .scripts/generate_cloud_jwt.ts` karma start karma.config.jwt.cjs",
"prepare": "husky"
},
"devDependencies": {
"@faker-js/faker": "^9.0.2",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@types/jasmine": "^5.1.4",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "^22.7.0",
"@types/sinon": "^17.0.3",
"@types/split2": "^4.2.3",
Expand All @@ -61,6 +63,7 @@
"jasmine": "^5.3.0",
"jasmine-core": "^5.3.0",
"jasmine-expect": "^5.0.0",
"jsonwebtoken": "^9.0.2",
"karma": "^6.4.4",
"karma-chrome-launcher": "^3.2.0",
"karma-firefox-launcher": "^2.1.3",
Expand Down
24 changes: 13 additions & 11 deletions packages/client-common/__tests__/integration/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ import { getAuthFromEnv } from '@test/utils/env'
import { createTestClient, guid } from '../utils'

describe('authentication', () => {
let client: ClickHouseClient
let invalidAuthClient: ClickHouseClient
beforeEach(() => {
client = createTestClient({
username: 'gibberish',
password: 'gibberish',
invalidAuthClient = createTestClient({
auth: {
username: 'gibberish',
password: 'gibberish',
},
})
})
afterEach(async () => {
await client.close()
await invalidAuthClient.close()
})

it('provides authentication error details', async () => {
await expectAsync(
client.query({
invalidAuthClient.query({
query: 'SELECT number FROM system.numbers LIMIT 3',
}),
).toBeRejectedWith(
Expand Down Expand Up @@ -51,13 +53,13 @@ describe('authentication', () => {
it('should with with insert and select', async () => {
tableName = `simple_table_${guid()}`
await createSimpleTable(defaultClient, tableName)
await client.insert({
await invalidAuthClient.insert({
table: tableName,
format: 'JSONEachRow',
values,
auth,
})
const rs = await client.query({
const rs = await invalidAuthClient.query({
query: `SELECT * FROM ${tableName} ORDER BY id ASC`,
format: 'JSONEachRow',
auth,
Expand All @@ -68,11 +70,11 @@ describe('authentication', () => {
it('should work with command and select', async () => {
tableName = `simple_table_${guid()}`
await createSimpleTable(defaultClient, tableName)
await client.command({
await invalidAuthClient.command({
query: `INSERT INTO ${tableName} VALUES (1, 'foo', [3, 4])`,
auth,
})
const rs = await client.query({
const rs = await invalidAuthClient.query({
query: `SELECT * FROM ${tableName} ORDER BY id ASC`,
format: 'JSONEachRow',
auth,
Expand All @@ -81,7 +83,7 @@ describe('authentication', () => {
})

it('should work with exec', async () => {
const { stream } = await client.exec({
const { stream } = await invalidAuthClient.exec({
query: 'SELECT 42, 144 FORMAT CSV',
auth,
})
Expand Down
Loading

0 comments on commit 862b552

Please sign in to comment.