Challenge 6: Session Management and Dual Authorisation

Objective: Implement the two-person rule for safety-critical operations to prevent single-person abuse while understanding the security vs usability trade-offs.

Category: Access Control & Insider Threat Prevention

Difficulty: Intermediate

Time Required: 30-45 minutes

Learning outcomes

By completing this challenge, you will:

  1. Understand the two-person rule for critical operations

  2. Implement dual authorisation for safety bypasses

  3. Manage authentication sessions and timeouts

  4. Balance security requirements with operational needs

  5. Detect potential collusion patterns

  6. Understand when prevention isn’t enough (detection matters)

Background: two-person rule

The Problem: Some operations are too critical for one person. A single insider with valid credentials can abuse their access.

Examples of Critical Operations:

  • Reactor shutdown (SCRAM)

  • Safety system bypass

  • Emergency turbine stop

  • Force operations (overriding sensors)

  • Firmware uploads to PLCs

Two-Person Rule: Require independent authorisation from two different users, both with appropriate permissions.

Not About Technology: The two-person rule is fundamentally a procedural control enforced by technology. Technical controls verify two authenticated sessions, but cannot guarantee two different people are physically present.

Current state (infrastructure ready)

Good news: The dual authorisation infrastructure is already implemented:

  • AuthenticationManager - Dual auth method exists

  • Session Management - Timeout support, session tracking

  • Permission System - Role-based permissions (SAFETY_BYPASS, etc.)

  • Audit Logging - All dual auth attempts logged

Your job: Use the dual authorisation system for critical operations.

Part 1: Understanding dual authorisation

Step 1.1: Review available users and permissions

Check which users can perform safety bypasses:

python tools/blue_team.py rbac list-users

Example output:

Users (5):
  admin          (admin     ) - permissions: all
  supervisor1    (supervisor) - permissions: read, write, config, safety_bypass
  supervisor2    (supervisor) - permissions: read, write, config, safety_bypass
  operator1      (operator  ) - permissions: read, write
  operator2      (operator  ) - permissions: read, write

Key Observations:

  • Only supervisors and admins have SAFETY_BYPASS permission

  • Operators can read/write but cannot bypass safety systems

  • Two-person rule requires two users with the permission

Step 1.2: Understand the dual authorisation API

The authentication system provides authorize_with_dual_auth():

from components.security.authentication import AuthenticationManager, PermissionType

auth = AuthenticationManager()

# Authenticate two users
session1 = await auth.authenticate("supervisor1", "super123")
session2 = await auth.authenticate("supervisor2", "super123")

# Dual authorisation for safety bypass
authorized = await auth.authorize_with_dual_auth(
    session1,                          # First user's session
    session2,                          # Second user's session
    PermissionType.SAFETY_BYPASS,      # Permission required
    resource="reactor_safety_plc_1",   # Device being accessed
    reason="Planned maintenance"       # Justification
)

if authorized:
    # Both users authorised - proceed with bypass
    await reactor_safety_plc.activate_bypass(authorization=session1)

Requirements:

  • Both sessions must be valid (not expired)

  • Both users must have the required permission

  • Must be two different users (can’t use same session twice)

  • All attempts are logged to audit trail

Part 2: Testing dual authorisation

Step 2.1: Run the dual authorisation demo

Execute the demonstration script:

python examples/dual_auth_demo.py

This demonstrates:

  1. Scenario 1: Single user attempt (DENIED - same user twice)

  2. Scenario 2: Two operators (DENIED - insufficient privileges)

  3. Scenario 3: Two supervisors (GRANTED - two-person rule satisfied)

  4. Scenario 4: Supervisor + Admin (GRANTED - role separation)

Watch the Output:

  • Which attempts succeeded?

  • Which attempts fail and why?

  • What gets logged to audit trail?

Step 2.2: Test with Blue Team CLI

View active sessions:

python tools/blue_team.py rbac list-sessions

Example output:

Active Sessions (2):
Session: a3b4c5d6...
  User: supervisor1
  Role: supervisor
  Created: 125.3s
  Expires: 3725.3s (0.9h remaining)

Session: e7f8g9h0...
  User: supervisor2
  Role: supervisor
  Created: 126.1s
  Expires: 3726.1s (0.9h remaining)

