Skip to content

Commit 6556eed

Browse files
ui,prefs: allow to configure node's TLS settings
1 parent ce7c3f8 commit 6556eed

File tree

3 files changed

+623
-340
lines changed

3 files changed

+623
-340
lines changed

ui/opensnitch/auth/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
TLSSimple = "tls-simple"
66
TLSMutual = "tls-mutual"
77

8+
NO_CLIENT_CERT = "no-client-cert"
9+
REQ_CERT = "req-cert"
10+
REQ_ANY_CERT = "req-any-cert"
11+
VERIFY_CERT = "verify-cert"
12+
REQ_AND_VERIFY_CERT = "req-and-verify-cert"
13+
814

915
def load_file(file_path):
1016
try:

ui/opensnitch/dialogs/preferences.py

Lines changed: 201 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,30 @@ class PreferencesDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
2929
TAB_NODES = 3
3030
TAB_DB = 4
3131

32+
NODE_PAGE_GENERAL = 0
33+
NODE_PAGE_LOGGING = 1
34+
NODE_PAGE_AUTH = 2
35+
3236
SUM = 1
3337
REST = 0
3438

3539
AUTH_SIMPLE = 0
3640
AUTH_TLS_SIMPLE = 1
3741
AUTH_TLS_MUTUAL = 2
3842

43+
NODE_AUTH = {
44+
AUTH_SIMPLE: auth.Simple,
45+
AUTH_TLS_SIMPLE: auth.TLSSimple,
46+
AUTH_TLS_MUTUAL: auth.TLSMutual
47+
}
48+
NODE_AUTH_VERIFY = {
49+
0: auth.NO_CLIENT_CERT,
50+
1: auth.REQ_CERT,
51+
2: auth.REQ_ANY_CERT,
52+
3: auth.VERIFY_CERT,
53+
4: auth.REQ_AND_VERIFY_CERT
54+
}
55+
3956
def __init__(self, parent=None, appicon=None):
4057
QtWidgets.QDialog.__init__(self, parent, QtCore.Qt.WindowStaysOnTopHint)
4158

@@ -82,6 +99,14 @@ def __init__(self, parent=None, appicon=None):
8299
self.comboAuthType.setItemData(PreferencesDialog.AUTH_SIMPLE, auth.Simple)
83100
self.comboAuthType.setItemData(PreferencesDialog.AUTH_TLS_SIMPLE, auth.TLSSimple)
84101
self.comboAuthType.setItemData(PreferencesDialog.AUTH_TLS_MUTUAL, auth.TLSMutual)
102+
self.comboNodeAuthType.setItemData(PreferencesDialog.AUTH_SIMPLE, auth.Simple)
103+
self.comboNodeAuthType.setItemData(PreferencesDialog.AUTH_TLS_SIMPLE, auth.TLSSimple)
104+
self.comboNodeAuthType.setItemData(PreferencesDialog.AUTH_TLS_MUTUAL, auth.TLSMutual)
105+
self.comboNodeAuthVerifyType.setItemData(0, auth.NO_CLIENT_CERT)
106+
self.comboNodeAuthVerifyType.setItemData(1, auth.REQ_CERT)
107+
self.comboNodeAuthVerifyType.setItemData(2, auth.REQ_ANY_CERT)
108+
self.comboNodeAuthVerifyType.setItemData(3, auth.VERIFY_CERT)
109+
self.comboNodeAuthVerifyType.setItemData(4, auth.REQ_AND_VERIFY_CERT)
85110

86111
self.comboUIRules.currentIndexChanged.connect(self._cb_combo_uirules_changed)
87112

