mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Fix oidc auto-register not cleaning up new user on errors #4563
This commit is contained in:
		
							parent
							
								
									99a3867ce9
								
							
						
					
					
						commit
						4018be6330
					
				@ -110,6 +110,8 @@ class OidcAuthStrategy {
 | 
				
			|||||||
   * @param {Function} done - Passport callback
 | 
					   * @param {Function} done - Passport callback
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async verifyCallback(tokenset, userinfo, done) {
 | 
					  async verifyCallback(tokenset, userinfo, done) {
 | 
				
			||||||
 | 
					    let isNewUser = false
 | 
				
			||||||
 | 
					    let user = null
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      Logger.debug(`[OidcAuth] openid callback userinfo=`, JSON.stringify(userinfo, null, 2))
 | 
					      Logger.debug(`[OidcAuth] openid callback userinfo=`, JSON.stringify(userinfo, null, 2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,9 +123,24 @@ class OidcAuthStrategy {
 | 
				
			|||||||
        throw new Error(`Group claim ${Database.serverSettings.authOpenIDGroupClaim} not found or empty in userinfo`)
 | 
					        throw new Error(`Group claim ${Database.serverSettings.authOpenIDGroupClaim} not found or empty in userinfo`)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let user = await Database.userModel.findOrCreateUserFromOpenIdUserInfo(userinfo)
 | 
					      user = await Database.userModel.findUserFromOpenIdUserInfo(userinfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!user?.isActive) {
 | 
					      if (user?.error) {
 | 
				
			||||||
 | 
					        throw new Error('Invalid userinfo or already linked')
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!user) {
 | 
				
			||||||
 | 
					        // If no existing user was matched, auto-register if configured
 | 
				
			||||||
 | 
					        if (global.ServerSettings.authOpenIDAutoRegister) {
 | 
				
			||||||
 | 
					          Logger.info(`[User] openid: Auto-registering user with sub "${userinfo.sub}"`, userinfo)
 | 
				
			||||||
 | 
					          user = await Database.userModel.createUserFromOpenIdUserInfo(userinfo)
 | 
				
			||||||
 | 
					          isNewUser = true
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          Logger.warn(`[User] openid: User not found and auto-register is disabled`)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!user.isActive) {
 | 
				
			||||||
        throw new Error('User not active or not found')
 | 
					        throw new Error('User not active or not found')
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -136,6 +153,10 @@ class OidcAuthStrategy {
 | 
				
			|||||||
      return done(null, user)
 | 
					      return done(null, user)
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
      Logger.error(`[OidcAuth] openid callback error: ${error?.message}\n${error?.stack}`)
 | 
					      Logger.error(`[OidcAuth] openid callback error: ${error?.message}\n${error?.stack}`)
 | 
				
			||||||
 | 
					      // Remove new user if an error occurs
 | 
				
			||||||
 | 
					      if (isNewUser && user) {
 | 
				
			||||||
 | 
					        await user.destroy()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      return done(null, null, 'Unauthorized')
 | 
					      return done(null, null, 'Unauthorized')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -211,18 +211,18 @@ class User extends Model {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Finds an existing user by OpenID subject identifier, or by email/username based on server settings,
 | 
					   * Finds an existing user by OpenID subject identifier, or by email/username based on server settings
 | 
				
			||||||
   * or creates a new user if configured to do so.
 | 
					   * Returns null if no user is found
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * @param {Object} userinfo
 | 
					   * @param {Object} userinfo
 | 
				
			||||||
   * @returns {Promise<User>}
 | 
					   * @returns {Promise<User|{error: string}>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static async findOrCreateUserFromOpenIdUserInfo(userinfo) {
 | 
					  static async findUserFromOpenIdUserInfo(userinfo) {
 | 
				
			||||||
    let user = await this.getUserByOpenIDSub(userinfo.sub)
 | 
					    let user = await this.getUserByOpenIDSub(userinfo.sub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Matched by sub
 | 
					    // Matched by sub
 | 
				
			||||||
    if (user) {
 | 
					    if (user) {
 | 
				
			||||||
      Logger.debug(`[User] openid: User found by sub`)
 | 
					      Logger.debug(`[User] openid: User found by sub "${userinfo.sub}"`)
 | 
				
			||||||
      return user
 | 
					      return user
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -232,20 +232,27 @@ class User extends Model {
 | 
				
			|||||||
        // Only disallow when email_verified explicitly set to false (allow both if not set or true)
 | 
					        // Only disallow when email_verified explicitly set to false (allow both if not set or true)
 | 
				
			||||||
        if (userinfo.email_verified === false) {
 | 
					        if (userinfo.email_verified === false) {
 | 
				
			||||||
          Logger.warn(`[User] openid: User not found and email "${userinfo.email}" is not verified`)
 | 
					          Logger.warn(`[User] openid: User not found and email "${userinfo.email}" is not verified`)
 | 
				
			||||||
          return null
 | 
					          return {
 | 
				
			||||||
 | 
					            error: 'Email not verified'
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          Logger.info(`[User] openid: User not found, checking existing with email "${userinfo.email}"`)
 | 
					          Logger.info(`[User] openid: User not found, checking existing with email "${userinfo.email}"`)
 | 
				
			||||||
          user = await this.getUserByEmail(userinfo.email)
 | 
					          user = await this.getUserByEmail(userinfo.email)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (user?.authOpenIDSub) {
 | 
					          if (user?.authOpenIDSub) {
 | 
				
			||||||
            Logger.warn(`[User] openid: User found with email "${userinfo.email}" but is already matched with sub "${user.authOpenIDSub}"`)
 | 
					            Logger.warn(`[User] openid: User found with email "${userinfo.email}" but is already matched with sub "${user.authOpenIDSub}"`)
 | 
				
			||||||
            return null // User is linked to a different OpenID subject; do not proceed.
 | 
					            // User is linked to a different OpenID subject; do not proceed.
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					              error: 'User already linked to a different OpenID subject'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        Logger.warn(`[User] openid: User not found and no email in userinfo`)
 | 
					        Logger.warn(`[User] openid: User not found and no email in userinfo`)
 | 
				
			||||||
        // We deny login, because if the admin whishes to match email, it makes sense to require it
 | 
					        // We deny login, because if the admin whishes to match email, it makes sense to require it
 | 
				
			||||||
        return null
 | 
					        return {
 | 
				
			||||||
 | 
					          error: 'No email in userinfo'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // Match existing user by username
 | 
					    // Match existing user by username
 | 
				
			||||||
@ -260,43 +267,40 @@ class User extends Model {
 | 
				
			|||||||
        username = userinfo.username
 | 
					        username = userinfo.username
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        Logger.warn(`[User] openid: User not found and neither preferred_username nor username in userinfo`)
 | 
					        Logger.warn(`[User] openid: User not found and neither preferred_username nor username in userinfo`)
 | 
				
			||||||
        return null
 | 
					        return {
 | 
				
			||||||
 | 
					          error: 'No username in userinfo'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      user = await this.getUserByUsername(username)
 | 
					      user = await this.getUserByUsername(username)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (user?.authOpenIDSub) {
 | 
					      if (user?.authOpenIDSub) {
 | 
				
			||||||
        Logger.warn(`[User] openid: User found with username "${username}" but is already matched with sub "${user.authOpenIDSub}"`)
 | 
					        Logger.warn(`[User] openid: User found with username "${username}" but is already matched with sub "${user.authOpenIDSub}"`)
 | 
				
			||||||
        return null // User is linked to a different OpenID subject; do not proceed.
 | 
					        // User is linked to a different OpenID subject; do not proceed.
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          error: 'User already linked to a different OpenID subject'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!user) {
 | 
				
			||||||
 | 
					      return null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Found existing user via email or username
 | 
					    // Found existing user via email or username
 | 
				
			||||||
    if (user) {
 | 
					    if (!user.isActive) {
 | 
				
			||||||
      if (!user.isActive) {
 | 
					      Logger.warn(`[User] openid: User found but is not active`)
 | 
				
			||||||
        Logger.warn(`[User] openid: User found but is not active`)
 | 
					 | 
				
			||||||
        return null
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Update user with OpenID sub
 | 
					 | 
				
			||||||
      if (!user.extraData) user.extraData = {}
 | 
					 | 
				
			||||||
      user.extraData.authOpenIDSub = userinfo.sub
 | 
					 | 
				
			||||||
      user.changed('extraData', true)
 | 
					 | 
				
			||||||
      await user.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Logger.debug(`[User] openid: User found by email/username`)
 | 
					 | 
				
			||||||
      return user
 | 
					      return user
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If no existing user was matched, auto-register if configured
 | 
					    // Update user with OpenID sub
 | 
				
			||||||
    if (global.ServerSettings.authOpenIDAutoRegister) {
 | 
					    if (!user.extraData) user.extraData = {}
 | 
				
			||||||
      Logger.info(`[User] openid: Auto-registering user with sub "${userinfo.sub}"`, userinfo)
 | 
					    user.extraData.authOpenIDSub = userinfo.sub
 | 
				
			||||||
      user = await this.createUserFromOpenIdUserInfo(userinfo)
 | 
					    user.changed('extraData', true)
 | 
				
			||||||
      return user
 | 
					    await user.save()
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Logger.warn(`[User] openid: User not found and auto-register is disabled`)
 | 
					    Logger.debug(`[User] openid: User found by email/username`)
 | 
				
			||||||
    return null
 | 
					    return user
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user