Silverfort

Use the Silverfort integration to get and update Silverfort risk severity.

Authentication & Identity Management · Silverfort

Details

IDSilverfort
ProviderSilverfort
CategoryAuthentication & Identity Management
From Version5.0.0
Docker Imagedemisto/auth-utils:1.0.0.10133006
Supported ModulesAgentix XSIAM

README

Silverfort protects organizations from data breaches by delivering strong authentication across entire corporate networks and cloud environments, without requiring any modifications to endpoints or servers. Using patent-pending technology, Silverfort’s agentless approach enables multi-factor authentication and AI-driven adaptive authentication even for systems that don’t support it today, including proprietary systems, critical infrastructure, shared folders, IoT devices, and more.

Use Silverfort integration to get & update Silverfort risk severity.

This integration was integrated and tested with Silverfort version 5.2.

Silverfort Playbook


  • Get risk information and block the user if the risk is ‘high’ or ‘critical’
  • Update the Silverfort user risk level

Use Cases


  • Consume Silverfort user and server risk levels
  • Enrich the Silverfort risk engine and trigger MFA on risky entities

Configure Silverfort in Cortex

Parameter Description Required
Name a textual name for the integration instance True
url Server URL True
apikey APIKEY True
insecure Trust any certificate (not secure) False
  • To generate an API token for external access:
    1. On the Silverfort Admin Console, navigate to the SETTINGS page, and then select Silverfort API.
    2. Enable the Allow 3rd party risk updates switch.
    3. Copy the Risk API Key (External Access) value - this will be your API key.
    4. For the URL, use one of the following based on your Silverfort region:
      • Global region: https://raven.silverfort.io
      • EU region: https://eu.raven.silverfort.io
      • Singapore region: https://sg.raven.silverfort.io
        // End of Selection

For more information, see the Silverfort documentation.

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details. DBot messages provide a structured summary of the command execution, including the inputs, outputs, and any relevant indicators of compromise (IOCs) or risk levels.

silverfort-get-user-risk


User risk commands - get the user entity risk.

Base Command

silverfort-get-user-risk

Input

Argument Name Description Required
upn The user principal name. Optional
email The email address. Optional
sam_account The sam account. Optional
domain The domain. Optional

Specify one of the following:

  • upn
  • email address and domain
  • sam account and domain

Context Output

Path Type Description
Silverfort.UserRisk.Risk String The risk level.
Silverfort.UserRisk.Reasons Unknown The reasons for the risk.
Silverfort.UserRisk.UPN String The user principal name.

Command Example

!silverfort-get-user-risk upn="sfuser@silverfort.io"

Human Readable Output

Silverfort User Risk

UPN Risk Reasons
sfuser@silverfort.io Medium Suspicious activity, Password never expires

silverfort-get-resource-risk


Gets the resource entity risk information.

Base Command

silverfort-get-resource-risk

Input

Argument Name Description Required
resource_name The hostname. Required
domain_name The domain. Required

Command Example

!silverfort-get-resource-risk resource_name="SF-DC-1" domain_name="silverfort.io"

Human Readable Output

Silverfort Resource Risk

ResourceName Risk Reasons
SF-DC-1 Low Unconstrained Delegation

silverfort-update-user-risk


Updates the user entity risk.

Base Command

silverfort-update-user-risk

Input

Argument Name Description Required
upn The user principal name. Optional
risk_name The risk name. Required
severity The severity. Required
valid_for The number of hours that the risk will be valid for. Required
description The risk description. Required

Command Example

!silverfort-update-user-risk upn="sfuser@silverfort.io" risk_name="activity_risk" severity=medium valid_for=1 description="Suspicious activity"

Human Readable Output

ok

silverfort-update-resource-risk


Update the resource entity risk.

Base Command

silverfort-update-resource-risk

Input

Argument Name Description Required
resource_name The hostname. Required
domain_name The domain name. Required
risk_name The risk name. Required
severity The severity. Required
valid_for The number of hours the severity will be relevant for. Required
description A short description about the risk. Required

Command Example

