-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
190 lines (168 loc) · 4.3 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
require("dotenv").config();
import { createServer } from "http";
import { readFileSync } from "fs";
import express, { Request, Response, NextFunction } from "express";
import bodyparser from "body-parser";
import cookieParser from "cookie-parser";
import session from "express-session";
import passport from "passport";
import { Strategy } from "passport-saml";
// Types
import User from "./@types/User";
// Passport Configuration
passport.serializeUser<Express.User>((user, done) => {
done(null, user);
});
passport.deserializeUser<Express.User>((user, done) => {
done(null, user);
});
// Create Strategy
const samlStrategy = new Strategy(
{
// URL that goes from the Identity Provider -> Service Provider
callbackUrl: process.env.CALLBACK_URL,
// URL that goes from the Service Provider -> Identity Provider
entryPoint: process.env.ENTRY_POINT,
// Usually specified as `/shibboleth` from site root
issuer: process.env.ISSUER,
identifierFormat: null,
// Service Provider private key
decryptionPvk: readFileSync(__dirname + "/cert/key.pem", "utf-8"),
// Service Provider private key
privateKey: readFileSync(__dirname + "/cert/key.pem", "utf-8"),
// Identity Provider certificate
cert: readFileSync(__dirname + "/cert/idp_cert.pem", "utf-8"),
},
(profile: any, done: any) => {
return done(
null,
new User(
profile.FirstName,
profile.LastName,
profile.Email,
profile["urn:oid:1.3.6.1.4.1.4447.1.41"].includes("Student")
)
);
}
);
passport.use(samlStrategy);
// Create Express App
const app = express();
// Setup Middleware
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());
app.use(cookieParser());
app.use(
session({
name: "sp",
secret: process.env.SESSION_SECRET as string,
resave: true,
saveUninitialized: true,
})
);
app.use(passport.initialize());
app.use(passport.session());
/**
* Ensure the user is authenticated.
*
* @param {Request} req Express Request
* @param {Response} res Express Response
* @param {NextFunction} next Express NextFunction
* @returns {void}
*/
const ensureAuthenticated = (
req: Request,
res: Response,
next: NextFunction
) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect("/login");
};
/**
* Main Route
*
* @name GET /
* @property {Request} req Express Request
* @property {Response} res Express Response
* @returns {void}
*/
app.get("/", ensureAuthenticated, (req: Request, res: Response): void => {
req.user && res.send(`Hello, ${req.user.FirstName} ${req.user.LastName}`);
});
/**
* Login Route
*
* @name GET /login
* @property {Response} res Express Response
* @returns {void}
*/
app.get(
"/login",
passport.authenticate("saml", { failureRedirect: "/login" }),
(_, res: Response) => {
res.redirect("/");
}
);
/**
* Login Callback Route
*
* @name GET /login/callback
* @property {Response} res Express Response
* @return {void}
*/
app.post(
"/login/callback",
passport.authenticate("saml", { failureRedirect: "/login" }),
(_, res: Response) => {
res.redirect("/");
}
);
/**
* Login Failed Route
*
* @name GET /login/fail
* @property {Response} res Express Response
* @returns {void}
*/
app.get("/login/fail", (_, res: Response) => {
res.status(401).send("Failed to authenticate");
});
/**
* Shibboleth Metadata Route
*
* @name GET /Shibboleth.sso/Metadata
* @property {Response} res Express Response
* @returns {void}
*/
app.get("/Shibboleth.sso/Metadata", (_, res: Response) => {
res.type("application/xml");
res
.status(200)
.send(
samlStrategy.generateServiceProviderMetadata(
readFileSync(__dirname + "/cert/cert.pem", "utf-8"),
readFileSync(__dirname + "/cert/cert.pem", "utf-8")
)
);
});
/**
* General Error Handler
*
* @param {any} err Error to be displayed
* @param {Request} _ Express Request
* @param {Response} res Express Response
* @param {NextFunction} next Express NextFunction
* @returns {void}
*/
app.use((err: any, _: Request, res: Response, next: NextFunction) => {
console.log(`Fatal Error: ${JSON.stringify(err)}`);
next(err);
});
// Create Server
const httpServer = createServer(app);
const port = process.env.PORT || 4006;
httpServer.listen(port, () => {
console.log(`Listening on port ${port}`);
});