Vulnerability Management

MFA, LDAP and Session Management for Operator Teams

By PMAP Security Team 21 min read

Every vulnerability finding, every asset record and every report inside a security platform is only as protected as the login that guards it. A vulnerability management platform holds a concentrated map of an organisation’s weaknesses. If an attacker reaches that map with a stolen password, the value of all your remediation work inverts. It becomes a target list.

That is why the credential layer is not a checkbox feature in PMAP. It is the outermost boundary of a multi-tenant security model, and it is built around four operational realities. Operator teams sign in from many devices. Some organisations want directory-driven identity rather than local accounts. Stolen passwords happen, so a second factor must hold even when the first one fails. Active sessions accumulate, so they must be visible, capped and revocable.

This article walks through how PMAP handles authentication, multi-factor enrollment and session management for operator teams. It is grounded in the platform’s actual behaviour, so every number and rule here reflects how the system runs, not a marketing approximation. If you want the step-by-step setup procedures, there are two companion guides linked throughout. If you are evaluating the wider identity story, this piece sits under the multi-tenant vulnerability management pillar and pairs closely with RBAC roles and scoped grants, which covers what a signed-in user is then allowed to do.

Why Identity Is the Outermost Security Boundary

In PMAP every downstream domain trusts a single object. After authentication, the platform produces a Claims object that carries the user identity, role, session and token identifiers. Findings, assets, projects, reports and analytics all read from that object to decide what the request is allowed to touch. There is no secondary identity source. The login handler is the first thing touched on every session, and it is the origin of the trust that every other layer relies on.

This design has a sharp consequence. If credential management at this layer is weak or unaudited, it undermines the value of all the vulnerability data the platform holds. A correctly scoped RBAC matrix means nothing if an attacker can borrow a session. Strong SLA tracking means nothing if a stolen password walks past the door. So the controls in this article are not isolated features. They are reinforcing layers on the one boundary that protects everything behind it.

Three properties define how PMAP treats that boundary. Authentication can come from a local password store or from your directory. A second factor stands between a correct password and an issued session for any user who enrols it. Sessions are first-class objects that can be listed, capped and revoked at any time. The rest of this article takes each of those in turn.

Local and LDAP/Active Directory Login

PMAP supports two authentication sources. Local accounts use email and password, with each password hashed using bcrypt at the default cost. Directory accounts authenticate against any RFC 4511 LDAP server, which includes Active Directory, using a bind-search-bind flow. You do not pick one mode for the whole platform. Both can coexist, and the login path decides per user which one applies.

That decision runs through a three-case dispatch, evaluated in order on every login call:

  1. If LDAP is disabled, or the user has no ldap_dn, the platform performs a local bcrypt verification against the stored password hash.
  2. If LDAP is enabled and the user already exists with an ldap_dn, the platform binds to the directory and re-syncs that user’s roles from their current group membership.
  3. If LDAP is enabled and the user does not exist yet, the platform binds to the directory. If auto-provisioning is on, it creates the account. If not, it returns ErrAccountNotProvisioned.

This dispatch order matters operationally. A local admin account keeps working even when the directory is the primary source for everyone else. A directory user always gets fresh roles on each login because group membership is re-read, not cached from the first sign-in. And the platform never silently creates accounts unless you explicitly allowed it.

One detail removes a common source of friction. LDAP configuration is read from the database on every login call, not loaded once at startup. When an administrator changes the bind DN, the server URL, the TLS mode or the group mapping, the change applies to the next login without a server restart. For a security team that cannot casually bounce a production service, that is the difference between a five-minute change and a maintenance window. The full directory onboarding flow, including group mapping setup, is covered in the onboarding users with LDAP and AD sync guide.

Auto-Provisioning and Group-to-Role Mapping

For organisations that already manage identity in a directory, retyping every analyst into a second system is wasted effort and a source of drift. PMAP’s auto-provisioning closes that gap. When auto_provision=true and a directory user signs in for the first time, the platform creates their PMAP account during that login, with no prior admin invite required.

