1 |
|
2 | const Base = require("./Base")
|
3 | const d = require("debug")("raptorjs:auth")
|
4 | const oauth2 = require("client-oauth2")
|
5 |
|
6 | const newExpires = () => Date.now() + (1000 * 60 * 5)
|
7 |
|
8 | class Auth extends Base {
|
9 |
|
10 | constructor(container) {
|
11 |
|
12 | super(container)
|
13 |
|
14 | this.defaultState = {
|
15 | token: null,
|
16 | user: null,
|
17 | expires: null,
|
18 | oauth2: null
|
19 | }
|
20 | this.state = null
|
21 |
|
22 | this.reset()
|
23 | }
|
24 |
|
25 | setUser(user) {
|
26 | this.state.user = user
|
27 | }
|
28 |
|
29 | getUser() {
|
30 | return this.state.user || null
|
31 | }
|
32 |
|
33 | setToken(token) {
|
34 | this.state.token = token
|
35 | }
|
36 |
|
37 | getToken() {
|
38 | return this.state.token || this.getConfig().token || null
|
39 | }
|
40 |
|
41 | setOAuth2Credentials(info) {
|
42 | this.state.oauth2 = info
|
43 | }
|
44 |
|
45 | getOAuth2Credentials() {
|
46 | return this.state.oauth2 || null
|
47 | }
|
48 |
|
49 | setExpires(expires) {
|
50 | this.state.expires = expires
|
51 | }
|
52 |
|
53 | getExpires() {
|
54 | return this.state.expires
|
55 | }
|
56 |
|
57 | reset() {
|
58 | this.state = Object.assign({}, this.defaultState)
|
59 | }
|
60 |
|
61 | changePassword(req) {
|
62 | if(!req.old) {
|
63 | throw new Error("Old password is missing")
|
64 | }
|
65 | if(!req.new) {
|
66 | throw new Error("New Password is missing")
|
67 | }
|
68 | return this.getClient().post(this.route("CHANGE_PASSWORD"), req)
|
69 | }
|
70 |
|
71 | loadUser(info) {
|
72 | return this.login(info)
|
73 | }
|
74 |
|
75 | loginIsExpired() {
|
76 | return !this.getConfig().token
|
77 | && (this.state.expires !== null
|
78 | && (Date.now() - this.state.expires) > 0)
|
79 | }
|
80 |
|
81 | login(config) {
|
82 |
|
83 | if(config) {
|
84 | const url = config.url || this.getConfig().url
|
85 | if (config.token) {
|
86 | this.setConfig({
|
87 | url, token: config.token
|
88 | })
|
89 | } else if (config.domain) {
|
90 | this.setConfig({
|
91 | url,
|
92 | domain: config.domain,
|
93 | username: config.username,
|
94 | password: config.password
|
95 | })
|
96 | } else {
|
97 | this.setConfig({
|
98 | url,
|
99 | username: config.username,
|
100 | password: config.password
|
101 | })
|
102 | }
|
103 | }
|
104 |
|
105 |
|
106 | if(this.getUser()) {
|
107 |
|
108 |
|
109 | if (this.loginIsExpired()) {
|
110 | d("Refreshing session token [user=%s]", this.getConfig().username)
|
111 | return this.refreshToken()
|
112 | }
|
113 |
|
114 | d("User avail [%s]", this.getUser().username)
|
115 | return Promise.resolve(this.getUser())
|
116 | }
|
117 |
|
118 | const credentials = this.getConfig()
|
119 | let promise = null
|
120 |
|
121 |
|
122 | this.reset()
|
123 |
|
124 | if(credentials.clientId) {
|
125 | promise = this.getAccessToken(credentials)
|
126 | .then(() => this.getContainer().Admin().User().read())
|
127 | .then((user) => {
|
128 | return Promise.resolve({ user, token: credentials.token })
|
129 | })
|
130 |
|
131 | } else if(credentials.token) {
|
132 | this.setToken(credentials.token)
|
133 | promise = this.getContainer().Admin().User().read()
|
134 | .then((user) => {
|
135 | return Promise.resolve({ user, token: credentials.token })
|
136 | })
|
137 | }
|
138 | else {
|
139 |
|
140 | if(!credentials.username || !credentials.password) {
|
141 | return Promise.reject(new Error("Username and password are required to login"))
|
142 | }
|
143 |
|
144 | d("Login user %s", credentials.username)
|
145 | promise = this.getClient().post(this.route("LOGIN"), credentials)
|
146 | }
|
147 |
|
148 | return promise
|
149 | .then(({user, token}) => {
|
150 | this.setToken(token)
|
151 | this.setUser(user)
|
152 | this.setExpires(newExpires())
|
153 | return Promise.resolve(this.getUser())
|
154 | })
|
155 | }
|
156 |
|
157 | getAccessToken(credentials) {
|
158 |
|
159 | const client = new oauth2(credentials, (method, url, body, headers) => {
|
160 | return this.getClient().baseRequest({
|
161 | method, url, body, headers, baseUrl: null,
|
162 | }).then((body) => {
|
163 |
|
164 | return Promise.resolve({ body: JSON.stringify(body) })
|
165 | })
|
166 | })
|
167 |
|
168 | let p
|
169 | switch (credentials.type) {
|
170 | default:
|
171 | case "client_credentials":
|
172 | p = client.credentials.getToken()
|
173 | break
|
174 | }
|
175 |
|
176 | return p.then((info) => {
|
177 | d("Retrieved oauth2 token")
|
178 | this.setOAuth2Credentials(info)
|
179 | this.setToken(info.accessToken)
|
180 | this.setExpires(info.expires.getTime())
|
181 | return this.getContainer().Admin().User().read()
|
182 | })
|
183 | }
|
184 |
|
185 | logout() {
|
186 | return this.getClient().delete(this.route("LOGOUT"))
|
187 | .then(() => {
|
188 | this.reset()
|
189 | return Promise.resolve()
|
190 | })
|
191 | }
|
192 |
|
193 | refreshToken() {
|
194 |
|
195 | if(this.getOAuth2Credentials()) {
|
196 | return this.getOAuth2Credentials().refresh()
|
197 | .then((info) => {
|
198 | this.setOAuth2Credentials(info)
|
199 | this.setToken(info.accessToken)
|
200 | this.setExpires(info.expires.getTime())
|
201 | return Promise.resolve()
|
202 | })
|
203 | }
|
204 |
|
205 | return this.getClient().get(this.route("REFRESH_TOKEN"))
|
206 | .then((res) => {
|
207 | this.setToken(res.token)
|
208 | this.setExpires(newExpires())
|
209 | return Promise.resolve(this.getUser())
|
210 | })
|
211 | }
|
212 |
|
213 | |
214 |
|
215 |
|
216 | syncDevice(req) {
|
217 | return this.getClient().post(this.route("DEVICE_SYNC"), req)
|
218 | }
|
219 |
|
220 | sync(req) {
|
221 | const invalid = ["type","permission","userId","subjectId"].filter((k) => !req[k])
|
222 | if(invalid.length) {
|
223 | throw new Error("Sync request has missing properties: " + invalid.join(","))
|
224 | }
|
225 | return this.getClient().post(this.route("ACL_SYNC"), req)
|
226 | }
|
227 |
|
228 | can(type, permission, subjectId, userId, domain) {
|
229 | if (typeof type === "object") {
|
230 | subjectId = type.subjectId
|
231 | permission = type.permission
|
232 | userId = type.userId
|
233 | domain = type.domain
|
234 | type = type.type
|
235 | }
|
236 |
|
237 | userId = userId || this.getContainer().Auth().getUser().uuid
|
238 | domain = domain || this.getContainer().getConfig().domain || null
|
239 |
|
240 | return this.getContainer().Admin().User().can({
|
241 | userId, type, permission, subjectId, domain
|
242 | })
|
243 | }
|
244 | }
|
245 |
|
246 | module.exports = Auth
|