Skip to content

Commit e18178a

Browse files
authored
Merge pull request #178 from Diluka/fix/auth-decorator-status-code
Fix/auth decorator status code
2 parents 52f8458 + 6970334 commit e18178a

File tree

5 files changed

+103
-36
lines changed

5 files changed

+103
-36
lines changed

src/driver/express/ExpressDriver.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {AccessDeniedError} from "../../error/AccessDeniedError";
1212
import {AuthorizationCheckerNotDefinedError} from "../../error/AuthorizationCheckerNotDefinedError";
1313
import {isPromiseLike} from "../../util/isPromiseLike";
1414
import {getFromContainer} from "../../container";
15+
import {AuthorizationRequiredError} from "../../error/AuthorizationRequiredError";
1516
const cookie = require("cookie");
1617
const templateUrl = require("template-url");
1718

@@ -114,21 +115,20 @@ export class ExpressDriver extends BaseDriver implements Driver {
114115

115116
const action: Action = {request, response, next};
116117
const checkResult = this.authorizationChecker(action, actionMetadata.authorizedRoles);
117-
if (isPromiseLike(checkResult)) {
118-
checkResult.then(result => {
119-
if (!result) {
120-
return this.handleError(new AccessDeniedError(action), actionMetadata, action);
121118

122-
} else {
123-
next();
124-
}
125-
});
126-
} else {
127-
if (!checkResult) {
128-
this.handleError(new AccessDeniedError(action), actionMetadata, action);
119+
const handleError = (result: any) => {
120+
if (!result) {
121+
let error = actionMetadata.authorizedRoles.length === 0 ? new AuthorizationRequiredError(action) : new AccessDeniedError(action);
122+
return this.handleError(error, actionMetadata, action);
129123
} else {
130124
next();
131125
}
126+
};
127+
128+
if (isPromiseLike(checkResult)) {
129+
checkResult.then(result => handleError(result));
130+
} else {
131+
handleError(checkResult);
132132
}
133133
});
134134
}

src/driver/koa/KoaDriver.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {AccessDeniedError} from "../../error/AccessDeniedError";
1212
import {isPromiseLike} from "../../util/isPromiseLike";
1313
import {getFromContainer} from "../../container";
1414
import {RoleChecker} from "../../RoleChecker";
15+
import {AuthorizationRequiredError} from "../../error/AuthorizationRequiredError";
1516
const cookie = require("cookie");
1617
const templateUrl = require("template-url");
1718

@@ -92,21 +93,19 @@ export class KoaDriver extends BaseDriver implements Driver {
9293
getFromContainer<RoleChecker>(actionMetadata.authorizedRoles).check(action) :
9394
this.authorizationChecker(action, actionMetadata.authorizedRoles);
9495

95-
if (isPromiseLike(checkResult)) {
96-
return checkResult.then(result => {
97-
if (!result) {
98-
return this.handleError(new AccessDeniedError(action), actionMetadata, action);
99-
100-
} else {
101-
return next();
102-
}
103-
});
104-
} else {
105-
if (!checkResult) {
106-
return this.handleError(new AccessDeniedError(action), actionMetadata, action);
96+
const handleError = (result: any) => {
97+
if (!result) {
98+
let error = actionMetadata.authorizedRoles.length === 0 ? new AuthorizationRequiredError(action) : new AccessDeniedError(action);
99+
return this.handleError(error, actionMetadata, action);
107100
} else {
108-
return next();
101+
next();
109102
}
103+
};
104+
105+
if (isPromiseLike(checkResult)) {
106+
checkResult.then(result => handleError(result));
107+
} else {
108+
handleError(checkResult);
110109
}
111110
});
112111
}

src/error/AccessDeniedError.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {Action} from "../Action";
2-
import {UnauthorizedError} from "../http-error/UnauthorizedError";
2+
import {ForbiddenError} from "../http-error/ForbiddenError";
33