The new account does not arrive role-less. A group_role_map translates directory group distinguished names into PMAP roles. On first login the platform reads the user’s group membership, resolves it through that map, and assigns the corresponding role. A default_role covers users whose groups are not explicitly mapped. From that point on, the user’s roles are re-synced from their groups on every subsequent login, so a directory-side change to a security team membership flows into PMAP the next time that person signs in.

The practical result is that your directory stays the single source of truth for who is on the team and what they are. A leaver removed from a directory group loses the corresponding PMAP role at their next login attempt, and an administrator’s group change does not require a parallel edit inside PMAP. This is how the platform keeps identity aligned with how enterprises already run access.

Account Lockout After Repeated Failures

Password guessing is the oldest attack against the login form, and PMAP answers it on the local path with a deliberately simple, auditable rule. Five consecutive failed bcrypt comparisons increment a counter stored in the database. Once that counter trips, the account is locked for 15 minutes, and further attempts are blocked regardless of whether the next password would have been correct. A successful login resets the counter to zero.

The behaviour is intentionally boring, which is what you want from a lockout control. There is no opaque scoring, no shifting threshold and no place for an attacker to learn a partial answer. After five misses the door closes for a fixed window. The 15-minute timer means a legitimate user who fat-fingered their password a few times is briefly inconvenienced rather than permanently shut out, while an automated guessing run is throttled to twenty attempts per hour per account.

This guard applies to local authentication, where PMAP owns the password. Directory users authenticate against your LDAP server, so the directory’s own lockout and password policies govern those accounts. That division keeps each system responsible for the credentials it actually stores.

TOTP MFA Enrollment for the Operator Team

A correct password is a single secret, and single secrets get phished, reused and leaked. Multi-factor authentication is the layer that keeps a stolen password from being enough. PMAP implements a TOTP second factor, the time-based one-time password standard described in RFC 6238 and recommended as an authenticator in NIST SP 800-63B. TOTP works with any standard authenticator app, including Google Authenticator, Authy and 1Password, with no vendor lock-in and no SMS dependency.

Enrollment is self-service from the profile security tab. When a user starts enrollment, the platform generates a 160-bit secret from a cryptographically secure random source. That is a 20-byte secret, comfortably above the entropy floor for a TOTP key. The secret is returned two ways. A 256-by-256 pixel QR code, sized to be reliably scannable from a laptop screen, lets the user point their phone at the screen. A raw base32 string lets them type the secret in manually if a camera is not available.

The secret is never left lying around. It is stored AES-encrypted in the user_mfa table. The plaintext is decrypted only in memory when a code needs verifying, and the secret field is tagged so it is never serialised into any API response. Even an operator with database read access sees ciphertext, not a working seed.

Enrollment is not active the moment the QR code appears. A pending enrollment becomes a live second factor only after the user proves they can produce a correct code. The confirmation step verifies that first TOTP code, and only then does the platform flip the enrollment to enabled. This prevents the failure mode where someone scans a code, navigates away, and later finds themselves locked out by a factor they never actually configured. The underlying TOTP parameters follow the RFC 6238 defaults: SHA-1, six digits, a 30-second period, with a one-step skew on either side that gives a 90-second acceptance window to tolerate clock drift between the phone and the server. The full enrollment walkthrough lives in the enrolling MFA TOTP for the operator team guide.

The 5-Minute MFA Login Challenge

When a user with MFA enabled signs in, the password step does not hand back a session. After the password is verified, the login response carries mfa_required: true and an opaque challenge token. No access token and no refresh token are issued at this point. The user is mid-login, not logged in.

That challenge token is the only credential for the second step. It is a 32-byte random value, stored in Redis with a 5-minute time-to-live. The user submits it together with their TOTP code to the dedicated MFA login endpoint. On a correct code, the platform consumes the challenge token immediately, so it cannot be replayed, and issues the same access and refresh pair a non-MFA login would have produced.

