/// <summary>
        /// Manager performs login, attempting to gain a new session.
        /// </summary>
        /// <param name="loginInfo">Login information</param>
        /// <param name="ipAddress">IP Address of request</param>
        public async Task <ManagerLoginResponse> Login(ManagerLoginRequest loginInfo, string ipAddress)
        {
            // Pull manager information from database.
            var manager = await _database.GetManagerByUsername(loginInfo.Username);

            // Default to a failed login attempt.
            bool canLogIn = false;

            if (manager.IsPasswordReset && loginInfo.Password == manager.Password)
            {
                // If the manager should reset their password and they have provided the correct cleartext password,
                // allow them to login -- assuming that the next phase will require them to reset their password.
                canLogIn = true;
            }
            else if (_password.IsPasswordMatch(loginInfo.Password, manager.Salt, manager.Password))
            {
                // If the manager password + salt combination matches the stored password allow them to login
                canLogIn = true;
            }

            // If the login failed, throw an exception.
            if (!canLogIn)
            {
                throw new BadLoginException();
            }

            // Create a new session.
            var newSession = new SessionDocument
            {
                Id = ObjectId.GenerateNewId().ToString(),
                // Generate a new sessionID.
                SessionId = await _session.GenerateSessionId(),
                ManagerId = manager.Id,
                IPAddress = ipAddress,
                CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                // If the manager needs to reset their password, limit the access to "RESET" status.
                AccessLevel = manager.IsPasswordReset ? "RESET" : "FULL",
                IsActive    = true
            };

            // Save new session. Note: _session.GenerateSessionId() handles retrying sessionID collisions.
            await _database.SaveSession(newSession);

            // Return manager login response information.
            return(new ManagerLoginResponse
            {
                SessionId = newSession.SessionId,
                AccessLevel = newSession.AccessLevel
            });
        }