Check for:

  • Who is currently logged in?

  • When do sessions expire?

  • Are there any expired sessions?

Step 2.3: Force session logout (emergency)

Test session management:

# Logout a specific session
python tools/blue_team.py rbac logout-session a3b4c5d6 \
  --reason "Emergency termination during security incident"

Use Cases:

  • Compromised credentials

  • User left session open

  • Testing session timeout handling

  • Emergency security lockdown

Part 3: Session timeout testing

Step 3.1: Understanding session timeouts

Session timeouts are configured in config/authentication.yml:

session_timeout_hours: 1  # Sessions expire after 1 hour (simulation time)

Why Timeouts Matter:

  • Prevent abandoned sessions from being exploited

  • Force periodic re-authentication

  • Limit window for session hijacking

Trade-off:

  • Long timeouts: Convenient, but risky if credentials compromised

  • Short timeouts: Secure, but disruptive during long operations

Step 3.2: Test session expiry

# Start a session
session = await auth.authenticate("supervisor1", "super123")

# Wait for timeout (in simulation)
await asyncio.sleep(3600 * 1.5)  # Wait 1.5 hours (simulation time)

# Try to use expired session
authorized = await auth.authorize(
    session,
    PermissionType.SAFETY_BYPASS,
    resource="reactor_1"
)
# Returns False - session expired

Question: What happens if a session expires during a critical operation?

Step 3.3: Handling timeout during dual auth

Consider this scenario:

  1. Supervisor1 approves bypass operation

  2. Waiting for Supervisor2 approval

  3. Supervisor1’s session expires while waiting

  4. Supervisor2 approves

Result: Dual auth fails because first session expired.

Solutions:

  • Session refresh mechanism

  • Time-limited approval windows

  • Re-authenticate if needed

  • Session extension for active operations

Part 4: Implementing dual auth in safety operations

Step 4.1: Modify Safety Bypass to Require Dual Auth

Current implementation uses single authorisation:

# components/devices/control_zone/safety/base_safety_controller.py
await controller.activate_bypass(authorization=session_id)

To require dual auth, create a wrapper or modify the operation:

# Example: Dual-auth wrapper for safety bypass
async def bypass_with_dual_auth(controller, session1, session2, reason=""):
    """Activate safety bypass with two-person rule."""
    from components.security.authentication import (
        AuthenticationManager,
        PermissionType
    )

    auth = AuthenticationManager()

    # Verify dual authorisation
    authorized = await auth.authorize_with_dual_auth(
        session1,
        session2,
        PermissionType.SAFETY_BYPASS,
        resource=controller.device_name,
        reason=reason
    )

    if authorized:
        # Both users authorised - proceed with bypass
        return await controller.activate_bypass(authorization=session1)
    else:
        print(f"❌ Dual authorisation required for safety bypass on {controller.device_name}")
        return False

Step 4.2: Identify critical operations

Search for operations that should require dual auth:

# Find safety-related operations
grep -r "bypass\|SCRAM\|shutdown\|emergency" components/devices/control_zone/ | grep "async def"

Candidates:

  • Safety system bypass (activate_bypass)

  • Reactor SCRAM operations

  • Emergency turbine stop

  • Force mode (override sensors)

  • Manual trip commands

Decision Criteria:

  • Is it safety-critical?

  • Could single insider cause harm?

  • Is delay acceptable?

  • Are two qualified people available?

Part 5: Detection over prevention

Step 5.1: Monitoring dual auth patterns

Even with dual auth, insiders can collude. Detection is essential:

# Find all dual auth attempts
python tools/blue_team.py audit search "DUAL AUTHORISATION"

# Look for suspicious patterns
python tools/blue_team.py audit query --category security --action dual_auth

Red Flags:

  • Same pair of users always working together

  • Unusual times (3 AM bypasses)

  • Rapid succession of critical operations

  • No maintenance tickets for bypass reasons

Step 5.2: Collusion detection

# Export dual auth events for analysis
python tools/blue_team.py audit export --format csv --category security

# Analyse in spreadsheet:
# - Group by user pairs
# - Check frequency of same pairs
# - Look for anomalous timing

