Merge pull request #1195 from automatisch/saml-configuration-create
feat: Add createSamlAuthProvider graphQL mutation
This commit is contained in:
@@ -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();
|
||||||
|
}
|
@@ -25,6 +25,7 @@ import updateRole from './mutations/update-role.ee';
|
|||||||
import updateStep from './mutations/update-step';
|
import updateStep from './mutations/update-step';
|
||||||
import updateUser from './mutations/update-user.ee';
|
import updateUser from './mutations/update-user.ee';
|
||||||
import verifyConnection from './mutations/verify-connection';
|
import verifyConnection from './mutations/verify-connection';
|
||||||
|
import createSamlAuthProvider from './mutations/create-saml-auth-provider.ee';
|
||||||
|
|
||||||
const mutationResolvers = {
|
const mutationResolvers = {
|
||||||
createConnection,
|
createConnection,
|
||||||
@@ -54,6 +55,7 @@ const mutationResolvers = {
|
|||||||
updateRole,
|
updateRole,
|
||||||
updateStep,
|
updateStep,
|
||||||
verifyConnection,
|
verifyConnection,
|
||||||
|
createSamlAuthProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default mutationResolvers;
|
export default mutationResolvers;
|
||||||
|
@@ -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;
|
@@ -42,10 +42,7 @@ type Query {
|
|||||||
getTrialStatus: GetTrialStatus
|
getTrialStatus: GetTrialStatus
|
||||||
getSubscriptionStatus: GetSubscriptionStatus
|
getSubscriptionStatus: GetSubscriptionStatus
|
||||||
getSamlAuthProviders: [GetSamlAuthProviders]
|
getSamlAuthProviders: [GetSamlAuthProviders]
|
||||||
getUsers(
|
getUsers(limit: Int!, offset: Int!): UserConnection
|
||||||
limit: Int!
|
|
||||||
offset: Int!
|
|
||||||
): UserConnection
|
|
||||||
getUser(id: String!): User
|
getUser(id: String!): User
|
||||||
getRoles: [Role]
|
getRoles: [Role]
|
||||||
getRole(id: String!): Role
|
getRole(id: String!): Role
|
||||||
@@ -81,6 +78,7 @@ type Mutation {
|
|||||||
updateStep(input: UpdateStepInput): Step
|
updateStep(input: UpdateStepInput): Step
|
||||||
updateUser(input: UpdateUserInput): User
|
updateUser(input: UpdateUserInput): User
|
||||||
verifyConnection(input: VerifyConnectionInput): Connection
|
verifyConnection(input: VerifyConnectionInput): Connection
|
||||||
|
createSamlAuthProvider(input: CreateSamlAuthProviderInput): SamlAuthProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -292,6 +290,20 @@ type Execution {
|
|||||||
flow: Flow
|
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 {
|
type UserConnection {
|
||||||
edges: [UserEdge]
|
edges: [UserEdge]
|
||||||
pageInfo: PageInfo
|
pageInfo: PageInfo
|
||||||
@@ -323,6 +335,20 @@ input VerifyConnectionInput {
|
|||||||
id: String!
|
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 {
|
input DeleteConnectionInput {
|
||||||
id: String!
|
id: String!
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ class SamlAuthProvider extends Base {
|
|||||||
id!: string;
|
id!: string;
|
||||||
name: string;
|
name: string;
|
||||||
certificate: string;
|
certificate: string;
|
||||||
signatureAlgorithm: SamlConfig["signatureAlgorithm"];
|
signatureAlgorithm: SamlConfig['signatureAlgorithm'];
|
||||||
issuer: string;
|
issuer: string;
|
||||||
entryPoint: string;
|
entryPoint: string;
|
||||||
firstnameAttributeName: string;
|
firstnameAttributeName: string;
|
||||||
@@ -39,7 +39,10 @@ class SamlAuthProvider extends Base {
|
|||||||
id: { type: 'string', format: 'uuid' },
|
id: { type: 'string', format: 'uuid' },
|
||||||
name: { type: 'string', minLength: 1 },
|
name: { type: 'string', minLength: 1 },
|
||||||
certificate: { 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 },
|
issuer: { type: 'string', minLength: 1 },
|
||||||
entryPoint: { type: 'string', minLength: 1 },
|
entryPoint: { type: 'string', minLength: 1 },
|
||||||
firstnameAttributeName: { type: 'string', minLength: 1 },
|
firstnameAttributeName: { type: 'string', minLength: 1 },
|
||||||
@@ -74,7 +77,7 @@ class SamlAuthProvider extends Base {
|
|||||||
entryPoint: this.entryPoint,
|
entryPoint: this.entryPoint,
|
||||||
issuer: this.issuer,
|
issuer: this.issuer,
|
||||||
signatureAlgorithm: this.signatureAlgorithm,
|
signatureAlgorithm: this.signatureAlgorithm,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
import bcrypt from 'bcrypt';
|
import bcrypt from 'bcrypt';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
import {
|
import { ModelOptions, QueryContext } from 'objection';
|
||||||
ModelOptions,
|
|
||||||
QueryContext
|
|
||||||
} from 'objection';
|
|
||||||
|
|
||||||
import appConfig from '../config/app';
|
import appConfig from '../config/app';
|
||||||
import checkLicense from '../helpers/check-license.ee';
|
import checkLicense from '../helpers/check-license.ee';
|
||||||
@@ -164,8 +161,8 @@ class User extends Base {
|
|||||||
join: {
|
join: {
|
||||||
from: 'identities.user_id',
|
from: 'identities.user_id',
|
||||||
to: 'users.id',
|
to: 'users.id',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
login(password: string) {
|
login(password: string) {
|
||||||
@@ -299,8 +296,10 @@ class User extends Base {
|
|||||||
if (Array.isArray(this.permissions)) {
|
if (Array.isArray(this.permissions)) {
|
||||||
this.permissions = this.permissions.filter((permission) => {
|
this.permissions = this.permissions.filter((permission) => {
|
||||||
const isRolePermission = permission.subject === 'Role';
|
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 relevantRule = this.ability.relevantRuleFor(action, subject);
|
||||||
|
|
||||||
const conditions = relevantRule?.conditions as string[] || [];
|
const conditions = (relevantRule?.conditions as string[]) || [];
|
||||||
const conditionMap: Record<string, true> = Object
|
const conditionMap: Record<string, true> = Object.fromEntries(
|
||||||
.fromEntries(
|
conditions.map((condition) => [condition, true])
|
||||||
conditions.map((condition) => [condition, true])
|
);
|
||||||
)
|
|
||||||
|
|
||||||
return conditionMap;
|
return conditionMap;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user