!silverfort-update-resource-risk resource_name="SF-DC-1" domain_name="silverfort.io" risk_name="malware_risk" severity="high" valid_for=1 description="Malware detected"

Human Readable Output

ok

Configuration parameters

  • url — Server URL (required)
  • apikey — APIKEY (required)
  • insecure — Trust any certificate (not secure)
  • operationalApiKey — Operational API Key
  • externalApiKey — External API Key

Commands (4)

  • silverfort-get-resource-risk

    Gets the resource entity risk information.

  • silverfort-get-user-risk

    User risk commands - get the user entity risk.

  • silverfort-update-resource-risk

    Update the resource entity risk.

  • silverfort-update-user-risk

    Updates the user entity risk.

import pytest
from Silverfort import (
    get_jwt_token,
    get_resource_entity_risk_command,
    get_user_entity_risk_command,
    update_resource_entity_risk_command,
    update_user_entity_risk_command,
)


@pytest.fixture(autouse=True)
def upn():
    return "sfuser@silverfort.io"


@pytest.fixture(autouse=True)
def base_url():
    return "https://test.com"


@pytest.fixture(autouse=True)
def email():
    return "john@silverfort.com"


@pytest.fixture(autouse=True)
def domain():
    return "silverfort.io"


@pytest.fixture(autouse=True)
def api_key():
    return "APP_USER_ID:APP_USER_SECRET"


@pytest.fixture(autouse=True)
def operational_api_key():
    return "OP_USER_ID:OP_USER_SECRET"


@pytest.fixture(autouse=True)
def risk():
    return {"risk_name": "activity_risk", "severity": "medium", "valid_for": 1, "description": "Suspicious activity"}


@pytest.fixture(autouse=True)
def resource_name():
    return "AA--DC-1"


@pytest.fixture(autouse=True)
def bad_response():
    return "No valid response"


@pytest.fixture(autouse=True)
def valid_update_response():
    return {"result": "updated successfully!"}


@pytest.fixture(autouse=True)
def valid_get_risk_response():
    return {"risk": "Low", "reasons": ["Password never expires", "Suspicious activity"]}


@pytest.fixture(autouse=True)
def valid_get_upn_response(upn):
    return {"user_principal_name": upn}


@pytest.fixture(autouse=True)
def sam_account():
    return "sfuser"


@pytest.fixture(autouse=True)
def client(base_url, api_key, operational_api_key):
    from Silverfort import Client

    app_user_id, app_user_secret = api_key.split(":")
    op_user_id, op_user_secret = operational_api_key.split(":")
    return Client(
        app_user_id=app_user_id,
        app_user_secret=app_user_secret,
        operational_user_id=op_user_id,
        operational_user_secret=op_user_secret,
        external_api_key=None,
        base_url=base_url,
        verify=False,
    )


@pytest.fixture(autouse=True)
def risk_args(risk):
    return {"risk_name": "activity_risk", "severity": "medium", "valid_for": 1, "description": "Suspicious activity"}


@pytest.fixture(autouse=True)
def current_time(risk):
    return 1656417207.2854111


@pytest.fixture(autouse=True)
def expected_jwt_token(api_key, current_time):
    import jwt

    app_user_id, app_user_secret = api_key.split(":")
    payload = {"iss": app_user_id, "iat": current_time, "exp": current_time + 60}
    return jwt.encode(payload, app_user_secret, algorithm="HS256")