Statistical Indicators:

  • Pair appears > 80% of the time together

  • Only bypass during off-hours

  • Bypass frequency doesn’t match maintenance schedule

Step 5.3: Beyond technical controls

Technical controls verify:

  • Two authenticated sessions exist

  • Both users have permissions

  • Sessions are from different users

Technical controls CANNOT verify:

  • ❌ Two people are physically present

  • ❌ They aren’t colluding

  • ❌ One isn’t coercing the other

  • ❌ Authorisation is legitimate

Additional Controls:

  • Video recording of critical operations

  • Supervisor observation

  • Random audits

  • Three-person rule for most critical ops

  • Time-delayed authorisation (cooling-off period)

Part 6: Balancing security and operations

Scenario: Emergency during single-person shift

Problem:

  • Reactor approaching unsafe temperature

  • Need to bypass safety interlock to activate emergency cooling

  • Only one supervisor on shift

  • Two-person rule blocks the operation

Options:

  1. Emergency Override Code:

    • Sealed envelope with override credentials

    • Requires breaking seal (evidence of use)

    • Automatic notification to security/management

    • Post-incident review required

  2. Remote Approval:

    • Video call with off-duty supervisor

    • Verbal approval + session sharing

    • Risk: Session hijacking if compromised

  3. Temporary Downgrade:

    • Security admin can temporarily remove dual auth requirement

    • Requires justification and approval

    • Automatically re-enabled after incident

  4. Accept the Risk:

    • Dual auth delays emergency response

    • But prevents 99% of insider abuse

    • Trade-off: Safety vs Security

Discussion: What would you do?

Scenario: Shift change during long operation

Problem:

  • Started bypass procedure with Supervisor1 + Supervisor2

  • Operation takes 2 hours

  • Shift change at 1 hour mark

  • Supervisor1 leaves, Supervisor3 arrives

  • Session timeout approaching

Options:

  1. Session Refresh:

    • Supervisor1 refreshes session before leaving

    • Risk: Session remains active after they leave

  2. Re-authorise:

    • Supervisor3 provides second authorisation

    • But Supervisor1 already left - need to wait?

  3. Session Handoff:

    • Transfer authorisation from Supervisor1 to Supervisor3

    • Technical complexity + audit trail confusion

  4. Complete Before Shift Change:

    • Require operations to finish within shift

    • May not be practical for long procedures

Discussion: How would you design session handoff?

Part 7: Advanced dual authorisation

Time-delayed authorisation

Prevent impulsive or coerced decisions:

async def authorize_with_delay(session1, session2, action, delay_seconds=300):
    """
    Require time delay between first and second authorisation.

    Prevents:
    - Impulsive decisions
    - Coercion (victim has time to alert)
    - Rushed bypasses during attacks
    """
    # Record first authorisation
    auth1_time = time.time()
    auth1 = await auth.authorize(session1, action)

    if not auth1:
        return False

    # Wait for time delay
    await asyncio.sleep(delay_seconds)

    # Second authorisation must be after delay
    auth2 = await auth.authorize(session2, action)
    auth2_time = time.time()

    if auth2 and (auth2_time - auth1_time >= delay_seconds):
        return True

    return False

Benefits:

  • Cooling-off period

  • Time to reconsider

  • Harder to coerce both users quickly

Drawbacks:

  • Delays genuine emergencies

  • May be impractical

Three-person rule

For most critical operations:

authorized = await auth.authorize_with_multi_auth(
    [session1, session2, session3],  # Three users required
    PermissionType.REACTOR_SHUTDOWN,
    resource="reactor_1"
)

When to Use:

  • Reactor shutdown

  • Firmware uploads

  • Safety system configuration changes

  • Irreversible operations

Role separation

Require different roles (not just different users):

async def authorize_with_role_separation(session1, session2, action):
    """Require different roles (e.g., engineer + supervisor)."""
    s1 = await auth.get_session(session1)
    s2 = await auth.get_session(session2)

    # Both must be authorised
    if not (await auth.authorize(session1, action) and
            await auth.authorize(session2, action)):
        return False

    # Must have different roles
    if s1.user.role != s2.user.role:
        return True

    return False