The challenge is hardened against brute force in two ways. Each token tolerates at most five wrong codes. On the fifth failure the token is deleted, and the user has to restart from the password step. There is no infinite retry loop against a single challenge. Equally important, an expired token and a token that never existed return the same error, so an attacker cannot probe the system to learn whether a given challenge was ever valid. The five-minute window keeps a captured challenge token from being useful for long, and because the token lives only in component state on the client during the flow, a page reload during the second step simply resets the user to the password step rather than stranding a half-authenticated session.

Recovery Codes for Lost Authenticators

A second factor that cannot be recovered becomes a second way to get locked out. Phones break, get replaced and get wiped. PMAP issues recovery codes so a lost authenticator does not mean a lost account. At the moment a user confirms their enrollment, the platform generates ten one-time recovery codes and shows them once, in the same response that activates MFA. That single display is the only time they appear in plaintext.

The codes are built for humans to read and machines to protect. Each code draws from an unambiguous alphabet that omits the characters most often confused, namely zero, capital O, the digit one, capital I and capital L. They are formatted in an XXXX-XXXX-XX pattern so they are easy to write down or store in a password manager. Behind the scenes each code is bcrypt-hashed at the same cost as the password store, so the database holds no usable copy. When a user redeems a code, it is stamped as used and can never be redeemed again.

Recovery codes can be regenerated, but only by someone who already controls the account. Regeneration requires proof of possession, either a valid TOTP code or an unused recovery code, and it atomically replaces the entire previous set in a single transaction. There is no window where two valid sets exist. The same possession requirement governs disabling MFA. A stolen bearer token on its own cannot tear down the second factor, because disabling MFA demands a fresh TOTP or recovery-code proof. That keeps the second factor meaningful even against an attacker who has temporarily hijacked a session.

Platform-Wide MFA Requirement

Voluntary MFA tends to reach the people who needed it least and miss the accounts that mattered most. PMAP lets an administrator make MFA non-optional across the platform with a single flag. When mfa_required_for_all_users is set, every user who has not yet enrolled sees a persistent enrollment banner on every authenticated page until they complete enrollment.

The banner is delivered through the same boot round-trip that carries the user profile, so the frontend learns the requirement immediately on sign-in rather than discovering it lazily. The reminder persists across page loads, which turns the requirement from a one-time notice that gets dismissed and forgotten into a standing prompt that follows the user until they act. For a security team that has to demonstrate universal MFA coverage to an auditor, this flag converts a policy intention into an enforced default rather than a hopeful suggestion.

JWT Issuance and Session-Aware Rotation

Once authentication and any MFA challenge are complete, PMAP issues a pair of tokens. A short-lived access token carries the user’s claims for the duration of normal requests and expires in 15 minutes. A longer-lived refresh token is used to obtain a new access token when the old one expires. Both embed the identity claims, and when the session module is wired they also carry the session identifier and a per-token JTI, the unique identifier that makes a specific token revocable.

The refresh token is single-use, and this is the core of the design. Every call to the refresh endpoint atomically rotates the JTI on the session row, minting a new access and refresh pair and invalidating the old refresh token in the same SQL operation. If an attacker captures a refresh token and tries to use it after the legitimate client has already refreshed, the rotation check fails and the replayed token is rejected with an invalid-token error. Refresh-token replay, a classic way to extend stolen access, is closed off by construction.

Because access tokens are validated statelessly for performance, a revoked session does not instantly kill an already-issued access token. It blocks the next refresh, and the active access token remains valid only until its 15-minute expiry. That bounded window is a deliberate trade between request-path speed and revocation immediacy, and the platform’s own documentation notes that a future denylist keyed on the access token identifier could shorten it further without breaking changes. For most operator-team scenarios, a 15-minute ceiling on a revoked-but-not-yet-expired token is an acceptable and well-understood boundary.

Concurrent-Session Limit and Self-Service Revocation

Sessions are not disposable artefacts in PMAP. Each successful sign-in creates a tracked session row with the device label, IP address, sign-in time, last activity and expiry, and the platform gives both users and administrators direct control over them.