class TestSiverfort:
    def test_get_status(self, requests_mock, base_url, api_key, client):
        from Silverfort import test_module

        # test_module uses getEntityRisk with ok_codes=(200, 400, 404)
        requests_mock.get(f"{base_url}/getEntityRisk", json={"risk": "Low", "reasons": []})
        output = test_module(client)
        assert output == "ok"

    def test_get_upn_by_email(self, requests_mock, upn, base_url, valid_get_upn_response, api_key, client, email, domain):
        requests_mock.get(f"{base_url}/getUPN?email={email}&domain={domain}", json=valid_get_upn_response)

        output = client.get_upn_by_email_or_sam_account_http_request(domain, email=email)
        assert output == upn

    def test_get_upn_by_sam_account(
        self, requests_mock, upn, base_url, valid_get_upn_response, api_key, client, sam_account, domain
    ):
        requests_mock.get(f"{base_url}/getUPN?sam_account={sam_account}&domain={domain}", json=valid_get_upn_response)

        output = client.get_upn_by_email_or_sam_account_http_request(domain, sam_account=sam_account)
        assert output == upn

    def test_get_user_entity_risk(self, requests_mock, upn, base_url, api_key, client, valid_get_risk_response):
        args = {"upn": upn}
        requests_mock.get(f"{base_url}/getEntityRisk?user_principal_name={upn}", json=valid_get_risk_response)

        _, outputs, _ = get_user_entity_risk_command(client, args)

        outputs = outputs["Silverfort.UserRisk(val.UPN && val.UPN == obj.UPN)"]

        assert outputs["UPN"] == upn
        assert outputs["Risk"] == valid_get_risk_response["risk"]
        assert outputs["Reasons"] == valid_get_risk_response["reasons"]

    def test_get_resource_entity_risk(
        self, requests_mock, base_url, api_key, client, valid_get_risk_response, resource_name, domain
    ):
        args = {"resource_name": resource_name, "domain_name": domain}
        requests_mock.get(
            f"{base_url}/getEntityRisk?resource_name={resource_name}&domain_name={domain}", json=valid_get_risk_response
        )

        _, outputs, _ = get_resource_entity_risk_command(client, args)

        outputs = outputs["Silverfort.ResourceRisk(val.ResourceName && val.ResourceName == obj.ResourceName)"]

        assert outputs["ResourceName"] == resource_name
        assert outputs["Risk"] == valid_get_risk_response["risk"]
        assert outputs["Reasons"] == valid_get_risk_response["reasons"]

    def test_update_user_entity_risk(
        self, requests_mock, upn, base_url, api_key, client, valid_update_response, bad_response, risk_args
    ):
        args = risk_args
        args["upn"] = upn

        requests_mock.post(f"{base_url}/updateEntityRisk", json=valid_update_response)
        assert update_user_entity_risk_command(client, args) == "updated successfully!"

        requests_mock.post(f"{base_url}/updateEntityRisk", json=bad_response)
        assert update_user_entity_risk_command(client, args) == "Couldn't update the user entity's risk"

    def test_update_resource_entity_risk_successfully(
        self, requests_mock, base_url, api_key, client, valid_update_response, bad_response, risk_args, resource_name, domain
    ):
        args = risk_args
        args["resource_name"] = resource_name
        args["domain_name"] = domain

        requests_mock.post(f"{base_url}/updateEntityRisk", json=valid_update_response)
        assert update_resource_entity_risk_command(client, args) == "updated successfully!"

        requests_mock.post(f"{base_url}/updateEntityRisk", json=bad_response)
        assert update_resource_entity_risk_command(client, args) == "Couldn't update the resource entity's risk"

    def test_get_jwt_token(self, api_key, current_time, expected_jwt_token):
        app_user_id, app_user_secret = api_key.split(":")
        jwt_token = get_jwt_token(app_user_id, app_user_secret, current_time)

        assert jwt_token == expected_jwt_token

    def test_build_operational_headers_uses_operational_credentials(self, client):
        """Test that build_operational_headers uses operational credentials when available"""
        headers = client.build_operational_headers()
        # The token should be generated from operational credentials (OP_USER_ID)
        assert "Authorization" in headers
        assert headers["Authorization"].startswith("Bearer ")

    def test_build_operational_headers_falls_back_to_main_credentials(self, base_url, api_key):
        """Test fallback to main credentials when operational ones are not provided"""
        from Silverfort import Client

        app_user_id, app_user_secret = api_key.split(":")
        client_without_op = Client(
            app_user_id=app_user_id,
            app_user_secret=app_user_secret,
            operational_user_id=None,
            operational_user_secret=None,
            external_api_key=None,
            base_url=base_url,
            verify=False,
        )
        headers = client_without_op.build_operational_headers()
        assert "Authorization" in headers
        # Should still have a valid Bearer token (from main credentials)
        assert headers["Authorization"].startswith("Bearer ")