Benefits:

  • Different perspectives

  • Checks and balances

  • Harder for single group to collude

Part 8: Testing and validation

Test Case 1: Legitimate bypass

# Two supervisors perform planned maintenance bypass
session1 = await auth.authenticate("supervisor1", "super123")
session2 = await auth.authenticate("supervisor2", "super123")

authorized = await auth.authorize_with_dual_auth(
    session1, session2,
    PermissionType.SAFETY_BYPASS,
    resource="reactor_safety_plc_1",
    reason="Planned maintenance - valve replacement"
)

assert authorized == True  # Should succeed

Test Case 2: Single user attempt

# Try to use same session twice
authorized = await auth.authorize_with_dual_auth(
    session1, session1,  # Same session!
    PermissionType.SAFETY_BYPASS,
    resource="reactor_safety_plc_1"
)

assert authorized == False  # Should fail

Test Case 3: Insufficient privileges

# Two operators try to bypass
op1 = await auth.authenticate("operator1", "pass123")
op2 = await auth.authenticate("operator2", "pass123")

authorized = await auth.authorize_with_dual_auth(
    op1, op2,
    PermissionType.SAFETY_BYPASS,
    resource="reactor_safety_plc_1"
)

assert authorized == False  # Should fail - operators lack permission

Test Case 4: Expired session

# First session expires before second authorisation
session1 = await auth.authenticate("supervisor1", "super123")
session2 = await auth.authenticate("supervisor2", "super123")

# Simulate session1 expiring
await asyncio.sleep(timeout_duration + 1)

authorized = await auth.authorize_with_dual_auth(
    session1, session2,  # session1 is expired
    PermissionType.SAFETY_BYPASS,
    resource="reactor_safety_plc_1"
)

assert authorized == False  # Should fail - expired session

Reflection

What you can learn

  1. Two-Person Rule:

    • Requires two different authenticated users

    • Both must have required permissions

    • Prevents single insider from abusing access

    • Cannot prevent collusion

  2. Session Management:

    • Timeout prevents abandoned session abuse

    • But complicates long operations

    • Session refresh vs re-authentication trade-off

    • Logout required for security incidents

  3. Trade-offs:

    • Security vs Usability: Two people slower than one

    • Prevention vs Detection: Can’t prevent all abuse, must detect

    • Compliance vs Emergency: Procedures may delay critical response

  4. Beyond Technology:

    • Technical controls verify authentication, not intent

    • Physical presence cannot be verified remotely

    • Procedural controls still essential

    • Audit and detection remain critical

Discussion

  1. Emergency Procedures:

    • How do you handle emergencies when only one qualified person available?

    • Should there be an override mechanism?

    • Who authorises the override?

  2. Collusion:

    • How do you detect two insiders colluding?

    • Statistical analysis of user pairs?

    • Behaviour analytics?

    • Whistleblower mechanisms?

  3. Usability:

    • Is two-person rule practical for all critical operations?

    • What operations genuinely need it?

    • How to reduce false security (security theatre)?

  4. Detection vs Prevention:

    • Can all abuse be prevented?

    • When is detection more important?

    • How fast must you detect?

    • What’s the response process?

Challenge success criteria

  • You understand the two-person rule concept

  • You can use dual authorisation API

  • You can view and manage active sessions

  • You understand session timeout implications

  • You can identify critical operations requiring dual auth

  • You understand detection requirements for collusion

  • You can balance security and operational needs

Next steps

Combine with Other Challenges:

Integration:

  • Modify SCRAM operations to require dual auth

  • Implement emergency override procedures

  • Deploy time-delayed authorisation for critical ops

  • Create collusion detection analytics

  • Implement session handoff for shift changes

References

Standards:

  • ISA 62443-3-3: Security technologies for IACS

  • ISA 62443-4-2: Technical security requirements for IACS components

  • NERC CIP-005: Electronic Security Perimeter(s)

Tools:

  • Blue Team CLI: python tools/blue_team.py rbac --help

  • Dual Auth Demo: python examples/dual_auth_demo.py

  • Authentication API: components/security/authentication.py

Further Reading:

  • Two-Person Integrity (US Nuclear)

  • Dual Control in Banking Systems

  • Separation of Duties (SOD) in SAP