Skip to content

Commit 4588551

Browse files
Merge pull request #147 from CrowdStrike/cid-option
CID Command Line Option for MSSP Auth Backend
2 parents ec1253f + 252a535 commit 4588551

File tree

10 files changed

+65
-27
lines changed

10 files changed

+65
-27
lines changed

falcon_toolkit/common/auth.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
if TYPE_CHECKING:
2020
from caracara import Client
21+
from click import Context
2122

2223

2324
class AuthBackend(ABC):
@@ -51,7 +52,7 @@ def __init__(self, config: Dict = None):
5152
"""
5253

5354
@abstractmethod
54-
def authenticate(self) -> Client:
55+
def authenticate(self, ctx: Context) -> Client:
5556
"""Return a complete OAuth2 object, ready for use with FalconPy."""
5657

5758
@abstractmethod

falcon_toolkit/common/auth_backends/public_mssp.py

+41-19
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
user which child CID to authenticate against.
55
"""
66

7-
import os
8-
97
from typing import Dict, Optional
108

9+
import click
1110
import keyring
1211

1312
from caracara import Client
@@ -94,15 +93,17 @@ def dump_config(self) -> Dict[str, object]:
9493
keyring.
9594
"""
9695
config: Dict[str, object] = {}
97-
config["client_id"]: str = self.client_id
98-
config["cloud_name"]: str = self.cloud_name
99-
config["ssl_verify"]: bool = self.ssl_verify
100-
config["proxy"]: Dict[str, str] = self.proxy
96+
config["client_id"] = self.client_id
97+
config["cloud_name"] = self.cloud_name
98+
config["ssl_verify"] = self.ssl_verify
99+
config["proxy"] = self.proxy
101100

102101
return config
103102

104-
def authenticate(self) -> Client:
103+
def authenticate(self, ctx: click.Context) -> Client:
105104
"""Log the Toolkit into Falcon using the settings and keys configured at instance setup."""
105+
chosen_cid_str = ctx.obj["cid"]
106+
106107
parent_client = Client(
107108
client_id=self.client_id,
108109
client_secret=self.client_secret,
@@ -111,18 +112,39 @@ def authenticate(self) -> Client:
111112
proxy=self.proxy,
112113
)
113114
child_cids = parent_client.flight_control.get_child_cids()
114-
chosen_cid_str = os.environ.get("FALCON_MSSP_CHILD_CID")
115-
if chosen_cid_str and chosen_cid_str.lower() in child_cids:
116-
chosen_cid = parent_client.flight_control.get_child_cid_data(cids=[chosen_cid_str])[
117-
chosen_cid_str
118-
]
119-
else:
120-
child_cids_data = parent_client.flight_control.get_child_cid_data(cids=child_cids)
121-
chosen_cid_str = choose_cid(cids=child_cids_data, prompt_text="MSSP Child CID Search")
122-
chosen_cid = child_cids_data[chosen_cid_str]
123-
124-
chosen_cid_name = chosen_cid["name"]
125-
print(f"Connecting to {chosen_cid_name}")
115+
116+
if chosen_cid_str and chosen_cid_str in child_cids:
117+
click.echo(
118+
click.style("Valid member CID ", fg="blue")
119+
+ click.style(chosen_cid_str, fg="blue", bold=True)
120+
+ click.style(" provided. Skipping CID selection.", fg="blue")
121+
)
122+
elif chosen_cid_str:
123+
click.echo(click.style("An invalid CID was provided at the command line.", fg="red"))
124+
click.echo("Please search for an alternative CID:")
125+
# Blank out a bad value
126+
chosen_cid_str = None
127+
128+
if not chosen_cid_str:
129+
if chosen_cid_str and chosen_cid_str.lower() in child_cids:
130+
chosen_cid = parent_client.flight_control.get_child_cid_data(
131+
cids=[chosen_cid_str],
132+
)[chosen_cid_str]
133+
else:
134+
child_cids_data = parent_client.flight_control.get_child_cid_data(cids=child_cids)
135+
if not child_cids_data:
136+
raise RuntimeError(
137+
"No child CIDs accessible. Please check your API credentials."
138+
)
139+
140+
chosen_cid_str = choose_cid(
141+
cids=child_cids_data,
142+
prompt_text="MSSP Child CID Search",
143+
)
144+
chosen_cid = child_cids_data[chosen_cid_str]
145+
146+
chosen_cid_name = chosen_cid["name"]
147+
print(f"Connecting to {chosen_cid_name}")
126148

127149
client = Client(
128150
client_id=self.client_id,

falcon_toolkit/common/auth_backends/public_single_cid.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from typing import Dict, Optional
88

9+
import click
910
import keyring
1011

1112
from caracara import Client
@@ -89,7 +90,7 @@ def dump_config(self) -> Dict[str, object]:
8990

9091
return config
9192

92-
def authenticate(self) -> Client:
93+
def authenticate(self, ctx: click.Context) -> Client:
9394
"""Log the Toolkit into Falcon using the settings and keys configured at instance setup."""
9495
client = Client(
9596
client_id=self.client_id,

falcon_toolkit/containment/cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def cli_containment(
6666
):
6767
"""Manage the containment status of hosts in Falcon."""
6868
instance = get_instance(ctx)
69-
client: Client = instance.auth_backend.authenticate()
69+
client: Client = instance.auth_backend.authenticate(ctx)
7070
ctx.obj["client"] = client
7171

7272
device_ids = None

falcon_toolkit/falcon.py

+14
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,22 @@
8686
"profile (Falcon Tenant) set up, this parameter is not required."
8787
),
8888
)
89+
@click.option(
90+
"--cid",
91+
envvar="FALCON_TOOLKIT_CID",
92+
type=click.STRING,
93+
default=None,
94+
help=(
95+
"Specify the CID to connect to. Note that this only applies to authentication backends "
96+
"(e.g., MSSP) that support multiple CIDs through the same set of API keys."
97+
),
98+
)
8999
def cli(
90100
ctx: click.Context,
91101
config_path: str,
92102
verbose: bool,
93103
profile: str,
104+
cid: str,
94105
):
95106
r"""Falcon Toolkit.
96107
@@ -207,6 +218,9 @@ def cli(
207218
# Pass a profile name down the chain in case one is selected
208219
ctx.obj["profile_name"] = profile
209220

221+
# Store the CID in the context for optional use later
222+
ctx.obj["cid"] = cid
223+
210224

211225
@cli.result_callback()
212226
def cli_process_result( # pylint: disable=unused-argument

falcon_toolkit/hosts/cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def cli_host_search(
5555
):
5656
"""Implement the host_search CLI command."""
5757
instance = get_instance(ctx)
58-
client = instance.auth_backend.authenticate()
58+
client = instance.auth_backend.authenticate(ctx)
5959
filters = parse_cli_filters(filter_kv_strings, client)
6060

6161
# Handle validation of the CSV export path here, before the search executes in host_search_cmd.

falcon_toolkit/maintenance_token/cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def cli_maintenance_token(
7575
):
7676
"""Get system maintenance tokens from Falcon."""
7777
instance = get_instance(ctx)
78-
client: Client = instance.auth_backend.authenticate()
78+
client: Client = instance.auth_backend.authenticate(ctx)
7979
ctx.obj["client"] = client
8080

8181
# Bulk token is a special case we can handle here.

falcon_toolkit/policies/cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def cli_policies(
5757
):
5858
"""Configure the future profiles commands by getting the context in shape."""
5959
instance = get_instance(ctx)
60-
client: Client = instance.auth_backend.authenticate()
60+
client: Client = instance.auth_backend.authenticate(ctx)
6161
ctx.obj["client"] = client
6262

6363
if prevention_policies_option:

falcon_toolkit/shell/cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def cli_shell( # pylint: disable=too-many-arguments,too-many-locals
122122
start the REPL command loop. This passes control over to the shell, via the Cmd2 library.
123123
"""
124124
instance = get_instance(ctx)
125-
client = instance.auth_backend.authenticate()
125+
client = instance.auth_backend.authenticate(ctx)
126126

127127
# Show online hosts only if queueing is false
128128
online_state = None if queueing else OnlineState.ONLINE

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "falcon-toolkit"
3-
version = "3.4.1"
3+
version = "3.4.2"
44
description = "Toolkit to interface with CrowdStrike Falcon via the API"
55
license = "MIT"
66
authors = [

0 commit comments

Comments
 (0)