Skip to content
Snippets Groups Projects
Commit e5271d97 authored by Václav Bartoš's avatar Václav Bartoš
Browse files

load API key from file just before making a request

parent 9e5c2e2d
Branches master
Tags v1.0
No related merge requests found
# Global configuration parameters
# Configuration of SOCTools user management web GUI
# Hostname of the SOCtools server
soctoolsproxy: "{{soctoolsproxy}}"
......@@ -15,31 +15,31 @@ smtp:
password: "{{smtp.password}}"
# Path to the SOCtools CA certificate
ca_cert_file: "../secrets/CA/ca.crt"
ca_cert_file: "{{playbook_dir}}/secrets/CA/ca.crt"
# Path to "easyrsa" executable and working directory
easyrsa_bin: "../roles/ca/files/easyrsa/easyrsa"
easyrsa_ca_dir: "../secrets/CA"
easyrsa_bin: "{{playbook_dir}}/roles/ca/files/easyrsa/easyrsa"
easyrsa_ca_dir: "{{playbook_dir}}/secrets/CA"
# File to store tokens allowing users to download certificates
token_file: "../secrets/cert_access_tokens"
token_file: "{{playbook_dir}}/secrets/cert_access_tokens"
# Credentials of the special user for account management
# Cert and key should be in .pem format, unencrypted
mgmt_user_name: "soctools-user-mgmt"
mgmt_user_cert_path: "../secrets/CA/issued/soctools-user-mgmt.crt"
mgmt_user_key_path: "../secrets/CA/private/soctools-user-mgmt.key"
mgmt_user_cert_path: "{{playbook_dir}}/secrets/CA/issued/soctools-user-mgmt.crt"
mgmt_user_key_path: "{{playbook_dir}}/secrets/CA/private/soctools-user-mgmt.key"
user_mgmt_base_url: "https://{{soctoolsproxy}}:5443"
keycloak_base_url: "https://{{soctoolsproxy}}:12443"
keycloak_users_url: "https://{{soctoolsproxy}}:12443/auth/admin/realms/{{openid_realm}}/users"
keycloak_admin_password: "{{lookup('password', '{{playbook_dir}}/secrets/passwords/keycloak_admin')}}"
keycloak_admin_password_file: "{{playbook_dir}}/secrets/passwords/keycloak_admin"
misp_api_key: "{{lookup('password', '{{playbook_dir}}/secrets/tokens/misp')}}"
misp_api_key_file: "{{playbook_dir}}/secrets/tokens/misp"
thehive_api_key: "{{lookup('password', '{{playbook_dir}}/secrets/tokens/thehive_secret_key')}}"
thehive_api_key_file: "{{playbook_dir}}/secrets/tokens/thehive_secret_key"
thehive_org_name: "{{org_name}}"
cortex_api_key: "{{lookup('password', '{{playbook_dir}}/secrets/tokens/cortex_secret_key')}}"
cortex_api_key_file: "{{playbook_dir}}/secrets/tokens/cortex_secret_key"
cortex_org_name: "{{org_name}}"
......@@ -132,10 +132,14 @@ def cortex_delete_user(login: str) -> None:
# Auxiliary functions
def _send_request(method:str, url:str, data:Optional[dict]=None):
try:
api_key = open(config['cortex_api_key_file'], 'r').read(100).strip() # read max 100 B, the key should never be so long
except IOError as e:
raise IOError(f"Can't load Cortex API key from file: {e}")
return getattr(requests, method)(
url,
headers={
"Authorization": "Bearer " + config['cortex_api_key'],
"Authorization": "Bearer " + api_key,
},
verify=config['ca_cert_file'],
json=data
......
......@@ -27,8 +27,9 @@ try:
# Check presence of all mandatory configuration parameters
for attr in ('soctoolsproxy', 'ca_cert_file', 'easyrsa_bin', 'easyrsa_ca_dir', 'token_file',
'mgmt_user_name', 'mgmt_user_cert_path', 'mgmt_user_key_path', 'user_mgmt_base_url',
'keycloak_base_url', 'keycloak_users_url', 'keycloak_admin_password',
'misp_api_key', 'thehive_api_key', 'thehive_org_name', 'cortex_api_key', 'cortex_org_name',):
'keycloak_base_url', 'keycloak_users_url', 'keycloak_admin_password_file',
'misp_api_key_file', 'thehive_api_key_file', 'thehive_org_name',
'cortex_api_key_file', 'cortex_org_name',):
if attr not in config or not config[attr]:
errors.append(f'Missing mandatory parameter "{attr}".')
config[attr] = None # to avoid attr-access errors in some imported modules
......@@ -41,7 +42,7 @@ try:
if not isinstance(config.get('smtp'), dict):
smtp_errors.append('Parameter "smtp" is missing or it is not a dict.')
else:
if not re.match('[a-zA-Z0-9.:-]+', config['smtp'].get('host')):
if not config['smtp'].get('host') or not re.match('[a-zA-Z0-9.:-]+', config['smtp'].get('host')):
smtp_errors.append('Parameter "smtp.host" is missing or it is not a valid hostname or IP address.')
if not config['smtp'].get('sender'):
smtp_errors.append('Parameter "smtp.sender" is missing.')
......@@ -61,10 +62,10 @@ if invalid_configuration_error:
print("ERROR: " + invalid_configuration_error)
else:
print(f"Config loaded:\nsoctoolsproxy={config['soctoolsproxy']}\nkeycloak_base_url={config['keycloak_base_url']}\n"
f"keycloak_admin_password={config['keycloak_admin_password'][:3]}...{config['keycloak_admin_password'][-4:]}\n"
f"misp_api_key={config['misp_api_key'][:3]}...{config['misp_api_key'][-4:]}\n"
f"thehive_api_key={config['thehive_api_key'][:3]}...{config['thehive_api_key'][-4:]}\n"
f"cortex_api_key={config['cortex_api_key'][:3]}...{config['cortex_api_key'][-4:]}\n"
f"keycloak_admin_password_file={config['keycloak_admin_password_file']}\n"
f"misp_api_key_file={config['misp_api_key_file']}\n"
f"thehive_api_key_file={config['thehive_api_key_file']}\n"
f"cortex_api_key_file={config['cortex_api_key_file']}\n"
f"thehive_org_name={config['thehive_org_name']}\n")
......@@ -157,11 +158,16 @@ def kc_get_token() -> str:
Return the token or raise KeycloakError
"""
try:
passwd = open(config['keycloak_admin_password_file'], 'r').read(100).strip() # read max 100 B, the key should never be so long
except IOError as e:
raise IOError(f"Can't load Keycloak admin password from file: {e}")
url = config['keycloak_base_url'] + "/auth/realms/master/protocol/openid-connect/token"
data = {
"client_id": "admin-cli",
"username": "admin",
"password": config['keycloak_admin_password'],
"password": passwd,
"grant_type": "password"
}
try:
......@@ -303,14 +309,14 @@ class AddUserForm(FlaskForm):
@app.route("/")
def main():
# In case of invalid SMTP configuration, show warning message
if invalid_smtp is not None and request.endpoint != "export_certificate":
if invalid_smtp is not None:
flash(invalid_smtp + f" To fix it, edit the configuration file ('{os.path.abspath('config.yml')}') and restart"
" the user-mgmt-ui service ('systemctl restart user-mgmt-ui').", "warning")
# Load existing users from Keycloak
try:
users = kc_get_users()
except KeycloakError as e:
except (KeycloakError, IOError) as e:
flash(f"ERROR: {e}", "error")
users = []
# Mark "internal" users
......@@ -337,7 +343,7 @@ def main():
# Load MISP users
try:
misp_users = misp_get_users()
except MISPError as e:
except (MISPError, IOError) as e:
flash(f"ERROR: {e}", "error")
misp_users = []
# Mark "internal" users
......@@ -351,7 +357,7 @@ def main():
# Load The Hive users
try:
thehive_users = thehive_get_users()
except TheHiveError as e:
except (TheHiveError, IOError) as e:
flash(f"ERROR: {e}", "error")
thehive_users = []
# Mark "internal" users
......@@ -365,7 +371,7 @@ def main():
# Load Cortex users
try:
cortex_users = cortex_get_users()
except CortexError as e:
except (CortexError, IOError) as e:
flash(f"ERROR: {e}", "error")
cortex_users = []
# List of usernames only (for easier cross-check with Keycloak users)
......@@ -458,7 +464,7 @@ def edit_user(username: str):
"""Edit existing user. On GET show user details, on POST update user params with new values."""
try:
user = kc_get_user_by_name(username)
except KeycloakError as e:
except (KeycloakError, IOError) as e:
flash(f'ERROR: {e}', "error")
return redirect_to_main_page()
keycloak_id = user.kcid
......@@ -478,7 +484,7 @@ def edit_user(username: str):
try:
kc_update_user(new_user)
flash(f'User "{new_user.username}" successfully updated in Keycloak.', "success")
except KeycloakError as e:
except (KeycloakError, IOError) as e:
flash(f'Error when updating user in Keycloak: {e}', "error")
# NiFi
......@@ -543,7 +549,7 @@ def delete_user(username: str):
"""Delete user given by username and redirect back to main page"""
try:
user_spec = kc_get_user_by_name(username)
except KeycloakError as e:
except (KeycloakError, IOError) as e:
flash(f"Error: Can't get user info from KeyCloak: {e}", "error")
return redirect_to_main_page()
......@@ -557,7 +563,7 @@ def delete_user(username: str):
try:
kc_delete_user(user_spec.kcid)
flash(f'User "{user_spec.username}" successfully deleted from KeyCloak.', "success")
except KeycloakError as e:
except (KeycloakError, IOError) as e:
flash(f'Error when deleting user from KeyCloak: {e}', "error")
# NiFi
......@@ -575,7 +581,7 @@ def delete_user(username: str):
flash(f'User "{user_spec.email}" successfully deleted from MISP.', "success")
except MISPUserNotFoundError:
flash(f'User "{user_spec.email}" was not found in MISP, nothing has changed.', "warning")
except MISPError as e:
except (MISPError, IOError) as e:
flash(f'Error when deleting user from MISP: {e}', "error")
# The Hive
......@@ -584,7 +590,7 @@ def delete_user(username: str):
flash(f'User "{user_spec.email}" successfully deleted from The Hive.', "success")
except TheHiveUserNotFoundError:
flash(f'Error when deleting user from The Hive: User with email "{user_spec.email}" not found', "error")
except TheHiveError as e:
except (TheHiveError, IOError) as e:
flash(f'Error when deleting user from The Hive: {e}', "error")
# Cortex
......@@ -593,7 +599,7 @@ def delete_user(username: str):
flash(f'User "{user_spec.email}" marked as "locked" in Cortex.', "success")
except CortexUserNotFoundError:
flash(f'Error when trying to mark user as "locked" in Cortex: User with email "{user_spec.email}" not found', "error")
except TheHiveError as e:
except (TheHiveError, IOError) as e:
flash(f'Error when trying to mark user as "locked" in Cortex: {e}', "error")
return redirect_to_main_page()
......
......@@ -131,10 +131,14 @@ def misp_delete_user(user_email: str) -> None:
# Auxiliary functions
def _send_request(method:str, url:str, data:Optional[dict]=None):
try:
api_key = open(config['misp_api_key_file'], 'r').read(100).strip() # read max 100 B, the key should never be so long
except IOError as e:
raise IOError(f"Can't load MISP API key from file: {e}")
return getattr(requests, method)(
url,
headers={
"Authorization": config['misp_api_key'],
"Authorization": api_key,
"Accept": "application/json",
},
verify=config['ca_cert_file'],
......
......@@ -135,10 +135,14 @@ def thehive_delete_user(login: str) -> None:
# Auxiliary functions
def _send_request(method:str, url:str, data:Optional[dict]=None):
try:
api_key = open(config['thehive_api_key_file'], 'r').read(100).strip() # read max 100 B, the key should never be so long
except IOError as e:
raise IOError(f"Can't load The Hive API key from file: {e}")
return getattr(requests, method)(
url,
headers={
"Authorization": "Bearer " + config['thehive_api_key'],
"Authorization": "Bearer " + api_key,
},
verify=config['ca_cert_file'],
json=data
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment