Skip to content

Commit 5d75047

Browse files
committed
Merge branch 'improvement/BB-742/sasl-scram' into tmp/octopus/w/9.1/improvement/BB-742/sasl-scram
2 parents 5b36d19 + 49843cc commit 5d75047

File tree

6 files changed

+256
-7
lines changed

6 files changed

+256
-7
lines changed

extensions/notification/NotificationConfigValidator.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const joi = require('joi');
22
const { probeServerJoi } = require('../../lib/config/configItems.joi');
3-
const { supportedSaslProtocols } = require('./constants');
3+
const { supportedSaslProtocols, supportedScramMechanisms } = require('./constants');
44

55
const { MAX_QUEUED_DEFAULT } = require('../../lib/constants').backbeatConsumer;
66

@@ -37,12 +37,27 @@ const basicAuthSchema = joi.alternatives().try(
3737
}),
3838
);
3939

40+
const scramAuthBaseSchema = saslAuthSchema.append({
41+
type: joi.string().valid('scram').required(),
42+
mechanism: joi.string().valid(...supportedScramMechanisms).required(),
43+
});
44+
45+
const scramAuthSchema = joi.alternatives().try(
46+
scramAuthBaseSchema.append({
47+
credentialsFile: joi.string().required(),
48+
}),
49+
scramAuthBaseSchema.append({
50+
username: joi.string().required(),
51+
password: joi.string().required(),
52+
}),
53+
);
54+
4055
const credentialsFileSchema = joi.object({
4156
username: joi.string().required(),
4257
password: joi.string().required(),
4358
});
4459

45-
const authSchema = joi.alternatives().try(sslSchema, kerberosAuthSchema, basicAuthSchema).default({});
60+
const authSchema = joi.alternatives().try(sslSchema, kerberosAuthSchema, basicAuthSchema, scramAuthSchema).default({});
4661

