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

feat(rbac): add support for rejectUnauthorized in PG SSL options #1613

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,74 @@ describe('CasbinAdapterFactory', () => {
},
});
});

it('test building an adapter using a PostgreSQL configuration with intentionally ssl and TLS options.', async () => {
const config = new ConfigReader({
backend: {
database: {
client: 'pg',
connection: {
host: 'localhost',
port: '5432',
user: 'postgresUser',
password: process.env.TEST,
ssl: {
ca: 'abc',
rejectUnauthorized: false,
},
},
},
},
});
const factory = new CasbinDBAdapterFactory(config, mockDatabaseManager);
const adapter = await factory.createAdapter();
expect(adapter).not.toBeNull();
expect(newAdapterMock).toHaveBeenCalledWith({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgresUser',
password: process.env.TEST,
database: 'test-database',
ssl: {
ca: 'abc',
rejectUnauthorized: false,
},
});
});

it('test building an adapter using a PostgreSQL configuration with intentionally ssl without CA.', async () => {
const config = new ConfigReader({
backend: {
database: {
client: 'pg',
connection: {
host: 'localhost',
port: '5432',
user: 'postgresUser',
password: process.env.TEST,
ssl: {
rejectUnauthorized: false,
},
},
},
},
});
const factory = new CasbinDBAdapterFactory(config, mockDatabaseManager);
const adapter = await factory.createAdapter();
expect(adapter).not.toBeNull();
expect(newAdapterMock).toHaveBeenCalledWith({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgresUser',
password: process.env.TEST,
database: 'test-database',
ssl: {
rejectUnauthorized: false,
},
});
});
});

it('ensure that building an adapter with an unknown configuration fails.', async () => {
Expand Down
21 changes: 16 additions & 5 deletions plugins/rbac-backend/src/database/casbin-adapter-factory.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there is some overlap between the knex client and typeORMAdapter. So we can update to instead do something like the below. Which would allow us to no longer have to use custom code to resolve ssl.

adapter = await TypeORMAdapter.newAdapter({
  type: 'postgres',
  username: databaseConfig?.getString('connection.user'),
  password: databaseConfig?.getString('connection.password'),
  ...knexClient.client.config.connection
});

What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PatAKnight, sorry, I have some concerns about mixing these two different types. The SSL type used in Backstage is:

boolean | ConnectionOptions | undefined

while the ORM adapter expects:

boolean | TlsOptions | undefined

These types aren’t interchangeable, so it might lead to issues if we try to mix them.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { TlsOptions } from 'tls';

const DEFAULT_SQLITE3_STORAGE_FILE_NAME = 'rbac.sqlite';

type DbSSLOptions = {
ca?: string;
rejectUnauthorized?: boolean;
};

export class CasbinDBAdapterFactory {
public constructor(
private readonly config: ConfigApi,
Expand Down Expand Up @@ -65,6 +70,7 @@ export class CasbinDBAdapterFactory {
if (!connection) {
return undefined;
}

const ssl = (connection as { ssl: Object | boolean | undefined }).ssl;

if (ssl === undefined) {
Expand All @@ -76,12 +82,17 @@ export class CasbinDBAdapterFactory {
}

if (typeof ssl.valueOf() === 'object') {
const ca = (ssl as { ca: string }).ca;
if (ca) {
return { ca };
const sslOpts = ssl as DbSSLOptions;
const tlsOpts = {
ca: sslOpts.ca,
rejectUnauthorized: sslOpts.rejectUnauthorized,
};

if (Object.values(tlsOpts).every(el => el === undefined)) {
return true;
}
// SSL object was defined with some options that we don't support yet.
return true;

return tlsOpts;
}

return undefined;
Expand Down
Loading