def _mkMsgArea(self): msg_area = MessageArea() warning_title = tr('Last warning') warning_message = tr("The restoration process will <b>completely " "delete</b> the current configuration of the appliance and " "replace it with the configuration supplied in the next step.") msg_area.setMessage(warning_title, warning_message, status='warning') msg_area.setWidth(65) return msg_area
def __setupgui(self, description): msg = MessageArea() msg.setMessage( tr('About this authentication method'), description, 'info' ) msg.setWidth(65) self.form.addRow(msg)
def _disable(self, title, message, main_message): if self._module_disabled: #already done return self._module_disabled = True msg = MessageArea() msg.setMessage( title, message, "critical" ) msg.setWidth(65) self.setWidget(msg) self.mainwindow.addToInfoArea( main_message ) self.setWidgetResizable(True)
class LdapWidget(DirectoryWidget): def __init__(self, config, specific_config, mainwindow, parent=None): assert config is not None assert specific_config is not None DirectoryWidget.__init__(self, config, specific_config, mainwindow, parent) self.buildInterface(config) self.updateView(self.specific_config) def buildInterface(self, config): #<server uri> self.uri = QLineEdit() self.texts.add(self.uri) self.connect(self.uri, SIGNAL('textChanged(QString)'), self.setUri) self.connect(self.uri, SIGNAL('textChanged(QString)'), self.signalModified) self.connect(self.uri, SIGNAL('textEdited(QString)'), self.helpURI) self.connect(self.uri, SIGNAL('editingFinished()'), self.noHelpURI) self.connect(self.uri, SIGNAL('editingFinished()'), self.updateUri) self.form.addRow(tr('LDAP Server(s) uri'), self.uri) self.uri.setToolTip(help_uri_tooltip) self.connect(self.uri, SIGNAL('returnPressed()'), self.signalModified) self.uri_message_area = MessageArea() self.empty_uri_label = QLabel() self.form.addRow(self.empty_uri_label, self.uri_message_area) self.empty_uri_label.hide() self.uri_message_area.hide() self.uri_message_area.setMessage(help_uri_title, help_uri_message_area) self.numeric_uri_warning = MessageArea() empty = QLabel() self.form.addRow(empty, self.numeric_uri_warning) empty.hide() self.numeric_uri_warning.hide() self.numeric_uri_warning.warning(numeric_warning_title, numeric_warning) self.numeric_uri_warning.setWidth(60) #</server uri> #<other fields> for args in self._genTextFieldsData(): text_input = self.addTextInput(*args[1:]) setattr(self, args[0], text_input) self.connect(text_input, SIGNAL('editingFinished(QString)'), self.valid) #</other fields> self.ssl_box = self.mkSslBox() self.connect(self.ssl_box, SIGNAL('toggled(bool)'), self.toggleSsl) self.form.addRow(self.ssl_box) self.form.addRow(separator()) test_widget = QPushButton(tr("Test this configuration")) self.form.addRow("", test_widget) test_widget.connect(test_widget, SIGNAL('clicked()'), self.test_ldap) def _genTextFieldsData(self): return ( ('dn_users', tr('LDAP DN for users'), self.setDnUsers), ('dn_groups', tr('LDAP DN for groups'), self.setDnGroups), ('user', tr('DN used to log in on the LDAP server'), self.setUser), ('password', tr('Password used to log in on the LDAP server'), self.setPassword, False) ) def test_ldap(self): dc, base, uri, filter, password = self.specific_config.generateTest() if uri is None or uri == '': QMessageBox.critical( self, "Missing data", "Please fill URI field" ) return if dc is None: dc == '' filter, ok = QInputDialog.getText( self, tr("LDAP Filter"), tr("Please enter a filter:"), QLineEdit.Normal, filter ) if not ok: return async = self.mainwindow.client.async() async.call( 'nuauth', 'testLDAP', dc, base, uri, unicode(filter), password, callback = self.success_test, errback = self.error_test ) def success_test(self, result): ans_no = tr("OK") ans_yes = tr("Show the server's answer") show_details = QMessageBox.question( self, tr('LDAP test results'), tr('LDAP test completed without error'), ans_no, ans_yes ) if show_details == 0: return title = tr('LDAP test results') QMessageBox.information( self, title, '<span><h2>%s</h2><pre>%s</pre></span>' % (title, unicode(result)) ) def error_test(self, result): basic_text = tr('LDAP test completed with an error') formatted_text = u"""\ <span> %s <pre> %s </pre> </span> """ % (basic_text, unicode(result)) QMessageBox.warning( self, tr('LDAP test results'), formatted_text ) def helpURI(self, text): self.uri_message_area.show() def noHelpURI(self): self.uri_message_area.hide() def toggleSsl(self, value): if value: self.selectCustomOrNupki(NUPKI) else: self.specific_config.custom_or_nupki = SSL_DISABLED self.signalModified() def setUri(self, uris_text): self.specific_config.setUri(self.readString(uris_text)) self.signalModified() self.numeric_uri_warning.setVisible(ip_in_ldapuri(self.specific_config.uri)) def setUser(self, user): self.specific_config.user = self.readString(user) def setPassword(self, password): self.specific_config.password = self.readString(password) def setDnUsers(self, dn): self.specific_config.dn_users = self.readString(dn) def setDnGroups(self, dn): self.specific_config.dn_groups = self.readString(dn) def mkSslBox(self): group = QGroupBox(tr("Check server certificate")) group.setCheckable(True) box = QVBoxLayout(group) #id 0 nupki = QRadioButton(tr("Upload certificate")) #id 1 custom = QRadioButton(tr("Use an internal PKI")) hbox = QHBoxLayout() box.addLayout(hbox) self.nupki_or_custom = QButtonGroup() self.connect(self.nupki_or_custom, SIGNAL('buttonClicked(int)'), self.toggleCustomOrNupki) for index, radio in enumerate((custom, nupki)): hbox.addWidget(radio) self.nupki_or_custom.addButton(radio, index) self.file_selector_widget = QWidget() vbox = QVBoxLayout(self.file_selector_widget) selector_label = QLabel(tr("Manually uploaded LDAP certificate")) vbox.addWidget(selector_label) add_cert_trigger = AddButton(text=tr("Upload a certificate")) vbox.addWidget(add_cert_trigger) vbox.addWidget(separator()) self.has_cert_message = QLabel( tr("There is no manually uploaded server certificate") ) self.del_cert = RemButton( tr("Delete certificate file from server") ) vbox.addWidget(self.has_cert_message) vbox.addWidget(self.del_cert) self.connect(add_cert_trigger, SIGNAL('clicked()'), self.upload_server_cert) self.connect(self.del_cert, SIGNAL('clicked()'), self.delete_server_cert) self.nupki_message = MessageArea() self.nupki_message.setMessage(tr("Warning"), tr( "There is no server certificate in the internal PKI.<br/>" "Please import or generate one using an internal PKI." ) ) for anti_button, widget in ((custom, self.nupki_message), (nupki, self.file_selector_widget)): box.addWidget(widget) self.connect(anti_button, SIGNAL('toggled(bool)'), widget.setVisible) self.selectCustomOrNupki(CUSTOM) return group def upload_server_cert(self): dialog = UploadDialog( selector_label=tr("LDAP certificate"), filter=tr("Certificate file (*.crt *.pem *)") ) accepted = dialog.exec_() if accepted != QDialog.Accepted: return filename = dialog.filename if not filename: return with open(filename, 'rb') as fd: content = fd.read() content = encodeFileContent(content) self.mainwindow.addToInfoArea(tr('Uploading of a certificate file for the ldap server')) async = self.mainwindow.client.async() async.call("nuauth", "upload_ldap_server_cert", content, callback = self.success_upload, errback = self.error_upload ) def success_upload(self, value): self.mainwindow.addToInfoArea(tr('[LDAP server cert upload] Success!')) self.specific_config.server_cert_set = True self.setServerCert() self.signalModified() def error_upload(self, value): self.mainwindow.addToInfoArea(tr('[LDAP server cert upload] Error!'), COLOR_ERROR) self.mainwindow.addToInfoArea(tr('[LDAP server cert upload] %s') % value, COLOR_ERROR) def setServerCert(self): if self.specific_config.server_cert_set: self.del_cert.show() self.has_cert_message.hide() else: self.del_cert.hide() self.has_cert_message.show() def delete_server_cert(self): confirm_box = QMessageBox(self) confirm_box.setText( tr( "Please confirm the deletion of the " "manually uploaded LDAP server certificate." ) ) confirm_box.setInformativeText( tr("Do you really want to delete the certificate file?") ) confirm_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) confirm_box.setDefaultButton(QMessageBox.Cancel) confirm = confirm_box.exec_() if confirm != QMessageBox.Ok: return async = self.mainwindow.client.async() async.call("nuauth", "delete_ldap_server_cert", callback = self.success_delete, errback = self.error_delete ) def success_delete(self, value): self.mainwindow.addToInfoArea(tr('[LDAP server cert deletion] Success!')) self.specific_config.server_cert_set = False self.setServerCert() self.signalModified() def error_delete(self, value): self.mainwindow.addToInfoArea(tr('[LDAP server cert deletion] Error!'), COLOR_ERROR) self.mainwindow.addToInfoArea(tr('[LDAP server cert deletion] %s') % value, COLOR_ERROR) def toggleCustomOrNupki(self, id): if id == 0: self.specific_config.custom_or_nupki = NUPKI else: self.specific_config.custom_or_nupki = CUSTOM self.signalModified() def selectCustomOrNupki(self, custom_or_nupki): if custom_or_nupki == CUSTOM: self.file_selector_widget.setEnabled(True) self.nupki_message.hide() id = 1 else: custom_or_nupki = NUPKI self.file_selector_widget.hide() id = 0 self.nupki_or_custom.button(id).setChecked(True) def setSslData(self, config): ssl_enabled = (SSL_DISABLED != config.custom_or_nupki) self.ssl_box.setChecked(ssl_enabled) if ssl_enabled: self.selectCustomOrNupki(config.custom_or_nupki) def updateUri(self, config=None): if config is None: config = self.specific_config self.setText(self.uri, config.uri) def updateView(self, config=None): if config is None: config = self.specific_config self.updateUri(config=config) self.setSslData(config) #never copy this one: self.setDefaultText(self.dn_users, self.specific_config.dn_users) self.setDefaultText(self.dn_groups, self.specific_config.dn_groups) self.setDefaultText(self.user, config.user) self.setDefaultText(self.password, config.password) self.setServerCert()
class ResolvFrontend(ScrollArea): COMPONENT = 'resolv' IDENTIFIER = 'dns' LABEL = tr('Hostname and DNS') REQUIREMENTS = ('resolv', 'hostname') FIXED_WIDTH = 40 ICON = ':/icons/computeur.png' def __init__(self, client, parent=None): ScrollArea.__init__(self) self.client = client self.mainwindow = parent self._modified = False self.cfg = {} self.host_loaded = False self.resolv_loaded = False self._can_edit_hostname = True self.qhostnamecfg = QHostnameObject.getInstance() self.qresolvcfg = QResolvObject.getInstance() main_widget = QWidget() self.setWidget(main_widget) self.setWidgetResizable(True) self.form = QFormLayout(main_widget) self.form.addRow(QLabel("<h1>%s</h1>" % tr('Hostname'))) host_box = self.mkHostBox() self.form.addRow(host_box) self.form.addItem( QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding) ) self.form.addRow(QLabel("<h1>%s</h1>" % tr('DNS'))) self.dns1 = self.addField(tr("Server 1"), IpEdit) self.dns2_label = QLabel(tr("Server 2")) self.dns2 = self.addField(self.dns2_label, IpEdit) self.form.addRow(QLabel("<h1>%s</h1>" % tr('Active configuration test'))) self.test_group = _mkTestGroup() self.form.addRow(self.test_group) self.connect(self.test_group.test_button, SIGNAL('clicked()'), self.full_test) self.mainwindow.writeAccessNeeded( self.dns1, self.dns2, self.edit_hostname, self.edit_domain ) self.message = MessageArea() self.message.setWidth(80) self.error_message = '' self.form.addRow(self.message) self.resetConf() if not self.host_loaded and not self.resolv_loaded: raise NuConfModuleDisabled if self.resolv_loaded: self._connectsignals() def _connectsignals(self): self.connect(self.dns1, SIGNAL('editingFinished()'), partial(self.setDns, self.dns1, self.qresolvcfg.resolvcfg.setNameserver1)) self.connect(self.dns2, SIGNAL('editingFinished()'), partial(self.setDns, self.dns2, self.qresolvcfg.resolvcfg.setNameserver2)) self.connect(self.dns1, SIGNAL('textEdited(QString)'), lambda x: self.setModified(True)) self.connect(self.dns2, SIGNAL('textEdited(QString)'), lambda x: self.setModified(True)) @staticmethod def get_calls(): """ services called by initial multicall """ return ( ('resolv', 'getResolvConfig'), ('resolv', 'getRunningConfig'), ('hostname', 'getHostnameConfig'), ) def setDns(self, edit_dns, set_dns): set_dns(edit_dns.text()) def mkHostBox(self): box = QGroupBox(tr("Hostname and domain configuration")) form = QFormLayout(box) form.setLabelAlignment(Qt.AlignLeft) self.hostname = QLabel() self.edit_hostname = EditButton(flat=False) self.connect(self.edit_hostname, SIGNAL('clicked()'), self._edit_hostname) form.addRow(self.hostname, self.edit_hostname) self.domain = QLabel() self.edit_domain = EditButton(flat=False) self.connect(self.edit_domain, SIGNAL('clicked()'), self._edit_domain) form.addRow(self.domain, self.edit_domain) self.qhostnamecfg.registerCallbacks( lambda: True, self.updateHostname) self.qresolvcfg.registerCallbacks( lambda: True, self.updateDomain) return box def updateHostname(self): if not self.host_loaded: hostname_text = "<i>%s</i>" % tr("not fetched", "The hostname is normally fetched from the server, and this " "text handles the case when it failed. " "The text 'not fetched' is written in italics." ) self._can_edit_hostname = False else: changeable = self.qhostnamecfg.hostnamecfg.changeable self._can_edit_hostname = changeable != NOT_CHANGEABLE hostname_text = "%s %s" % ( tr("Hostname:", "Displaying the hostname"), self.qhostnamecfg.hostnamecfg.hostname ) if changeable == NOT_CHANGEABLE: self.mainwindow.addToInfoArea(_HOSTNAME_NOT_CHANGEABLE, COLOR_VERBOSE) self.hostname.setText(hostname_text) def updateDomain(self): self.domain.setText(tr("Domain: %s") % self.qresolvcfg.resolvcfg.domain) def __editFieldDialog(self, title, label, text): """ return text, ok """ #Signature: text, ok = QInputDialog.getText( # QWidget parent, # QString title, # QString label, # QLineEdit.EchoMode echo = QLineEdit.Normal, # QString text = QString(), # Qt.WindowFlags f = 0) return QInputDialog.getText( self, title, label, QLineEdit.Normal, text ) def _continue_edit(self, title, message): continuing = QMessageBox.question( self, title, message, QMessageBox.Cancel|QMessageBox.Ok, QMessageBox.Cancel, #default button ) return continuing == QMessageBox.Ok def _edit_hostname(self): changeable = self.qhostnamecfg.hostnamecfg.changeable if not self._can_edit_hostname: QMessageBox.critical( self, _CANNOT_CHANGE_HOSTNAME_TITLE, _CANNOT_CHANGE_HOSTNAME, ) return if changeable == CHANGE_DISCOURAGED: if not self._continue_edit( tr("About hostname change", "popup title"), _HOSTNAME_CHANGE_DISCLAIMER ): return hostname, ok = self.__editFieldDialog( tr("Edit hostname"), tr("Enter new hostname"), self.qhostnamecfg.hostnamecfg.hostname ) if ok: hostname = unicode(hostname).strip() if hostname == self.qhostnamecfg.hostnamecfg.hostname: return self.qhostnamecfg.pre_modify() self.qhostnamecfg.hostnamecfg.hostname = hostname self.qhostnamecfg.post_modify() self.setModified() def _edit_domain(self): changeable = self.qhostnamecfg.hostnamecfg.changeable if changeable == CHANGE_DISCOURAGED: if not self._continue_edit( tr("About domain change", "popup title"), _DOMAIN_CHANGE_DISCLAIMER ): return domain, ok = self.__editFieldDialog( tr("Edit domain"), tr("Enter new domain name"), self.qresolvcfg.resolvcfg.domain ) if ok: domain = unicode(domain).strip() if domain == self.qresolvcfg.resolvcfg.domain: return self.qresolvcfg.pre_modify() self.qresolvcfg.resolvcfg.setDomain(domain) self.qresolvcfg.post_modify() self.setModified() def default_test(self): async = self.client.async() async.call('resolv', 'test', {}, callback=self.defaultTest_success, errback=self.test_error ) self.mainwindow.addToInfoArea(tr("Testing current DNS server...")) def full_test(self): fields = { self.test_group.server_input: tr("test server field"), self.test_group.query_input: tr("test query field"), } default_test = True for item in fields: if not item.isEmpty(): default_test = False if not item.isValid(): self.mainwindow.addToInfoArea( tr("Wrong value in %s, can not test.") % fields[item] ) return if default_test: self.default_test() return self.deactivate_tests() async = self.client.async() async.call('resolv', 'test', { 'server': unicode(self.test_group.server_input.text()).strip(), 'query': unicode(self.test_group.query_input.text()).strip() }, callback=self.test_success, errback=self.test_error ) self.mainwindow.addToInfoArea(tr("Testing DNS server with custom parameters...")) def defaultTest_success(self, result): self.mainwindow.addToInfoArea(tr("[DNS Test] Success: The server is available (empty query).")) self.reactivate_tests() def test_success(self, result): self.mainwindow.addToInfoArea(tr("[DNS Test] Success!")) dialog = DnsResult(result, self) dialog.exec_() self.reactivate_tests() def test_error(self, err): err = exceptionAsUnicode(err) self.mainwindow.addWarningMessage( tr("[DNS Test] Error! %s") % err ) self.reactivate_tests() def deactivate_tests(self): self.test_group.test_button.setEnabled(False) def reactivate_tests(self): self.test_group.test_button.setEnabled(True) def addField(self, field_name, inputcls): field = inputcls(self) field.setFixedWidth(field.fontMetrics().averageCharWidth() * self.FIXED_WIDTH) self.form.addRow(field_name, field) return field def isModified(self): return self._modified def setModified(self, modif=True): if modif: self.mainwindow.setModified(self, True) self._modified = modif def resetConf(self): self._reset_hostname() self._reset_resolv() self.updateHostname() self.updateDomain() self.dns1.setText(self.qresolvcfg.resolvcfg.nameserver1) self.dns1.validColor() self.dns2.setText(self.qresolvcfg.resolvcfg.nameserver2) self.dns2.validColor() self.message.setNoMessage() self.setModified(False) self._reset_tests_texts() def isValid(self): self.message.setNoMessage() self.error_message = '' hasInvalidData = False for widget in [self.dns1, self.dns2]: if not widget.isValid(): hasInvalidData = True error = "'%s' : must be '%s'<br />" % (widget.text(), widget.getFieldInfo()) self.error_message += error self.message.setMessage('', "<ul>%s" % error, status=MessageArea.WARNING) confs = { tr("hostname"): self.qhostnamecfg.cfg, tr("DNS"): self.qresolvcfg.cfg } for name, item in confs.iteritems(): if not item.isValid(): hasInvalidData = True error = tr("%s configuration is invalid<br />") % name self.message.setMessage('', error, status=MessageArea.WARNING) self.error_message += error if not hasInvalidData: error = self.qresolvcfg.resolvcfg.isInvalid() if error: hasInvalidData = True self.error_message = error self.message.setMessage('', error, status=MessageArea.WARNING) if hasInvalidData: self.mainwindow.addToInfoArea(tr("'Hostname and DNS : invalid configuration'")) return False else: return True def saveConf(self, message): if self.host_loaded: self.client.call('hostname', 'setShortHostname', self.qhostnamecfg.hostnamecfg.hostname, message) if self.resolv_loaded: self.client.call('resolv', 'setResolvConfig', self.qresolvcfg.resolvcfg.serialize(), message) self.setModified(False) self.mainwindow.addToInfoArea(tr("'Hostname and DNS : configuration saved'")) def _reset_hostname(self): """ Specifically resets values for hostname config. sets self.host_loaded according to success in doing so. """ self.host_loaded = self._reset_helper( 'hostname', 'getHostnameConfig', self.qhostnamecfg, tr("Hostname interface enabled"), tr("Hostname interface disabled: backend not loaded") ) def _reset_resolv(self): """ Specifically resets values for DNS resolution config. sets self.resolv_loaded according to success in doing so. """ self.resolv_loaded = self._reset_helper( 'resolv', 'getResolvConfig', self.qresolvcfg, tr("DNS interface enabled"), tr("DNS interface disabled: backend not loaded") ) def _reset_tests_texts(self): serialized = self._fetch_serialized('resolv', 'getRunningConfig') if serialized is not None: running_cfg = deserialize(serialized) servers = {'DNS_SERVERS': ' and '.join( tuple(running_cfg.iterNameServers()) )} text = _FULL_TEST_TEXT % servers else: self.message.warning( tr("Warning on tests", "Testing DNS resolution from the server"), tr( "Tests are run with the configuration that is applied on " "the appliance. This configuration can not be displayed " "(probably because the software version of the appliance does " "not provide this functionality)." ) ) text = _FULL_TEST_TEXT_NOINFO self.test_group.full_test_info.setText("%s %s" % (_INFO_IMG, text))