This repository has been archived by the owner on Nov 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathauth.js
227 lines (199 loc) · 8.78 KB
/
auth.js
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
Copyright 2019 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/
import passport from 'passport'
import StrategyBuilder from './strategy/builder'
import cookie from 'cookie'
const refresh = require('passport-oauth2-refresh')
function _authenticate(params) {
return new Promise((resolve, reject) => {
//build a strategy for Passport based on input params
let builder = new StrategyBuilder()
.withProvider(params.auth_provider)
.withCredentials(params.client_id, params.client_secret)
.withCallbackURL(params.callback_url)
.withVerifyer(function (accessToken, refreshToken, authParams, profile) {
console.log("Logged in successfully ... ");
profile.id = params.client_id + ":oauth:" + profile.id;
let persistence = (params.persistence || 'false').toString().toLowerCase()
if(persistence !== 'true')
params.accessToken=accessToken //Store in cookie context
let ctx = _updateContext(params, profile);
ctx.success_redirect = ctx.success_redirect || params.redirect_url;
let refreshExpDate = new Date();
let refreshTTL = params["refresh_token_ttl_"+params.auth_provider_name] || 7
refreshExpDate.setDate(refreshExpDate.getDate() + refreshTTL);
refreshExpDate = formatDate(refreshExpDate);
let currentTimeInseconds = new Date().getTime() / 1000;
let accessTokenExpiry = (currentTimeInseconds + authParams.expires_in)*1000;
response.body = {
"profileID": profile.id,
"accessToken": accessToken,
"accessTokenExpiry": accessTokenExpiry,
"refreshToken": refreshToken,
"refreshTokenExpiry": refreshExpDate || 0,
"profile": profile,
"context": ctx,
"provider": params.auth_provider_name
};
resolve(get_action_response(response));
});
let strategy = builder.buildStrategy();
if (strategy === null) {
reject({
"message": "Could not load " + params.auth_provider,
"error": builder.getError().toString()
}
);
}
// create a lightweight request object to be used in the serverless context
let request = {
query: params, // expose query parameters
session: strategy._requestTokenStore || strategy._stateStore // inherit the session from Passport
};
// create a lightweight response object to be used in the serverless context
let response = {
headers: {},
setHeader: function (name, val) {
response.headers[name] = val;
},
end: function () {
console.log("response end()");
resolve(get_action_response(response));
}
};
let get_action_response = function (resp) {
if (resp.body instanceof Error) {
console.error(resp.body);
resp.body = resp.body.toString();
}
// save the success_redirect in a cookie to
// set it in the context once the user logs in
//TODO The following block may not be needed because of package params.
if (resp.statusCode == 302) {
let cookie_header = resp.headers['Set-Cookie'];
if ((cookie_header === null || typeof(cookie_header) === "undefined") &&
(params.success_redirect !== null && typeof(params.success_redirect) !== "undefined")) {
let ctx = _getContext(params);
ctx.success_redirect = params.success_redirect;
let cookiePath = ctx.cookie_path || params.cookie_path || process.env['__OW_NAMESPACE'] + "/"
resp.headers["Set-Cookie"] = '__Secure-auth_context=' + JSON.stringify(ctx) + '; Secure; HttpOnly; Max-Age=600; Path=/api/v1/web/' + cookiePath
}
}
return {
headers: resp.headers,
statusCode: resp.statusCode,
body: resp.body || ''
}
};
let next = function (opts) {
console.log("next()");
response.body = opts;
resolve(get_action_response(response));
};
passport.use(strategy);
refresh.use(strategy);
let scopes = params.scopes || null;
if (scopes !== null) {
scopes = scopes.split(",");
}
if (params.auth_type === 'refresh'){
refresh.requestNewAccessToken(params.provider, params.refreshToken, function(retVal, accessToken, refreshToken, results){
let refreshExpDate = new Date();
let refreshTTL = params["refresh_token_ttl_"+params.provider] || 7
refreshExpDate.setDate(refreshExpDate.getDate() + refreshTTL);
refreshExpDate = formatDate(refreshExpDate);
let currentTimeInseconds = new Date().getTime() / 1000;
let accessTokenExpiry = (currentTimeInseconds + results.expires_in)*1000;
resolve({
"accessToken" : accessToken,
"refreshToken" : refreshToken,
"expires_in" : accessTokenExpiry,
"refreshTokenExpiry" : refreshExpDate
});
});
}else{
let res = passport.authenticate(params.auth_provider_name || params.auth_provider, {
scope: scopes,
successRedirect: '/success', // TODO: TBD should this be read from parameters ?
failureRedirect: '/login' // TODO: TBD should this be read from parameters ?
});
res(request, response, next);
}
});
}
function _getContext(params) {
const CONTEXT_COOKIE_NAME = "__Secure-auth_context";
//console.log("Cookies:" + params.__ow_headers['cookie']);
let cookies = cookie.parse(params.__ow_headers['cookie'] || '');
//console.log("Cookies parsed:" + JSON.stringify(cookies));
return cookies[CONTEXT_COOKIE_NAME] ? JSON.parse(cookies[CONTEXT_COOKIE_NAME]) : {};
}
/**
* Returns a context object for this action.
* If this action is used to link multiple social IDs together
* it reads the linked identities from a Cookie named "auth_context".
* For Example the cookie header might be
* Cookie: "auth_context={"identities":[{"provider":"adobe","user_id":"123"}
* In this case the context.identities object is populated with the value from the cookie
* This context object should be used by another action in order to persist
* the information about the linked accounts
*
* @param params Action input parameters
* @param profile User Profile
*/
function _updateContext(params, profile) {
let ctx = _getContext(params);
//console.log("ctx.identities=" + JSON.stringify(ctx.identities));
// NOTE: there's no check for duplicated providers, ne design.
// 2 accounts from the same provider can be linked together as well.
// avoid duplicated identities
let provider = (params.auth_provider_name || params.auth_provider)
ctx.identities = ctx.identities || [];
for (let i=0; i<ctx.identities.length; i++ ){
let ident = ctx.identities[i];
if (ident !== null && typeof(ident) !== "undefined" &&
ident.provider == provider && ident.user_id == profile.id) {
if(params.accessToken)
ident.accessToken = params.accessToken
return ctx;
}
}
let newIdentity = {
"provider": (params.auth_provider_name || params.auth_provider),
"user_id": profile.id
}
if(params.accessToken)
newIdentity.accessToken = params.accessToken
ctx.identities.push(newIdentity);
return ctx;
}
function formatDate(date) {
let monthNames = [
"Jan", "Feb", "Mar",
"Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct",
"Nov", "Dec"
];
let day = date.getDate();
let monthIndex = date.getMonth();
let year = date.getFullYear();
return day + '' + monthNames[monthIndex] + '' + year;
}
/**
* The entry point for the action.
* @param params Input object
* @returns {Promise}
*/
function main(params) {
//console.log(params);
return _authenticate(params);
}
export default main;