Commit 2a80bfd9 authored by jan.koester's avatar jan.koester
Browse files

test

parent 5ab3f808
Loading
Loading
Loading
Loading
Loading
+240 −210
Changes for src/session.cpp: 240 added lines, 210 removed lines.
Original line number Diff line number Diff line
@@ -181,28 +181,15 @@ void authdb::SessionData::setGPOResults(const std::vector<std::pair<uuid::uuid,
    }
}

authdb::Session::Session() {
// ===== LocalSession =====

authdb::LocalSession::LocalSession() {
    _firstData=nullptr;
    _lastData=nullptr;
}

authdb::Session::Session(const Session& src) : Session(){
    std::lock_guard<std::mutex> guard(_SessionLock);

    for(SessionData *cur=src._firstData; cur; cur=cur->_next){
        if(!_firstData){
            _firstData=new SessionData(cur->_sid,cur->_uid,cur->_did,cur->_members);
            _lastData=_firstData;
        }else{
            _lastData->_next=new SessionData(cur->_sid,cur->_uid,cur->_did,cur->_members);
            _lastData=_lastData->_next;
        }

        _lastData->_username=cur->_username;
    }
}

void authdb::Session::clear(){
void authdb::LocalSession::clear(){
    std::lock_guard<std::mutex> guard(_lock);
    SessionData *del=_firstData;
    while(del){
        SessionData *next=del->_next;
@@ -214,78 +201,83 @@ void authdb::Session::clear(){
    _lastData=nullptr;
}


authdb::Session::~Session(){
authdb::LocalSession::~LocalSession(){
    clear();
};

const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){
}

    // --- Cluster deduplication: check if session for this user+domain already exists ---
    if (g_Cluster && g_Cluster->isRunning()) {
        // Check local sessions first (same user+domain)
        {
            std::lock_guard<std::mutex> guard(_SessionLock);
authdb::SessionData *authdb::LocalSession::findLocal(uuid::uuid sessionid){
    for(SessionData *cur=_firstData; cur; cur=cur->_next){
                uuid::uuid cur_uid, cur_did;
                cur->getUid(cur_uid);
                cur->getDid(cur_did);
                if (cur_uid == userid && cur_did == domainid) {
                    return cur; // Reuse existing local session
                }
        if(cur->_sid==sessionid)
            return cur;
    }
    return nullptr;
}

        // Check cluster peers for existing session
        uuid::uuid cluster_sid;
        std::vector<uuid::uuid> cluster_members;
        std::string cluster_username;
        std::vector<std::pair<uuid::uuid, bool>> cluster_gpo;
        if (g_Cluster->fetchSession(userid, domainid, cluster_sid,
                                     cluster_members, cluster_username, cluster_gpo)) {
            // Session exists on another node, import it locally
            SessionData *imported = new SessionData(cluster_sid, userid, domainid, cluster_members);
            imported->_username = cluster_username;
            imported->setGPOResults(cluster_gpo);

            std::lock_guard<std::mutex> guard(_SessionLock);
void authdb::LocalSession::appendLocal(SessionData *sess){
    if(!_firstData){
                _firstData = imported;
        _firstData=sess;
        _lastData=_firstData;
    }else{
                _lastData->_next = imported;
        _lastData->_next=sess;
        _lastData=_lastData->_next;
    }
            return imported;
}
    } else {
        // No cluster: still deduplicate locally
        std::lock_guard<std::mutex> guard(_SessionLock);

void authdb::LocalSession::removeLocal(uuid::uuid sessionid){
    SessionData *prev=nullptr;
    for(SessionData *cur=_firstData; cur; cur=cur->_next){
            uuid::uuid cur_uid, cur_did;
            cur->getUid(cur_uid);
            cur->getDid(cur_did);
            if (cur_uid == userid && cur_did == domainid) {
                return cur;
        if(cur->_sid==sessionid){
            if(prev)
                prev->_next=cur->_next;
            if(cur==_firstData)
                _firstData=cur->_next;
            if(cur==_lastData)
                _lastData=prev;
            cur->_next=nullptr;
            delete cur;
            return;
        }
        prev=cur;
    }
}

void authdb::LocalSession::cleanupExpired(){
    auto now=std::chrono::steady_clock::now();
    SessionData *prev=nullptr;
    SessionData *cur=_firstData;
    while(cur){
        auto age=std::chrono::duration_cast<std::chrono::hours>(now - cur->_created).count();
        if(age >= 24){
            SessionData *next=cur->_next;
            if(prev)
                prev->_next=next;
            if(cur==_firstData)
                _firstData=next;
            if(cur==_lastData)
                _lastData=prev;
            cur->_next=nullptr;
            delete cur;
            cur=next;
        }else{
            prev=cur;
            cur=cur->_next;
        }
    }
}

static authdb::SessionData *createSessionData(authdb::AuthBackend &backend, uuid::uuid domainid, uuid::uuid userid){
    using namespace authdb;
    std::string username;
    std::shared_ptr<authdb::AuthData::Record> cur=std::make_shared<authdb::AuthData::Record>();
    std::shared_ptr<AuthData::Record> cur=std::make_shared<AuthData::Record>();

    size_t rd=sizeof(authdb::AuthHeader),end=backend.end();
    size_t rd=sizeof(AuthHeader),end=backend.end();
    while(rd<end){
        cur->type=EmptyData;

        backend.setPos(rd);
        backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record));

        rd=backend.getPos()+cur->datasize;

        if(cur->type == UserData && strcmp(cur->fieldname,"username")==0
            && userid==cur->ruid){

            unsigned char *tmp = new unsigned char[cur->datasize];
            backend.read(tmp,cur->datasize);
            username=reinterpret_cast<char*>(tmp);
@@ -293,20 +285,16 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid
        }
    }


    std::shared_ptr<std::vector<uuid::uuid>> mbs = std::make_shared<std::vector<uuid::uuid>>();
    rd=sizeof(authdb::AuthHeader);

    rd=sizeof(AuthHeader);
    while(rd<end){
        backend.setPos(rd);
        backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record));

        rd=backend.getPos()+cur->datasize;

        if( !uuid::uuid(cur->ruid).empty() && cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){
            Group group;
            std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid);
            size_t upos=sizeof(authdb::AuthHeader);
            size_t upos=sizeof(AuthHeader);
            group.info(backend,*grpi,upos);
            if(grpi->isMember(userid)){
                mbs->emplace_back(cur->ruid);
@@ -319,27 +307,21 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid

    SessionData *newSession=new SessionData(sid,userid,domainid,*mbs);
    newSession->_username=username;

    newSession->_GPOResult.next=nullptr;

    SessionData::GPOResult *gpores=&newSession->_GPOResult;

    Gpo gpo;
    std::vector<uuid::uuid> allow;

    rd=sizeof(authdb::AuthHeader);


    rd=sizeof(AuthHeader);

    while(rd<end){
        backend.setPos(rd);
        backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record));

        rd=backend.getPos()+cur->datasize;

        if(cur->type == PolicyData && strcmp(cur->fieldname,"gponame")==0){
            std::shared_ptr<class GpoData> gpodat=std::make_shared<class GpoData>(cur->ruid);
            size_t upos=sizeof(authdb::AuthHeader);
            size_t upos=sizeof(AuthHeader);
            gpo.info(backend,*gpodat,upos);
            if(!gpores->GPOId.empty()){
                gpores->next=new SessionData::GPOResult();
@@ -373,42 +355,156 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid
        }
        if(!found){
            bool defval=(strcmp(gpo_default[i][3],"true")==0);

            // Add to session result
            if(!gpores->GPOId.empty()){
                gpores->next=new SessionData::GPOResult();
                gpores=gpores->next;
            }
            gpores->GPOId=defid;
            gpores->GPORes=defval;

            // Create the missing GPO record in the backend
            try {
                GpoData gdat(defid);
                gdat.setName(gpo_default[i][1]);
                gdat.setDesc(gpo_default[i][2]);
                gdat.setGpoValue(defval);
                gpo.create(backend, &gdat);
            } catch (...) {
                // GPO may already exist from concurrent creation
            } catch (...) {}
        }
    }

    return newSession;
}

static void reloadSessionData(authdb::AuthBackend &backend, authdb::SessionData *cursess){
    using namespace authdb;
    Group group;
    std::string username;

    cursess->_members.clear();

    std::shared_ptr<AuthData::Record> cur=std::make_shared<AuthData::Record>();
    size_t rd=sizeof(AuthHeader),end=backend.end();
    while(rd<end){
        cur->type=EmptyData;
        backend.setPos(rd);
        backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record));
        rd=backend.getPos()+cur->datasize;

        if(cur->type == UserData && strcmp(cur->fieldname,"username")==0
            && uuid::uuid(cur->ruid)==cursess->_uid.value){
            const std::shared_ptr<unsigned char[]>tmp(new unsigned char[cur->datasize]);
            backend.read(tmp.get(),cur->datasize);
            username=reinterpret_cast<char*>(tmp.get());
        }
        if(cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){
            std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid);
            size_t upos=sizeof(AuthHeader);
            group.info(backend,*grpi,upos);
            if(grpi->isMember(cursess->_uid.value))
                cursess->_members.emplace_back(cur->ruid);
        }
    }
    cursess->_username=username;
}

const authdb::SessionData *authdb::LocalSession::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){
    {
        std::lock_guard<std::mutex> guard(_SessionLock);
        std::lock_guard<std::mutex> guard(_lock);
        cleanupExpired();
        for (SessionData *cur = _firstData; cur; cur = cur->_next) {
            uuid::uuid cur_uid, cur_did;
            cur->getUid(cur_uid);
            cur->getDid(cur_did);
            if (cur_uid == userid && cur_did == domainid)
                return cur;
        }
    }

    SessionData *newSession = createSessionData(backend, domainid, userid);

    std::lock_guard<std::mutex> guard(_lock);
    appendLocal(newSession);
    return newSession;
}

const authdb::SessionData *authdb::LocalSession::getSession(uuid::uuid sessionid){
    std::lock_guard<std::mutex> guard(_lock);
    cleanupExpired();
    return findLocal(sessionid);
}

        if(!_firstData){
            _firstData=newSession;
            _lastData=_firstData;
        }else{
            _lastData->_next=newSession;
            _lastData=_lastData->_next;
void authdb::LocalSession::remSession(uuid::uuid sessionid){
    std::lock_guard<std::mutex> guard(_lock);
    removeLocal(sessionid);
}

void authdb::LocalSession::relSession(AuthBackend &backend,uuid::uuid sessionid){
    std::lock_guard<std::mutex> guard(_lock);
    SessionData *cursess = findLocal(sessionid);
    if(!cursess)
        throw AuthBackendError("reload session: sessionid not found !");
    reloadSessionData(backend, cursess);
}

void authdb::LocalSession::listSessions(std::vector<SessionInfo> &out){
    std::lock_guard<std::mutex> guard(_lock);
    cleanupExpired();
    out.clear();
    for(SessionData *cur=_firstData; cur; cur=cur->_next){
        SessionInfo info;
        cur->getSid(info.sid);
        cur->getUid(info.uid);
        cur->getDid(info.did);
        info.username = cur->getUsername();
        out.push_back(std::move(info));
    }
}

// ===== ClusterSession =====

authdb::ClusterSession::ClusterSession() : LocalSession() {}

authdb::ClusterSession::~ClusterSession() {}

const authdb::SessionData *authdb::ClusterSession::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){
    // Check local cache first
    {
        std::lock_guard<std::mutex> guard(_lock);
        cleanupExpired();
        for (SessionData *cur = _firstData; cur; cur = cur->_next) {
            uuid::uuid cur_uid, cur_did;
            cur->getUid(cur_uid);
            cur->getDid(cur_did);
            if (cur_uid == userid && cur_did == domainid)
                return cur;
        }
    }

    // Check cluster for existing session
    if (g_Cluster && g_Cluster->isRunning()) {
        uuid::uuid cluster_sid;
        std::vector<uuid::uuid> cluster_members;
        std::string cluster_username;
        std::vector<std::pair<uuid::uuid, bool>> cluster_gpo;
        if (g_Cluster->fetchSession(userid, domainid, cluster_sid,
                                     cluster_members, cluster_username, cluster_gpo)) {
            SessionData *imported = new SessionData(cluster_sid, userid, domainid, cluster_members);
            imported->_username = cluster_username;
            imported->setGPOResults(cluster_gpo);

            std::lock_guard<std::mutex> guard(_lock);
            appendLocal(imported);
            return imported;
        }
    }

    // Create new session
    SessionData *newSession = createSessionData(backend, domainid, userid);

    {
        std::lock_guard<std::mutex> guard(_lock);
        appendLocal(newSession);
    }

    // Push to cluster for replication
    if (g_Cluster && g_Cluster->isRunning()) {
        g_Cluster->pushSession(*newSession);
@@ -417,12 +513,12 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid
    return newSession;
}

const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){
const authdb::SessionData *authdb::ClusterSession::getSession(uuid::uuid sessionid){
    {
        std::lock_guard<std::mutex> guard(_SessionLock);
        std::lock_guard<std::mutex> guard(_lock);
        cleanupExpired();
        for(SessionData *cur=_firstData; cur; cur=cur->_next){
            if(cur->_sid==sessionid){
        SessionData *cur = findLocal(sessionid);
        if (cur) {
            // Sync with cluster session_store_ (local memory only, no network)
            if (g_Cluster && g_Cluster->isRunning()) {
                uuid::uuid c_sid, c_uid, c_did;
@@ -431,31 +527,20 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){
                std::vector<std::pair<uuid::uuid, bool>> c_gpo;
                if (g_Cluster->fetchSessionLocalBySid(sessionid, c_sid, c_uid, c_did,
                                                      c_members, c_username, c_gpo)) {
                        // Session still exists — update local copy with cluster data
                    cur->_members = c_members;
                    cur->_username = c_username;
                    cur->setGPOResults(c_gpo);
                } else {
                    // Session removed on another node — purge local copy
                        SessionData *prev = nullptr;
                        for (SessionData *p = _firstData; p; p = p->_next) {
                            if (p == cur) break;
                            prev = p;
                        }
                        if (prev) prev->_next = cur->_next;
                        if (cur == _firstData) _firstData = cur->_next;
                        if (cur == _lastData) _lastData = prev;
                        cur->_next = nullptr;
                        delete cur;
                    removeLocal(sessionid);
                    return nullptr;
                }
            }
            return cur;
        }
    }
    }

    // Not found locally — fetch from cluster peers by SID
    // Not found locally — fetch from cluster peers
    if (g_Cluster && g_Cluster->isRunning()) {
        uuid::uuid sid, uid, did;
        std::vector<uuid::uuid> members;
@@ -466,14 +551,8 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){
            imported->_username = username;
            imported->setGPOResults(gpo_results);

            std::lock_guard<std::mutex> guard(_SessionLock);
            if (!_firstData) {
                _firstData = imported;
                _lastData = _firstData;
            } else {
                _lastData->_next = imported;
                _lastData = _lastData->_next;
            }
            std::lock_guard<std::mutex> guard(_lock);
            appendLocal(imported);
            return imported;
        }
    }
@@ -481,49 +560,20 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){
    return nullptr;
}

void authdb::Session::remSession(uuid::uuid sessionid){
    // Always remove from cluster (covers all nodes)
void authdb::ClusterSession::remSession(uuid::uuid sessionid){
    // Remove from cluster on ALL nodes
    if (g_Cluster && g_Cluster->isRunning()) {
        g_Cluster->removeSessionBySid(sessionid);
    }

    // Remove from local linked list if present
    std::lock_guard<std::mutex> guard(_SessionLock);
    SessionData *prev=nullptr;

    for(SessionData *cur=_firstData; cur; cur=cur->_next){
        if(cur->_sid==sessionid){
            if(prev)
                prev->_next=cur->_next;

            if(cur==_firstData)
                _firstData=cur->_next;

            if(cur==_lastData)
                _lastData=prev;

            cur->_next=nullptr;
            delete cur;
            break;
        }
        prev=cur;
    }
    // Remove from local cache
    std::lock_guard<std::mutex> guard(_lock);
    removeLocal(sessionid);
}

void authdb::Session::relSession(AuthBackend &backend,uuid::uuid sessionid){
    std::lock_guard<std::mutex> guard(_SessionLock);
    Group group;

    std::string username;

    SessionData *cursess=nullptr;

    for(SessionData *cur=_firstData; cur; cur=cur->_next){
        if(cur->_sid==sessionid){
            cursess=cur;
            break;
        }
    }
void authdb::ClusterSession::relSession(AuthBackend &backend,uuid::uuid sessionid){
    {
        std::lock_guard<std::mutex> guard(_lock);
        SessionData *cursess = findLocal(sessionid);

        // Not found locally — try to import from cluster
        if (!cursess && g_Cluster && g_Cluster->isRunning()) {
@@ -535,79 +585,59 @@ void authdb::Session::relSession(AuthBackend &backend,uuid::uuid sessionid){
                cursess = new SessionData(sid, uid, did, members);
                cursess->_username = c_username;
                cursess->setGPOResults(gpo_results);
            if(!_firstData){
                _firstData = cursess;
                _lastData = _firstData;
            }else{
                _lastData->_next = cursess;
                _lastData = _lastData->_next;
            }
                appendLocal(cursess);
            }
        }

        if (!cursess)
            throw AuthBackendError("reload session: sessionid not found !");

    cursess->_members.clear();

    std::shared_ptr<authdb::AuthData::Record> cur=std::make_shared<authdb::AuthData::Record>();
        reloadSessionData(backend, cursess);

    size_t rd=sizeof(authdb::AuthHeader),end=backend.end();
    while(rd<end){
        cur->type=EmptyData;

        backend.setPos(rd);
        backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record));

        rd=backend.getPos()+cur->datasize;

        if(cur->type == UserData && strcmp(cur->fieldname,"username")==0
            && uuid::uuid(cur->ruid)==cursess->_uid.value){

            const std::shared_ptr<unsigned char[]>tmp(new unsigned char[cur->datasize]);
            backend.read(tmp.get(),cur->datasize);
            username=reinterpret_cast<char*>(tmp.get());
        // Push updated data to cluster
        if (g_Cluster && g_Cluster->isRunning()) {
            g_Cluster->pushSession(*cursess);
        }

        if(cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){
            std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid);
            size_t upos=sizeof(authdb::AuthHeader);
            group.info(backend,*grpi,upos);

            if(grpi->isMember(cursess->_uid.value))
                cursess->_members.emplace_back(cur->ruid);
    }
}

    cursess->_username=username;
void authdb::ClusterSession::listSessions(std::vector<SessionInfo> &out){
    out.clear();
    std::set<std::string> seen_sids;

    // Update cluster with refreshed session data
    if (g_Cluster && g_Cluster->isRunning()) {
        g_Cluster->pushSession(*cursess);
    }
    // Local sessions
    {
        std::lock_guard<std::mutex> guard(_lock);
        cleanupExpired();
        for(SessionData *cur=_firstData; cur; cur=cur->_next){
            SessionInfo info;
            cur->getSid(info.sid);
            cur->getUid(info.uid);
            cur->getDid(info.did);
            info.username = cur->getUsername();
            seen_sids.insert(std::string(info.sid.c_str()));
            out.push_back(std::move(info));
        }

const authdb::SessionData *authdb::Session::firstData() const{
    std::lock_guard<std::mutex> guard(_SessionLock);
    return _firstData;
    }

void authdb::Session::cleanupExpired(){
    auto now=std::chrono::steady_clock::now();
    SessionData *prev=nullptr;
    SessionData *cur=_firstData;
    while(cur){
        auto age=std::chrono::duration_cast<std::chrono::hours>(now - cur->_created).count();
        if(age >= 24){
            // Remove from cluster
    // Cluster sessions
    if (g_Cluster && g_Cluster->isRunning()) {
                uuid::uuid uid, did;
                cur->getUid(uid);
                cur->getDid(did);
                g_Cluster->removeSession(uid, did);
        std::vector<Cluster::SessionInfo> csessions;
        g_Cluster->listAllSessions(csessions);
        for (const auto &cs : csessions) {
            std::string sidstr = cs.sid.c_str();
            if (seen_sids.count(sidstr))
                continue;
            seen_sids.insert(sidstr);
            SessionInfo info;
            info.sid = cs.sid;
            info.uid = cs.uid;
            info.did = cs.did;
            info.username = cs.username;
            out.push_back(std::move(info));
        }
    }
}

            SessionData *next=cur->_next;
            if(prev)
                prev->_next=next;
            if(cur==_firstData)