Beispiel #1
0
        /// <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;
        }
Beispiel #2
0
        /// <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()
            });
        }
Beispiel #3
0
        /// <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
            });
        }
Beispiel #4
0
 /// <summary>
 /// Resolves this instance.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <returns>``0.</returns>
 public T Resolve <T>()
 {
     return(_appHost.Resolve <T>());
 }
Beispiel #5
0
        /// <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
            });
        }