From the profile sessions tab a user sees every active session they own, with the current one clearly flagged. They can revoke any individual session except the one they are using, a guard that exists specifically to prevent accidental self-lockout. A “sign out everywhere else” action revokes every other session in a single call and returns a count so the UI can confirm exactly how many devices were signed out. If the user is trying to recover from an unrecognised device, that one action evicts everything but their current tab.

The platform can also enforce a ceiling. When a concurrent-session limit is configured, a new login that would push the user over the cap evicts the oldest sessions first, in a single atomic SQL operation, before the new session is inserted. This implements the concurrent session control described as AC-10 in NIST SP 800-53. The enforcement is automatic and requires no manual intervention, so a policy of, for example, three sessions per user simply holds itself. Every revocation records a structured reason from a fixed set, including user, admin, password_change, refresh_rotated, expired and session_limit_exceeded, which makes the session audit trail queryable rather than a stream of undifferentiated logout events. A password change with the sign-out-others option enabled, for instance, revokes all other sessions with the password_change reason, giving a clean audit answer to the question of why those sessions ended.

Login Anomaly Detection Without Blocking

Not every unusual login is an attack, and a control that blocks on suspicion punishes travelling analysts and new laptops more reliably than it stops adversaries. PMAP takes a detect-and-alert posture rather than a block-on-doubt posture, aligned with the audit-review intent of AU-6 in NIST SP 800-53.

At login the new session is compared against the user’s sign-in history over the last 30 days. If neither the IP address nor the derived device label has been seen in that window, the platform emits an asynchronous suspicious-login notification. The login itself is never blocked, delayed or failed because of the anomaly. The notification fires in a detached goroutine, so even after the HTTP response has shipped, the alert still completes.

Two design choices keep the signal clean. The comparison uses a partial match to suppress noise. If either the IP or the device is already known, no alert is raised, because a known person on a new network or a known network with a new browser is routine. Only a complete miss on both dimensions trips the notification. And the device comparison runs against a derived label such as “Chrome on Windows” rather than the raw user-agent string. Browser updates rotate user-agent strings on practically every release, so matching on the raw string would fire a false alarm every time someone’s browser auto-updated. Matching on the stable derived label avoids that whole class of false positives.

Admin Emergency MFA Reset and Force-Revocation

Even a well-run MFA program produces the occasional total loss. A user drops their phone in a lake and discovers their printed recovery codes went out with last month’s recycling. Without an escape hatch, that account is permanently locked. PMAP gives platform administrators two emergency controls, both audited.

The first is an emergency MFA reset. An administrator can force-clear a user’s MFA, which deletes the user_mfa row and cascades to remove every recovery code, with no TOTP proof required. The authority for this action comes from the admin route group itself, not from possessing the user’s lost factor. After the reset the user can sign in with their password alone, and re-enrollment is not automatic, so an administrator who wants the second factor back in place has to ask the user to enrol again. This is the documented recovery path for a user who has lost both their authenticator and their recovery codes.

The second is force-revocation of sessions. An administrator can view every active session for any user and terminate any specific one during incident response, with the acting administrator recorded in the audit trail. The platform verifies that the targeted session UUID actually belongs to the named user before writing anything, and a mismatch returns a not-found response rather than a permission error. That choice is deliberate. It avoids leaking whether a given session exists across user boundaries, denying an attacker a way to enumerate sessions by guessing identifiers. These emergency capabilities, along with login, MFA and session events, feed the platform’s audit record, which is explored from a compliance-evidence angle in vulnerability management compliance and audit.

How PMAP Protects the Credential Layer

Stepping back from the individual controls, the credential layer in PMAP is built as a set of reinforcing boundaries rather than a single gate. Authentication can flow from local accounts or from your directory, with per-user dispatch, live config reload and auto-provisioning that keeps identity aligned with how your organisation already manages people. A TOTP second factor with a 160-bit secret, a five-minute challenge, a five-attempt cap and ten one-time recovery codes ensures a stolen password is not enough on its own. Sessions are first-class objects with rotation that defeats refresh replay, a concurrent-session cap that enforces itself, self-service and admin revocation, and anomaly detection that alerts without blocking.

