]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/auth.ts
Add plugin ldap tests
[github/Chocobozzz/PeerTube.git] / server / lib / auth.ts
CommitLineData
7fed6375
C
1import * as express from 'express'
2import { OAUTH_LIFETIME } from '@server/initializers/constants'
3import * as OAuthServer from 'express-oauth-server'
4import { PluginManager } from '@server/lib/plugins/plugin-manager'
5import { RegisterServerAuthPassOptions } from '@shared/models/plugins/register-server-auth.model'
6import { logger } from '@server/helpers/logger'
7import { UserRole } from '@shared/models'
e1c55031 8import { revokeToken } from '@server/lib/oauth-model'
e307e4fc 9import { OAuthTokenModel } from '@server/models/oauth/oauth-token'
7fed6375
C
10
11const oAuthServer = new OAuthServer({
12 useErrorHandler: true,
13 accessTokenLifetime: OAUTH_LIFETIME.ACCESS_TOKEN,
14 refreshTokenLifetime: OAUTH_LIFETIME.REFRESH_TOKEN,
15 continueMiddleware: true,
16 model: require('./oauth-model')
17})
18
19function onExternalAuthPlugin (npmName: string, username: string, email: string) {
20
21}
22
23async function handleIdAndPassLogin (req: express.Request, res: express.Response, next: express.NextFunction) {
e307e4fc
C
24 const grantType = req.body.grant_type
25
26 if (grantType === 'password') await proxifyPasswordGrant(req, res)
27 else if (grantType === 'refresh_token') await proxifyRefreshGrant(req, res)
28
29 return forwardTokenReq(req, res, next)
30}
31
32async function handleTokenRevocation (req: express.Request, res: express.Response) {
33 const token = res.locals.oauth.token
34
35 res.locals.explicitLogout = true
36 await revokeToken(token)
37
38 // FIXME: uncomment when https://github.com/oauthjs/node-oauth2-server/pull/289 is released
39 // oAuthServer.revoke(req, res, err => {
40 // if (err) {
41 // logger.warn('Error in revoke token handler.', { err })
42 //
43 // return res.status(err.status)
44 // .json({
45 // error: err.message,
46 // code: err.name
47 // })
48 // .end()
49 // }
50 // })
51
52 return res.sendStatus(200)
53}
54
55// ---------------------------------------------------------------------------
56
57export {
58 oAuthServer,
59 handleIdAndPassLogin,
60 onExternalAuthPlugin,
61 handleTokenRevocation
62}
63
64// ---------------------------------------------------------------------------
65
66function forwardTokenReq (req: express.Request, res: express.Response, next: express.NextFunction) {
67 return oAuthServer.token()(req, res, err => {
68 if (err) {
69 logger.warn('Login error.', { err })
70
71 return res.status(err.status)
72 .json({
73 error: err.message,
74 code: err.name
75 })
76 .end()
77 }
78
79 return next()
80 })
81}
82
83async function proxifyRefreshGrant (req: express.Request, res: express.Response) {
84 const refreshToken = req.body.refresh_token
85 if (!refreshToken) return
86
87 const tokenModel = await OAuthTokenModel.loadByRefreshToken(refreshToken)
88 if (tokenModel?.authName) res.locals.refreshTokenAuthName = tokenModel.authName
89}
90
91async function proxifyPasswordGrant (req: express.Request, res: express.Response) {
7fed6375
C
92 const plugins = PluginManager.Instance.getIdAndPassAuths()
93 const pluginAuths: { npmName?: string, registerAuthOptions: RegisterServerAuthPassOptions }[] = []
94
95 for (const plugin of plugins) {
96 const auths = plugin.idAndPassAuths
97
98 for (const auth of auths) {
99 pluginAuths.push({
100 npmName: plugin.npmName,
101 registerAuthOptions: auth
102 })
103 }
104 }
105
106 pluginAuths.sort((a, b) => {
107 const aWeight = a.registerAuthOptions.getWeight()
108 const bWeight = b.registerAuthOptions.getWeight()
109
e1c55031 110 // DESC weight order
7fed6375 111 if (aWeight === bWeight) return 0
e1c55031 112 if (aWeight < bWeight) return 1
7fed6375
C
113 return -1
114 })
115
116 const loginOptions = {
117 id: req.body.username,
118 password: req.body.password
119 }
120
121 for (const pluginAuth of pluginAuths) {
e1c55031
C
122 const authOptions = pluginAuth.registerAuthOptions
123
7fed6375 124 logger.debug(
e1c55031
C
125 'Using auth method %s of plugin %s to login %s with weight %d.',
126 authOptions.authName, pluginAuth.npmName, loginOptions.id, authOptions.getWeight()
7fed6375
C
127 )
128
055cfb11
C
129 try {
130 const loginResult = await authOptions.login(loginOptions)
131 if (loginResult) {
132 logger.info(
133 'Login success with auth method %s of plugin %s for %s.',
134 authOptions.authName, pluginAuth.npmName, loginOptions.id
135 )
136
137 res.locals.bypassLogin = {
138 bypass: true,
139 pluginName: pluginAuth.npmName,
140 authName: authOptions.authName,
141 user: {
142 username: loginResult.username,
143 email: loginResult.email,
144 role: loginResult.role || UserRole.USER,
145 displayName: loginResult.displayName || loginResult.username
146 }
7fed6375 147 }
7fed6375 148
055cfb11
C
149 return
150 }
151 } catch (err) {
152 logger.error('Error in auth method %s of plugin %s', authOptions.authName, pluginAuth.npmName, { err })
7fed6375
C
153 }
154 }
7fed6375 155}