/// <summary> /// Starts the external web socket server. /// </summary> private void ReloadExternalWebSocketServer() { DisposeExternalWebSocketServer(); ExternalWebSocketServer = _applicationHost.Resolve <IWebSocketServer>(); ExternalWebSocketServer.Start(ConfigurationManager.Configuration.LegacyWebSocketPortNumber); ExternalWebSocketServer.WebSocketConnected += HttpServer_WebSocketConnected; }
/// <inheritdoc /> public async Task <PinRedeemResult> RedeemPasswordResetPin(string pin) { var userManager = _appHost.Resolve <IUserManager>(); var usersReset = new List <string>(); foreach (var resetFile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*")) { SerializablePasswordReset spr; await using (var str = File.OpenRead(resetFile)) { spr = await JsonSerializer.DeserializeAsync <SerializablePasswordReset>(str).ConfigureAwait(false) ?? throw new ResourceNotFoundException($"Provided path ({resetFile}) is not valid."); } if (spr.ExpirationDate < DateTime.UtcNow) { File.Delete(resetFile); } else if (string.Equals( spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal), pin.Replace("-", string.Empty, StringComparison.Ordinal), StringComparison.InvariantCultureIgnoreCase)) { var resetUser = userManager.GetUserByName(spr.UserName) ?? throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found"); await userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); usersReset.Add(resetUser.Username); File.Delete(resetFile); } } if (usersReset.Count < 1) { throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}"); } return(new PinRedeemResult { Success = true, UsersReset = usersReset.ToArray() }); }
/// <summary> /// Authenticate user against the ldap server. /// </summary> /// <param name="username">Username to authenticate.</param> /// <param name="password">Password to authenticate.</param> /// <returns>A <see cref="ProviderAuthenticationResult"/> with the authentication result.</returns> /// <exception cref="AuthenticationException">Exception when failing to authenticate.</exception> public async Task <ProviderAuthenticationResult> Authenticate(string username, string password) { var userManager = _applicationHost.Resolve <IUserManager>(); User user = null; var ldapUser = LocateLdapUser(username); var ldapUsername = GetAttribute(ldapUser, UsernameAttr)?.StringValue; _logger.LogDebug("Setting username: {LdapUsername}", ldapUsername); try { user = userManager.GetUserByName(ldapUsername); } catch (Exception e) { _logger.LogWarning("User Manager could not find a user for LDAP User, this may not be fatal", e); } using (var currentUserConnection = ConnectToLdap(ldapUser.Dn, password)) { if (!currentUserConnection.Bound) { _logger.LogError("Error logging in, invalid LDAP username or password"); throw new AuthenticationException("Error completing LDAP login. Invalid username or password."); } } // Determine if the user should be an administrator var ldapIsAdmin = false; if (!string.IsNullOrEmpty(AdminFilter) && !string.Equals(AdminFilter, "_disabled_", StringComparison.Ordinal)) { using var ldapClient = ConnectToLdap(); ldapClient.Constraints = GetSearchConstraints( ldapClient, LdapPlugin.Instance.Configuration.LdapBindUser, LdapPlugin.Instance.Configuration.LdapBindPassword); try { var adminBaseDn = LdapPlugin.Instance.Configuration.LdapAdminBaseDn; if (string.IsNullOrEmpty(adminBaseDn)) { adminBaseDn = LdapPlugin.Instance.Configuration.LdapBaseDn; } var ldapUsers = ldapClient.Search( adminBaseDn, LdapConnection.ScopeSub, AdminFilter.Replace("{username}", username, StringComparison.OrdinalIgnoreCase), Array.Empty <string>(), false); var foundUser = false; while (ldapUsers.HasMore() && !foundUser) { var currentUser = ldapUsers.Next(); if (string.Equals(ldapUser.Dn, currentUser.Dn, StringComparison.Ordinal)) { ldapIsAdmin = true; foundUser = true; } } } catch (LdapException e) { _logger.LogError(e, "Failed to check for admin with: {Filter}", SearchFilter); throw new AuthenticationException("Error completing LDAP login while applying admin filter."); } } if (user == null) { _logger.LogDebug("Creating new user {Username} - is admin? {IsAdmin}", ldapUsername, ldapIsAdmin); if (LdapPlugin.Instance.Configuration.CreateUsersFromLdap) { user = await userManager.CreateUserAsync(ldapUsername).ConfigureAwait(false); var providerName = GetType().FullName !; user.AuthenticationProviderId = providerName; user.PasswordResetProviderId = providerName; user.SetPermission(PermissionKind.IsAdministrator, ldapIsAdmin); user.SetPermission(PermissionKind.EnableAllFolders, LdapPlugin.Instance.Configuration.EnableAllFolders); if (!LdapPlugin.Instance.Configuration.EnableAllFolders) { user.SetPreference(PreferenceKind.EnabledFolders, LdapPlugin.Instance.Configuration.EnabledFolders); } await userManager.UpdateUserAsync(user).ConfigureAwait(false); } else { _logger.LogError("User not configured for LDAP Uid: {LdapUsername}", ldapUsername); throw new AuthenticationException( $"Automatic User Creation is disabled and there is no Jellyfin user for authorized Uid: {ldapUsername}"); } } else { // User exists; if the admin has enabled an AdminFilter, check if the user's // 'IsAdministrator' matches the LDAP configuration and update if there is a difference. if (!string.IsNullOrEmpty(AdminFilter) && !string.Equals(AdminFilter, "_disabled_", StringComparison.Ordinal)) { var isJellyfinAdmin = user.HasPermission(PermissionKind.IsAdministrator); if (isJellyfinAdmin != ldapIsAdmin) { _logger.LogDebug("Updating user {Username} admin status to: {LdapIsAdmin}.", ldapUsername, ldapIsAdmin); user.SetPermission(PermissionKind.IsAdministrator, ldapIsAdmin); await userManager.UpdateUserAsync(user).ConfigureAwait(false); } } } return(new ProviderAuthenticationResult { Username = ldapUsername }); }
/// <summary> /// Resolves this instance. /// </summary> /// <typeparam name="T"></typeparam> /// <returns>``0.</returns> public T Resolve <T>() { return(_appHost.Resolve <T>()); }
/// <summary> /// Authenticate user against the ldap server. /// </summary> /// <param name="username">Username to authenticate.</param> /// <param name="password">Password to authenticate.</param> /// <returns>A <see cref="ProviderAuthenticationResult"/> with the authentication result.</returns> /// <exception cref="AuthenticationException">Exception when failing to authenticate.</exception> public async Task <ProviderAuthenticationResult> Authenticate(string username, string password) { var userManager = _applicationHost.Resolve <IUserManager>(); User user = null; var ldapUser = LocateLdapUser(username); var ldapUsername = GetAttribute(ldapUser, UsernameAttr)?.StringValue; _logger.LogDebug("Setting username: {1}", ldapUsername); try { user = userManager.GetUserByName(ldapUsername); } catch (Exception e) { _logger.LogWarning("User Manager could not find a user for LDAP User, this may not be fatal", e); } using var ldapClient = new LdapConnection { SecureSocketLayer = LdapPlugin.Instance.Configuration.UseSsl }; _logger.LogDebug("Trying bind as user {1}", ldapUser.Dn); try { if (LdapPlugin.Instance.Configuration.SkipSslVerify) { ldapClient.UserDefinedServerCertValidationDelegate += LdapClient_UserDefinedServerCertValidationDelegate; } ldapClient.Connect(LdapPlugin.Instance.Configuration.LdapServer, LdapPlugin.Instance.Configuration.LdapPort); if (LdapPlugin.Instance.Configuration.UseStartTls) { ldapClient.StartTls(); } ldapClient.Bind(ldapUser.Dn, password); } catch (Exception e) { _logger.LogError(e, "Failed to Connect or Bind to server as user {1}", ldapUser.Dn); throw new AuthenticationException("Error completing LDAP login. Invalid username or password.", e); } finally { ldapClient.UserDefinedServerCertValidationDelegate -= LdapClient_UserDefinedServerCertValidationDelegate; } if (ldapClient.Bound) { if (user == null) { // Determine if the user should be an administrator var ldapIsAdmin = false; // Search the current user DN with the adminFilter var ldapUsers = ldapClient.Search( ldapUser.Dn, 0, AdminFilter, LdapUsernameAttributes, false); // If we got non-zero, then the filter matched and the user is an admin if (ldapUsers.Count != 0) { ldapIsAdmin = true; } _logger.LogDebug("Creating new user {1} - is admin? {2}", ldapUsername, ldapIsAdmin); if (LdapPlugin.Instance.Configuration.CreateUsersFromLdap) { user = await userManager.CreateUserAsync(ldapUsername).ConfigureAwait(false); user.AuthenticationProviderId = GetType().FullName; user.SetPermission(PermissionKind.IsAdministrator, ldapIsAdmin); await userManager.UpdateUserAsync(user).ConfigureAwait(false); } else { _logger.LogError($"User not configured for LDAP Uid: {ldapUsername}"); throw new AuthenticationException( $"Automatic User Creation is disabled and there is no Jellyfin user for authorized Uid: {ldapUsername}"); } } return(new ProviderAuthenticationResult { Username = ldapUsername }); } _logger.LogError("Error logging in, invalid LDAP username or password"); throw new AuthenticationException("Error completing LDAP login. Invalid username or password."); }
public async Task <ProviderAuthenticationResult> Authenticate(string username, string password) { _userManager ??= _applicationHost.Resolve <IUserManager>(); string totp = null; if (Enable2FA) { var match = Regex.Match(password, TwoFactorPattern); if (match.Success) { password = match.Groups[1].Value; totp = match.Groups[2].Value; } } User user = null; try { user = _userManager.GetUserByName(username); } catch (Exception e) { _logger.LogWarning("User Manager could not find a user for Keycloak User, this may not be fatal", e); } KeycloakUser keycloakUser = await GetKeycloakUser(username, password, totp); if (keycloakUser == null) { throw new AuthenticationException("Error completing Keycloak login. Invalid username or password."); } if (user == null) { if (CreateUser) { _logger.LogInformation($"Creating user {username}"); user = await _userManager.CreateUserAsync(username).ConfigureAwait(false); user.AuthenticationProviderId = GetType().FullName; await UpdateUserInfo(keycloakUser, user); } else { _logger.LogError("Keycloak User not configured for Jellyfin: {username}", username); throw new AuthenticationException( $"Automatic User Creation is disabled and there is no Jellyfin user for authorized Uid: {username}"); } } else { await UpdateUserInfo(keycloakUser, user); } if (user.HasPermission(PermissionKind.IsDisabled)) { // If the user no longer has permission to access revoke all sessions for this user _logger.LogInformation($"{username} is disabled, revoking all sessions"); var sessionHandler = _applicationHost.Resolve <ISessionManager>(); sessionHandler.RevokeUserTokens(user.Id, null); } return(new ProviderAuthenticationResult { Username = username }); }