mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 13:27:31 -08:00
Merge pull request #3019 from n8n-io/n8n-3171-add-authentication-handler
⚡ Add authentication handler - public api
This commit is contained in:
commit
53d88b33ce
|
@ -9,6 +9,9 @@ import path = require('path');
|
||||||
|
|
||||||
import express = require('express');
|
import express = require('express');
|
||||||
|
|
||||||
|
import { OpenAPIV3 } from 'express-openapi-validator/dist/framework/types';
|
||||||
|
import { Db } from '../..';
|
||||||
|
|
||||||
export interface N8nApp {
|
export interface N8nApp {
|
||||||
app: Application;
|
app: Application;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +26,29 @@ export const getRoutes = (): express.Router => {
|
||||||
operationHandlers: path.join(__dirname),
|
operationHandlers: path.join(__dirname),
|
||||||
validateRequests: true, // (default)
|
validateRequests: true, // (default)
|
||||||
validateApiSpec: true,
|
validateApiSpec: true,
|
||||||
|
validateSecurity: {
|
||||||
|
handlers: {
|
||||||
|
ApiKeyAuth: async (req, scopes, schema: OpenAPIV3.ApiKeySecurityScheme) => {
|
||||||
|
|
||||||
|
const apiKey = req.headers[schema.name.toLowerCase()];
|
||||||
|
|
||||||
|
const user = await Db.collections.User!.find({
|
||||||
|
where: {
|
||||||
|
apiKey,
|
||||||
|
},
|
||||||
|
relations: ['globalRole'],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user = user[0];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
//add error handler
|
//add error handler
|
||||||
|
|
|
@ -7,7 +7,6 @@ export = {
|
||||||
res.json({ success: true});
|
res.json({ success: true});
|
||||||
},
|
},
|
||||||
deleteUser: async (req: UserRequest.Delete, res: express.Response) => {
|
deleteUser: async (req: UserRequest.Delete, res: express.Response) => {
|
||||||
console.log('aja')
|
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
},
|
},
|
||||||
getUser: async (req: UserRequest.Get, res: express.Response) => {
|
getUser: async (req: UserRequest.Get, res: express.Response) => {
|
||||||
|
|
|
@ -57,7 +57,7 @@ import * as clientOAuth1 from 'oauth-1.0a';
|
||||||
import { RequestOptions } from 'oauth-1.0a';
|
import { RequestOptions } from 'oauth-1.0a';
|
||||||
import * as csrf from 'csrf';
|
import * as csrf from 'csrf';
|
||||||
import * as requestPromise from 'request-promise-native';
|
import * as requestPromise from 'request-promise-native';
|
||||||
import { createHmac } from 'crypto';
|
import { createHmac, randomBytes } from 'crypto';
|
||||||
// IMPORTANT! Do not switch to anther bcrypt library unless really necessary and
|
// IMPORTANT! Do not switch to anther bcrypt library unless really necessary and
|
||||||
// tested with all possible systems like Windows, Alpine on ARM, FreeBSD, ...
|
// tested with all possible systems like Windows, Alpine on ARM, FreeBSD, ...
|
||||||
import { compare } from 'bcryptjs';
|
import { compare } from 'bcryptjs';
|
||||||
|
@ -564,6 +564,24 @@ class App {
|
||||||
// Public API
|
// Public API
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//test routes to create/regenerate/delete token
|
||||||
|
//NOTE: Only works with admin role
|
||||||
|
//This should be within the user's management user scope
|
||||||
|
this.app.post('/token', async (req: express.Request, res: express.Response) => {
|
||||||
|
const ramdonToken = randomBytes(20).toString('hex');
|
||||||
|
//@ts-ignore
|
||||||
|
await Db.collections.User!.update({ globalRole: 1 }, { apiKey: ramdonToken });
|
||||||
|
return ResponseHelper.sendSuccessResponse(res, { token: ramdonToken }, true, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.app.delete('/token', async (req: express.Request, res: express.Response) => {
|
||||||
|
//@ts-ignore
|
||||||
|
await Db.collections.User!.update({ globalRole: 1 }, { apiKey: null });
|
||||||
|
return ResponseHelper.sendSuccessResponse(res, {}, true, 204);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
this.app.use(`/${this.publicApiEndpoint}`, publicApiv1Routes.getRoutes());
|
this.app.use(`/${this.publicApiEndpoint}`, publicApiv1Routes.getRoutes());
|
||||||
|
|
||||||
// Parse cookies for easier access
|
// Parse cookies for easier access
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Response } from 'express';
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import { Db } from '../..';
|
import { Db } from '../..';
|
||||||
import { AUTH_COOKIE_NAME } from '../../constants';
|
import { AUTH_COOKIE_NAME } from '../../constants';
|
||||||
import { JwtToken, JwtPayload } from '../Interfaces';
|
import { JwtPayload, JwtToken } from '../Interfaces';
|
||||||
import { User } from '../../databases/entities/User';
|
import { User } from '../../databases/entities/User';
|
||||||
import config = require('../../../config');
|
import config = require('../../../config');
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,9 @@ export class User {
|
||||||
this.updatedAt = new Date();
|
this.updatedAt = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Column({ type: String, nullable: true })
|
||||||
|
apiKey?: string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user is pending setup completion.
|
* Whether the user is pending setup completion.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {MigrationInterface, QueryRunner} from 'typeorm';
|
||||||
|
import * as config from '../../../../config';
|
||||||
|
|
||||||
|
export class AddAPIKeyColumn1647888658687 implements MigrationInterface {
|
||||||
|
name = 'AddAPIKeyColumn1647888658687';
|
||||||
|
|
||||||
|
async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
const tablePrefix = config.get('database.tablePrefix');
|
||||||
|
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" ADD apiKey varchar`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
const tablePrefix = config.get('database.tablePrefix');
|
||||||
|
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "${tablePrefix}user" ("id" varchar PRIMARY KEY NOT NULL, "email" varchar(255), "firstName" varchar(32), "lastName" varchar(32), "password" varchar, "resetPasswordToken" varchar, "resetPasswordTokenExpiration" integer DEFAULT (NULL), "personalizationAnswers" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "globalRoleId" integer NOT NULL, CONSTRAINT "FK_f0609be844f9200ff4365b1bb3d" FOREIGN KEY ("globalRoleId") REFERENCES "role" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "${tablePrefix}user"("id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId") SELECT "id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId" FROM "temporary_user"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_user"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import { AddWaitColumn1621707690587 } from './1621707690587-AddWaitColumn';
|
||||||
import { UpdateWorkflowCredentials1630330987096 } from './1630330987096-UpdateWorkflowCredentials';
|
import { UpdateWorkflowCredentials1630330987096 } from './1630330987096-UpdateWorkflowCredentials';
|
||||||
import { AddExecutionEntityIndexes1644421939510 } from './1644421939510-AddExecutionEntityIndexes';
|
import { AddExecutionEntityIndexes1644421939510 } from './1644421939510-AddExecutionEntityIndexes';
|
||||||
import { CreateUserManagement1646992772331 } from './1646992772331-CreateUserManagement';
|
import { CreateUserManagement1646992772331 } from './1646992772331-CreateUserManagement';
|
||||||
|
import { AddAPIKeyColumn1647888658687 } from './1647888658687-AddAPIKeyColumn';
|
||||||
|
|
||||||
const sqliteMigrations = [
|
const sqliteMigrations = [
|
||||||
InitialMigration1588102412422,
|
InitialMigration1588102412422,
|
||||||
|
@ -24,6 +25,7 @@ const sqliteMigrations = [
|
||||||
UpdateWorkflowCredentials1630330987096,
|
UpdateWorkflowCredentials1630330987096,
|
||||||
AddExecutionEntityIndexes1644421939510,
|
AddExecutionEntityIndexes1644421939510,
|
||||||
CreateUserManagement1646992772331,
|
CreateUserManagement1646992772331,
|
||||||
|
AddAPIKeyColumn1647888658687,
|
||||||
];
|
];
|
||||||
|
|
||||||
export { sqliteMigrations };
|
export { sqliteMigrations };
|
||||||
|
|
Loading…
Reference in a new issue