@tsed/platform-test-sdk
Version:
Package to test platform adapter integration with Ts.ED
343 lines (342 loc) • 14.1 kB
JavaScript
var OAuthMiddleware_1;
import { __decorate, __metadata, __param } from "tslib";
import { useDecorators } from "@tsed/core";
import { Controller, Inject, Injectable } from "@tsed/di";
import { BadRequest, Forbidden, Unauthorized } from "@tsed/exceptions";
import { Req } from "@tsed/platform-http";
import { PlatformTest } from "@tsed/platform-http/testing";
import { Middleware, UseAuth } from "@tsed/platform-middlewares";
import { Context } from "@tsed/platform-params";
import { Get, In, Post, Returns, Security } from "@tsed/schema";
import SuperTest from "supertest";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import baseSpec from "../data/swagger.json";
let TokenService = class TokenService {
constructor() {
this._token = "EMPTY";
}
token(token) {
if (token) {
this._token = token;
}
return this._token;
}
isValid(token) {
return String(token).match(/token/);
}
};
TokenService = __decorate([
Injectable()
], TokenService);
export { TokenService };
let OAuthMiddleware = OAuthMiddleware_1 = class OAuthMiddleware {
use(ctx) {
const { endpoint, request } = ctx;
const options = endpoint.get(OAuthMiddleware_1) || {};
if (!request.get("authorization")) {
throw new Unauthorized("Unauthorized");
}
if (!this.tokenService.isValid(request.get("authorization"))) {
throw new BadRequest("Bad token format");
}
if (options && options.role === "admin" && request.get("authorization") !== "admin_token") {
throw new Forbidden("Forbidden");
}
ctx.getRequest().user = {
id: "id",
name: "name"
};
}
};
__decorate([
Inject(),
__metadata("design:type", TokenService)
], OAuthMiddleware.prototype, "tokenService", void 0);
__decorate([
__param(0, Context()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], OAuthMiddleware.prototype, "use", null);
OAuthMiddleware = OAuthMiddleware_1 = __decorate([
Middleware()
], OAuthMiddleware);
export function OAuth(options = {}) {
return useDecorators(UseAuth(OAuthMiddleware, options), Security("global_auth", ...(options.scopes || [])), In("header").Type(String).Name("Authorization").Required(), Returns(401).Description("Unauthorized"), Returns(403).Description("Forbidden"));
}
let TestAuthCtrl = class TestAuthCtrl {
authorize() {
this.tokenService.token("access_token");
return {
access_token: this.tokenService.token()
};
}
token(user) {
return user;
}
admin() {
return {
granted: true
};
}
stepUp() {
this.tokenService.token("admin_token");
return {
access_token: this.tokenService.token()
};
}
};
__decorate([
Inject(),
__metadata("design:type", TokenService)
], TestAuthCtrl.prototype, "tokenService", void 0);
__decorate([
Post("/authorize"),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], TestAuthCtrl.prototype, "authorize", null);
__decorate([
Get("/userinfo"),
OAuth(),
__param(0, Req("user")),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], TestAuthCtrl.prototype, "token", null);
__decorate([
Get("/admin"),
OAuth({ role: "admin", scopes: ["admin"] }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], TestAuthCtrl.prototype, "admin", null);
__decorate([
Post("/stepUp"),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], TestAuthCtrl.prototype, "stepUp", null);
TestAuthCtrl = __decorate([
Controller("/auth")
], TestAuthCtrl);
export function testAuth(options) {
let request;
beforeAll(PlatformTest.bootstrap(options.server, {
...options,
mount: {
"/rest": [TestAuthCtrl]
},
swagger: [
{
path: "/doc",
spec: baseSpec
}
]
}));
beforeAll(() => {
request = SuperTest.agent(PlatformTest.callback());
});
afterAll(PlatformTest.reset);
describe("Scenario 1: Create token, test token and stepup token", () => {
it("should create a token, call /userinfo to get userinfo and try admin route", async () => {
await request.get("/rest/auth/userinfo").expect(401);
await request
.get("/rest/auth/userinfo")
.set({
Authorization: "wrong"
})
.expect(400);
const { body } = await request.post("/rest/auth/authorize").expect(200);
expect(body.access_token).toEqual("access_token");
const { body: userInfo } = await request
.get("/rest/auth/userinfo")
.set({
Authorization: body.access_token
})
.expect(200);
expect(userInfo).toEqual({
id: "id",
name: "name"
});
await request
.get("/rest/auth/admin")
.set({
Authorization: body.access_token
})
.expect(403);
const { body: { access_token } } = await request.post("/rest/auth/stepUp").expect(200);
expect(access_token).toEqual("admin_token");
const { body: result } = await request
.get("/rest/auth/admin")
.set({
Authorization: access_token
})
.expect(200);
expect(result).toEqual({
granted: true
});
});
});
describe("Scenario 2: GET /swagger.json", () => {
it("should generate the swagger.spec", async () => {
const { body: spec } = await request.get("/doc/swagger.json").expect(200);
expect(spec).toEqual({
openapi: "3.0.1",
info: {
version: "1.0.0",
title: "Swagger Title",
description: "Swagger description",
termsOfService: "http://swagger.io/terms/",
contact: { email: "apiteam@swagger.io" },
license: { name: "Apache 2.0", url: "http://www.apache.org/licenses/LICENSE-2.0.html" }
},
paths: {
"/rest/auth/authorize": {
post: {
operationId: "testAuthCtrlAuthorize",
responses: { "200": { description: "Success" } },
parameters: [],
tags: ["TestAuthCtrl"]
}
},
"/rest/auth/userinfo": {
get: {
operationId: "testAuthCtrlToken",
responses: {
"401": {
content: { "application/json": { schema: { $ref: "#/components/schemas/Unauthorized" } } },
description: "Unauthorized"
},
"403": {
content: { "application/json": { schema: { $ref: "#/components/schemas/Forbidden" } } },
description: "Forbidden"
}
},
security: [{ global_auth: [] }],
parameters: [
{
name: "Authorization",
required: true,
in: "header",
schema: { type: "string" }
}
],
tags: ["TestAuthCtrl"]
}
},
"/rest/auth/admin": {
get: {
operationId: "testAuthCtrlAdmin",
responses: {
"401": {
content: { "application/json": { schema: { $ref: "#/components/schemas/Unauthorized" } } },
description: "Unauthorized"
},
"403": {
content: { "application/json": { schema: { $ref: "#/components/schemas/Forbidden" } } },
description: "Forbidden"
}
},
security: [{ global_auth: ["admin"] }],
parameters: [
{
name: "Authorization",
required: true,
in: "header",
schema: { type: "string" }
}
],
tags: ["TestAuthCtrl"]
}
},
"/rest/auth/stepUp": {
post: {
operationId: "testAuthCtrlStepUp",
responses: { "200": { description: "Success" } },
parameters: [],
tags: ["TestAuthCtrl"]
}
}
},
components: {
securitySchemes: {
global_auth: {
type: "oauth2",
flows: {
implicit: {
authorizationUrl: "http://petstore.swagger.io/oauth/dialog",
scopes: { admin: "Admin access" }
}
}
}
},
schemas: {
Unauthorized: {
type: "object",
properties: {
name: {
type: "string",
description: "The error name",
minLength: 1,
example: "UNAUTHORIZED",
default: "UNAUTHORIZED"
},
message: { type: "string", description: "An error message", minLength: 1 },
status: {
type: "number",
description: "The status code of the exception",
example: 401,
default: 401
},
errors: {
type: "array",
items: { $ref: "#/components/schemas/GenericError" },
description: "A list of related errors"
},
stack: { type: "string", description: "The stack trace (only in development mode)" }
},
required: ["name", "message", "status"]
},
GenericError: {
type: "object",
properties: {
name: { type: "string", description: "The error name", minLength: 1 },
message: { type: "string", description: "An error message", minLength: 1 }
},
additionalProperties: true,
required: ["name", "message"]
},
Forbidden: {
type: "object",
properties: {
name: {
type: "string",
description: "The error name",
minLength: 1,
example: "FORBIDDEN",
default: "FORBIDDEN"
},
message: { type: "string", description: "An error message", minLength: 1 },
status: {
type: "number",
description: "The status code of the exception",
example: 403,
default: 403
},
errors: {
type: "array",
items: { $ref: "#/components/schemas/GenericError" },
description: "A list of related errors"
},
stack: { type: "string", description: "The stack trace (only in development mode)" }
},
required: ["name", "message", "status"]
}
}
},
tags: [{ name: "TestAuthCtrl" }]
});
});
});
}