]>
Commit | Line | Data |
---|---|---|
9107d791 C |
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | ||
3 | import 'mocha' | |
4 | import { expect } from 'chai' | |
5 | import { ServerConfig, User, UserRole } from '@shared/models' | |
6 | import { | |
7 | decodeQueryString, | |
8 | getConfig, | |
9 | getExternalAuth, | |
10 | getMyUserInformation, | |
11 | getPluginTestPath, | |
12 | installPlugin, | |
13 | loginUsingExternalToken, | |
14 | logout, | |
15 | refreshToken, | |
16 | setAccessTokensToServers, | |
17 | uninstallPlugin, | |
18 | updateMyUser, | |
19 | wait | |
20 | } from '../../../shared/extra-utils' | |
21 | import { cleanupTests, flushAndRunServer, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers' | |
22 | ||
23 | async function loginExternal (options: { | |
24 | server: ServerInfo | |
25 | npmName: string | |
26 | authName: string | |
27 | username: string | |
28 | query?: any | |
29 | statusCodeExpected?: number | |
30 | }) { | |
31 | const res = await getExternalAuth({ | |
32 | url: options.server.url, | |
33 | npmName: options.npmName, | |
34 | npmVersion: '0.0.1', | |
35 | authName: options.authName, | |
36 | query: options.query, | |
37 | statusCodeExpected: options.statusCodeExpected || 302 | |
38 | }) | |
39 | ||
40 | if (res.status !== 302) return | |
41 | ||
42 | const location = res.header.location | |
43 | const { externalAuthToken } = decodeQueryString(location) | |
44 | ||
45 | const resLogin = await loginUsingExternalToken( | |
46 | options.server, | |
47 | options.username, | |
48 | externalAuthToken as string | |
49 | ) | |
50 | ||
51 | return resLogin.body | |
52 | } | |
53 | ||
54 | describe('Test external auth plugins', function () { | |
55 | let server: ServerInfo | |
56 | ||
57 | let cyanAccessToken: string | |
58 | let cyanRefreshToken: string | |
59 | ||
60 | let kefkaAccessToken: string | |
61 | let kefkaRefreshToken: string | |
62 | ||
63 | let externalAuthToken: string | |
64 | ||
65 | before(async function () { | |
66 | this.timeout(30000) | |
67 | ||
68 | server = await flushAndRunServer(1) | |
69 | await setAccessTokensToServers([ server ]) | |
70 | ||
71 | for (const suffix of [ 'one', 'two' ]) { | |
72 | await installPlugin({ | |
73 | url: server.url, | |
74 | accessToken: server.accessToken, | |
75 | path: getPluginTestPath('-external-auth-' + suffix) | |
76 | }) | |
77 | } | |
78 | }) | |
79 | ||
80 | it('Should display the correct configuration', async function () { | |
81 | const res = await getConfig(server.url) | |
82 | ||
83 | const config: ServerConfig = res.body | |
84 | ||
85 | const auths = config.plugin.registeredExternalAuths | |
86 | expect(auths).to.have.lengthOf(3) | |
87 | ||
88 | const auth2 = auths.find((a) => a.authName === 'external-auth-2') | |
89 | expect(auth2).to.exist | |
90 | expect(auth2.authDisplayName).to.equal('External Auth 2') | |
91 | expect(auth2.npmName).to.equal('peertube-plugin-test-external-auth-one') | |
92 | }) | |
93 | ||
94 | it('Should redirect for a Cyan login', async function () { | |
95 | const res = await getExternalAuth({ | |
96 | url: server.url, | |
97 | npmName: 'test-external-auth-one', | |
98 | npmVersion: '0.0.1', | |
99 | authName: 'external-auth-1', | |
100 | query: { | |
101 | username: 'cyan' | |
102 | }, | |
103 | statusCodeExpected: 302 | |
104 | }) | |
105 | ||
106 | const location = res.header.location | |
107 | expect(location.startsWith('/login?')).to.be.true | |
108 | ||
109 | const searchParams = decodeQueryString(location) | |
110 | ||
111 | expect(searchParams.externalAuthToken).to.exist | |
112 | expect(searchParams.username).to.equal('cyan') | |
113 | ||
114 | externalAuthToken = searchParams.externalAuthToken as string | |
115 | }) | |
116 | ||
117 | it('Should reject auto external login with a missing or invalid token', async function () { | |
118 | await loginUsingExternalToken(server, 'cyan', '', 400) | |
119 | await loginUsingExternalToken(server, 'cyan', 'blabla', 400) | |
120 | }) | |
121 | ||
122 | it('Should reject auto external login with a missing or invalid username', async function () { | |
123 | await loginUsingExternalToken(server, '', externalAuthToken, 400) | |
124 | await loginUsingExternalToken(server, '', externalAuthToken, 400) | |
125 | }) | |
126 | ||
127 | it('Should reject auto external login with an expired token', async function () { | |
128 | this.timeout(15000) | |
129 | ||
130 | await wait(5000) | |
131 | ||
132 | await loginUsingExternalToken(server, 'cyan', externalAuthToken, 400) | |
133 | ||
134 | await waitUntilLog(server, 'expired external auth token') | |
135 | }) | |
136 | ||
137 | it('Should auto login Cyan, create the user and use the token', async function () { | |
138 | { | |
139 | const res = await loginExternal({ | |
140 | server, | |
141 | npmName: 'test-external-auth-one', | |
142 | authName: 'external-auth-1', | |
143 | query: { | |
144 | username: 'cyan' | |
145 | }, | |
146 | username: 'cyan' | |
147 | }) | |
148 | ||
149 | cyanAccessToken = res.access_token | |
150 | cyanRefreshToken = res.refresh_token | |
151 | } | |
152 | ||
153 | { | |
154 | const res = await getMyUserInformation(server.url, cyanAccessToken) | |
155 | ||
156 | const body: User = res.body | |
157 | expect(body.username).to.equal('cyan') | |
158 | expect(body.account.displayName).to.equal('cyan') | |
159 | expect(body.email).to.equal('cyan@example.com') | |
160 | expect(body.role).to.equal(UserRole.USER) | |
161 | } | |
162 | }) | |
163 | ||
164 | it('Should auto login Kefka, create the user and use the token', async function () { | |
165 | { | |
166 | const res = await loginExternal({ | |
167 | server, | |
168 | npmName: 'test-external-auth-one', | |
169 | authName: 'external-auth-2', | |
170 | username: 'kefka' | |
171 | }) | |
172 | ||
173 | kefkaAccessToken = res.access_token | |
174 | kefkaRefreshToken = res.refresh_token | |
175 | } | |
176 | ||
177 | { | |
178 | const res = await getMyUserInformation(server.url, kefkaAccessToken) | |
179 | ||
180 | const body: User = res.body | |
181 | expect(body.username).to.equal('kefka') | |
182 | expect(body.account.displayName).to.equal('Kefka Palazzo') | |
183 | expect(body.email).to.equal('kefka@example.com') | |
184 | expect(body.role).to.equal(UserRole.ADMINISTRATOR) | |
185 | } | |
186 | }) | |
187 | ||
188 | it('Should refresh Cyan token, but not Kefka token', async function () { | |
189 | { | |
190 | const resRefresh = await refreshToken(server, cyanRefreshToken) | |
191 | cyanAccessToken = resRefresh.body.access_token | |
192 | cyanRefreshToken = resRefresh.body.refresh_token | |
193 | ||
194 | const res = await getMyUserInformation(server.url, cyanAccessToken) | |
195 | const user: User = res.body | |
196 | expect(user.username).to.equal('cyan') | |
197 | } | |
198 | ||
199 | { | |
200 | await refreshToken(server, kefkaRefreshToken, 400) | |
201 | } | |
202 | }) | |
203 | ||
204 | it('Should update Cyan profile', async function () { | |
205 | await updateMyUser({ | |
206 | url: server.url, | |
207 | accessToken: cyanAccessToken, | |
208 | displayName: 'Cyan Garamonde', | |
209 | description: 'Retainer to the king of Doma' | |
210 | }) | |
211 | ||
212 | const res = await getMyUserInformation(server.url, cyanAccessToken) | |
213 | ||
214 | const body: User = res.body | |
215 | expect(body.account.displayName).to.equal('Cyan Garamonde') | |
216 | expect(body.account.description).to.equal('Retainer to the king of Doma') | |
217 | }) | |
218 | ||
219 | it('Should logout Cyan', async function () { | |
220 | await logout(server.url, cyanAccessToken) | |
221 | }) | |
222 | ||
223 | it('Should have logged out Cyan', async function () { | |
224 | await waitUntilLog(server, 'On logout cyan') | |
225 | ||
226 | await getMyUserInformation(server.url, cyanAccessToken, 401) | |
227 | }) | |
228 | ||
229 | it('Should login Cyan and keep the old existing profile', async function () { | |
230 | { | |
231 | const res = await loginExternal({ | |
232 | server, | |
233 | npmName: 'test-external-auth-one', | |
234 | authName: 'external-auth-1', | |
235 | query: { | |
236 | username: 'cyan' | |
237 | }, | |
238 | username: 'cyan' | |
239 | }) | |
240 | ||
241 | cyanAccessToken = res.access_token | |
242 | } | |
243 | ||
244 | const res = await getMyUserInformation(server.url, cyanAccessToken) | |
245 | ||
246 | const body: User = res.body | |
247 | expect(body.username).to.equal('cyan') | |
248 | expect(body.account.displayName).to.equal('Cyan Garamonde') | |
249 | expect(body.account.description).to.equal('Retainer to the king of Doma') | |
250 | expect(body.role).to.equal(UserRole.USER) | |
251 | }) | |
252 | ||
253 | it('Should reject token of Kefka by the plugin hook', async function () { | |
254 | this.timeout(10000) | |
255 | ||
256 | await wait(5000) | |
257 | ||
258 | await getMyUserInformation(server.url, kefkaAccessToken, 401) | |
259 | }) | |
260 | ||
261 | it('Should uninstall the plugin one and do not login Cyan', async function () { | |
262 | await uninstallPlugin({ | |
263 | url: server.url, | |
264 | accessToken: server.accessToken, | |
265 | npmName: 'peertube-plugin-test-external-auth-one' | |
266 | }) | |
267 | ||
268 | await loginExternal({ | |
269 | server, | |
270 | npmName: 'test-external-auth-one', | |
271 | authName: 'external-auth-1', | |
272 | query: { | |
273 | username: 'cyan' | |
274 | }, | |
275 | username: 'cyan', | |
276 | statusCodeExpected: 404 | |
277 | }) | |
278 | }) | |
279 | ||
280 | it('Should display the correct configuration', async function () { | |
281 | const res = await getConfig(server.url) | |
282 | ||
283 | const config: ServerConfig = res.body | |
284 | ||
285 | const auths = config.plugin.registeredExternalAuths | |
286 | expect(auths).to.have.lengthOf(1) | |
287 | ||
288 | const auth2 = auths.find((a) => a.authName === 'external-auth-2') | |
289 | expect(auth2).to.not.exist | |
290 | }) | |
291 | ||
292 | after(async function () { | |
293 | await cleanupTests([ server ]) | |
294 | }) | |
295 | }) |