Skip to content

ABAC + SSO + LDAP/AD — Enterprise Identity Setup

UVP

HeliosDB Full ships three enterprise-identity layers in one binary: an XACML-style ABAC engine (PDP/PEP/PIP/PAP), SAML 2.0 + OAuth 2.0 + OIDC SSO with built-in connectors for Okta / Auth0 / Azure AD / Google Workspace, and LDAP / Active Directory integration with group-to-role mapping. JIT user provisioning, SCIM 2.0, single logout, session limits, and PKCE are first-class. Plug your IdP in once, get RBAC + ABAC + JIT + SLO across every protocol HeliosDB speaks (PostgreSQL, MySQL, MongoDB, REST, GraphQL).


Prerequisites

  • HeliosDB Full v8.0.3
  • An IdP you control (Okta, Auth0, Azure AD, Google Workspace, or a custom SAML/OIDC provider)
  • LDAP or Active Directory bind credentials, if you want directory integration
  • ~45 minutes if you do all three; ~15 if you only do SSO

The three subsystems are independent. You can enable just SSO, just ABAC, or any combination.


1. Architecture in 90 Seconds

┌──────────────────────────────────┐
user request ───▶ │ Protocol layer (PG/MySQL/REST/…) │
└──────────────┬───────────────────┘
┌──────────────▼───────────────────┐
│ Auth pipeline │
│ SSO ─────► JIT provisioning │
│ LDAP ───► group → role mapping │
│ RBAC v2 ► role → privilege set │
│ ABAC ───► PDP evaluates request │
└──────────────┬───────────────────┘
│ allow/deny + obligations
┌──────────────▼───────────────────┐
│ Storage / query engine │
└──────────────────────────────────┘

RBAC answers “what role does this user have?”. ABAC answers “given this user, this resource, this action, this environment — should I let it through?”. They compose: RBAC narrows the set, ABAC vetoes within it.


2. SSO — SAML, OAuth, OIDC

2a. Configuration File

Create sso.toml:

# Okta SAML 2.0
[[providers]]
name = "okta"
type = "saml"
enabled = true
entity_id = "heliosdb-prod"
acs_url = "https://app.example.com/sso/acs"
metadata_url = "https://dev-123.okta.com/app/metadata"
# Auth0 OIDC
[[providers]]
name = "auth0"
type = "oauth"
enabled = true
client_id = "your-client-id"
client_secret_env = "AUTH0_SECRET"
authorization_endpoint = "https://tenant.auth0.com/authorize"
token_endpoint = "https://tenant.auth0.com/oauth/token"
redirect_uri = "https://app.example.com/oauth/callback"
[session]
timeout_seconds = 28800 # 8 hours
max_concurrent_sessions = 5
[provisioning]
enabled = true
default_roles = ["user"]

2b. Wire It In

use heliosdb_sso::{SsoManager, SsoConfig};
let config = SsoConfig::from_file("sso.toml")?;
let manager = SsoManager::new(config).await?;
// Initiate SAML
let auth_url = manager.initiate_saml_login("okta").await?;
// redirect the user to auth_url ...
// Receive SAMLResponse on /sso/acs
let user = manager.handle_saml_response(saml_response).await?;
println!("Authenticated: {} ({})", user.user.email, user.session.id);

2c. Provider-Specific Setup

ProviderTime to set upCritical claims
Okta SAML10 minemail, name, groups
Azure AD SAML12 minemail, name, groups (security-group GUIDs)
Google Workspace SAML8 minemail, name
Auth0 OIDC5 minsub, email, https://example.com/groups
Custom OIDCvariessub, email, custom-namespaced groups

Tip: for Azure AD, request the groups claim using the security group GUIDs mode, not display names — display names are not unique.

2d. SQL Surface

-- Show all configured providers
SHOW SSO PROVIDERS;
-- Active sessions
SHOW SSO SESSIONS;
SHOW SSO SESSIONS WHERE user_id = 'jane@example.com';
-- Force-logout
TERMINATE SSO SESSION 'sso_abc123';