44
/**
55
* Thrown when route is guarded by @Authorized decorator.
66
*/
7-
export class AccessDeniedError extends UnauthorizedError {
7+
export class AccessDeniedError extends ForbiddenError {
88

99
name = "AccessDeniedError";
1010

src/metadata/ActionMetadata.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ export class ActionMetadata {
5656
/**
5757
* Route to be registered for the action.
5858
*/
59-
route: string|RegExp;
59+
route: string | RegExp;
6060

6161
/**
6262
* Full route to this action (includes controller base route).
6363
*/
64-
fullRoute: string|RegExp;
64+
fullRoute: string | RegExp;
6565

6666
/**
6767
* Indicates if this action uses Body.
@@ -96,12 +96,12 @@ export class ActionMetadata {
9696
/**
9797
* Http code to be used on undefined action returned content.
9898
*/
99-
undefinedResultCode: number|Function;
99+
undefinedResultCode: number | Function;
100100

101101
/**
102102
* Http code to be used on null action returned content.
103103
*/
104-
nullResultCode: number|Function;
104+
nullResultCode: number | Function;
105105

106106
/**
107107
* Http code to be set on successful response.
@@ -141,12 +141,12 @@ export class ActionMetadata {
141141
/**
142142
* Special function that will be called instead of orignal method of the target.
143143
*/
144-
methodOverride?: (actionMetadata: ActionMetadata, action: Action, params: any[]) => Promise<any>|any;
144+
methodOverride?: (actionMetadata: ActionMetadata, action: Action, params: any[]) => Promise<any> | any;
145145

146146
// -------------------------------------------------------------------------
147147
// Constructor
148148
// -------------------------------------------------------------------------
149-
149+
150150
constructor(controllerMetadata: ControllerMetadata, args: ActionMetadataArgs) {
151151
this.controllerMetadata = controllerMetadata;
152152
this.route = args.route;
@@ -197,7 +197,7 @@ export class ActionMetadata {
197197
this.headers = this.buildHeaders(responseHandlers);
198198

199199
this.isAuthorizedUsed = this.controllerMetadata.isAuthorizedUsed || !!authorizedHandler;
200-
this.authorizedRoles = (this.controllerMetadata.authorizedRoles || []).concat(authorizedHandler ? authorizedHandler.value : []);
200+
this.authorizedRoles = (this.controllerMetadata.authorizedRoles || []).concat(authorizedHandler && authorizedHandler.value ? authorizedHandler.value : []);
201201
}
202202

203203
// -------------------------------------------------------------------------
@@ -207,7 +207,7 @@ export class ActionMetadata {
207207
/**
208208
* Builds full action route.
209209
*/
210-
private buildFullRoute(): string|RegExp {
210+
private buildFullRoute(): string | RegExp {
211211
if (this.route instanceof RegExp) {
212212
if (this.controllerMetadata.route) {
213213
return ActionMetadata.appendBaseRoute(this.controllerMetadata.route, this.route);
@@ -263,7 +263,6 @@ export class ActionMetadata {
263263
*/
264264
static appendBaseRoute(baseRoute: string, route: RegExp|string) {
265265
const prefix = `${baseRoute.length > 0 && baseRoute.indexOf("/") < 0 ? "/" : ""}${baseRoute}`;
266-
267266
if (typeof route === "string")
268267
return `${prefix}${route}`;
269268

@@ -273,5 +272,5 @@ export class ActionMetadata {
273272

274273
return new RegExp(fullPath, route.flags);
275274
}
276-
275+
277276
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import "reflect-metadata";
2+
import {Get} from "../../src/decorator/Get";
3+
import {createExpressServer, createKoaServer, getMetadataArgsStorage} from "../../src/index";
4+
import {assertRequest} from "./test-utils";
5+
import {JsonController} from "../../src/decorator/JsonController";
6+
import {Authorized} from "../../src/decorator/Authorized";
7+
import {Action} from "../../src/Action";
8+
import {RoutingControllersOptions} from "../../src/RoutingControllersOptions";
9+
const chakram = require("chakram");
10+
const expect = chakram.expect;
11+
12+
describe("Authorized Decorators Http Status Code", function () {
13+
14+
before(() => {
15+
16+
// reset metadata args storage
17+
getMetadataArgsStorage().reset();
18+
19+
@JsonController()
20+
class AuthController {
21+
22+
@Authorized()
23+
@Get("/auth1")
24+
auth1() {
25+
return {test: "auth1"};
26+
}
27+
28+
@Authorized(["role1"])
29+
@Get("/auth2")
30+
auth2() {
31+
return {test: "auth2"};
32+
}
33+
34+
}
35+
});
36+
37+
const serverOptions: RoutingControllersOptions = {
38+
authorizationChecker: async (action: Action, roles?: string[]) => {
39+
return false;
40+
}
41+
};
42+
43+
let expressApp: any;
44+
before(done => {
45+
const server = createExpressServer(serverOptions);
46+
expressApp = server.listen(3001, done);
47+
});
48+
after(done => expressApp.close(done));
49+
50+
let koaApp: any;
51+
before(done => {
52+
const server = createKoaServer(serverOptions);
53+
koaApp = server.listen(3002, done);
54+
});
55+
after(done => koaApp.close(done));
56+
57+
describe("without roles", () => {
58+
assertRequest([3001, 3002], "get", "auth1", response => {
59+
expect(response).to.have.status(401);
60+
});
61+
});
62+
63+
describe("with roles", () => {
64+
assertRequest([3001, 3002], "get", "auth2", response => {
65+
expect(response).to.have.status(403);
66+
});
67+
});
68+
69+
});

0 commit comments

Comments
 (0)