besapi 3.8.3__tar.gz → 3.9.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {besapi-3.8.3/src/besapi.egg-info → besapi-3.9.4}/PKG-INFO +1 -1
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/besapi.py +17 -1
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/plugin_utilities.py +74 -12
- besapi-3.9.4/src/besapi/plugin_utilities_win.py +216 -0
- {besapi-3.8.3 → besapi-3.9.4/src/besapi.egg-info}/PKG-INFO +1 -1
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi.egg-info/SOURCES.txt +1 -0
- {besapi-3.8.3 → besapi-3.9.4}/tests/test_besapi.py +134 -10
- {besapi-3.8.3 → besapi-3.9.4}/LICENSE.txt +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/MANIFEST.in +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/README.md +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/pyproject.toml +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/setup.cfg +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/setup.py +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/__init__.py +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/__main__.py +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/schemas/BES.xsd +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/schemas/BESAPI.xsd +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi/schemas/BESActionSettings.xsd +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi.egg-info/dependency_links.txt +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi.egg-info/requires.txt +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/besapi.egg-info/top_level.txt +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/bescli/__init__.py +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/bescli/__main__.py +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/src/bescli/bescli.py +0 -0
- {besapi-3.8.3 → besapi-3.9.4}/tests/tests.py +0 -0
|
@@ -25,7 +25,7 @@ import lxml.etree
|
|
|
25
25
|
import lxml.objectify
|
|
26
26
|
import requests
|
|
27
27
|
|
|
28
|
-
__version__ = "3.
|
|
28
|
+
__version__ = "3.9.4"
|
|
29
29
|
|
|
30
30
|
besapi_logger = logging.getLogger("besapi")
|
|
31
31
|
|
|
@@ -283,6 +283,20 @@ def validate_xml_bes_file(file_path):
|
|
|
283
283
|
return validate_xsd(file_data)
|
|
284
284
|
|
|
285
285
|
|
|
286
|
+
def get_bes_conn_using_env():
|
|
287
|
+
"""Get BESConnection using environment variables."""
|
|
288
|
+
username = os.getenv("BES_USER_NAME")
|
|
289
|
+
password = os.getenv("BES_PASSWORD")
|
|
290
|
+
rootserver = os.getenv("BES_ROOT_SERVER")
|
|
291
|
+
|
|
292
|
+
if username and password and rootserver:
|
|
293
|
+
bes_conn = BESConnection(username, password, rootserver)
|
|
294
|
+
if bes_conn:
|
|
295
|
+
return bes_conn
|
|
296
|
+
|
|
297
|
+
return None
|
|
298
|
+
|
|
299
|
+
|
|
286
300
|
def get_bes_conn_using_config_file(conf_file=None):
|
|
287
301
|
"""
|
|
288
302
|
Read connection values from config file.
|
|
@@ -479,6 +493,8 @@ class BESConnection:
|
|
|
479
493
|
|
|
480
494
|
This will submit the relevance string as json instead of html form data.
|
|
481
495
|
"""
|
|
496
|
+
# not sure if the following is needed to handle some cases:
|
|
497
|
+
# relevance = "(it as string) of ( " + relevance + " )"
|
|
482
498
|
rel_result_array = self.session_relevance_json_array(relevance, **kwargs)
|
|
483
499
|
# Ensure each element is converted to a string
|
|
484
500
|
return "\n".join(map(str, rel_result_array))
|
|
@@ -10,6 +10,7 @@ import logging.handlers
|
|
|
10
10
|
import ntpath
|
|
11
11
|
import os
|
|
12
12
|
import sys
|
|
13
|
+
from typing import Union
|
|
13
14
|
|
|
14
15
|
import besapi
|
|
15
16
|
|
|
@@ -131,12 +132,35 @@ def get_plugin_logging_config(log_file_path="", verbose=0, console=True):
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
|
|
134
|
-
def
|
|
135
|
-
"""Get connection to besapi using
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
def get_besapi_connection_env_then_config():
|
|
136
|
+
"""Get connection to besapi using env vars first, then config file."""
|
|
137
|
+
logging.info("attempting connection to BigFix using ENV method.")
|
|
138
|
+
# try to get connection from env vars:
|
|
139
|
+
bes_conn = besapi.besapi.get_bes_conn_using_env()
|
|
140
|
+
if bes_conn:
|
|
141
|
+
return bes_conn
|
|
142
|
+
|
|
143
|
+
logging.info("attempting connection to BigFix using config file method.")
|
|
144
|
+
bes_conn = besapi.besapi.get_bes_conn_using_config_file()
|
|
145
|
+
return bes_conn
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def get_besapi_connection_args(
|
|
149
|
+
args: argparse.Namespace,
|
|
150
|
+
) -> Union[besapi.besapi.BESConnection, None]:
|
|
151
|
+
"""Get connection to besapi using provided args."""
|
|
152
|
+
password = None
|
|
153
|
+
bes_conn = None
|
|
154
|
+
|
|
155
|
+
if args.password:
|
|
156
|
+
password = args.password
|
|
138
157
|
|
|
139
|
-
password
|
|
158
|
+
# if user was provided as arg but password was not:
|
|
159
|
+
if args.user and not password:
|
|
160
|
+
if os.name == "nt":
|
|
161
|
+
# attempt to get password from windows root server registry:
|
|
162
|
+
# this is specifically for the case where user is provided for a plugin
|
|
163
|
+
password = besapi.plugin_utilities_win.get_win_registry_rest_pass()
|
|
140
164
|
|
|
141
165
|
# if user was provided as arg but password was not:
|
|
142
166
|
if args.user and not password:
|
|
@@ -144,7 +168,7 @@ def get_besapi_connection(args):
|
|
|
144
168
|
print("Password was not provided, provide REST API password:")
|
|
145
169
|
password = getpass.getpass()
|
|
146
170
|
|
|
147
|
-
if
|
|
171
|
+
if password:
|
|
148
172
|
logging.debug("REST API Password Length: %s", len(password))
|
|
149
173
|
|
|
150
174
|
# process args, setup connection:
|
|
@@ -158,13 +182,13 @@ def get_besapi_connection(args):
|
|
|
158
182
|
if args.user and password:
|
|
159
183
|
try:
|
|
160
184
|
if not rest_url:
|
|
161
|
-
raise AttributeError
|
|
185
|
+
raise AttributeError("args.rest_url is not set.")
|
|
162
186
|
bes_conn = besapi.besapi.BESConnection(args.user, password, rest_url)
|
|
163
187
|
except (
|
|
164
188
|
AttributeError,
|
|
165
189
|
ConnectionRefusedError,
|
|
166
190
|
besapi.besapi.requests.exceptions.ConnectionError,
|
|
167
|
-
):
|
|
191
|
+
) as e:
|
|
168
192
|
logging.exception(
|
|
169
193
|
"connection to `%s` failed, attempting `%s` instead",
|
|
170
194
|
rest_url,
|
|
@@ -172,7 +196,7 @@ def get_besapi_connection(args):
|
|
|
172
196
|
)
|
|
173
197
|
try:
|
|
174
198
|
if not args.besserver:
|
|
175
|
-
raise AttributeError
|
|
199
|
+
raise AttributeError("args.besserver is not set.") from e
|
|
176
200
|
bes_conn = besapi.besapi.BESConnection(
|
|
177
201
|
args.user, password, args.besserver
|
|
178
202
|
)
|
|
@@ -185,7 +209,7 @@ def get_besapi_connection(args):
|
|
|
185
209
|
)
|
|
186
210
|
return None
|
|
187
211
|
except BaseException as err:
|
|
188
|
-
# always log error
|
|
212
|
+
# always log error
|
|
189
213
|
logging.exception("ERROR: %s", err)
|
|
190
214
|
logging.exception(
|
|
191
215
|
"----- ERROR: BigFix Connection Failed! Unknown reason ------"
|
|
@@ -193,8 +217,46 @@ def get_besapi_connection(args):
|
|
|
193
217
|
return None
|
|
194
218
|
else:
|
|
195
219
|
logging.info(
|
|
196
|
-
"
|
|
220
|
+
"No user arg provided, no password found. Cannot create connection."
|
|
221
|
+
)
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
return bes_conn
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_besapi_connection(
|
|
228
|
+
args: Union[argparse.Namespace, None] = None,
|
|
229
|
+
) -> Union[besapi.besapi.BESConnection, None]:
|
|
230
|
+
"""Get connection to besapi.
|
|
231
|
+
|
|
232
|
+
If on Windows, will attempt to get connection from Windows Registry first.
|
|
233
|
+
If args provided, will attempt to get connection using provided args.
|
|
234
|
+
If no args provided, will attempt to get connection from env vars.
|
|
235
|
+
If no env vars, will attempt to get connection from config file.
|
|
236
|
+
|
|
237
|
+
Arguments:
|
|
238
|
+
args: argparse.Namespace object, usually from setup_plugin_argparse()
|
|
239
|
+
Returns:
|
|
240
|
+
A BESConnection object if successful, otherwise None.
|
|
241
|
+
"""
|
|
242
|
+
# if windows, try to get connection from windows registry:
|
|
243
|
+
if os.name == "nt":
|
|
244
|
+
bes_conn = besapi.plugin_utilities_win.get_besconn_root_windows_registry()
|
|
245
|
+
if bes_conn:
|
|
246
|
+
return bes_conn
|
|
247
|
+
|
|
248
|
+
# if no args provided, try to get connection from env then config file:
|
|
249
|
+
if not args:
|
|
250
|
+
logging.info("no args provided, attempting connection using env then config.")
|
|
251
|
+
return get_besapi_connection_env_then_config()
|
|
252
|
+
|
|
253
|
+
# attempt bigfix connection with provided args:
|
|
254
|
+
if args.user:
|
|
255
|
+
bes_conn = get_besapi_connection_args(args)
|
|
256
|
+
else:
|
|
257
|
+
logging.info(
|
|
258
|
+
"no user arg provided, attempting connection using env then config."
|
|
197
259
|
)
|
|
198
|
-
|
|
260
|
+
return get_besapi_connection_env_then_config()
|
|
199
261
|
|
|
200
262
|
return bes_conn
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Plugin utilities for Windows systems, including DPAPI encryption/decryption
|
|
3
|
+
and Windows Registry access.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import base64
|
|
7
|
+
import logging
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
11
|
+
import besapi
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import winreg
|
|
17
|
+
except (ImportError, ModuleNotFoundError) as e:
|
|
18
|
+
if not sys.platform.startswith("win"):
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
"This script requires the 'winreg' module, which is only available on Windows."
|
|
21
|
+
) from e
|
|
22
|
+
else:
|
|
23
|
+
raise e
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
import win32crypt
|
|
27
|
+
except (ImportError, ModuleNotFoundError) as e:
|
|
28
|
+
if not sys.platform.startswith("win"):
|
|
29
|
+
raise RuntimeError("This script only works on Windows systems") from e
|
|
30
|
+
raise ImportError(
|
|
31
|
+
"This script requires the pywin32 package. Install it via 'pip install pywin32'."
|
|
32
|
+
) from e
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def win_dpapi_encrypt_str(
|
|
36
|
+
plaintext: str, scope_flags: int = 4, entropy: Union[str, bytes, None] = None
|
|
37
|
+
) -> Union[str, None]:
|
|
38
|
+
"""Encrypt a string using Windows DPAPI and return it as a base64-encoded string.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
plaintext (str): The string to encrypt.
|
|
42
|
+
scope_flags (int): The context scope for encryption (default is 4).
|
|
43
|
+
entropy (bytes | None): Optional entropy for encryption.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: The base64-encoded encrypted string.
|
|
47
|
+
"""
|
|
48
|
+
if not plaintext or plaintext.strip() == "":
|
|
49
|
+
logger.warning("No plaintext provided for encryption.")
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
# 1. Convert the plaintext string to bytes
|
|
53
|
+
plaintext_bytes = plaintext.encode("utf-8")
|
|
54
|
+
|
|
55
|
+
# 2. Call CryptProtectData.
|
|
56
|
+
# The last parameter (flags) is set to 4
|
|
57
|
+
# to indicate that the data should be encrypted in the machine context.
|
|
58
|
+
#
|
|
59
|
+
# The function returns a tuple: (description, encrypted_bytes)
|
|
60
|
+
# We only need the second element.
|
|
61
|
+
encrypted_bytes = win32crypt.CryptProtectData(
|
|
62
|
+
plaintext_bytes,
|
|
63
|
+
None, # Description
|
|
64
|
+
entropy, # Optional entropy
|
|
65
|
+
None, # Reserved
|
|
66
|
+
None, # Prompt Struct
|
|
67
|
+
scope_flags,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# 3. Encode the encrypted bytes to a Base64 string
|
|
71
|
+
encrypted_b64 = base64.b64encode(encrypted_bytes).decode("utf-8")
|
|
72
|
+
|
|
73
|
+
return encrypted_b64
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def win_dpapi_decrypt_base64(
|
|
77
|
+
encrypted_b64: str, scope_flags: int = 4, entropy: Union[str, bytes, None] = None
|
|
78
|
+
) -> Union[str, None]:
|
|
79
|
+
"""Decrypt a base64-encoded string encrypted with Windows DPAPI.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
encrypted_b64 (str): The base64-encoded encrypted string.
|
|
83
|
+
scope_flags (int): The context scope for decryption (default is 4).
|
|
84
|
+
entropy (bytes | None): Optional entropy for decryption.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
str: The decrypted string.
|
|
88
|
+
"""
|
|
89
|
+
if not encrypted_b64 or encrypted_b64.strip() == "":
|
|
90
|
+
logger.warning("No encrypted data provided for decryption.")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
# 1. Decode the Base64 string to get the raw encrypted bytes
|
|
94
|
+
encrypted_bytes = base64.b64decode(encrypted_b64)
|
|
95
|
+
|
|
96
|
+
# 2. Call CryptUnprotectData.
|
|
97
|
+
# The last parameter (flags) is set to 4
|
|
98
|
+
# to indicate that the data was encrypted in the machine context.
|
|
99
|
+
#
|
|
100
|
+
# The function returns a tuple: (description, decrypted_bytes)
|
|
101
|
+
# We only need the second element.
|
|
102
|
+
_, decrypted_bytes = win32crypt.CryptUnprotectData(
|
|
103
|
+
encrypted_bytes,
|
|
104
|
+
entropy, # Optional entropy
|
|
105
|
+
None, # Reserved
|
|
106
|
+
None, # Prompt Struct
|
|
107
|
+
scope_flags,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if decrypted_bytes:
|
|
111
|
+
decrypted_string = decrypted_bytes.decode("utf-8").strip()
|
|
112
|
+
return decrypted_string
|
|
113
|
+
|
|
114
|
+
logger.debug("Decryption returned no data.")
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def win_registry_value_read(hive, subkey, value_name):
|
|
119
|
+
"""
|
|
120
|
+
Reads a value from the Windows Registry.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
hive: The root hive (e.g., winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER).
|
|
124
|
+
subkey: The path to the subkey (e.g., "SOFTWARE\\Microsoft\\Windows\\CurrentVersion").
|
|
125
|
+
value_name: The name of the value to read.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
The value data if found, otherwise None.
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
# Open the specified registry key
|
|
132
|
+
key = winreg.OpenKey(hive, subkey, 0, winreg.KEY_READ)
|
|
133
|
+
|
|
134
|
+
# Query the value data
|
|
135
|
+
value_data, _ = winreg.QueryValueEx(key, value_name)
|
|
136
|
+
|
|
137
|
+
# Close the key
|
|
138
|
+
winreg.CloseKey(key)
|
|
139
|
+
|
|
140
|
+
return value_data
|
|
141
|
+
except FileNotFoundError:
|
|
142
|
+
logger.debug("Registry key or value '%s\\%s' not found.", subkey, value_name)
|
|
143
|
+
return None
|
|
144
|
+
except Exception as e:
|
|
145
|
+
logger.error("An error occurred: %s", e)
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_win_registry_rest_pass() -> Union[str, None]:
|
|
150
|
+
"""
|
|
151
|
+
Retrieves the base64 encrypted REST Password from the Windows Registry.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
The REST Password if found, otherwise None.
|
|
155
|
+
"""
|
|
156
|
+
hive = winreg.HKEY_LOCAL_MACHINE # type: ignore[attr-defined]
|
|
157
|
+
# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig
|
|
158
|
+
subkey = r"SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig"
|
|
159
|
+
value_name = "RESTPassword"
|
|
160
|
+
|
|
161
|
+
reg_value = win_registry_value_read(hive, subkey, value_name)
|
|
162
|
+
|
|
163
|
+
if not reg_value:
|
|
164
|
+
logger.debug("No registry value found for %s.", value_name)
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
# remove {obf} from start of string if present:
|
|
168
|
+
if reg_value and reg_value.startswith("{obf}"):
|
|
169
|
+
reg_value = reg_value[5:]
|
|
170
|
+
|
|
171
|
+
if reg_value and len(reg_value) > 50:
|
|
172
|
+
password = win_dpapi_decrypt_base64(reg_value)
|
|
173
|
+
if password and len(password) > 3:
|
|
174
|
+
return password
|
|
175
|
+
|
|
176
|
+
logger.debug("Decryption failed or decrypted password length is too short.")
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_besconn_root_windows_registry() -> Union[besapi.besapi.BESConnection, None]:
|
|
181
|
+
"""
|
|
182
|
+
Attempts to create a BESConnection using credentials stored in the Windows
|
|
183
|
+
Registry.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
A BESConnection object if successful, otherwise None.
|
|
187
|
+
"""
|
|
188
|
+
password = get_win_registry_rest_pass()
|
|
189
|
+
if not password:
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
hive = winreg.HKEY_LOCAL_MACHINE # type: ignore[attr-defined]
|
|
193
|
+
subkey = r"SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig"
|
|
194
|
+
|
|
195
|
+
user = win_registry_value_read(hive, subkey, "RESTUsername")
|
|
196
|
+
|
|
197
|
+
if not user:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
rest_url = win_registry_value_read(hive, subkey, "RESTURL")
|
|
201
|
+
|
|
202
|
+
if not rest_url:
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
# normalize url to https://HostOrIP:52311
|
|
206
|
+
if rest_url and rest_url.endswith("/api"):
|
|
207
|
+
rest_url = rest_url.replace("/api", "")
|
|
208
|
+
|
|
209
|
+
if user and password and rest_url:
|
|
210
|
+
try:
|
|
211
|
+
return besapi.besapi.BESConnection(user, password, rest_url)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
logger.error("Failed to create BESConnection from registry values: %s", e)
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
return None
|
|
@@ -25,6 +25,9 @@ if not os.getenv("TEST_PIP"):
|
|
|
25
25
|
import besapi
|
|
26
26
|
import besapi.plugin_utilities
|
|
27
27
|
|
|
28
|
+
if os.name == "nt":
|
|
29
|
+
import besapi.plugin_utilities_win
|
|
30
|
+
|
|
28
31
|
|
|
29
32
|
def test_besapi_version():
|
|
30
33
|
"""Test that the besapi version is not None."""
|
|
@@ -228,40 +231,92 @@ def test_bescli():
|
|
|
228
231
|
assert bes_conn.login()
|
|
229
232
|
|
|
230
233
|
|
|
234
|
+
def test_plugin_utilities_win_get_besconn_root_windows_registry():
|
|
235
|
+
"""Test getting a BESConnection from the Windows Registry."""
|
|
236
|
+
if "BES_ROOT_SERVER" not in os.environ:
|
|
237
|
+
pytest.skip("Skipping Windows Registry test, BES_ROOT_SERVER not set.")
|
|
238
|
+
if "BES_USER_NAME" not in os.environ:
|
|
239
|
+
pytest.skip("Skipping Windows Registry test, BES_USER_NAME not set.")
|
|
240
|
+
if "BES_PASSWORD" not in os.environ:
|
|
241
|
+
pytest.skip("Skipping Windows Registry test, BES_PASSWORD not set.")
|
|
242
|
+
|
|
243
|
+
if not os.name == "nt":
|
|
244
|
+
pytest.skip("Skipping Windows Registry test on non-Windows system.")
|
|
245
|
+
|
|
246
|
+
# only run this test if besapi > v3.9.1:
|
|
247
|
+
if besapi.besapi.__version__ <= "3.9.1":
|
|
248
|
+
pytest.skip("Skipping test for besapi <= 3.9.1")
|
|
249
|
+
|
|
250
|
+
# get env vars for testing:
|
|
251
|
+
root_server = os.getenv("BES_ROOT_SERVER")
|
|
252
|
+
root_user = os.getenv("BES_USER_NAME")
|
|
253
|
+
root_user_password = os.getenv("BES_PASSWORD")
|
|
254
|
+
|
|
255
|
+
encrypted_str = besapi.plugin_utilities_win.win_dpapi_encrypt_str(
|
|
256
|
+
root_user_password
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
import winreg
|
|
260
|
+
|
|
261
|
+
# write user and encrypted password to registry for testing:
|
|
262
|
+
# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig
|
|
263
|
+
subkey = r"SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig"
|
|
264
|
+
hive = winreg.HKEY_LOCAL_MACHINE # type: ignore[attr-defined]
|
|
265
|
+
|
|
266
|
+
key = winreg.CreateKey(hive, subkey)
|
|
267
|
+
winreg.SetValueEx(
|
|
268
|
+
key, "RESTURL", 0, winreg.REG_SZ, "https://" + root_server + ":52311/api"
|
|
269
|
+
)
|
|
270
|
+
winreg.SetValueEx(key, "RESTUsername", 0, winreg.REG_SZ, root_user)
|
|
271
|
+
winreg.SetValueEx(key, "RESTPassword", 0, winreg.REG_SZ, "{obf}" + encrypted_str)
|
|
272
|
+
winreg.CloseKey(key)
|
|
273
|
+
bes_conn = besapi.plugin_utilities_win.get_besconn_root_windows_registry()
|
|
274
|
+
assert bes_conn is not None
|
|
275
|
+
|
|
276
|
+
|
|
231
277
|
def test_bes_conn_json():
|
|
232
278
|
"""Test the BESConnection class with JSON output."""
|
|
233
|
-
|
|
279
|
+
|
|
280
|
+
bes_conn = besapi.plugin_utilities.get_besapi_connection(None)
|
|
281
|
+
|
|
234
282
|
if bes_conn and bes_conn.login():
|
|
235
283
|
print("testing session_relevance_json")
|
|
236
|
-
result = bes_conn.session_relevance_json("number of bes
|
|
284
|
+
result = bes_conn.session_relevance_json("number of all bes sites")
|
|
237
285
|
assert result is not None
|
|
238
286
|
assert int(result["result"][0]) > 0
|
|
239
287
|
result = bes_conn.session_relevance_json(
|
|
240
|
-
"""("[%22" & it & "%22]") of concatenation "%22, %22" of names of bes
|
|
288
|
+
"""("[%22" & it & "%22]") of concatenation "%22, %22" of names of all bes sites"""
|
|
241
289
|
)
|
|
242
290
|
assert result is not None
|
|
243
291
|
string_first_result_json = result["result"][0]
|
|
244
292
|
print(string_first_result_json)
|
|
245
293
|
assert '", "' in string_first_result_json
|
|
246
294
|
assert '["' in string_first_result_json
|
|
247
|
-
|
|
248
|
-
if "10.0." in bes_conn.rootserver:
|
|
249
|
-
print("doing check specific to my env")
|
|
250
|
-
assert '", "BIGFIX", "' in string_first_result_json
|
|
295
|
+
assert '"BES Support"' in string_first_result_json
|
|
251
296
|
|
|
252
297
|
print("testing session_relevance_json_array")
|
|
253
|
-
result = bes_conn.session_relevance_json_array("number of bes
|
|
298
|
+
result = bes_conn.session_relevance_json_array("number of all bes sites")
|
|
254
299
|
print(result)
|
|
255
300
|
assert result is not None
|
|
256
301
|
assert int(result[0]) > 0
|
|
257
302
|
print("testing session_relevance_json_string")
|
|
258
|
-
result = bes_conn.session_relevance_json_string("number of bes
|
|
303
|
+
result = bes_conn.session_relevance_json_string("number of all bes sites")
|
|
259
304
|
print(result)
|
|
260
305
|
assert result is not None
|
|
261
306
|
assert int(result) > 0
|
|
307
|
+
print("testing session_relevance_json_string tuple")
|
|
308
|
+
result = bes_conn.session_relevance_json_string(
|
|
309
|
+
'(ids of it, names of it, "TestString") of all bes sites'
|
|
310
|
+
)
|
|
311
|
+
print(result)
|
|
312
|
+
assert result is not None
|
|
313
|
+
assert "TestString" in result
|
|
314
|
+
assert "BES Support" in result
|
|
315
|
+
else:
|
|
316
|
+
pytest.skip("Skipping BESConnection test, no config file or login failed.")
|
|
262
317
|
|
|
263
318
|
|
|
264
|
-
def
|
|
319
|
+
def test_plugin_utilities_logging():
|
|
265
320
|
"""Test the plugin_utilities module."""
|
|
266
321
|
print(besapi.plugin_utilities.get_invoke_folder())
|
|
267
322
|
print(besapi.plugin_utilities.get_invoke_file_name())
|
|
@@ -282,3 +337,72 @@ def test_plugin_utilities():
|
|
|
282
337
|
logging.warning("Just testing to see if logging is working!")
|
|
283
338
|
|
|
284
339
|
assert os.path.isfile("./tests.log")
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def test_plugin_utilities_win_dpapi():
|
|
343
|
+
"""Test the Windows DPAPI encryption function, if on Windows."""
|
|
344
|
+
if not os.name == "nt":
|
|
345
|
+
pytest.skip("Skipping Windows Registry test on non-Windows system.")
|
|
346
|
+
|
|
347
|
+
# only run this test if besapi > v3.8.3:
|
|
348
|
+
if besapi.besapi.__version__ <= "3.8.3":
|
|
349
|
+
pytest.skip("Skipping test for besapi <= 3.8.3")
|
|
350
|
+
|
|
351
|
+
test_string = "This is just a test string " + str(random.randint(0, 9999))
|
|
352
|
+
encrypted_str = besapi.plugin_utilities_win.win_dpapi_encrypt_str(test_string)
|
|
353
|
+
print("Encrypted string:", encrypted_str)
|
|
354
|
+
assert encrypted_str != ""
|
|
355
|
+
assert encrypted_str != test_string
|
|
356
|
+
decrypted_str = besapi.plugin_utilities_win.win_dpapi_decrypt_base64(encrypted_str)
|
|
357
|
+
print("Decrypted string:", decrypted_str)
|
|
358
|
+
assert decrypted_str == test_string
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def test_plugin_utilities_win_win_registry_value_read():
|
|
362
|
+
"""Test reading a Windows registry value."""
|
|
363
|
+
if not os.name == "nt":
|
|
364
|
+
pytest.skip("Skipping Windows Registry test on non-Windows system.")
|
|
365
|
+
|
|
366
|
+
# only run this test if besapi > v3.8.3:
|
|
367
|
+
if besapi.besapi.__version__ <= "3.8.3":
|
|
368
|
+
pytest.skip("Skipping test for besapi <= 3.8.3")
|
|
369
|
+
|
|
370
|
+
import winreg
|
|
371
|
+
|
|
372
|
+
registry_key = r"SOFTWARE\Microsoft\Windows\CurrentVersion"
|
|
373
|
+
registry_value = "ProgramFilesDir"
|
|
374
|
+
result = besapi.plugin_utilities_win.win_registry_value_read(
|
|
375
|
+
winreg.HKEY_LOCAL_MACHINE, registry_key, registry_value
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
assert result is not None
|
|
379
|
+
print("Registry value:", result)
|
|
380
|
+
assert "Program Files" in result
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def test_plugin_utilities_win_get_win_registry_rest_pass():
|
|
384
|
+
"""Test getting the Windows Registry REST password."""
|
|
385
|
+
if not os.name == "nt":
|
|
386
|
+
pytest.skip("Skipping Windows Registry test on non-Windows system.")
|
|
387
|
+
|
|
388
|
+
# only run this test if besapi > v3.8.3:
|
|
389
|
+
if besapi.besapi.__version__ <= "3.8.3":
|
|
390
|
+
pytest.skip("Skipping test for besapi <= 3.8.3")
|
|
391
|
+
|
|
392
|
+
import winreg
|
|
393
|
+
|
|
394
|
+
test_string = "This is just a test string " + str(random.randint(0, 9999))
|
|
395
|
+
encrypted_str = besapi.plugin_utilities_win.win_dpapi_encrypt_str(test_string)
|
|
396
|
+
|
|
397
|
+
# write encrypted string to registry for testing:
|
|
398
|
+
# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig
|
|
399
|
+
subkey = r"SOFTWARE\Wow6432Node\BigFix\Enterprise Server\MFSConfig"
|
|
400
|
+
|
|
401
|
+
key = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, subkey)
|
|
402
|
+
winreg.SetValueEx(key, "RESTPassword", 0, winreg.REG_SZ, "{obf}" + encrypted_str)
|
|
403
|
+
winreg.CloseKey(key)
|
|
404
|
+
|
|
405
|
+
result = besapi.plugin_utilities_win.get_win_registry_rest_pass()
|
|
406
|
+
assert result is not None
|
|
407
|
+
print("Windows Registry REST password:", result)
|
|
408
|
+
assert result == test_string
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|