@@ -162,11 +187,22 @@ def showEvent(self, event):
162187
self.comboNodeAddress.currentTextChanged.connect(self._cb_node_needs_update)
163188
self.checkInterceptUnknown.clicked.connect(self._cb_node_needs_update)
164189
self.checkApplyToNodes.clicked.connect(self._cb_node_needs_update)
165-
self.comboDBType.currentIndexChanged.connect(self._cb_db_type_changed)
166-
self.checkDBMaxDays.toggled.connect(self._cb_db_max_days_toggled)
190+
self.comboNodeAction.currentIndexChanged.connect(self._cb_node_needs_update)
191+
self.checkNodeAuthSkipVerify.clicked.connect(self._cb_node_needs_update)
192+
self.comboNodeAuthVerifyType.currentIndexChanged.connect(self._cb_node_needs_update)
193+
194+
self.comboAuthType.currentIndexChanged.connect(self._cb_combo_auth_type_changed)
195+
self.comboNodeAuthType.currentIndexChanged.connect(self._cb_combo_node_auth_type_changed)
196+
167197
self.lineCACertFile.textChanged.connect(self._cb_line_certs_changed)
168198
self.lineCertFile.textChanged.connect(self._cb_line_certs_changed)
169199
self.lineCertKeyFile.textChanged.connect(self._cb_line_certs_changed)
200+
self.lineNodeCACertFile.textChanged.connect(self._cb_node_line_certs_changed)
201+
self.lineNodeCertFile.textChanged.connect(self._cb_node_line_certs_changed)
202+
self.lineNodeCertKeyFile.textChanged.connect(self._cb_node_line_certs_changed)
203+
204+
self.comboDBType.currentIndexChanged.connect(self._cb_db_type_changed)
205+
self.checkDBMaxDays.toggled.connect(self._cb_db_max_days_toggled)
170206

171207
# True when any node option changes
172208
self._node_needs_update = False
@@ -298,38 +334,42 @@ def _load_settings(self):
298334

299335
def _load_node_settings(self):
300336
addr = self.comboNodes.currentText()
301-
if addr != "":
302-
try:
303-
node_data = self._node_list[addr]['data']
304-
self.labelNodeVersion.setText(node_data.version)
305-
self.labelNodeName.setText(node_data.name)
306-
self.comboNodeLogLevel.setCurrentIndex(node_data.logLevel)
307-
308-
node_config = json.loads(node_data.config)
309-
self.comboNodeAction.setCurrentText(node_config['DefaultAction'])
310-
self.comboNodeDuration.setCurrentText(node_config['DefaultDuration'])
311-
self.comboNodeMonitorMethod.setCurrentText(node_config['ProcMonitorMethod'])
312-
self.checkInterceptUnknown.setChecked(node_config['InterceptUnknown'])
313-
self.comboNodeLogLevel.setCurrentIndex(int(node_config['LogLevel']))
314-
315-
if node_config.get('LogUTC') == None:
316-
node_config['LogUTC'] = False
317-
self.checkNodeLogUTC.setChecked(node_config['LogUTC'])
318-
if node_config.get('LogMicro') == None:
319-
node_config['LogMicro'] = False
320-
self.checkNodeLogMicro.setChecked(node_config['LogMicro'])
321-
322-
if node_config.get('Server') != None:
323-
self.comboNodeAddress.setEnabled(True)
324-
self.comboNodeLogFile.setEnabled(True)
325-
326-
self.comboNodeAddress.setCurrentText(node_config['Server']['Address'])
327-
self.comboNodeLogFile.setCurrentText(node_config['Server']['LogFile'])
328-
else:
329-
self.comboNodeAddress.setEnabled(False)
330-
self.comboNodeLogFile.setEnabled(False)
331-
except Exception as e:
332-
print(self.LOG_TAG + "exception loading config: ", e)
337+
if addr == "":
338+
return
339+
340+
try:
341+
node_data = self._node_list[addr]['data']
342+
self.labelNodeVersion.setText(node_data.version)
343+
self.labelNodeName.setText(node_data.name)
344+
self.comboNodeLogLevel.setCurrentIndex(node_data.logLevel)
345+
346+
node_config = json.loads(node_data.config)
347+
self.comboNodeAction.setCurrentText(node_config['DefaultAction'])
348+
self.comboNodeDuration.setCurrentText(node_config['DefaultDuration'])
349+
self.comboNodeMonitorMethod.setCurrentText(node_config['ProcMonitorMethod'])
350+
self.checkInterceptUnknown.setChecked(node_config['InterceptUnknown'])
351+
self.comboNodeLogLevel.setCurrentIndex(int(node_config['LogLevel']))
352+
353+
if node_config.get('LogUTC') == None:
354+
node_config['LogUTC'] = False
355+
self.checkNodeLogUTC.setChecked(node_config['LogUTC'])
356+
if node_config.get('LogMicro') == None:
357+
node_config['LogMicro'] = False
358+
self.checkNodeLogMicro.setChecked(node_config['LogMicro'])
359+
360+
if node_config.get('Server') != None:
361+
self.comboNodeAddress.setEnabled(True)
362+
self.comboNodeLogFile.setEnabled(True)
363+
364+
self.comboNodeAddress.setCurrentText(node_config['Server']['Address'])
365+
self.comboNodeLogFile.setCurrentText(node_config['Server']['LogFile'])
366+
367+
self._load_node_auth_settings(node_config['Server'])
368+
else:
369+
self.comboNodeAddress.setEnabled(False)
370+
self.comboNodeLogFile.setEnabled(False)
371+
except Exception as e:
372+
print(self.LOG_TAG + "exception loading config: ", e)
333373

