aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-12-29 15:31:40 +0100
committerChocobozzz <me@florianbigard.com>2023-01-04 11:41:29 +0100
commit7e0c26066a5c59af742ae56bddaff9635debe034 (patch)
tree405a97a1c8a7c79c62c620406e6556d2c53c4d97
parentb65f5367baf799b425be0bcfb9220922751bb6eb (diff)
downloadPeerTube-7e0c26066a5c59af742ae56bddaff9635debe034.tar.gz
PeerTube-7e0c26066a5c59af742ae56bddaff9635debe034.tar.zst
PeerTube-7e0c26066a5c59af742ae56bddaff9635debe034.zip
External auth can set more user fields
videoQuota, videoQuotaDaily, adminFlags
-rw-r--r--server/lib/auth/external-auth.ts60
-rw-r--r--server/lib/auth/oauth-model.ts22
-rw-r--r--server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js5
-rw-r--r--server/tests/plugins/external-auth.ts8
-rw-r--r--server/types/plugins/register-server-auth.model.ts7
5 files changed, 54 insertions, 48 deletions
diff --git a/server/lib/auth/external-auth.ts b/server/lib/auth/external-auth.ts
index 053112801..155ec03d8 100644
--- a/server/lib/auth/external-auth.ts
+++ b/server/lib/auth/external-auth.ts
@@ -1,26 +1,33 @@
1 1
2import { isUserDisplayNameValid, isUserRoleValid, isUserUsernameValid } from '@server/helpers/custom-validators/users' 2import {
3 isUserAdminFlagsValid,
4 isUserDisplayNameValid,
5 isUserRoleValid,
6 isUserUsernameValid,
7 isUserVideoQuotaDailyValid,
8 isUserVideoQuotaValid
9} from '@server/helpers/custom-validators/users'
3import { logger } from '@server/helpers/logger' 10import { logger } from '@server/helpers/logger'
4import { generateRandomString } from '@server/helpers/utils' 11import { generateRandomString } from '@server/helpers/utils'
5import { PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME } from '@server/initializers/constants' 12import { PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME } from '@server/initializers/constants'
6import { PluginManager } from '@server/lib/plugins/plugin-manager' 13import { PluginManager } from '@server/lib/plugins/plugin-manager'
7import { OAuthTokenModel } from '@server/models/oauth/oauth-token' 14import { OAuthTokenModel } from '@server/models/oauth/oauth-token'
15import { MUser } from '@server/types/models'
8import { 16import {
9 RegisterServerAuthenticatedResult, 17 RegisterServerAuthenticatedResult,
10 RegisterServerAuthPassOptions, 18 RegisterServerAuthPassOptions,
11 RegisterServerExternalAuthenticatedResult 19 RegisterServerExternalAuthenticatedResult
12} from '@server/types/plugins/register-server-auth.model' 20} from '@server/types/plugins/register-server-auth.model'
13import { UserRole } from '@shared/models' 21import { UserAdminFlag, UserRole } from '@shared/models'
22
23export type ExternalUser =
24 Pick<MUser, 'username' | 'email' | 'role' | 'adminFlags' | 'videoQuotaDaily' | 'videoQuota'> &
25 { displayName: string }
14 26
15// Token is the key, expiration date is the value 27// Token is the key, expiration date is the value
16const authBypassTokens = new Map<string, { 28const authBypassTokens = new Map<string, {
17 expires: Date 29 expires: Date
18 user: { 30 user: ExternalUser
19 username: string
20 email: string
21 displayName: string
22 role: UserRole
23 }
24 authName: string 31 authName: string
25 npmName: string 32 npmName: string
26}>() 33}>()
@@ -172,30 +179,20 @@ function getBypassFromExternalAuth (username: string, externalAuthToken: string)
172} 179}
173 180
174function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) { 181function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) {
175 if (!isUserUsernameValid(result.username)) { 182 const returnError = (field: string) => {
176 logger.error('Auth method %s of plugin %s did not provide a valid username.', authName, npmName, { username: result.username }) 183 logger.error('Auth method %s of plugin %s did not provide a valid %s.', authName, npmName, field, { [field]: result[field] })
177 return false 184 return false
178 } 185 }
179 186
180 if (!result.email) { 187 if (!isUserUsernameValid(result.username)) return returnError('username')
181 logger.error('Auth method %s of plugin %s did not provide a valid email.', authName, npmName, { email: result.email }) 188 if (!result.email) return returnError('email')
182 return false
183 }
184 189
185 // role is optional 190 // Following fields are optional
186 if (result.role && !isUserRoleValid(result.role)) { 191 if (result.role && !isUserRoleValid(result.role)) return returnError('role')
187 logger.error('Auth method %s of plugin %s did not provide a valid role.', authName, npmName, { role: result.role }) 192 if (result.displayName && !isUserDisplayNameValid(result.displayName)) return returnError('displayName')
188 return false 193 if (result.adminFlags && !isUserAdminFlagsValid(result.adminFlags)) return returnError('adminFlags')
189 } 194 if (result.videoQuota && !isUserVideoQuotaValid(result.videoQuota + '')) return returnError('videoQuota')
190 195 if (result.videoQuotaDaily && !isUserVideoQuotaDailyValid(result.videoQuotaDaily + '')) return returnError('videoQuotaDaily')
191 // display name is optional
192 if (result.displayName && !isUserDisplayNameValid(result.displayName)) {
193 logger.error(
194 'Auth method %s of plugin %s did not provide a valid display name.',
195 authName, npmName, { displayName: result.displayName }
196 )
197 return false
198 }
199 196
200 return true 197 return true
201} 198}
@@ -205,7 +202,12 @@ function buildUserResult (pluginResult: RegisterServerAuthenticatedResult) {
205 username: pluginResult.username, 202 username: pluginResult.username,
206 email: pluginResult.email, 203 email: pluginResult.email,
207 role: pluginResult.role ?? UserRole.USER, 204 role: pluginResult.role ?? UserRole.USER,
208 displayName: pluginResult.displayName || pluginResult.username 205 displayName: pluginResult.displayName || pluginResult.username,
206
207 adminFlags: pluginResult.adminFlags ?? UserAdminFlag.NONE,
208
209 videoQuota: pluginResult.videoQuota,
210 videoQuotaDaily: pluginResult.videoQuotaDaily
209 } 211 }
210} 212}
211 213
diff --git a/server/lib/auth/oauth-model.ts b/server/lib/auth/oauth-model.ts
index 322b69e3a..603cc0f5f 100644
--- a/server/lib/auth/oauth-model.ts
+++ b/server/lib/auth/oauth-model.ts
@@ -5,7 +5,6 @@ import { MOAuthClient } from '@server/types/models'
5import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' 5import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token'
6import { MUser } from '@server/types/models/user/user' 6import { MUser } from '@server/types/models/user/user'
7import { pick } from '@shared/core-utils' 7import { pick } from '@shared/core-utils'
8import { UserRole } from '@shared/models/users/user-role'
9import { logger } from '../../helpers/logger' 8import { logger } from '../../helpers/logger'
10import { CONFIG } from '../../initializers/config' 9import { CONFIG } from '../../initializers/config'
11import { OAuthClientModel } from '../../models/oauth/oauth-client' 10import { OAuthClientModel } from '../../models/oauth/oauth-client'
@@ -13,6 +12,7 @@ import { OAuthTokenModel } from '../../models/oauth/oauth-token'
13import { UserModel } from '../../models/user/user' 12import { UserModel } from '../../models/user/user'
14import { findAvailableLocalActorName } from '../local-actor' 13import { findAvailableLocalActorName } from '../local-actor'
15import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user' 14import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user'
15import { ExternalUser } from './external-auth'
16import { TokensCache } from './tokens-cache' 16import { TokensCache } from './tokens-cache'
17 17
18type TokenInfo = { 18type TokenInfo = {
@@ -26,12 +26,7 @@ export type BypassLogin = {
26 bypass: boolean 26 bypass: boolean
27 pluginName: string 27 pluginName: string
28 authName?: string 28 authName?: string
29 user: { 29 user: ExternalUser
30 username: string
31 email: string
32 displayName: string
33 role: UserRole
34 }
35} 30}
36 31
37async function getAccessToken (bearerToken: string) { 32async function getAccessToken (bearerToken: string) {
@@ -219,16 +214,11 @@ export {
219 214
220// --------------------------------------------------------------------------- 215// ---------------------------------------------------------------------------
221 216
222async function createUserFromExternal (pluginAuth: string, options: { 217async function createUserFromExternal (pluginAuth: string, userOptions: ExternalUser) {
223 username: string 218 const username = await findAvailableLocalActorName(userOptions.username)
224 email: string
225 role: UserRole
226 displayName: string
227}) {
228 const username = await findAvailableLocalActorName(options.username)
229 219
230 const userToCreate = buildUser({ 220 const userToCreate = buildUser({
231 ...pick(options, [ 'email', 'role' ]), 221 ...pick(userOptions, [ 'email', 'role', 'adminFlags', 'videoQuota', 'videoQuotaDaily' ]),
232 222
233 username, 223 username,
234 emailVerified: null, 224 emailVerified: null,
@@ -238,7 +228,7 @@ async function createUserFromExternal (pluginAuth: string, options: {
238 228
239 const { user } = await createUserAccountAndChannelAndPlaylist({ 229 const { user } = await createUserAccountAndChannelAndPlaylist({
240 userToCreate, 230 userToCreate,
241 userDisplayName: options.displayName 231 userDisplayName: userOptions.displayName
242 }) 232 })
243 233
244 return user 234 return user
diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js b/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js
index c65b8d3a8..cdbaf11ac 100644
--- a/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js
+++ b/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js
@@ -33,7 +33,10 @@ async function register ({
33 username: 'kefka', 33 username: 'kefka',
34 email: 'kefka@example.com', 34 email: 'kefka@example.com',
35 role: 0, 35 role: 0,
36 displayName: 'Kefka Palazzo' 36 displayName: 'Kefka Palazzo',
37 adminFlags: 1,
38 videoQuota: 42000,
39 videoQuotaDaily: 42100
37 }) 40 })
38 }, 41 },
39 hookTokenValidity: (options) => { 42 hookTokenValidity: (options) => {
diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts
index 437777e90..ee78ae5aa 100644
--- a/server/tests/plugins/external-auth.ts
+++ b/server/tests/plugins/external-auth.ts
@@ -2,7 +2,7 @@
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { wait } from '@shared/core-utils' 4import { wait } from '@shared/core-utils'
5import { HttpStatusCode, UserRole } from '@shared/models' 5import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 createSingleServer, 8 createSingleServer,
@@ -156,6 +156,9 @@ describe('Test external auth plugins', function () {
156 expect(body.account.displayName).to.equal('cyan') 156 expect(body.account.displayName).to.equal('cyan')
157 expect(body.email).to.equal('cyan@example.com') 157 expect(body.email).to.equal('cyan@example.com')
158 expect(body.role.id).to.equal(UserRole.USER) 158 expect(body.role.id).to.equal(UserRole.USER)
159 expect(body.adminFlags).to.equal(UserAdminFlag.NONE)
160 expect(body.videoQuota).to.equal(5242880)
161 expect(body.videoQuotaDaily).to.equal(-1)
159 } 162 }
160 }) 163 })
161 164
@@ -178,6 +181,9 @@ describe('Test external auth plugins', function () {
178 expect(body.account.displayName).to.equal('Kefka Palazzo') 181 expect(body.account.displayName).to.equal('Kefka Palazzo')
179 expect(body.email).to.equal('kefka@example.com') 182 expect(body.email).to.equal('kefka@example.com')
180 expect(body.role.id).to.equal(UserRole.ADMINISTRATOR) 183 expect(body.role.id).to.equal(UserRole.ADMINISTRATOR)
184 expect(body.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST)
185 expect(body.videoQuota).to.equal(42000)
186 expect(body.videoQuotaDaily).to.equal(42100)
181 } 187 }
182 }) 188 })
183 189
diff --git a/server/types/plugins/register-server-auth.model.ts b/server/types/plugins/register-server-auth.model.ts
index 79c18c406..a17fc4b0f 100644
--- a/server/types/plugins/register-server-auth.model.ts
+++ b/server/types/plugins/register-server-auth.model.ts
@@ -1,5 +1,5 @@
1import express from 'express' 1import express from 'express'
2import { UserRole } from '@shared/models' 2import { UserAdminFlag, UserRole } from '@shared/models'
3import { MOAuthToken, MUser } from '../models' 3import { MOAuthToken, MUser } from '../models'
4 4
5export type RegisterServerAuthOptions = RegisterServerAuthPassOptions | RegisterServerAuthExternalOptions 5export type RegisterServerAuthOptions = RegisterServerAuthPassOptions | RegisterServerAuthExternalOptions
@@ -9,6 +9,11 @@ export interface RegisterServerAuthenticatedResult {
9 email: string 9 email: string
10 role?: UserRole 10 role?: UserRole
11 displayName?: string 11 displayName?: string
12
13 adminFlags?: UserAdminFlag
14
15 videoQuota?: number
16 videoQuotaDaily?: number
12} 17}
13 18
14export interface RegisterServerExternalAuthenticatedResult extends RegisterServerAuthenticatedResult { 19export interface RegisterServerExternalAuthenticatedResult extends RegisterServerAuthenticatedResult {