Silverfort
Use the Silverfort integration to get and update Silverfort risk severity.
Authentication & Identity Management · Silverfort
Details
| ID | Silverfort |
|---|---|
| Provider | Silverfort |
| Category | Authentication & Identity Management |
| From Version | 5.0.0 |
| Docker Image | demisto/auth-utils:1.0.0.10133006 |
| Supported Modules | Agentix 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:
- On the Silverfort Admin Console, navigate to the SETTINGS page, and then select Silverfort API.
- Enable the Allow 3rd party risk updates switch.
- Copy the Risk API Key (External Access) value - this will be your API key.
- 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 |
| 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 KeyexternalApiKey— External API Key
Commands (4)
-
silverfort-get-resource-riskGets the resource entity risk information.
-
silverfort-get-user-riskUser risk commands - get the user entity risk.
-
silverfort-update-resource-riskUpdate the resource entity risk.
-
silverfort-update-user-riskUpdates 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 ")