feat: Add createSamlAuthProvider graphQL mutation

This commit is contained in:
Faruk AYDIN
2023-08-07 15:02:25 +02:00
parent b4cda90338
commit 8101c9f0bc
6 changed files with 135 additions and 19 deletions

View File

@@ -0,0 +1,33 @@
import { Knex } from 'knex';
const getPermissionForRole = (
roleId: string,
subject: string,
actions: string[]
) =>
actions.map((action) => ({
role_id: roleId,
subject,
action,
conditions: [],
}));
export async function up(knex: Knex): Promise<void> {
const role = (await knex('roles')
.first(['id', 'key'])
.where({ key: 'admin' })
.limit(1)) as { id: string; key: string };
await knex('permissions').insert(
getPermissionForRole(role.id, 'SamlAuthProvider', [
'create',
'read',
'delete',
'update',
])
);
}
export async function down(knex: Knex): Promise<void> {
await knex('permissions').where({ subject: 'SamlAuthProvider' }).delete();
}

View File

@@ -25,6 +25,7 @@ import updateRole from './mutations/update-role.ee';
import updateStep from './mutations/update-step';
import updateUser from './mutations/update-user.ee';
import verifyConnection from './mutations/verify-connection';
import createSamlAuthProvider from './mutations/create-saml-auth-provider.ee';
const mutationResolvers = {
createConnection,
@@ -54,6 +55,7 @@ const mutationResolvers = {
updateRole,
updateStep,
verifyConnection,
createSamlAuthProvider,
};
export default mutationResolvers;

View File

@@ -0,0 +1,54 @@
import type { SamlConfig } from '@node-saml/passport-saml';
import SamlAuthProvider from '../../models/saml-auth-provider.ee';
import Context from '../../types/express/context';
type Params = {
input: {
name: string;
certificate: string;
signatureAlgorithm: SamlConfig['signatureAlgorithm'];
issuer: string;
entryPoint: string;
firstnameAttributeName: string;
surnameAttributeName: string;
emailAttributeName: string;
roleAttributeName: string;
defaultRoleId: string;
active: boolean;
};
};
const createSamlAuthProvider = async (
_parent: unknown,
params: Params,
context: Context
) => {
context.currentUser.can('create', 'SamlAuthProvider');
const samlAuthProviderPayload: Partial<SamlAuthProvider> = {
...params.input,
};
const existingSamlAuthProvider = await SamlAuthProvider.query()
.limit(1)
.first();
let samlAuthProvider: SamlAuthProvider;
if (!existingSamlAuthProvider) {
samlAuthProvider = await SamlAuthProvider.query().insert(
samlAuthProviderPayload
);
return samlAuthProvider;
}
samlAuthProvider = await SamlAuthProvider.query().patchAndFetchById(
existingSamlAuthProvider.id,
samlAuthProviderPayload
);
return samlAuthProvider;
};
export default createSamlAuthProvider;

View File

@@ -42,10 +42,7 @@ type Query {
getTrialStatus: GetTrialStatus
getSubscriptionStatus: GetSubscriptionStatus
getSamlAuthProviders: [GetSamlAuthProviders]
getUsers(
limit: Int!
offset: Int!
): UserConnection
getUsers(limit: Int!, offset: Int!): UserConnection
getUser(id: String!): User
getRoles: [Role]
getRole(id: String!): Role
@@ -81,6 +78,7 @@ type Mutation {
updateStep(input: UpdateStepInput): Step
updateUser(input: UpdateUserInput): User
verifyConnection(input: VerifyConnectionInput): Connection
createSamlAuthProvider(input: CreateSamlAuthProviderInput): SamlAuthProvider
}
"""
@@ -292,6 +290,20 @@ type Execution {
flow: Flow
}
type SamlAuthProvider {
id: String
name: String
certificate: String
signatureAlgorithm: String
issuer: String
entryPoint: String
firstnameAttributeName: String
surnameAttributeName: String
emailAttributeName: String
roleAttributeName: String
active: Boolean
}
type UserConnection {
edges: [UserEdge]
pageInfo: PageInfo
@@ -323,6 +335,20 @@ input VerifyConnectionInput {
id: String!
}
input CreateSamlAuthProviderInput {
name: String!
certificate: String!
signatureAlgorithm: String!
issuer: String!
entryPoint: String!
firstnameAttributeName: String!
surnameAttributeName: String!
emailAttributeName: String!
roleAttributeName: String!
defaultRoleId: String!
active: Boolean!
}
input DeleteConnectionInput {
id: String!
}

View File

@@ -8,7 +8,7 @@ class SamlAuthProvider extends Base {
id!: string;
name: string;
certificate: string;
signatureAlgorithm: SamlConfig["signatureAlgorithm"];
signatureAlgorithm: SamlConfig['signatureAlgorithm'];
issuer: string;
entryPoint: string;
firstnameAttributeName: string;
@@ -39,7 +39,10 @@ class SamlAuthProvider extends Base {
id: { type: 'string', format: 'uuid' },
name: { type: 'string', minLength: 1 },
certificate: { type: 'string', minLength: 1 },
signatureAlgorithm: { type: 'string', enum: ['sha1', 'sha256', 'sha512'] },
signatureAlgorithm: {
type: 'string',
enum: ['sha1', 'sha256', 'sha512'],
},
issuer: { type: 'string', minLength: 1 },
entryPoint: { type: 'string', minLength: 1 },
firstnameAttributeName: { type: 'string', minLength: 1 },
@@ -74,7 +77,7 @@ class SamlAuthProvider extends Base {
entryPoint: this.entryPoint,
issuer: this.issuer,
signatureAlgorithm: this.signatureAlgorithm,
}
};
}
}

View File

@@ -1,10 +1,7 @@
import bcrypt from 'bcrypt';
import { DateTime } from 'luxon';
import crypto from 'node:crypto';
import {
ModelOptions,
QueryContext
} from 'objection';
import { ModelOptions, QueryContext } from 'objection';
import appConfig from '../config/app';
import checkLicense from '../helpers/check-license.ee';
@@ -164,8 +161,8 @@ class User extends Base {
join: {
from: 'identities.user_id',
to: 'users.id',
}
}
},
},
});
login(password: string) {
@@ -299,8 +296,10 @@ class User extends Base {
if (Array.isArray(this.permissions)) {
this.permissions = this.permissions.filter((permission) => {
const isRolePermission = permission.subject === 'Role';
const isSamlAuthProviderPermission =
permission.subject === 'SamlAuthProvider';
return !isRolePermission;
return !isRolePermission && !isSamlAuthProviderPermission;
});
}
@@ -318,11 +317,10 @@ class User extends Base {
const relevantRule = this.ability.relevantRuleFor(action, subject);
const conditions = relevantRule?.conditions as string[] || [];
const conditionMap: Record<string, true> = Object
.fromEntries(
conditions.map((condition) => [condition, true])
)
const conditions = (relevantRule?.conditions as string[]) || [];
const conditionMap: Record<string, true> = Object.fromEntries(
conditions.map((condition) => [condition, true])
);
return conditionMap;
}