diff options
-rw-r--r-- | server/lib/auth/external-auth.ts | 60 | ||||
-rw-r--r-- | server/lib/auth/oauth-model.ts | 22 | ||||
-rw-r--r-- | server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js | 5 | ||||
-rw-r--r-- | server/tests/plugins/external-auth.ts | 8 | ||||
-rw-r--r-- | server/types/plugins/register-server-auth.model.ts | 7 |
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 | ||
2 | import { isUserDisplayNameValid, isUserRoleValid, isUserUsernameValid } from '@server/helpers/custom-validators/users' | 2 | import { |
3 | isUserAdminFlagsValid, | ||
4 | isUserDisplayNameValid, | ||
5 | isUserRoleValid, | ||
6 | isUserUsernameValid, | ||
7 | isUserVideoQuotaDailyValid, | ||
8 | isUserVideoQuotaValid | ||
9 | } from '@server/helpers/custom-validators/users' | ||
3 | import { logger } from '@server/helpers/logger' | 10 | import { logger } from '@server/helpers/logger' |
4 | import { generateRandomString } from '@server/helpers/utils' | 11 | import { generateRandomString } from '@server/helpers/utils' |
5 | import { PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME } from '@server/initializers/constants' | 12 | import { PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME } from '@server/initializers/constants' |
6 | import { PluginManager } from '@server/lib/plugins/plugin-manager' | 13 | import { PluginManager } from '@server/lib/plugins/plugin-manager' |
7 | import { OAuthTokenModel } from '@server/models/oauth/oauth-token' | 14 | import { OAuthTokenModel } from '@server/models/oauth/oauth-token' |
15 | import { MUser } from '@server/types/models' | ||
8 | import { | 16 | import { |
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' |
13 | import { UserRole } from '@shared/models' | 21 | import { UserAdminFlag, UserRole } from '@shared/models' |
22 | |||
23 | export 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 |
16 | const authBypassTokens = new Map<string, { | 28 | const 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 | ||
174 | function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) { | 181 | function 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' | |||
5 | import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' | 5 | import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' |
6 | import { MUser } from '@server/types/models/user/user' | 6 | import { MUser } from '@server/types/models/user/user' |
7 | import { pick } from '@shared/core-utils' | 7 | import { pick } from '@shared/core-utils' |
8 | import { UserRole } from '@shared/models/users/user-role' | ||
9 | import { logger } from '../../helpers/logger' | 8 | import { logger } from '../../helpers/logger' |
10 | import { CONFIG } from '../../initializers/config' | 9 | import { CONFIG } from '../../initializers/config' |
11 | import { OAuthClientModel } from '../../models/oauth/oauth-client' | 10 | import { OAuthClientModel } from '../../models/oauth/oauth-client' |
@@ -13,6 +12,7 @@ import { OAuthTokenModel } from '../../models/oauth/oauth-token' | |||
13 | import { UserModel } from '../../models/user/user' | 12 | import { UserModel } from '../../models/user/user' |
14 | import { findAvailableLocalActorName } from '../local-actor' | 13 | import { findAvailableLocalActorName } from '../local-actor' |
15 | import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user' | 14 | import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user' |
15 | import { ExternalUser } from './external-auth' | ||
16 | import { TokensCache } from './tokens-cache' | 16 | import { TokensCache } from './tokens-cache' |
17 | 17 | ||
18 | type TokenInfo = { | 18 | type 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 | ||
37 | async function getAccessToken (bearerToken: string) { | 32 | async function getAccessToken (bearerToken: string) { |
@@ -219,16 +214,11 @@ export { | |||
219 | 214 | ||
220 | // --------------------------------------------------------------------------- | 215 | // --------------------------------------------------------------------------- |
221 | 216 | ||
222 | async function createUserFromExternal (pluginAuth: string, options: { | 217 | async 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 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { wait } from '@shared/core-utils' | 4 | import { wait } from '@shared/core-utils' |
5 | import { HttpStatusCode, UserRole } from '@shared/models' | 5 | import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models' |
6 | import { | 6 | import { |
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 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { UserRole } from '@shared/models' | 2 | import { UserAdminFlag, UserRole } from '@shared/models' |
3 | import { MOAuthToken, MUser } from '../models' | 3 | import { MOAuthToken, MUser } from '../models' |
4 | 4 | ||
5 | export type RegisterServerAuthOptions = RegisterServerAuthPassOptions | RegisterServerAuthExternalOptions | 5 | export 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 | ||
14 | export interface RegisterServerExternalAuthenticatedResult extends RegisterServerAuthenticatedResult { | 19 | export interface RegisterServerExternalAuthenticatedResult extends RegisterServerAuthenticatedResult { |