334374
def _load_node_config(self, addr):
335375
try:
@@ -359,6 +399,10 @@ def _load_node_config(self, addr):
359399
# skip setting Server Address if we're applying the config to all nodes
360400
node_config['Server']['Address'] = self.comboNodeAddress.currentText()
361401
node_config['Server']['LogFile'] = self.comboNodeLogFile.currentText()
402+
403+
cfg = self._load_node_auth_config(node_config['Server'])
404+
if cfg != None:
405+
node_config['Server'] = cfg
362406
else:
363407
print(addr, " doesn't have Server item")
364408
return json.dumps(node_config, indent=" "), None
@@ -367,6 +411,52 @@ def _load_node_config(self, addr):
367411

368412
return None, QC.translate("preferences", "Error loading {0} configuration").format(addr)
369413

414+
def _load_node_auth_settings(self, config):
415+
try:
416+
if config.get('Authentication') == None:
417+
self.toolBox.setItemEnabled(self.NODE_PAGE_AUTH, False)
418+
return
419+
authtype_idx = self.comboNodeAuthType.findData(config['Authentication']['Type'])
420+
self.lineNodeCACertFile.setEnabled(authtype_idx >= 0)
421+
self.lineNodeServerCertFile.setEnabled(authtype_idx >= 0)
422+
self.lineNodeCertFile.setEnabled(authtype_idx >= 0)
423+
self.lineNodeCertKeyFile.setEnabled(authtype_idx >= 0)
424+
if authtype_idx >= 0:
425+
self.lineNodeCACertFile.setText(config['Authentication']['TLSOptions']['CACert'])
426+
self.lineNodeServerCertFile.setText(config['Authentication']['TLSOptions']['ServerCert'])
427+
self.lineNodeCertFile.setText(config['Authentication']['TLSOptions']['ClientCert'])
428+
self.lineNodeCertKeyFile.setText(config['Authentication']['TLSOptions']['ClientKey'])
429+
self.checkNodeAuthSkipVerify.setChecked(config['Authentication']['TLSOptions']['SkipVerify'])
430+
431+
clienttype_idx = self.comboNodeAuthVerifyType.findData(config['Authentication']['TLSOptions']['ClientAuthType'])
432+
if clienttype_idx >= 0:
433+
self.comboNodeAuthVerifyType.setCurrentIndex(clienttype_idx)
434+
else:
435+
authtype_idx = 0
436+
self.comboNodeAuthType.setCurrentIndex(authtype_idx)
437+
except Exception as e:
438+
print("[prefs] node auth options exception:", e)
439+
self._set_status_error(str(e))
440+
441+
def _load_node_auth_config(self, config):
442+
try:
443+
if config.get('Authentication') == None:
444+
self.toolBox.setItemEnabled(self.NODE_PAGE_AUTH, False)
445+
return
446+
config['Authentication']['Type'] = self.NODE_AUTH[self.comboNodeAuthType.currentIndex()]
447+
config['Authentication']['TLSOptions']['CACert']= self.lineNodeCACertFile.text()
448+
config['Authentication']['TLSOptions']['ServerCert'] = self.lineNodeServerCertFile.text()
449+
config['Authentication']['TLSOptions']['ClientCert'] = self.lineNodeCertFile.text()
450+
config['Authentication']['TLSOptions']['ClientKey'] = self.lineNodeCertKeyFile.text()
451+
config['Authentication']['TLSOptions']['SkipVerify'] = self.checkNodeAuthSkipVerify.isChecked()
452+
config['Authentication']['TLSOptions']['ClientAuthType'] = self.NODE_AUTH_VERIFY[self.comboNodeAuthVerifyType.currentIndex()]
453+
454+
return config
455+
except Exception as e:
456+
print("[prefs] node auth options exception:", e)
457+
self._set_status_error(str(e))
458+
return None
459+
370460
def _load_ui_columns_config(self):
371461
cols = self._cfg.getSettings(Config.STATS_SHOW_COLUMNS)
372462
if cols == None:
@@ -405,39 +495,11 @@ def _reset_node_settings(self):
405495