2e. Admin REST API

GET /api/sso/providers
GET /api/sso/providers/okta
POST /api/sso/providers/okta/test
GET /api/sso/sessions
DELETE /api/sso/sessions/sso_123
GET /api/sso/stats

2f. Performance & Limits

  • 1000+ concurrent SSO sessions per node
  • Sub-millisecond session validation (in-memory cache)
  • JWKS auto-refresh
  • PKCE on every OAuth Authorization Code flow

3. LDAP / Active Directory

LDAP authentication is a thin layer: bind, look up the user, fetch group memberships, map groups to HeliosDB roles. The crate is intentionally small (~883 LOC) — one module — and re-uses the upstream ldap3 library.

3a. Configure

ldap.toml
[ldap]
url = "ldaps://dc01.corp.example.com:636"
bind_dn = "CN=heliosdb-svc,OU=Service Accounts,DC=corp,DC=example,DC=com"
bind_password_env = "LDAP_SVC_PASSWORD"
user_base_dn = "OU=Users,DC=corp,DC=example,DC=com"
user_filter = "(&(objectClass=user)(sAMAccountName={username}))"
group_base_dn = "OU=Groups,DC=corp,DC=example,DC=com"
group_filter = "(&(objectClass=group)(member={user_dn}))"
[[group_mapping]]
ldap_group = "DBA-Admins"
heliosdb_role = "admin"
[[group_mapping]]
ldap_group = "Engineering"
heliosdb_role = "developer"
[[group_mapping]]
ldap_group = "Compliance-RO"
heliosdb_role = "auditor"

3b. Wire It In

The Active Directory case is the same — AD is just an LDAP server with extra schema. Set url to your domain controller, user_filter typically uses sAMAccountName, group lookups walk memberOf.

3c. Verifying Group Mapping

-- Show what role HeliosDB resolved for a given LDAP user
SELECT * FROM heliosdb_ldap_resolved_roles WHERE username = 'jane.doe';
-- → role: 'admin', source_group: 'DBA-Admins'

If a user is a member of multiple mapped groups, the highest-privilege role wins (admin > developer > auditor > user).


4. ABAC — Fine-Grained Access Control

ABAC is the layer that makes “this analyst can only see customer rows from the EU between 09:00 and 18:00 CET, except their own team’s rows which they can see anytime” expressible. The engine implements XACML-style PDP/PEP/PIP/PAP separation.

4a. The Four Components

AcronymModuleJob
PEPevaluator.rsPolicy Enforcement Point — sits in the request path
PDPpdp.rsPolicy Decision Point — evaluates policies and returns Permit/Deny
PIPpip.rsPolicy Information Point — fetches attributes (user, resource, environment)
PAPpap.rsPolicy Administration Point — admin API for CRUD on policies

4b. Define a Policy

-- Policy: analysts can SELECT from `customers` where the row's region matches the user's region,
-- only during business hours in the user's timezone.
CREATE ABAC POLICY analyst_customer_access
TARGET resource = 'customers' AND action = 'SELECT'
CONDITION (
user.role = 'analyst'
AND resource.region = user.region
AND env.local_hour BETWEEN 9 AND 18
)
EFFECT permit
OBLIGATION audit ('analyst-customer-read');

The CONDITION clause is evaluated by the PDP for every query. Attributes with the user., resource., and env. prefixes are fetched by the PIP — user.* from the SSO/LDAP claims, resource.* from row metadata or labels, env.* from the runtime (time, IP, MFA status).

4c. Test It

-- Dry-run a request through the PDP without executing the query
EXPLAIN ABAC FOR USER 'jane.doe' ACTION 'SELECT' ON 'customers' WHERE id = 7;

Result:

decision : Permit
matched : analyst_customer_access
obligations: audit('analyst-customer-read')
attributes:
user.region = 'EU'
resource.region = 'EU'
env.local_hour = 14

If the decision is Deny, the response shows which policy denied it and why.