4762
const destinationSchema = joi.object({
4863
resource: joi.string().required(),

extensions/notification/constants.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const constants = {
2424
eventVersion: '1.0',
2525
eventSource: 'scality:s3',
2626
eventS3SchemaVersion: '1.0',
27-
supportedSaslProtocols: ['SASL_PLAINTEXT', 'SASL_SSL']
27+
supportedSaslProtocols: ['SASL_PLAINTEXT', 'SASL_SSL'],
28+
supportedScramMechanisms: ['SHA-256', 'SHA-512']
2829
};
2930

3031
module.exports = constants;

extensions/notification/queueProcessor/task.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ let destinationAuth = {
4040
serviceName: process.env.SERVICE_NAME,
4141
username: process.env.BASIC_USERNAME,
4242
password: process.env.BASIC_PASSWORD,
43+
mechanism: process.env.SCRAM_MECHANISM,
4344
};
4445
// Drop undefined environment variables to prevent hitting unknown fields when validating the auth schema.
4546
Object.keys(destinationAuth).forEach(key => {

extensions/notification/utils/auth.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const fs = require('fs');
22
const joi = require('joi');
33

4-
const { authFilesFolder, supportedSaslProtocols } = require('../constants');
4+
const { authFilesFolder, supportedSaslProtocols, supportedScramMechanisms } = require('../constants');
55
const { credentialsFileSchema } = require('../NotificationConfigValidator');
66

77
function getAuthFilePath(fileName) {
@@ -84,12 +84,20 @@ function generateKafkaAuthObject(auth) {
8484
}
8585
break;
8686
}
87-
case 'basic': {
88-
const { protocol, credentialsFile, username, password } = auth;
87+
case 'basic':
88+
case 'scram': {
89+
const { protocol, mechanism, credentialsFile, username, password } = auth;
8990
if (!supportedSaslProtocols.includes(protocol)) {
9091
throw new Error(`Unsupported security.protocol: ${protocol}`);
9192
}
92-
authObject['sasl.mechanisms'] = 'PLAIN';
93+
if (type === 'basic') {
94+
authObject['sasl.mechanisms'] = 'PLAIN';
95+
} else {
96+
if (!supportedScramMechanisms.includes(mechanism)) {
97+
throw new Error(`Unsupported SCRAM mechanism: ${mechanism}`);
98+
}
99+
authObject['sasl.mechanisms'] = `SCRAM-${mechanism}`;
100+
}
93101
authObject['security.protocol'] = protocol;
94102
if (credentialsFile) {
95103
const credsFilePath = getAuthFilePath(credentialsFile);

tests/unit/notification/NotificationConfigValidator.js

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,164 @@ describe('NotificationConfigValidator ::', () => {
275275
}
276276
},
277277
},
278+
// SCRAM auth
279+
{
280+
valid: true,
281+
description: 'scram auth credentialsFile',
282+
destinationConfig: {
283+
resource: 'resource',
284+
type: 'kafka',
285+
host: 'host',
286+
port: 8000,
287+
topic: 'topic',
288+
auth: {
289+
type: 'scram',
290+
protocol: 'SASL_SSL',
291+
mechanism: 'SHA-256',
292+
credentialsFile: 'path/to/credentials',
293+
}
294+
},
295+
},
296+
{
297+
valid: true,
298+
description: 'scram auth username/password',
299+
destinationConfig: {
300+
resource: 'resource',
301+
type: 'kafka',
302+
host: 'host',
303+
port: 8000,
304+
topic: 'topic',
305+
auth: {
306+
type: 'scram',
307+
protocol: 'SASL_PLAINTEXT',
308+
mechanism: 'SHA-512',
309+
username: 'foo',
310+
password: 'bar',
311+
}
312+
},
313+
},
314+
{
315+
valid: false,
316+
description: 'scram auth missing credentials',
317+
destinationConfig: {
318+
resource: 'resource',
319+
type: 'kafka',
320+
host: 'host',
321+
port: 8000,
322+
topic: 'topic',
323+
auth: {
324+
type: 'scram',
325+
protocol: 'SASL_PLAINTEXT',
326+
mechanism: 'SHA-256',
327+
}
328+
},
329+
},
330+
{
331+
valid: false,
332+
description: 'scram auth empty password',
333+
destinationConfig: {
334+
resource: 'resource',
335+
type: 'kafka',
336+
host: 'host',
337+
port: 8000,
338+
topic: 'topic',
339+
auth: {
340+
type: 'scram',
341+
protocol: 'SASL_PLAINTEXT',
342+
mechanism: 'SHA-256',
343+
username: 'foo',
344+
password: '',
345+
}
346+
},
347+
},
348+
{
349+
valid: false,
350+
description: 'scram auth unset username',
351+
destinationConfig: {
352+
resource: 'resource',
353+
type: 'kafka',
354+
host: 'host',
355+
port: 8000,
356+
topic: 'topic',
357+
auth: {
358+
type: 'scram',
359+
protocol: 'SASL_PLAINTEXT',
360+
mechanism: 'SHA-256',
361+
password: 'bar',
362+
}
363+
},
364+
},
365+
{
366+
valid: false,
367+
description: 'scram auth inline credentials and credentials file',
368+
destinationConfig: {
369+
resource: 'resource',
370+
type: 'kafka',
371+
host: 'host',
372+
port: 8000,
373+
topic: 'topic',
374+
auth: {
375+
type: 'scram',
376+
protocol: 'SASL_PLAINTEXT',
377+
mechanism: 'SHA-256',
378+
credentialsFile: 'credentials.json',
379+
username: 'testuser',
380+
password: 'testpassword',
381+
}
382+
},
383+
},
384+
{
385+
valid: false,
386+
description: 'scram auth empty credentialsFile',
387+
destinationConfig: {
388+
resource: 'resource',
389+
type: 'kafka',
390+
host: 'host',
391+
port: 8000,
392+
topic: 'topic',
393+
auth: {
394+
type: 'scram',
395+
protocol: 'SASL_PLAINTEXT',
396+
mechanism: 'SHA-256',
397+
credentialsFile: '',
398+
}
399+
},
400+
},
401+
{
402+
valid: false,
403+
description: 'scram auth missing mechanism',
404+
destinationConfig: {
405+
resource: 'resource',
406+
type: 'kafka',
407+
host: 'host',
408+
port: 8000,
409+
topic: 'topic',
410+
auth: {
411+
type: 'scram',
412+
protocol: 'SASL_PLAINTEXT',
413+
username: 'foo',
414+
password: 'bar',
415+
}
416+
},
417+
},
418+
{
419+
valid: false,
420+
description: 'scram auth invalid mechanism',
421+
destinationConfig: {
422+
resource: 'resource',
423+
type: 'kafka',
424+
host: 'host',
425+
port: 8000,
426+
topic: 'topic',
427+
auth: {
428+
type: 'scram',
429+
protocol: 'SASL_PLAINTEXT',
430+
mechanism: 'SHA-1',
431+
username: 'foo',
432+
password: 'bar',
433+
}
434+
},
435+
},
278436
{
279437
valid: true,
280438
description: 'empty auth',

tests/unit/notification/utils/auth.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,72 @@ describe('generateKafkaAuthObject', () => {
151151
'sasl.password': 'testpassword',
152152
},
153153
},
154+
// SCRAM authentication
155+
{
156+
description: 'SCRAM-SHA-256 authentication with credentials file',
157+
valid: true,
158+
input: {
159+
type: 'scram',
160+
protocol: 'SASL_SSL',
161+
mechanism: 'SHA-256',
162+
credentialsFile: 'credentials.json',
163+
},
164+
expected: {
165+
'security.protocol': 'SASL_SSL',
166+
'sasl.mechanisms': 'SCRAM-SHA-256',
167+
'sasl.username': 'testuser',
168+
'sasl.password': 'testpassword',
169+
},
170+
},
171+
{
172+
description: 'SCRAM-SHA-512 authentication with inline credentials',
173+
valid: true,
174+
input: {
175+
type: 'scram',
176+
protocol: 'SASL_PLAINTEXT',
177+
mechanism: 'SHA-512',
178+
username: 'testuser',
179+
password: 'testpassword',
180+
},
181+
expected: {
182+
'security.protocol': 'SASL_PLAINTEXT',
183+
'sasl.mechanisms': 'SCRAM-SHA-512',
184+
'sasl.username': 'testuser',
185+
'sasl.password': 'testpassword',
186+
},
187+
},
188+
{
189+
description: 'SCRAM authentication with missing credentials file',
190+
valid: false,
191+
input: {
192+
type: 'scram',
193+
protocol: 'SASL_PLAINTEXT',
194+
mechanism: 'SHA-256',
195+
credentialsFile: 'nonexistent.json',
196+
},
197+
},
198+
{
199+
description: 'SCRAM authentication with unsupported protocol',
200+
valid: false,
201+
input: {
202+
type: 'scram',
203+
protocol: 'UNSUPPORTED_PROTOCOL',
204+
mechanism: 'SHA-256',
205+
username: 'testuser',
206+
password: 'testpassword',
207+
},
208+
},
209+
{
210+
description: 'SCRAM authentication with unsupported mechanism',
211+
valid: false,
212+
input: {
213+
type: 'scram',
214+
protocol: 'SASL_PLAINTEXT',
215+
mechanism: 'SHA-1',
216+
username: 'testuser',
217+
password: 'testpassword',
218+
},
219+
},
154220
{
155221
description: 'Basic authentication with missing credentials file',
156222
valid: false,

0 commit comments

Comments
 (0)