]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/auth.ts
Add plugin auth migrations
[github/Chocobozzz/PeerTube.git] / server / lib / auth.ts
index 18d52fa5a7ff5f5623f9a2dbf43a0f03007ed03e..c47ec62d08499140a95cfc50f72fa2e9db35d81b 100644 (file)
@@ -5,6 +5,8 @@ import { PluginManager } from '@server/lib/plugins/plugin-manager'
 import { RegisterServerAuthPassOptions } from '@shared/models/plugins/register-server-auth.model'
 import { logger } from '@server/helpers/logger'
 import { UserRole } from '@shared/models'
+import { revokeToken } from '@server/lib/oauth-model'
+import { OAuthTokenModel } from '@server/models/oauth/oauth-token'
 
 const oAuthServer = new OAuthServer({
   useErrorHandler: true,
@@ -19,6 +21,74 @@ function onExternalAuthPlugin (npmName: string, username: string, email: string)
 }
 
 async function handleIdAndPassLogin (req: express.Request, res: express.Response, next: express.NextFunction) {
+  const grantType = req.body.grant_type
+
+  if (grantType === 'password') await proxifyPasswordGrant(req, res)
+  else if (grantType === 'refresh_token') await proxifyRefreshGrant(req, res)
+
+  return forwardTokenReq(req, res, next)
+}
+
+async function handleTokenRevocation (req: express.Request, res: express.Response) {
+  const token = res.locals.oauth.token
+
+  res.locals.explicitLogout = true
+  await revokeToken(token)
+
+  // FIXME: uncomment when https://github.com/oauthjs/node-oauth2-server/pull/289 is released
+  // oAuthServer.revoke(req, res, err => {
+  //   if (err) {
+  //     logger.warn('Error in revoke token handler.', { err })
+  //
+  //     return res.status(err.status)
+  //               .json({
+  //                 error: err.message,
+  //                 code: err.name
+  //               })
+  //               .end()
+  //   }
+  // })
+
+  return res.sendStatus(200)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  oAuthServer,
+  handleIdAndPassLogin,
+  onExternalAuthPlugin,
+  handleTokenRevocation
+}
+
+// ---------------------------------------------------------------------------
+
+function forwardTokenReq (req: express.Request, res: express.Response, next: express.NextFunction) {
+  return oAuthServer.token()(req, res, err => {
+    if (err) {
+      logger.warn('Login error.', { err })
+
+      return res.status(err.status)
+                .json({
+                  error: err.message,
+                  code: err.name
+                })
+                .end()
+    }
+
+    return next()
+  })
+}
+
+async function proxifyRefreshGrant (req: express.Request, res: express.Response) {
+  const refreshToken = req.body.refresh_token
+  if (!refreshToken) return
+
+  const tokenModel = await OAuthTokenModel.loadByRefreshToken(refreshToken)
+  if (tokenModel?.authName) res.locals.refreshTokenAuthName = tokenModel.authName
+}
+
+async function proxifyPasswordGrant (req: express.Request, res: express.Response) {
   const plugins = PluginManager.Instance.getIdAndPassAuths()
   const pluginAuths: { npmName?: string, registerAuthOptions: RegisterServerAuthPassOptions }[] = []
 
@@ -37,8 +107,9 @@ async function handleIdAndPassLogin (req: express.Request, res: express.Response
     const aWeight = a.registerAuthOptions.getWeight()
     const bWeight = b.registerAuthOptions.getWeight()
 
+    // DESC weight order
     if (aWeight === bWeight) return 0
-    if (aWeight > bWeight) return 1
+    if (aWeight < bWeight) return 1
     return -1
   })
 
@@ -48,54 +119,37 @@ async function handleIdAndPassLogin (req: express.Request, res: express.Response
   }
 
   for (const pluginAuth of pluginAuths) {
+    const authOptions = pluginAuth.registerAuthOptions
+
     logger.debug(
-      'Using auth method of %s to login %s with weight %d.',
-      pluginAuth.npmName, loginOptions.id, pluginAuth.registerAuthOptions.getWeight()
+      'Using auth method %s of plugin %s to login %s with weight %d.',
+      authOptions.authName, pluginAuth.npmName, loginOptions.id, authOptions.getWeight()
     )
 
-    const loginResult = await pluginAuth.registerAuthOptions.login(loginOptions)
-    if (loginResult) {
-      logger.info('Login success with plugin %s for %s.', pluginAuth.npmName, loginOptions.id)
-
-      res.locals.bypassLogin = {
-        bypass: true,
-        pluginName: pluginAuth.npmName,
-        user: {
-          username: loginResult.username,
-          email: loginResult.email,
-          role: loginResult.role || UserRole.USER,
-          displayName: loginResult.displayName || loginResult.username
+    try {
+      const loginResult = await authOptions.login(loginOptions)
+      if (loginResult) {
+        logger.info(
+          'Login success with auth method %s of plugin %s for %s.',
+          authOptions.authName, pluginAuth.npmName, loginOptions.id
+        )
+
+        res.locals.bypassLogin = {
+          bypass: true,
+          pluginName: pluginAuth.npmName,
+          authName: authOptions.authName,
+          user: {
+            username: loginResult.username,
+            email: loginResult.email,
+            role: loginResult.role || UserRole.USER,
+            displayName: loginResult.displayName || loginResult.username
+          }
         }
-      }
 
-      break
+        return
+      }
+    } catch (err) {
+      logger.error('Error in auth method %s of plugin %s', authOptions.authName, pluginAuth.npmName, { err })
     }
   }
-
-  return localLogin(req, res, next)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  oAuthServer,
-  handleIdAndPassLogin,
-  onExternalAuthPlugin
-}
-
-// ---------------------------------------------------------------------------
-
-function localLogin (req: express.Request, res: express.Response, next: express.NextFunction) {
-  return oAuthServer.token()(req, res, err => {
-    if (err) {
-      return res.status(err.status)
-                .json({
-                  error: err.message,
-                  code: err.name
-                })
-                .end()
-    }
-
-    return next()
-  })
 }