406496
def _save_settings(self):
407497
self._reset_status_message()
498+
self._show_status_label()
408499
self._save_ui_config()
409500
if not self._save_db_config():
410501
return
411-
412-
if self.tabWidget.currentIndex() == self.TAB_NODES:
413-
self._show_status_label()
414-
415-
addr = self.comboNodes.currentText()
416-
if (self._node_needs_update or self.checkApplyToNodes.isChecked()) and addr != "":
417-
try:
418-
notif = ui_pb2.Notification(
419-
id=int(str(time.time()).replace(".", "")),
420-
type=ui_pb2.CHANGE_CONFIG,
421-
data="",
422-
rules=[])
423-
if self.checkApplyToNodes.isChecked():
424-
for addr in self._nodes.get_nodes():
425-
error = self._save_node_config(notif, addr)
426-
if error != None:
427-
self._set_status_error(error)
428-
return
429-
else:
430-
error = self._save_node_config(notif, addr)
431-
if error != None:
432-
self._set_status_error(error)
433-
return
434-
except Exception as e:
435-
print(self.LOG_TAG + "exception saving config: ", e)
436-
self._set_status_error(QC.translate("preferences", "Exception saving config: {0}").format(str(e)))
437-
elif addr == "":
438-
self._set_status_message(QC.translate("preferences", "There're no nodes connected"))
439-
440-
self._node_needs_update = False
502+
self._save_nodes_config()
441503

442504
self.saved.emit()
443505
self._settingsSaved = True
@@ -564,6 +626,34 @@ def _save_ui_columns_config(self):
564626

565627
self._cfg.setSettings(Config.STATS_SHOW_COLUMNS, cols)
566628

629+
def _save_nodes_config(self):
630+
addr = self.comboNodes.currentText()
631+
if (self._node_needs_update or self.checkApplyToNodes.isChecked()) and addr != "":
632+
try:
633+
notif = ui_pb2.Notification(
634+
id=int(str(time.time()).replace(".", "")),
635+
type=ui_pb2.CHANGE_CONFIG,
636+
data="",
637+
rules=[])
638+
if self.checkApplyToNodes.isChecked():
639+
for addr in self._nodes.get_nodes():
640+
error = self._save_node_config(notif, addr)
641+
if error != None:
642+
self._set_status_error(error)
643+
return
644+
else:
645+
error = self._save_node_config(notif, addr)
646+
if error != None:
647+
self._set_status_error(error)
648+
return
649+
except Exception as e:
650+
print(self.LOG_TAG + "exception saving config: ", e)
651+
self._set_status_error(QC.translate("preferences", "Exception saving config: {0}").format(str(e)))
652+
elif addr == "":
653+
self._set_status_message(QC.translate("preferences", "There're no nodes connected"))
654+
655+
self._node_needs_update = False
656+
567657
def _save_node_config(self, notifObject, addr):
568658
try:
569659
self._set_status_message(QC.translate("preferences", "Applying configuration on {0} ...").format(addr))
@@ -589,6 +679,34 @@ def _save_node_config(self, notifObject, addr):
589679

