Skip to content

Commit 4f50316

Browse files
committed
Oauth fixes
1 parent 50fc998 commit 4f50316

5 files changed

Lines changed: 190 additions & 24 deletions

File tree

OpenFlow/src/OAuthProvider.ts

Lines changed: 186 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,221 @@
1-
import * as oauthServer from "oauth2-server";
1+
import * as OAuthServer from "oauth2-server";
22
import * as winston from "winston";
33
import * as express from "express";
4+
import { TokenUser } from "openflow-api";
5+
const Request = OAuthServer.Request;
6+
const Response = OAuthServer.Response;
47
export class OAuthProvider {
58
private _logger: winston.Logger;
69
private app: express.Express;
7-
private clients = [{ clientId: 'thom', clientSecret: 'nightworld', redirectUris: [''] }];
10+
public static instance: OAuthProvider = null;
11+
private clients = [{
12+
id: 'application', // TODO: Needed by refresh_token grant, because there is a bug at line 103 in https://github.com/oauthjs/node-oauth2-server/blob/v3.0.1/lib/grant-types/refresh-token-grant-type.js (used client.id instead of client.clientId)
13+
clientId: 'application',
14+
clientSecret: 'secret',
15+
grants: [
16+
'password',
17+
'refresh_token',
18+
'authorization_code'
19+
],
20+
redirectUris: []
21+
}];
822
private tokens = [];
9-
private users = [{ id: '123', username: 'thomseddon', password: 'nightworld' }];
23+
private codes = {};
24+
public oauthServer: any = null;
25+
private authorizationCodeStore: any = {};
26+
1027
static configure(logger: winston.Logger, app: express.Express): OAuthProvider {
1128
var instance = new OAuthProvider();
12-
instance._logger = logger;
13-
instance.app = app;
29+
try {
30+
OAuthProvider.instance = instance;
31+
instance._logger = logger;
32+
instance.app = app;
33+
instance.oauthServer = new OAuthServer({
34+
model: instance,
35+
grants: ['authorization_code', 'refresh_token'],
36+
accessTokenLifetime: 60 * 60 * 24, // 24 hours, or 1 day
37+
allowEmptyState: true,
38+
allowExtendedTokenAttributes: true
39+
});
40+
(app as any).oauth = instance.oauthServer;
41+
app.all('/oauth/token', instance.obtainToken.bind(instance));
42+
app.get('/oauth/login', (req, res) => {
43+
let GRAFANA_URI = "http://localhost.openrpa.dk:3000";
44+
let state = req.params.state;
45+
if (state == null) state = encodeURIComponent(req.query.state as any);
46+
const access_type = req.query.access_type;
47+
const client_id = req.query.client_id;
48+
const redirect_uri = req.query.redirect_uri;
49+
const response_type = req.query.response_type;
50+
const scope = req.query.scope;
51+
if (req.user) {
52+
// TODO: Add logic for configurering redirect url's !!!!!!!!
53+
if (instance.clients[0].redirectUris.indexOf(redirect_uri) == -1) {
54+
instance.clients[0].redirectUris.push(redirect_uri);
55+
}
1456

15-
(app as any).oauth = oauthServer({
16-
model: instance
17-
});
18-
app.post('/oauth/token', (app as any).oauth.token());
57+
instance._logger.info("[OAuth][" + (req.user as any).username + "] /oauth/login " + state);
58+
instance.codes["cc536d98d27750394a87ab9d057016e636a8ac31"] = req.user;
59+
instance.codes["cc536d98d27750394a87ab9d057016e636a8ac31"].redirect_uri = redirect_uri;
60+
// res.redirect(`${GRAFANA_URI}/login/generic_oauth?state=${state}&code=cc536d98d27750394a87ab9d057016e636a8ac31`);
61+
res.redirect(`${redirect_uri}?state=${state}&code=cc536d98d27750394a87ab9d057016e636a8ac31`);
62+
} else {
63+
instance._logger.info("[OAuth][anon] /oauth/login " + state);
64+
res.redirect(`https://localhost.openrpa.dk`);
65+
}
66+
});
67+
// app.get('/oauth/authorize', instance.authorize.bind(instance));
68+
app.all('/oauth/authorize', (req, res) => {
69+
var request = new Request(req);
70+
var response = new Response(res);
71+
return instance.oauthServer.authenticate(request, response)
72+
.then((token) => {
73+
res.json(token.user);
74+
}).catch((err) => {
75+
console.error(err);
76+
res.status(err.code || 500).json(err);
77+
});
78+
});
79+
// app.all('/oauth/authorize', instance.oauthServer.authenticate.bind(instance));
80+
// app.all('/oauth/authorize/emails', instance.oauthServer.authenticate.bind(instance));
81+
} catch (error) {
82+
console.error(error);
83+
var json = JSON.stringify(error, null, 3);
84+
console.error(json);
85+
throw error;
86+
}
1987
return instance;
2088
}
89+
authorize(req, res) {
90+
this._logger.info("[OAuth] authorize");
91+
var request = new Request(req);
92+
var response = new Response(res);
93+
console.log(request.headers);
94+
return this.oauthServer.authorize(request, response)
95+
.then((token) => {
96+
res.json(token);
97+
}).catch((err) => {
98+
console.error(err);
99+
res.status(err.code || 500).json(err);
100+
});
101+
102+
}
103+
authenticateHandler() {
104+
return {
105+
handle: (request, response) => {
106+
//in this example, we store the logged-in user as the 'loginUser' attribute in session
107+
if (request.session.loginUser) {
108+
return { username: request.session.loginUser.username };
109+
}
110+
111+
return null;
112+
}
113+
};
114+
}
115+
obtainToken(req, res) {
116+
this._logger.info("[OAuth] obtainToken");
117+
var request = new Request(req);
118+
var response = new Response(res);
119+
return this.oauthServer.token(request, response)
120+
.then((token) => {
121+
this._logger.info("[OAuth] obtainToken::success: token:");
122+
res.json(token);
123+
}).catch((err) => {
124+
this._logger.info("[OAuth] obtainToken::failed: token:");
125+
console.error(err);
126+
res.status(err.code || 500).json(err);
127+
});
128+
}
21129
public getAccessToken(bearerToken) {
22-
var tokens = this.tokens.filter(function (token) {
130+
this._logger.info("[OAuth] getAccessToken " + bearerToken);
131+
var tokens = this.tokens.filter((token) => {
23132
return token.accessToken === bearerToken;
24133
});
25134
return tokens.length ? tokens[0] : false;
26135
}
27136
public getRefreshToken(bearerToken) {
28-
var tokens = this.tokens.filter(function (token) {
137+
this._logger.info("[OAuth] getRefreshToken " + bearerToken);
138+
var tokens = this.tokens.filter((token) => {
29139
return token.refreshToken === bearerToken;
30140
});
31141
return tokens.length ? tokens[0] : false;
32142
}
33143
public getClient(clientId, clientSecret) {
34-
var clients = this.clients.filter(function (client) {
144+
this._logger.info("[OAuth] getClient " + clientId);
145+
var clients = this.clients.filter((client) => {
35146
return client.clientId === clientId && client.clientSecret === clientSecret;
36147
});
37148
return clients.length ? clients[0] : false;
38149
}
39150
public saveToken(token, client, user) {
40-
this.tokens.push({
151+
this._logger.info("[OAuth] saveToken " + token);
152+
var result = {
41153
accessToken: token.accessToken,
154+
access_token: token.accessToken,
42155
accessTokenExpiresAt: token.accessTokenExpiresAt,
43156
clientId: client.clientId,
44157
refreshToken: token.refreshToken,
158+
refresh_token: token.refreshToken,
45159
refreshTokenExpiresAt: token.refreshTokenExpiresAt,
46-
userId: user.id
47-
});
160+
userId: user.id,
161+
162+
user: user,
163+
client: this.clients[0]
164+
};
165+
this.tokens.push(result);
166+
return result;
48167
}
49-
public getUser(username, password) {
50-
var users = this.users.filter(function (user) {
51-
return user.username === username && user.password === password;
168+
saveAuthorizationCode(code, client, user) {
169+
this._logger.info("[OAuth] saveAuthorizationCode " + code);
170+
var codeToSave: any = this.codes[code];
171+
codeToSave = {
172+
'authorizationCode': code.authorizationCode,
173+
'expiresAt': code.expiresAt,
174+
'redirectUri': code.redirectUri,
175+
'scope': code.scope,
176+
'client': client.id,
177+
'user': user.username
178+
};
179+
this.codes[code] = codeToSave;
180+
code = Object.assign({}, code, {
181+
'client': client.id,
182+
'user': user.username
52183
});
53-
return users.length ? users[0] : false;
54-
};
184+
return code;
185+
}
186+
getAuthorizationCode(code) {
187+
this._logger.info("[OAuth] getAuthorizationCode " + code);
188+
var user: TokenUser = this.codes[code];
189+
if (user == null) return null;
190+
var redirect_uri = (user as any).redirect_uri;
191+
var expiresAt = new Date();
192+
expiresAt.setMonth(expiresAt.getMonth() + 1);
193+
var role = "Viewer";
194+
user = TokenUser.From(user);
195+
if (user.HasRoleName("admins")) role = "Admin";
196+
var result = {
197+
code: code,
198+
client: this.clients[0],
199+
user: {
200+
id: user._id,
201+
_id: user._id,
202+
name: user.name,
203+
username: user.username,
204+
email: user.username,
205+
role: role
206+
},
207+
expiresAt: expiresAt,
208+
redirectUri: redirect_uri
209+
}
210+
// Viewer, Editor, Admin
211+
// return result;
212+
return result;
213+
}
214+
revokeAuthorizationCode(code) {
215+
this._logger.info("[OAuth] revokeAuthorizationCode " + code);
216+
return true;
217+
// var user: TokenUser = this.codes[code];
218+
// if (user != null) delete this.codes[code];
219+
// return code;
220+
}
55221
}

OpenFlow/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ try {
258258
if (GrafanaProxy != null) {
259259
const grafana = await GrafanaProxy.GrafanaProxy.configure(logger, WebServer.app);
260260
}
261-
// OAuthProvider.configure(logger, WebServer.app);
261+
OAuthProvider.configure(logger, WebServer.app);
262262
WebSocketServer.configure(logger, server);
263263
logger.info("listening on " + Config.baseurl());
264264
logger.info("namespace: " + Config.namespace);

OpenFlowNodeRED/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openflow-nodered",
3-
"version": "1.0.92",
3+
"version": "1.0.93",
44
"description": "Simple wrapper around NodeRed, RabbitMQ and MongoDB to support a more scaleable NodeRed implementation.\r Also the \"backend\" for [OpenRPA](https://github.com/skadefro/OpenRPA)",
55
"main": "index.js",
66
"scripts": {

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.92
1+
1.0.93

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openiap",
3-
"version": "1.0.92",
3+
"version": "1.0.93",
44
"description": "Simple wrapper around NodeRed, RabbitMQ and MongoDB to support a more scaleable NodeRed implementation.\r Also the \"backend\" for [OpenRPA](https://github.com/skadefro/OpenRPA)",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)