4d. Combining Policies

The PDP evaluates all matching policies and combines them with a configurable algorithm:

AlgorithmBehaviour
permit-overridesAny Permit wins (default for read)
deny-overridesAny Deny wins (recommended for writes)
first-applicableFirst matching policy wins
only-one-applicableError if more than one matches

Set per-action:

ALTER ABAC ENGINE
SET combining_algorithm_for SELECT = 'permit-overrides',
combining_algorithm_for INSERT = 'deny-overrides',
combining_algorithm_for UPDATE = 'deny-overrides',
combining_algorithm_for DELETE = 'deny-overrides';

5. End-to-End — A Realistic Setup

The goal: an analyst signs in via Okta SAML, lands in the analyst role via group mapping, can read customers only in their region during business hours, with every read audited.

5a. SSO

[[providers]]
name = "okta"
type = "saml"
entity_id = "heliosdb-prod"
acs_url = "https://app.example.com/sso/acs"
metadata_url = "https://dev-123.okta.com/app/metadata"
[provisioning]
enabled = true
default_roles = ["user"]

5b. Group → Role mapping (driven by SAML claim)

CREATE GROUP MAPPING 'okta-analysts' TO ROLE 'analyst';

Okta sends groups: ["okta-analysts"] in the SAML assertion; JIT provisioning attaches the role.

5c. ABAC

CREATE ABAC POLICY analyst_region_read
TARGET resource = 'customers' AND action = 'SELECT'
CONDITION (user.role = 'analyst'
AND resource.region = user.region
AND env.local_hour BETWEEN 9 AND 18)
EFFECT permit
OBLIGATION audit ('analyst-region-read');
CREATE ABAC POLICY analyst_no_writes
TARGET resource = 'customers' AND action IN ('INSERT', 'UPDATE', 'DELETE')
CONDITION (user.role = 'analyst')
EFFECT deny;

5d. Verify

EXPLAIN ABAC FOR USER 'jane.doe' ACTION 'SELECT' ON 'customers' WHERE id = 7;
EXPLAIN ABAC FOR USER 'jane.doe' ACTION 'UPDATE' ON 'customers' WHERE id = 7;

The first returns Permit with the audit obligation; the second returns Deny and names analyst_no_writes.


6. Production Checklist

SSO

  • HTTPS enforced on the ACS / redirect URL
  • XML signature verification is on for SAML
  • PKCE is on for every OAuth flow (the default — don’t disable it)
  • max_concurrent_sessions is set per your security policy
  • Session timeout is short enough that lost devices don’t stay authenticated for days

LDAP / AD

  • Bind via ldaps:// (port 636), not plain LDAP
  • Service account credentials are in a secret manager, not the config file
  • Group-to-role mapping is documented and reviewed quarterly
  • user_filter excludes service accounts from interactive login

ABAC

  • Combining algorithm is deny-overrides for writes
  • Every Permit policy has an OBLIGATION audit (…) for traceability
  • Policies are version-controlled (the PAP supports import/export — keep them in git)
  • An emergency superuser-bypass policy exists, and access to that role is gated by MFA

7. Verification Status

ComponentStatus notes
SSO (SAML / OAuth / OIDC)Production. 70+ tests, supports 1000+ concurrent sessions, sub-ms session validation
LDAP / ADActive. Single-module crate (~883 LOC). Group → role mapping is straightforward; complex AD topologies (multiple forests, trust boundaries) may need custom code
ABACProduction. PDP/PEP/PIP/PAP separation matches XACML 3.0 vocabulary; combining algorithms above implemented
SCIM 2.0 user syncDocumented as optional in the SSO crate — verify against your IdP before relying on it

Where Next


References

  • Source: /home/app/Helios/Full/heliosdb-security/crates/{abac,sso,ldap}/
  • ABAC modules: pdp.rs, pep.rs (in evaluator.rs), pip.rs, pap.rs, policy_engine.rs, xacml.rs
  • SSO providers directory: heliosdb-security/crates/sso/src/providers/