123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
- import 'mocha'
- import { expect } from 'chai'
- import { wait } from '@shared/core-utils'
- import { HttpStatusCode, UserRole } from '@shared/models'
- import {
- cleanupTests,
- createSingleServer,
- decodeQueryString,
- PeerTubeServer,
- PluginsCommand,
- setAccessTokensToServers
- } from '@shared/server-commands'
- async function loginExternal (options: {
- server: PeerTubeServer
- npmName: string
- authName: string
- username: string
- query?: any
- expectedStatus?: HttpStatusCode
- expectedStatusStep2?: HttpStatusCode
- }) {
- const res = await options.server.plugins.getExternalAuth({
- npmName: options.npmName,
- npmVersion: '0.0.1',
- authName: options.authName,
- query: options.query,
- expectedStatus: options.expectedStatus || HttpStatusCode.FOUND_302
- })
- if (res.status !== HttpStatusCode.FOUND_302) return
- const location = res.header.location
- const { externalAuthToken } = decodeQueryString(location)
- const resLogin = await options.server.login.loginUsingExternalToken({
- username: options.username,
- externalAuthToken: externalAuthToken as string,
- expectedStatus: options.expectedStatusStep2
- })
- return resLogin.body
- }
- describe('Test external auth plugins', function () {
- let server: PeerTubeServer
- let cyanAccessToken: string
- let cyanRefreshToken: string
- let kefkaAccessToken: string
- let kefkaRefreshToken: string
- let externalAuthToken: string
- before(async function () {
- this.timeout(30000)
- server = await createSingleServer(1)
- await setAccessTokensToServers([ server ])
- for (const suffix of [ 'one', 'two', 'three' ]) {
- await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-external-auth-' + suffix) })
- }
- })
- it('Should display the correct configuration', async function () {
- const config = await server.config.getConfig()
- const auths = config.plugin.registeredExternalAuths
- expect(auths).to.have.lengthOf(8)
- const auth2 = auths.find((a) => a.authName === 'external-auth-2')
- expect(auth2).to.exist
- expect(auth2.authDisplayName).to.equal('External Auth 2')
- expect(auth2.npmName).to.equal('peertube-plugin-test-external-auth-one')
- })
- it('Should redirect for a Cyan login', async function () {
- const res = await server.plugins.getExternalAuth({
- npmName: 'test-external-auth-one',
- npmVersion: '0.0.1',
- authName: 'external-auth-1',
- query: {
- username: 'cyan'
- },
- expectedStatus: HttpStatusCode.FOUND_302
- })
- const location = res.header.location
- expect(location.startsWith('/login?')).to.be.true
- const searchParams = decodeQueryString(location)
- expect(searchParams.externalAuthToken).to.exist
- expect(searchParams.username).to.equal('cyan')
- externalAuthToken = searchParams.externalAuthToken as string
- })
- it('Should reject auto external login with a missing or invalid token', async function () {
- const command = server.login
- await command.loginUsingExternalToken({ username: 'cyan', externalAuthToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- await command.loginUsingExternalToken({ username: 'cyan', externalAuthToken: 'blabla', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- })
- it('Should reject auto external login with a missing or invalid username', async function () {
- const command = server.login
- await command.loginUsingExternalToken({ username: '', externalAuthToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- await command.loginUsingExternalToken({ username: '', externalAuthToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- })
- it('Should reject auto external login with an expired token', async function () {
- this.timeout(15000)
- await wait(5000)
- await server.login.loginUsingExternalToken({
- username: 'cyan',
- externalAuthToken,
- expectedStatus: HttpStatusCode.BAD_REQUEST_400
- })
- await server.servers.waitUntilLog('expired external auth token', 4)
- })
- it('Should auto login Cyan, create the user and use the token', async function () {
- {
- const res = await loginExternal({
- server,
- npmName: 'test-external-auth-one',
- authName: 'external-auth-1',
- query: {
- username: 'cyan'
- },
- username: 'cyan'
- })
- cyanAccessToken = res.access_token
- cyanRefreshToken = res.refresh_token
- }
- {
- const body = await server.users.getMyInfo({ token: cyanAccessToken })
- expect(body.username).to.equal('cyan')
- expect(body.account.displayName).to.equal('cyan')
- expect(body.email).to.equal('cyan@example.com')
- expect(body.role).to.equal(UserRole.USER)
- }
- })
- it('Should auto login Kefka, create the user and use the token', async function () {
- {
- const res = await loginExternal({
- server,
- npmName: 'test-external-auth-one',
- authName: 'external-auth-2',
- username: 'kefka'
- })
- kefkaAccessToken = res.access_token
- kefkaRefreshToken = res.refresh_token
- }
- {
- const body = await server.users.getMyInfo({ token: kefkaAccessToken })
- expect(body.username).to.equal('kefka')
- expect(body.account.displayName).to.equal('Kefka Palazzo')
- expect(body.email).to.equal('kefka@example.com')
- expect(body.role).to.equal(UserRole.ADMINISTRATOR)
- }
- })
- it('Should refresh Cyan token, but not Kefka token', async function () {
- {
- const resRefresh = await server.login.refreshToken({ refreshToken: cyanRefreshToken })
- cyanAccessToken = resRefresh.body.access_token
- cyanRefreshToken = resRefresh.body.refresh_token
- const body = await server.users.getMyInfo({ token: cyanAccessToken })
- expect(body.username).to.equal('cyan')
- }
- {
- await server.login.refreshToken({ refreshToken: kefkaRefreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- }
- })
- it('Should update Cyan profile', async function () {
- await server.users.updateMe({
- token: cyanAccessToken,
- displayName: 'Cyan Garamonde',
- description: 'Retainer to the king of Doma'
- })
- const body = await server.users.getMyInfo({ token: cyanAccessToken })
- expect(body.account.displayName).to.equal('Cyan Garamonde')
- expect(body.account.description).to.equal('Retainer to the king of Doma')
- })
- it('Should logout Cyan', async function () {
- await server.login.logout({ token: cyanAccessToken })
- })
- it('Should have logged out Cyan', async function () {
- await server.servers.waitUntilLog('On logout cyan')
- await server.users.getMyInfo({ token: cyanAccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
- })
- it('Should login Cyan and keep the old existing profile', async function () {
- {
- const res = await loginExternal({
- server,
- npmName: 'test-external-auth-one',
- authName: 'external-auth-1',
- query: {
- username: 'cyan'
- },
- username: 'cyan'
- })
- cyanAccessToken = res.access_token
- }
- const body = await server.users.getMyInfo({ token: cyanAccessToken })
- expect(body.username).to.equal('cyan')
- expect(body.account.displayName).to.equal('Cyan Garamonde')
- expect(body.account.description).to.equal('Retainer to the king of Doma')
- expect(body.role).to.equal(UserRole.USER)
- })
- it('Should not update an external auth email', async function () {
- await server.users.updateMe({
- token: cyanAccessToken,
- email: 'toto@example.com',
- currentPassword: 'toto',
- expectedStatus: HttpStatusCode.BAD_REQUEST_400
- })
- })
- it('Should reject token of Kefka by the plugin hook', async function () {
- this.timeout(10000)
- await wait(5000)
- await server.users.getMyInfo({ token: kefkaAccessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
- })
- it('Should unregister external-auth-2 and do not login existing Kefka', async function () {
- await server.plugins.updateSettings({
- npmName: 'peertube-plugin-test-external-auth-one',
- settings: { disableKefka: true }
- })
- await server.login.login({ user: { username: 'kefka', password: 'fake' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- await loginExternal({
- server,
- npmName: 'test-external-auth-one',
- authName: 'external-auth-2',
- query: {
- username: 'kefka'
- },
- username: 'kefka',
- expectedStatus: HttpStatusCode.NOT_FOUND_404
- })
- })
- it('Should have disabled this auth', async function () {
- const config = await server.config.getConfig()
- const auths = config.plugin.registeredExternalAuths
- expect(auths).to.have.lengthOf(7)
- const auth1 = auths.find(a => a.authName === 'external-auth-2')
- expect(auth1).to.not.exist
- })
- it('Should uninstall the plugin one and do not login Cyan', async function () {
- await server.plugins.uninstall({ npmName: 'peertube-plugin-test-external-auth-one' })
- await loginExternal({
- server,
- npmName: 'test-external-auth-one',
- authName: 'external-auth-1',
- query: {
- username: 'cyan'
- },
- username: 'cyan',
- expectedStatus: HttpStatusCode.NOT_FOUND_404
- })
- await server.login.login({ user: { username: 'cyan', password: null }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- await server.login.login({ user: { username: 'cyan', password: '' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- await server.login.login({ user: { username: 'cyan', password: 'fake' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
- })
- it('Should not login kefka with another plugin', async function () {
- await loginExternal({
- server,
- npmName: 'test-external-auth-two',
- authName: 'external-auth-4',
- username: 'kefka2',
- expectedStatusStep2: HttpStatusCode.BAD_REQUEST_400
- })
- await loginExternal({
- server,
- npmName: 'test-external-auth-two',
- authName: 'external-auth-4',
- username: 'kefka',
- expectedStatusStep2: HttpStatusCode.BAD_REQUEST_400
- })
- })
- it('Should not login an existing user', async function () {
- await server.users.create({ username: 'existing_user', password: 'super_password' })
- await loginExternal({
- server,
- npmName: 'test-external-auth-two',
- authName: 'external-auth-6',
- username: 'existing_user',
- expectedStatusStep2: HttpStatusCode.BAD_REQUEST_400
- })
- })
- it('Should display the correct configuration', async function () {
- const config = await server.config.getConfig()
- const auths = config.plugin.registeredExternalAuths
- expect(auths).to.have.lengthOf(6)
- const auth2 = auths.find((a) => a.authName === 'external-auth-2')
- expect(auth2).to.not.exist
- })
- after(async function () {
- await cleanupTests([ server ])
- })
- it('Should forward the redirectUrl if the plugin returns one', async function () {
- const resLogin = await loginExternal({
- server,
- npmName: 'test-external-auth-three',
- authName: 'external-auth-7',
- username: 'cid'
- })
- const { redirectUrl } = await server.login.logout({ token: resLogin.access_token })
- expect(redirectUrl).to.equal('https://example.com/redirectUrl')
- })
- it('Should call the plugin\'s onLogout method with the request', async function () {
- const resLogin = await loginExternal({
- server,
- npmName: 'test-external-auth-three',
- authName: 'external-auth-8',
- username: 'cid'
- })
- const { redirectUrl } = await server.login.logout({ token: resLogin.access_token })
- expect(redirectUrl).to.equal('https://example.com/redirectUrl?access_token=' + resLogin.access_token)
- })
- })
|