Skip to content

Commit 7224ff5

Browse files
committed
Angular Security course
1 parent 9df5b7c commit 7224ff5

10 files changed

+67
-46
lines changed
File renamed without changes.

server/authorization.middleware.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
import {Request, Response, NextFunction} from 'express';
3+
import * as _ from 'lodash';
4+
5+
6+
7+
export function checkIfAuthorized(allowedRoles: string[], req: Request, res: Response, next: NextFunction) {
8+
9+
const userInfo = req['user'];
10+
11+
console.log("Checking authorization for user", userInfo);
12+
console.log("Checking if user has the following roles", allowedRoles);
13+
14+
const roles = _.intersection(userInfo.roles, allowedRoles);
15+
16+
console.log("Common roles", roles);
17+
18+
if (userInfo && roles.length > 0) {
19+
next();
20+
}
21+
else {
22+
console.log("Unauthorized, only the following roles are allowed: ", allowedRoles);
23+
res.sendStatus(403);
24+
}
25+
}
26+
27+

server/database-data.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,17 @@ import {DbUser} from "./db-user";
33
export const USERS: { [key: number]: DbUser } = {
44
1: {
55
id: 1,
6-
email: 'admin@gmail.com',
6+
email: 'student@gmail.com',
77
// ADMIN user (password is Password10) can read all lessons and also can login on behalf of other users
88
passwordDigest: '$argon2i$v=19$m=4096,t=3,p=1$vfrhde0OMBNSSE9rRWtVrQ$gBaNgJFPBZfzuvrzfX8iSr2+OCD8K8Iu/JjwpYp8/TY',
9-
roles: {
10-
'STUDENT': true
11-
}
9+
roles: ['STUDENT']
1210
},
1311
2: {
1412
id: 2,
15-
email: 'user@gmail.com',
13+
email: 'admin@gmail.com',
1614
// normal user (password is Password10), does not have access to login as another user functionality
1715
passwordDigest: '$argon2i$v=19$m=4096,t=3,p=1$vfrhde0OMBNSSE9rRWtVrQ$gBaNgJFPBZfzuvrzfX8iSr2+OCD8K8Iu/JjwpYp8/TY',
18-
roles: {
19-
'STUDENT': true,
20-
'ADMIN': true
21-
}
16+
roles: ['STUDENT', 'ADMIN']
2217
}
2318
};
2419

server/db-user.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ export interface DbUser {
44
id:number;
55
email:string;
66
passwordDigest:string,
7-
roles: Object
7+
roles: string[]
88
}

server/get-user.route.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import {db} from "./database";
77

88
export function getUser(req:Request, res:Response) {
99

10-
const user = db.findUserById(req["userId"]);
10+
const userInfo = req["user"];
11+
12+
const user = db.findUserById(userInfo.sub);
1113

1214
if (user) {
1315
res.status(200).json({email:user.email, id:user.id, roles: user.roles});

server/login-as-user.route.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,29 @@ import {createSessionToken} from "./security.utils";
77

88
export function loginAsUser(req, res) {
99

10-
const adminUser = req["user"],
11-
roles = adminUser.userRoles,
12-
userEmail = req.body.email;
10+
const user = req["user"],
11+
impersonatedUserEmail = req.body.email;
1312

14-
if (roles && roles['ADMIN']) {
13+
const impersonatedUser = db.findUserByEmail(impersonatedUserEmail);
1514

16-
const newUser = db.findUserByEmail(userEmail);
15+
createSessionToken(impersonatedUser)
16+
.then(sessionToken => {
1717

18-
createSessionToken(newUser)
19-
.then(sessionToken => {
18+
res.cookie("SESSIONID", sessionToken, {httpOnly:true, secure:true});
2019

21-
res.cookie("SESSIONID", sessionToken, {httpOnly:true, secure:true});
22-
23-
res.status(200).json({ id: newUser.id, email: newUser.email });
24-
25-
})
26-
.catch(err => {
27-
console.log("Error trying to login as user",err);
28-
res.sendStatus(500);
20+
res.status(200).json({
21+
id: impersonatedUser.id,
22+
email: impersonatedUser.email,
23+
roles: impersonatedUser.roles
2924
});
3025

26+
})
27+
.catch(err => {
28+
console.log("Error trying to login as user",err);
29+
res.sendStatus(500);
30+
});
31+
3132

32-
}
33-
else {
34-
res.SendStatus(403);
35-
}
3633
}
3734

3835

server/read-all-lessons.route.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ import {db} from "./database";
44

55
export function readAllLessons(req, res) {
66

7-
const user = req["user"];
8-
9-
if (user.isStudent) {
10-
res.status(200).json({lessons:db.readAllLessons()});
11-
}
12-
else {
13-
res.sendStatus(403);
14-
}
7+
res.status(200).json({lessons:db.readAllLessons()});
8+
159
}

server/security.utils.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ const SESSION_DURATION = 1000;
2424

2525
export async function createSessionToken(user: DbUser) {
2626
return signJwt({
27-
isAdmin: !!user.roles["ADMIN"],
28-
isStudent: !!user.roles["STUDENT"]
27+
roles: user.roles
2928
},
3029
RSA_PRIVATE_KEY, {
3130
algorithm: 'RS256',

server/server.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ import {getUser} from "./get-user.route";
1010
import {logout} from "./logout.route";
1111
import {login} from "./login.route";
1212
import {retrieveUserIdFromRequest} from "./get-user.middleware";
13-
import {checkIfAuthenticated} from "./auth.middleware";
13+
import {checkIfAuthenticated} from "./authentication.middleware";
1414
import {checkCsrfToken} from "./csrf.middleware";
15+
import {loginAsUser} from "./login-as-user.route";
16+
import {checkIfAuthorized} from "./authorization.middleware";
17+
import * as _ from 'lodash';
1518
const bodyParser = require('body-parser');
1619
const cookieParser = require('cookie-parser');
1720

@@ -33,11 +36,15 @@ const options = commandLineArgs(optionDefinitions);
3336

3437
// REST API
3538
app.route('/api/lessons')
36-
.get(checkIfAuthenticated, readAllLessons);
39+
.get(checkIfAuthenticated, _.partial(checkIfAuthorized, ['STUDENT']), readAllLessons);
3740

3841
app.route('/api/signup')
3942
.post(createUser);
4043

44+
45+
app.route('/api/admin')
46+
.post(checkIfAuthenticated, _.partial(checkIfAuthorized, ['ADMIN']) , loginAsUser);
47+
4148
app.route('/api/user')
4249
.get(getUser);
4350

src/app/admin/admin.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class AdminComponent {
1818
private router: Router) {
1919

2020
this.form = this.fb.group({
21-
userEmail: ['user@gmail.com',Validators.required]
21+
userEmail: ['student@gmail.com',Validators.required]
2222
});
2323
}
2424

@@ -28,10 +28,10 @@ export class AdminComponent {
2828
const val = this.form.value;
2929

3030
if (val.userEmail) {
31-
this.authService.loginAsUser(val.email)
31+
this.authService.loginAsUser(val.userEmail)
3232
.subscribe(
33-
() => {
34-
console.log("Logged in as user with email " + val.email);
33+
user => {
34+
console.log("Logged in as user with email " + user.email);
3535
this.router.navigateByUrl('/');
3636
}
3737
);

0 commit comments

Comments
 (0)