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 | loadUser(info) {
|
62 | return this.login(info)
|
63 | }
|
64 |
|
65 | loginIsExpired() {
|
66 | return !this.getConfig().token
|
67 | && (this.state.expires !== null
|
68 | && (Date.now() - this.state.expires) > 0)
|
69 | }
|
70 |
|
71 | login(config) {
|
72 |
|
73 | if(config) {
|
74 | const url = config.url || this.getConfig().url
|
75 | if (config.token) {
|
76 | this.setConfig({
|
77 | url, token: config.token
|
78 | })
|
79 | } else if (config.domain) {
|
80 | this.setConfig({
|
81 | url,
|
82 | domain: config.domain,
|
83 | username: config.username,
|
84 | password: config.password
|
85 | })
|
86 | } else {
|
87 | this.setConfig({
|
88 | url,
|
89 | username: config.username,
|
90 | password: config.password
|
91 | })
|
92 | }
|
93 | }
|
94 |
|
95 |
|
96 | if(this.getUser()) {
|
97 |
|
98 |
|
99 | if (this.loginIsExpired()) {
|
100 | d("Refreshing session token [user=%s]", this.getConfig().username)
|
101 | return this.refreshToken()
|
102 | }
|
103 |
|
104 | d("User avail [%s]", this.getUser().username)
|
105 | return Promise.resolve(this.getUser())
|
106 | }
|
107 |
|
108 | const credentials = this.getConfig()
|
109 | let promise = null
|
110 |
|
111 |
|
112 | this.reset()
|
113 |
|
114 | if(credentials.clientId) {
|
115 | promise = this.getAccessToken(credentials)
|
116 | .then(() => this.getContainer().Admin().User().read())
|
117 | .then((user) => {
|
118 | return Promise.resolve({ user, token: credentials.token })
|
119 | })
|
120 |
|
121 | } else if(credentials.token) {
|
122 | this.setToken(credentials.token)
|
123 | promise = this.getContainer().Admin().User().read()
|
124 | .then((user) => {
|
125 | return Promise.resolve({ user, token: credentials.token })
|
126 | })
|
127 | }
|
128 | else {
|
129 |
|
130 | if(!credentials.username || !credentials.password) {
|
131 | return Promise.reject(new Error("Username and password are required to login"))
|
132 | }
|
133 |
|
134 | d("Login user %s", credentials.username)
|
135 | promise = this.getClient().post(this.route("LOGIN"), credentials)
|
136 | }
|
137 |
|
138 | return promise
|
139 | .then(({user, token}) => {
|
140 | this.setToken(token)
|
141 | this.setUser(user)
|
142 | this.setExpires(newExpires())
|
143 | return Promise.resolve(this.getUser())
|
144 | })
|
145 | }
|
146 |
|
147 | getAccessToken(credentials) {
|
148 |
|
149 | const client = new oauth2(credentials, (method, url, body, headers) => {
|
150 | return this.getClient().baseRequest({
|
151 | method, url, body, headers, baseUrl: null,
|
152 | }).then((body) => {
|
153 |
|
154 | return Promise.resolve({ body: JSON.stringify(body) })
|
155 | })
|
156 | })
|
157 |
|
158 | let p
|
159 | switch (credentials.type) {
|
160 | default:
|
161 | case "client_credentials":
|
162 | p = client.credentials.getToken()
|
163 | break
|
164 | }
|
165 |
|
166 | return p.then((info) => {
|
167 | d("Retrieved oauth2 token")
|
168 | this.setOAuth2Credentials(info)
|
169 | this.setToken(info.accessToken)
|
170 | this.setExpires(info.expires.getTime())
|
171 | return this.getContainer().Admin().User().read()
|
172 | })
|
173 | }
|
174 |
|
175 | logout() {
|
176 | return this.getClient().delete(this.route("LOGOUT"))
|
177 | .then(() => {
|
178 | this.reset()
|
179 | return Promise.resolve()
|
180 | })
|
181 | }
|
182 |
|
183 | refreshToken() {
|
184 |
|
185 | if(this.getOAuth2Credentials()) {
|
186 | return this.getOAuth2Credentials().refresh()
|
187 | .then((info) => {
|
188 | this.setOAuth2Credentials(info)
|
189 | this.setToken(info.accessToken)
|
190 | this.setExpires(info.expires.getTime())
|
191 | return Promise.resolve()
|
192 | })
|
193 | }
|
194 |
|
195 | return this.getClient().get(this.route("REFRESH_TOKEN"))
|
196 | .then((res) => {
|
197 | this.setToken(res.token)
|
198 | this.setExpires(newExpires())
|
199 | return Promise.resolve(this.getUser())
|
200 | })
|
201 | }
|
202 |
|
203 | |
204 |
|
205 |
|
206 | syncDevice(req) {
|
207 | return this.getClient().post(this.route("DEVICE_SYNC"), req)
|
208 | }
|
209 |
|
210 | sync(req) {
|
211 | const invalid = ["type","permission","userId","subjectId"].filter((k) => !req[k])
|
212 | if(invalid.length) {
|
213 | throw new Error("Sync request has missing properties: " + invalid.join(","))
|
214 | }
|
215 | return this.getClient().post(this.route("ACL_SYNC"), req)
|
216 | }
|
217 |
|
218 | can(type, permission, subjectId, userId, domain) {
|
219 | if (typeof type === "object") {
|
220 | subjectId = type.subjectId
|
221 | permission = type.permission
|
222 | userId = type.userId
|
223 | domain = type.domain
|
224 | type = type.type
|
225 | }
|
226 |
|
227 | userId = userId || this.getContainer().Auth().getUser().uuid
|
228 | domain = domain || this.getContainer().getConfig().domain || null
|
229 |
|
230 | return this.getContainer().Admin().User().can({
|
231 | userId, type, permission, subjectId, domain
|
232 | })
|
233 | }
|
234 | }
|
235 |
|
236 | module.exports = Auth
|