590680
return None
591681

682+
def _save_node_auth_config(self, config):
683+
try:
684+
if config.get('Authentication') == None:
685+
self.toolBox.setItemEnabled(self.NODE_PAGE_AUTH, False)
686+
return
687+
authtype_idx = self.comboNodeAuthType.findData(config['Authentication']['Type'])
688+
self.lineNodeCACertFile.setEnabled(authtype_idx >= 0)
689+
self.lineNodeServerCertFile.setEnabled(authtype_idx >= 0)
690+
self.lineNodeCertFile.setEnabled(authtype_idx >= 0)
691+
self.lineNodeCertKeyFile.setEnabled(authtype_idx >= 0)
692+
if authtype_idx >= 0:
693+
self.lineNodeCACertFile.setText(config['Authentication']['TLSOptions']['CACert'])
694+
self.lineNodeServerCertFile.setText(config['Authentication']['TLSOptions']['ServerCert'])
695+
self.lineNodeCertFile.setText(config['Authentication']['TLSOptions']['ClientCert'])
696+
self.lineNodeCertKeyFile.setText(config['Authentication']['TLSOptions']['ClientKey'])
697+
self.checkNodeAuthSkipVerify.setChecked(config['Authentication']['TLSOptions']['SkipVerify'])
698+
699+
clienttype_idx = self.comboNodeAuthVerifyType.findData(config['Authentication']['TLSOptions']['ClientAuthType'])
700+
if clienttype_idx >= 0:
701+
self.comboNodeAuthVerifyType.setCurrentIndex(clienttype_idx)
702+
else:
703+
authtype_idx = 0
704+
self.comboNodeAuthType.setCurrentIndex(authtype_idx)
705+
except Exception as e:
706+
print("[prefs] node auth options exception:", e)
707+
self._set_status_error(str(e))
708+
709+
592710
def _validate_certs(self):
593711
try:
594712
if self.comboAuthType.currentIndex() == PreferencesDialog.AUTH_SIMPLE:
@@ -677,6 +795,10 @@ def _cb_notification_callback(self, reply):
677795
def _cb_line_certs_changed(self, text):
678796
self._changes_needs_restart = QC.translate("preferences", "Certs changed")
679797

798+
def _cb_node_line_certs_changed(self, text):
799+
self._changes_needs_restart = QC.translate("preferences", "Node certs changed")
800+
self._node_needs_update = True
801+
680802
def _cb_file_db_clicked(self):
681803
options = QtWidgets.QFileDialog.Options()
682804
fileName, _ = QtWidgets.QFileDialog.getSaveFileName(self, "", "","All Files (*)", options=options)
@@ -744,6 +866,21 @@ def _cb_combo_auth_type_changed(self, index):
744866
self.lineCertFile.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
745867
self.lineCertKeyFile.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
746868

869+
def _cb_combo_node_auth_type_changed(self, index):
870+
curtype = self.comboNodeAuthType.itemData(self.comboNodeAuthType.currentIndex())
871+
#savedtype = self._cfg.getSettings(Config.AUTH_TYPE)
872+
#if curtype != savedtype:
873+
# self._changes_needs_restart = QC.translate("preferences", "Auth type changed")
874+
875+
self.lineNodeCACertFile.setEnabled(index == PreferencesDialog.AUTH_TLS_MUTUAL)
876+
self.lineNodeServerCertFile.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
877+
self.lineNodeCertFile.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
878+
self.lineNodeCertKeyFile.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
879+
self.checkNodeAuthSkipVerify.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
880+
self.comboNodeAuthVerifyType.setEnabled(index >= PreferencesDialog.AUTH_TLS_SIMPLE)
881+
882+
self._node_needs_update = True
883+
747884
def _cb_db_max_days_toggled(self, state):
748885
self._enable_db_cleaner_options(state, 1)
749886

0 commit comments

Comments
 (0)