Each layer assumes the one before it might fail. The lockout assumes a password might be guessed. MFA assumes a password might be stolen. Session rotation assumes a token might be captured. Anomaly detection assumes all of those might slip through quietly. That layered posture, grounded in NIST SP 800-63B and the access and audit control families of NIST SP 800-53, is what lets the rest of PMAP trust the Claims object it depends on. Once a user is authenticated, what they can actually do is governed by RBAC roles and scoped grants, the authorisation half of the identity story.

To put these controls in place across your operator team, read the identity datasheet and enforce MFA, LDAP and session policy from one console.

Frequently Asked Questions

Does PMAP support both local accounts and LDAP or Active Directory at the same time?

Yes. Authentication is decided per user, not per platform. On each login the platform runs a three-case dispatch. A user with no directory binding authenticates locally against a bcrypt password hash, a user already linked to the directory authenticates by LDAP bind with roles re-synced from their groups, and an unknown directory user can be auto-provisioned if you enabled it. Local admin accounts and directory accounts coexist, and LDAP configuration is re-read from the database on every login, so directory changes take effect without a server restart.

What kind of MFA does PMAP use, and do I need a special app?

PMAP uses TOTP, the time-based one-time password standard from RFC 6238. Any standard authenticator app works, including Google Authenticator, Authy and 1Password, with no SMS and no proprietary app required. Enrollment generates a 160-bit secret, presents it as both a scannable QR code and a base32 string, and only activates the factor after the user verifies their first code. The runtime parameters are the RFC defaults: six digits, a 30-second period and a 90-second acceptance window for clock drift.

What happens if a user loses their authenticator?

There are two paths. The user can sign in with one of the ten one-time recovery codes issued when they enrolled, each usable exactly once. If both the authenticator and the recovery codes are gone, a platform administrator can perform an emergency MFA reset that clears the MFA row and all recovery codes without requiring any TOTP proof. After the reset the user signs in with their password alone, and the reset is recorded in the audit trail.

How does PMAP stop a stolen refresh token from being reused?

Refresh tokens are single-use. Every call to the refresh endpoint atomically rotates the token identifier on the session row and invalidates the old refresh token in the same operation. If a captured refresh token is replayed after the real client has already refreshed, the rotation check fails and the replayed token is rejected. Because access tokens are validated statelessly, a revoked session blocks the next refresh while any already-issued access token remains valid only until its 15-minute expiry.

Can the platform limit how many sessions a single user keeps open?

Yes. When a concurrent-session limit is configured, a new login that would exceed the cap evicts the oldest sessions first, in a single atomic operation, before the new session is created. This implements NIST SP 800-53 AC-10 concurrent session control, and enforcement is automatic. Separately, every user can list their own active sessions and revoke any of them except the current one, and a single “sign out everywhere else” action clears all other devices at once.

Does an unusual login get blocked automatically?

No. PMAP detects and alerts rather than blocks. At login the new session is compared against the last 30 days of the user’s history. If neither the IP nor the derived device label has been seen, an asynchronous suspicious-login notification is sent, but the login completes normally. A partial match on either the IP or the device suppresses the alert, and device matching uses a stable derived label rather than the raw user-agent string, which avoids false alarms when browsers auto-update.

How are TOTP secrets and recovery codes stored?

TOTP secrets are stored AES-encrypted in the database and decrypted only in memory when a code is verified, and the secret field is never serialised into any API response. Recovery codes are bcrypt-hashed at the same cost as the password store, so the database holds no usable copy, and each code is stamped as used once redeemed. An operator with database read access sees ciphertext for secrets and hashes for recovery codes, not working credentials.

author avatar
PMAP Security Team

Newsletter

Get the next writeup in your inbox

One short email when a new case writeup or detection deep dive ships. No marketing drip, no third-party tracking.