def accountUnlockable(self, user, object_dn): index = PluginRegistry.getInstance("ObjectIndex") # Do we have read permissions for the requested attribute env = Environment.getInstance() topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "isLocked") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "r", base=object_dn): self.__log.debug( "user '%s' has insufficient permissions to read %s on %s, required is %s:%s" % (user, "isLocked", object_dn, topic, "r")) raise ACLException( C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) res = index.search({ 'dn': object_dn, 'userPassword': '******' }, {'userPassword': 1}) if len(res): hsh = res[0]['userPassword'][0] else: # No password hash -> cannot lock/unlock account return False # Try to detect the responsible password method-class pwd_o = self.detect_method_by_hash(hsh) if not pwd_o: # Could not identify password method return False return pwd_o.isUnlockable(hsh)
def handle_request(self, topic, message): if topic == self.subtopic: # event from proxy received try: data = etree.fromstring(message, PluginRegistry.getEventParser()) event_type = stripNs(data.xpath('/g:Event/*', namespaces={'g': "http://www.gonicus.de/Events"})[0].tag) if event_type == "ClientLeave": proxy_id = str(data.ClientLeave.Id) registry = PluginRegistry.getInstance("BackendRegistry") registry.unregisterBackend(proxy_id) except etree.XMLSyntaxError as e: self.log.error("Event parsing error: %s" % e) elif topic.startswith(self.subtopic): response_topic = "%s/response" % "/".join(topic.split("/")[0:4]) try: id_, res = self.process(topic, message) if is_future(res): res = yield res response = dumps({"result": res, "id": id_}) self.log.debug("MQTT-RPC response: %s on topic %s" % (response, topic)) except Exception as e: err = str(e) self.log.error("MQTT RPC call error: %s" % err) response = dumps({'id': topic.split("/")[-2], 'error': err}) # Get rid of it... self.mqtt.send_message(response, topic=response_topic, qos=2) else: self.log.warning("unhandled topic request received: %s" % topic)
def test_handle_backend_message(self): e = EventMaker() # send client poll with mock.patch.object(self.service.proxy_mqtt, "send_message") as mps: # send ACLChanged m_resolver = PluginRegistry.getInstance("ACLResolver") self.service._handle_backend_message( "%s/proxy" % self.env.domain, etree.tostring(e.Event(e.Trigger(e.Type("ACLChanged"))), pretty_print=True).decode()) assert m_resolver.load_acls.called assert not mps.called m_index = PluginRegistry.getInstance("ObjectIndex") self.service._handle_backend_message( "%s/client/broadcast" % self.env.domain, etree.tostring(e.Event(e.ClientPoll()), pretty_print=True).decode()) assert m_index.registerProxy.called assert mps.called mps.reset_mock() # send client RPC payload = dumps({"id": "jsonrpc", "method": "test", "params": []}) topic = "%s/client/client_id/request_id/request" % self.env.domain self.service._handle_backend_message(topic, payload) mps.assert_called_with(payload, topic, qos=1)
def __dbus_proxy_monitor(self, bus_name): """ This method monitors the DBus service 'org.gosa' and whenever there is a change in the status (dbus closed/startet) we will take notice. And can register or unregister methods to the dbus """ if "org.gosa" in self.bus.list_names(): if self.gosa_dbus: del self.gosa_dbus # Trigger resend of capapability event self.gosa_dbus = self.bus.get_object('org.gosa', '/org/gosa/inventory') ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.register("request_inventory", 'Inventory.request_inventory', [], ['old_checksum=None'], 'Request client inventory information') mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("established dbus connection") else: if self.gosa_dbus: del(self.gosa_dbus) # Trigger resend of capapability event ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.unregister("request_inventory") mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("lost dbus connection") else: self.log.info("no dbus connection")
def serve(self): """ Start JSONRPC service for this GOsa service provider. """ # Get http service instance self.__http = PluginRegistry.getInstance("HTTPService") cr = PluginRegistry.getInstance("CommandRegistry") # Register ourselves app = JsonRpcApp(cr) self.__http.app.register( self.path, AuthCookieHandler( app, timeout=self.env.config.get("jsonrpc.cookie-lifetime", default=1800), cookie_name="GOsaRPC", secret=self.env.config.get("http.cookie_secret", default="TecloigJink4"), ), ) # Announce service self.__zeroconf = ZeroconfService( name="GOsa JSONRPC command service", port=self.__http.port, stype="_%s._tcp" % self.__http.scheme, text="path=%s\001service=gosa" % self.path, ) self.__zeroconf.publish() self.log.info("ready to process incoming requests")
def __dbus_proxy_monitor(self, bus_name): """ This method monitors the DBus service 'org.gosa' and whenever there is a change in the status (dbus closed/started) we will take notice. And can register or unregister methods to the dbus """ if "org.gosa" in self.bus.list_names(): if self.gosa_dbus: del self.gosa_dbus self.gosa_dbus = self.bus.get_object('org.gosa', '/org/gosa/notify') ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.register("notify", 'Notify.notify', [], ['user', 'title', 'message', 'timeout', 'icon'], 'Sent a notification to a given user') ccr.register("notify_all", 'Notify.notify_all', [], ['title', 'message', 'timeout', 'icon'], 'Sent a notification to a given user') mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("established dbus connection") else: if self.gosa_dbus: del self.gosa_dbus # Trigger resend of capapability event ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.unregister("notify") ccr.unregister("notify_all") mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("lost dbus connection") else: self.log.info("no dbus connection")
def mainLoop(env): """ Main event loop which will process all registerd threads in a loop. It will run as long env.active is set to True. """ log = logging.getLogger(__name__) try: # Load plugins oreg = ObjectRegistry.getInstance() #@UnusedVariable pr = PluginRegistry() #@UnusedVariable cr = PluginRegistry.getInstance("CommandRegistry") httpd = PluginRegistry.getInstance("HTTPService") if not hasattr(sys, "_called_from_test") or sys._called_from_test is False: httpd.thread.join() # Catchall, pylint: disable=W0703 except Exception as detail: log.critical("unexpected error in mainLoop") log.exception(detail) except KeyboardInterrupt: log.info("console requested shutdown") finally: if not hasattr(sys, "_called_from_test") or sys._called_from_test is False: shutdown()
def serve(self): """ Start AMQP service for this GOsa service provider. """ # Load AMQP and Command registry instances amqp = PluginRegistry.getInstance('AMQPHandler') self.__cr = PluginRegistry.getInstance('CommandRegistry') # Create a list of queues we need here queues = {} for dsc in self.__cr.commands.values(): queues[dsc['target']] = True # Finally create the queues for queue in queues: # Add round robin processor for queue self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address='%s.command.%s; { create:always, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s" } ] } }' % (self.env.domain, queue, self.env.domain, queue), workers=self.env.config.get('amqp.command-worker', default=1), callback=self.commandReceived) # Add private processor for queue self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address='%s.command.%s.%s; { create:always, delete:receiver, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s.%s" } ] } }' % (self.env.domain, queue, self.env.id, self.env.domain, queue, self.env.id), workers=self.env.config.get('amqp.command-worker', default=1), callback=self.commandReceived) # Announce service url = parseURL(self.env.config.get("amqp.url")) self.__zeroconf = ZeroconfService(name="GOsa AMQP command service", port=url['port'], stype="_%s._tcp" % url['scheme'], text="path=%s\001service=gosa" % url['path']) self.__zeroconf.publish() self.log.info("ready to process incoming requests")
def __dbus_proxy_monitor(self, bus_name): """ This method monitors the DBus service 'org.gosa' and whenever there is a change in the status (dbus closed/startet) we will take notice. And can register or unregister methods to the dbus """ if "org.gosa" in self.bus.list_names(): if self.gosa_dbus: del self.gosa_dbus # Trigger resend of capapability event self.gosa_dbus = self.bus.get_object('org.gosa', '/org/gosa/inventory') ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.register("request_inventory", 'Inventory.request_inventory', [], ['old_checksum=None'], 'Request client inventory information') mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("established dbus connection") else: if self.gosa_dbus: del (self.gosa_dbus) # Trigger resend of capapability event ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.unregister("request_inventory") mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("lost dbus connection") else: self.log.info("no dbus connection")
def setSambaPassword(self, user, object_dn, password): """ Set a new samba-password for a user """ # Do we have read permissions for the requested attribute env = Environment.getInstance() topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "sambaNTPassword") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "w", base=object_dn): self.__log.debug("user '%s' has insufficient permissions to write %s on %s, required is %s:%s" % ( user, "isLocked", object_dn, topic, "w")) raise ACLException(C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "sambaLMPassword") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "w", base=object_dn): self.__log.debug("user '%s' has insufficient permissions to write %s on %s, required is %s:%s" % ( user, "isLocked", object_dn, topic, "w")) raise ACLException(C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) # Set the password and commit the changes user = ObjectProxy(object_dn) user.sambaNTPassword = nthash.encrypt(password) user.sambaLMPassword = lmhash.encrypt(password) user.commit()
def __dbus_proxy_monitor(self, bus_name): """ This method monitors the DBus service 'org.freedesktop.login1' and whenever there is a change in the status (dbus closed/startet) we will take notice. And can register or unregister methods to the dbus """ if "org.freedesktop.login1" in self.bus.list_names(): if self.hal_dbus: del(self.hal_dbus) # Trigger resend of capability event self.hal_dbus = self.bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1') ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.register("shutdown", 'PowerManagement.shutdown', [], [], 'Execute a shutdown of the client.') ccr.register("reboot", 'PowerManagement.reboot', [], [], 'Execute a reboot of the client.') ccr.register("suspend", 'PowerManagement.suspend', [], [], 'Execute a suspend of the client.') ccr.register("hibernate", 'PowerManagement.hibernate', [], [], 'Execute a hibernation of the client.') mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("established dbus connection") else: if self.hal_dbus: del(self.hal_dbus) # Trigger resend of capapability event ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.unregister("shutdown") ccr.unregister("reboot") ccr.unregister("suspend") ccr.unregister("hibernate") mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("lost dbus connection") else: self.log.info("no dbus connection")
def accountUnlockable(self, user, object_dn): index = PluginRegistry.getInstance("ObjectIndex") # Do we have read permissions for the requested attribute env = Environment.getInstance() topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "isLocked") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "r", base=object_dn): self.__log.debug("user '%s' has insufficient permissions to read %s on %s, required is %s:%s" % ( user, "isLocked", object_dn, topic, "r")) raise ACLException(C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) res = index.search({'dn': object_dn, 'userPassword': '******'}, {'userPassword': 1}) if len(res): hsh = res[0]['userPassword'][0] else: # No password hash -> cannot lock/unlock account return False # Try to detect the responsible password method-class pwd_o = self.detect_method_by_hash(hsh) if not pwd_o: # Could not identify password method return False return pwd_o.isUnlockable(hsh)
def test_handle_backend_message(self): e = EventMaker() # send client poll with mock.patch.object(self.service.proxy_mqtt, "send_message") as mps: # send ACLChanged m_resolver = PluginRegistry.getInstance("ACLResolver") self.service._handle_backend_message("%s/proxy" % self.env.domain, etree.tostring(e.Event(e.Trigger(e.Type("ACLChanged"))), pretty_print=True).decode()) assert m_resolver.load_acls.called assert not mps.called m_index = PluginRegistry.getInstance("ObjectIndex") self.service._handle_backend_message("%s/client/broadcast" % self.env.domain, etree.tostring(e.Event(e.ClientPoll()), pretty_print=True).decode()) assert m_index.registerProxy.called assert mps.called mps.reset_mock() # send client RPC payload = dumps({"id": "mqttrpc", "method": "test", "params": []}) topic = "%s/client/client_id/request_id/request" % self.env.domain self.service._handle_backend_message(topic, payload) mps.assert_called_with(payload, topic, qos=1, proxied=True)
def serve(self): # Collect value extenders self.__value_extender = gosa.backend.objects.renderer.get_renderers() self.__search_aid = PluginRegistry.getInstance("ObjectIndex").get_search_aid() self.__oi = PluginRegistry.getInstance("ObjectIndex") # Load DB session self.__session = self.env.getDatabaseSession('backend-database')
def shutdown(): """ Function to shut down the backend. Do some clean up and close sockets. """ # Shutdown plugin registry PluginRegistry.shutdown() logging.info("shut down") logging.shutdown()
def use_test_config(): Environment.reset() Environment.config = os.path.join( os.path.dirname(os.path.realpath(__file__)), "..", "..", "test_conf") Environment.noargs = True oreg = ObjectRegistry.getInstance() # @UnusedVariable pr = PluginRegistry() # @UnusedVariable cr = PluginRegistry.getInstance("CommandRegistry") # @UnusedVariable
def serve(self): # Collect value extenders self.__value_extender = gosa.backend.objects.renderer.get_renderers() self.__search_aid = PluginRegistry.getInstance( "ObjectIndex").get_search_aid() self.__oi = PluginRegistry.getInstance("ObjectIndex") # Load DB session self.__session = self.env.getDatabaseSession('backend-database')
def test_clientLeave(self): service = PluginRegistry.getInstance("MQTTRPCService") e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id("fake_uuid"))) data = etree.tostring(goodbye).decode('utf-8') with mock.patch.object(PluginRegistry.getInstance("BackendRegistry"), "unregisterBackend") as m: service.handle_request("%s/proxy" % Environment.getInstance().domain, data) m.assert_called_with("fake_uuid")
def sendEvent(self, user, data): """ Sends an event to the SSE handler and the zope event bus. Data must be in XML format, see :ref:`Events handling <events>` for details. ========== ============ Parameter Description ========== ============ data valid event ========== ============ *sendEvent* will indirectly validate the event against the bundled "XSD". """ try: event = "<?xml version='1.0'?>\n" if isinstance(data, str): event += data elif isinstance(data, bytes): event += data.decode('utf-8') else: event += etree.tostring(data, pretty_print=True).decode('utf-8') # Validate event xml = objectify.fromstring(event, PluginRegistry.getEventParser()) event_type = list(xml.__dict__.keys())[0] # If a user was supplied, check if she's authorized... if user: acl = PluginRegistry.getInstance("ACLResolver") topic = ".".join([self.env.domain, 'event', event_type]) if not acl.check(user, topic, "x"): raise EventNotAuthorized( "sending the event '%s' is not permitted" % topic) if event_type in [ 'ObjectChanged', 'Notification', 'ObjectCloseAnnouncement' ]: params = {'channel': 'broadcast'} if event_type == "Notification" and xml.Notification.Target.text != "all": params[ 'channel'] = "user.%s" % xml.Notification.Target.text if event_type == "ObjectCloseAnnouncement": params[ 'channel'] = "user.%s" % xml.ObjectCloseAnnouncement.Target.text SseHandler.notify(xml, **params) zope.event.notify(Event(data=xml, emitter=user)) except etree.XMLSyntaxError as e: if self.env: self.log.error("event rejected (%s): %s" % (str(e), data)) raise
def initialize(self): self.dispatcher = PluginRegistry.getInstance('CommandRegistry') self.env = Environment.getInstance() self.log = logging.getLogger(__name__) self.ident = "GOsa JSON-RPC service (%s)" % VERSION self.executor = PluginRegistry.getInstance('ExecutorWrapper').executor if JsonRpcHandler.__gc_job is None: sched = PluginRegistry.getInstance('SchedulerService').getScheduler() JsonRpcHandler.__gc_job = sched.add_interval_job(self.__gc_sessions, minutes=180, tag='_internal', jobstore="ram")
def test_clientLeave(self): service = PluginRegistry.getInstance("MQTTRPCService") e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id("fake_uuid"))) data = etree.tostring(goodbye).decode('utf-8') with mock.patch.object(PluginRegistry.getInstance("BackendRegistry"), "unregisterBackend") as m: service.handle_request( "%s/proxy" % Environment.getInstance().domain, data) m.assert_called_with("fake_uuid")
def reload_signatures(self): """ Reloads the dbus signatures. """ to_register = {} to_unregister = {} if not self.gosa_dbus: self.log.debug( "no dbus service registered for '%s' - is gosa-dbus running?" % ("org.gosa")) to_unregister = self.methods self.methods = {} else: try: self.log.debug( 'loading dbus-methods registered by GOsa (introspection)') new_methods = self._call_introspection("org.gosa", "/") # Detect new methods for meth in new_methods: if meth not in self.methods or self.methods[meth][ 'args'] != new_methods[meth]['args']: to_register[meth] = new_methods[meth] # Find removed methods for meth in self.methods: if not meth in new_methods: to_unregister[meth] = self.methods[meth] self.methods = new_methods self.log.debug("found %s registered dbus methods" % (str(len(self.methods)))) except DBusException as exception: self.log.error("failed to load dbus methods: %s" % (str(exception))) raise exception # (Re-)register the methods we've found ccr = PluginRegistry.getInstance('ClientCommandRegistry') for name in to_register: ccr.register(name, 'DBUSProxy.callDBusMethod', [name], ['(signatur)'], 'docstring') for name in to_unregister: ccr.unregister(name) # Trigger resend of capability event mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce()
def shutdown(): env.active = False # Wait for threads to shut down for t in env.threads: if hasattr(t, 'stop'): t.stop() if hasattr(t, 'cancel'): t.cancel() t.join(2) PluginRegistry.shutdown() if has_dbus: dr.stop()
def post(self, uuid): try: self.ps.data_complete() # You MUST call this to close the incoming stream. # Here can use self.ps to access the fields and the corresponding ``StreamedPart`` objects. self.upload_handler.handle_upload(self.ps.get_parts_by_name('file')[0], self.request) # cleanup PluginRegistry.getInstance("UploadManager").unregisterUploadPath(uuid) self.upload_handler = None finally: # When ready, don't forget to release resources. self.ps.release_parts() self.finish() # And of course, you MUST call finish()
def sendEvent(self, user, data): """ Sends an event to the SSE handler and the zope event bus. Data must be in XML format, see :ref:`Events handling <events>` for details. ========== ============ Parameter Description ========== ============ data valid event ========== ============ *sendEvent* will indirectly validate the event against the bundled "XSD". """ try: event = "<?xml version='1.0'?>\n" if isinstance(data, str): event += data elif isinstance(data, bytes): event += data.decode('utf-8') else: event += etree.tostring(data, pretty_print=True).decode('utf-8') # Validate event xml = objectify.fromstring(event, PluginRegistry.getEventParser()) event_type = list(xml.__dict__.keys())[0] # If a user was supplied, check if she's authorized... if user: acl = PluginRegistry.getInstance("ACLResolver") topic = ".".join([self.env.domain, 'event', event_type]) if not acl.check(user, topic, "x"): raise EventNotAuthorized("sending the event '%s' is not permitted" % topic) if event_type in ['ObjectChanged', 'Notification', 'ObjectCloseAnnouncement']: params = {'channel': 'broadcast'} if event_type == "Notification" and xml.Notification.Target.text != "all": params['channel'] = "user.%s" % xml.Notification.Target.text if event_type == "ObjectCloseAnnouncement": params['channel'] = "user.%s" % xml.ObjectCloseAnnouncement.Target.text SseHandler.notify(xml, **params) zope.event.notify(Event(data=xml, emitter=user)) except etree.XMLSyntaxError as e: if self.env: self.log.error("event rejected (%s): %s" % (str(e), data)) raise
def shutdown(a=None, b=None): """ Function to shut down the agent. Do some clean up and close sockets.""" amqp = PluginRegistry.getInstance("AMQPHandler") # Tell others that we're away now e = EventMaker() goodbye = e.Event(e.NodeLeave(e.Id(amqp.env.id))) amqp.sendEvent(goodbye) # Shutdown plugins PluginRegistry.shutdown() logging.info("shut down") logging.shutdown() exit(0)
def __dbus_proxy_monitor(self, bus_name): """ This method monitors the DBus service 'org.freedesktop.login1' and whenever there is a change in the status (dbus closed/startet) we will take notice. And can register or unregister methods to the dbus """ if "org.freedesktop.login1" in self.bus.list_names(): if self.hal_dbus: del (self.hal_dbus) # Trigger resend of capability event self.hal_dbus = self.bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1') ccr = PluginRegistry.getInstance('ClientCommandRegistry') if self.hal_dbus.CanPowerOff( dbus_interface="org.freedesktop.login1.Manager") == "yes": ccr.register("shutdown", 'PowerManagement.shutdown', [], [], 'Execute a shutdown of the client.') if self.hal_dbus.CanReboot( dbus_interface="org.freedesktop.login1.Manager") == "yes": ccr.register("reboot", 'PowerManagement.reboot', [], [], 'Execute a reboot of the client.') if self.hal_dbus.CanSuspend( dbus_interface="org.freedesktop.login1.Manager") == "yes": ccr.register("suspend", 'PowerManagement.suspend', [], [], 'Execute a suspend of the client.') if self.hal_dbus.CanHibernate( dbus_interface="org.freedesktop.login1.Manager") == "yes": ccr.register("hibernate", 'PowerManagement.hibernate', [], [], 'Execute a hibernation of the client.') mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("established dbus connection") else: if self.hal_dbus: del (self.hal_dbus) # Trigger resend of capability event ccr = PluginRegistry.getInstance('ClientCommandRegistry') ccr.unregister("shutdown") ccr.unregister("reboot") ccr.unregister("suspend") ccr.unregister("hibernate") mqtt = PluginRegistry.getInstance('MQTTClientService') mqtt.reAnnounce() self.log.info("lost dbus connection") else: self.log.info("no dbus connection")
def getObjectSearchItem(self, user, dn): """ This method returns the search result for one specific object. It is used to gain some useful information about the object like title and icon. :param dn: string - Object DN :return: dict """ # Start the query and bring the result in a usable form index = PluginRegistry.getInstance("ObjectIndex") item = index.find(user, {'dn': dn}) if len(item) == 1: item = item[0] else: return None if item['_type'] not in self.__search_aid['mapping']: return None entry = {'tag': item['_type']} for k, v in self.__search_aid['mapping'][item['_type']].items(): if k: if v in item and item[v]: if v == "dn": entry[k] = item[v] else: entry[k] = item[v][0] else: entry[k] = self.__build_value(v, item) return entry
def serve(self): try: server = self.env.config.get("cups.server") port = self.env.config.get("cups.port") user = self.env.config.get("cups.user") password = self.env.config.get("cups.password") encryption_policy = getattr(cups, "HTTP_ENCRYPT_%s" % self.env.config.get("cups.encryption-policy", default="IF_REQUESTED").upper()) if server is not None: cups.setServer(server) if port is not None: cups.setPort(int(port)) if user is not None: cups.setUser(user) if encryption_policy is not None: cups.setEncryption(encryption_policy) if password is not None: def pw_callback(prompt): return password cups.setPasswordCB(pw_callback) self.client = cups.Connection() sched = PluginRegistry.getInstance("SchedulerService").getScheduler() sched.add_interval_job(self.__gc, minutes=60, tag='_internal', jobstore="ram") sched.add_interval_job(self.__update_printer_list, minutes=30, tag='_internal', jobstore="ram") except RuntimeError as e: self.log.error(str(e)) self.client = None
def test_add_action(self): acl = ACL(scope=ACL.ONE) with pytest.raises(ACLException): # wrong options type acl.add_action('topic', "w", True) with pytest.raises(ACLException): # unknown acls acl.add_action('topic', "qx", {}) role = ACLRole('role1') resolver = PluginRegistry.getInstance("ACLResolver") resolver.add_acl_role(role) acl.use_role("role1") with pytest.raises(ACLException): # no actions allowed for role ACLs acl.add_action('topic', "r", {}) acl = ACL(scope=ACL.ONE) assert len(acl.actions) == 0 acl.add_action('topic', "r", {}) assert len(acl.actions) == 1 acl.clear_actions() assert len(acl.actions) == 0
def use_test_config(request): Environment.reset() Environment.config = os.path.join( os.path.dirname(os.path.realpath(__file__)), "..", "test_conf") Environment.noargs = True env = Environment.getInstance() if has_dbus: # Enable DBus runner dr = DBusRunner() dr.start() PluginRegistry(component='gosa.client.module') # @UnusedVariable env.active = True def shutdown(): env.active = False # Wait for threads to shut down for t in env.threads: if hasattr(t, 'stop'): t.stop() if hasattr(t, 'cancel'): t.cancel() t.join(2) PluginRegistry.shutdown() if has_dbus: dr.stop() request.addfinalizer(shutdown)
def __update_population(self): # collect current attribute values data = {} for prop in self._get_attributes(): data[prop] = getattr(self, prop) changes = {} for key in self.__attribute_map: if self.__attribute_map[key][ 'values_populate'] and self.__attribute_map[key][ 're_populate_on_update'] is True: cr = PluginRegistry.getInstance('CommandRegistry') values = cr.call(self.__attribute_map[key]['values_populate'], data) if self.__attribute_map[key]['values'] != values: changes[key] = values self.__attribute_map[key]['values'] = values if len(changes.keys()) and self.__user is not None: e = EventMaker() changed = list() for key, values in changes.items(): change = e.Change(e.PropertyName(key), e.NewValues(dumps(values))) changed.append(change) ev = e.Event( e.ObjectPropertyValuesChanged(e.UUID(self.uuid), *changed)) event_object = objectify.fromstring( etree.tostring(ev).decode('utf-8')) SseHandler.notify(event_object, channel="user.%s" % self.__user)
def getUserPPDs(self, user): index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"_type": "User", "uid": user}, {"dn": 1}) if len(res) == 0: raise EntryNotFound(C.make_error("USER_NOT_FOUND", topic=user)) object = ObjectProxy(res[0]["dn"]) printer_cns = [] if object.is_extended_by("GotoEnvironment"): printer_cns.append(object.gotoPrinters) if object.is_extended_by("PosixUser"): for group_cn in object.groupMembership: group = ObjectProxy(group_cn) if group.is_extended_by("GotoEnvironment"): printer_cns.append(group.gotoPrinters) # collect all PPDs res = index.search({ "_type": "GotoPrinter", "cn": { "in_": printer_cns } }, {"gotoPrinterPPD": 1}) ppds = [] for r in res: ppds.append(r["gotoPrinterPPD"]) return ppds
def process(self, obj, key, valDict, make_attribute=None, server_ppd_attribute=None, override="false"): ppd_file = valDict[key]['value'][0] if len( valDict[key]['value']) else None if ppd_file is not None: cups = PluginRegistry.getInstance("CupsClient") res = cups.get_attributes_from_ppd(ppd_file, ["Manufacturer", "NickName"]) if "Manufacturer" in res: if make_attribute is not None and make_attribute in valDict: if len(valDict[make_attribute] ['value']) == 0 or override == "true": valDict[make_attribute]['value'] = [ res["Manufacturer"] ] if server_ppd_attribute is not None and server_ppd_attribute in valDict and "NickName" in res: for ppd, entry in cups.getPrinterModels( res["Manufacturer"]).items(): if entry["value"] == res["NickName"]: if len(valDict[make_attribute] ['value']) == 0 or override == "true": valDict[server_ppd_attribute]['value'] = [ppd] break return key, valDict
def post(self, path): mime_type = self.request.headers.get('Content-Type') registry = PluginRegistry.getInstance("WebhookRegistry") # verify content token = registry.get_token(mime_type, self.sender) # no token, not allowed if token is None: raise HTTPError(401) # as the content is bytes the token needs to be converted to bytes to token = bytes(token, 'ascii') # wrong signature, not allowed if not self._verify_signature(self.request.body, token): raise HTTPError(401) # forward to the registered handler handler = registry.get_handler(mime_type) if handler is None: # usually this code is unreachable because if there is no registered handler, there is no token raise HTTPError(401) try: handler.handle_request(self) except Exception as e: self.log.error(e) raise e
def _execute_embedded_script(self, script): try: env = dict(data=self._get_data()) dispatcher = PluginRegistry.getInstance('CommandRegistry') def make_dispatch(method): def call(*args, **kwargs): return dispatcher.call(method, *args, **kwargs) return call # Add public calls for method in dispatcher.getMethods(): env[method] = make_dispatch(method) exec(script, env) except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] print("Exception while executing the embedded script:") print(fname, "line", exc_tb.tb_lineno) print(exc_type) print(exc_obj) return False return True
def ref_to_obj(ref): """ Returns the object pointed to by ``ref``. """ if not isinstance(ref, basestring): raise TypeError('References must be strings') if not ':' in ref: raise ValueError('Invalid reference') if ref == "gosa.backend.command:CommandRegistry.dispatch": return getattr(PluginRegistry.getInstance('CommandRegistry'), "dispatch") modulename, rest = ref.split(':', 1) try: obj = __import__(modulename) except ImportError: raise LookupError('Error resolving reference %s: ' 'could not import module' % ref) try: for name in modulename.split('.')[1:] + rest.split('.'): obj = getattr(obj, name) return obj except Exception: raise LookupError('Error resolving reference %s: ' 'error looking up object' % ref)
def lockAccountPassword(self, user, object_dn): """ Locks the account password for the given DN """ # Do we have read permissions for the requested attribute env = Environment.getInstance() topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "userPassword") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "w", base=object_dn): self.__log.debug( "user '%s' has insufficient permissions to write %s on %s, required is %s:%s" % (user, "isLocked", object_dn, topic, "w")) raise ACLException( C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) # Get the object for the given dn user = ObjectProxy(object_dn) # Check if there is a userPasswort available and set if not "userPassword" in user.get_attributes(): raise PasswordException(C.make_error("PASSWORD_NO_ATTRIBUTE")) if not user.userPassword: raise PasswordException(C.make_error("PASSWORD_NOT_AVAILABLE")) # Try to detect the responsible password method-class pwd_o = self.detect_method_by_hash(user.userPassword) if not pwd_o: raise PasswordException(C.make_error("PASSWORD_METHOD_UNKNOWN")) # Lock the hash and save it user.userPassword = pwd_o.lock_account(user.userPassword) user.commit()
def setUserPassword(self, user, object_dn, password): """ Set a new password for a user """ # Do we have write permissions for the requested attribute env = Environment.getInstance() topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "userPassword") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "w", base=object_dn): self.__log.debug( "user '%s' has insufficient permissions to write %s on %s, required is %s:%s" % (user, "isLocked", object_dn, topic, "w")) raise ACLException( C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) user = ObjectProxy(object_dn) method = user.passwordMethod # Try to detect the responsible password method-class pwd_o = self.get_method_by_method_type(method) if not pwd_o: raise PasswordException( C.make_error("PASSWORD_UNKNOWN_HASH", type=method)) # Generate the new password hash using the detected method pwd_str = pwd_o.generate_password_hash(password, method) # Set the password and commit the changes user.userPassword = pwd_str user.commit()
def lockAccountPassword(self, user, object_dn): """ Locks the account password for the given DN """ # Do we have read permissions for the requested attribute env = Environment.getInstance() topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "userPassword") aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "w", base=object_dn): self.__log.debug("user '%s' has insufficient permissions to write %s on %s, required is %s:%s" % ( user, "isLocked", object_dn, topic, "w")) raise ACLException(C.make_error('PERMISSION_ACCESS', topic, target=object_dn)) # Get the object for the given dn user = ObjectProxy(object_dn) # Check if there is a userPasswort available and set if not "userPassword" in user.get_attributes(): raise PasswordException(C.make_error("PASSWORD_NO_ATTRIBUTE")) if not user.userPassword: raise PasswordException(C.make_error("PASSWORD_NOT_AVAILABLE")) # Try to detect the responsible password method-class pwd_o = self.detect_method_by_hash(user.userPassword) if not pwd_o: raise PasswordException(C.make_error("PASSWORD_METHOD_UNKNOWN")) # Lock the hash and save it user.userPassword = pwd_o.lock_account(user.userPassword) user.commit()
def registerWebhook(self, user, sender_name, mime_type): topic = "%s.webhook.%s" % (self.env.domain, mime_type) aclresolver = PluginRegistry.getInstance("ACLResolver") if not aclresolver.check(user, topic, "e"): self.log.debug("user '%s' has insufficient permissions to register webhook for mime-type %s" % (user, mime_type)) raise ACLException(C.make_error('PERMISSION_ACCESS', topic)) # check sender_name syntax if not self.name_check.match(sender_name): raise WebhookException(C.make_error('INVALID_WEBHOOK_SENDER_NAME')) # check mime-type syntax if not self.mime_type_check.match(mime_type): raise WebhookException(C.make_error('INVALID_WEBHOOK_MIME_TYPE')) # check for duplicates if mime_type not in self.__handlers: raise WebhookException(C.make_error('NO_REGISTERED_WEBHOOK_HANDLER', mime_type)) path = self.get_path(mime_type, sender_name) if self.settings.has(path): raise WebhookException(C.make_error('EXISTING_WEBHOOK_HANDLER', mime_type, name=sender_name)) self.settings.set(path, str(uuid.uuid4())) return self.getWebhookUrl(), self.settings.get(path)
def createAddGroupIfNotExists(self, user_dn, user_name, gid_number): if user_dn is None or user_name is None or gid_number is None: return index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ "_type": "PosixGroup", "gidNumber": gid_number }, {"dn": 1}) if len(res) == 0: # create group user = ObjectProxy(user_dn) group = ObjectProxy(user.get_adjusted_parent_dn(), "PosixGroup") group.cn = user_name group.description = N_("Group of user %s" % user_name) group.autoGid = False group.gidNumber = gid_number group.memberUid = [user_name] group.commit() elif len(res) == 1: group = ObjectProxy(res[0]["dn"]) if user_name not in group.memberUid: group.memberUid.append(user_name) group.commit() else: raise GosaException( C.make_error('GROUP_ID_IS_AMBIGUOUS', gid=gid_number))
def prepare(self): uuid = self.request.uri[len('/uploads/'):] manager = PluginRegistry.getInstance("UploadManager") path_settings = manager.get_path_settings(uuid) if path_settings is None: # invalid temporary path used raise web.HTTPError(status_code=404, reason="Temporary upload path does not exist") # check user and session if path_settings['user'] != self.get_secure_cookie( 'REMOTE_USER').decode('ascii'): raise web.HTTPError( status_code=403, reason="Temporary upload path was created for another user") if path_settings['session_id'] != self.get_secure_cookie( 'REMOTE_SESSION').decode('ascii'): raise web.HTTPError( status_code=403, reason="Temporary upload path was created for another session") # check if we can handle the upload type self.upload_handler = manager.get_upload_handler(path_settings['type']) if self.upload_handler is None: raise web.HTTPError( status_code=501, reason="No upload handler registered for type '%s'" % path_settings['type']) else: try: total = int(self.request.headers.get("Content-Length", "0")) except KeyError: total = 0 self.ps = MultiPartStreamer(total)
def getMethods(self, locale=None): """ Lists the all methods that are available in the domain. ================= ========================== Parameter Description ================= ========================== locale Translate __help__ strings to the desired language ================= ========================== ``Return``: dict describing all methods """ res = {} for name, info in self.commands.items(): # Only list local methods res[name] = info # Adapt to locale if required if locale: mod = PluginRegistry.getInstance(info['path'].split(".")[0]).get_locale_module() t = gettext.translation('messages', resource_filename(mod, "locale"), fallback=True, languages=[locale]) res[name]['doc'] = t.gettext(info['doc']) return res
def getMethods(self, locale=None): """ Lists the all methods that are available in the domain. ================= ========================== Parameter Description ================= ========================== locale Translate __help__ strings to the desired language ================= ========================== ``Return``: dict describing all methods """ res = {} for name, info in self.commands.items(): # Only list local methods res[name] = info # Adapt to locale if required if locale: mod = PluginRegistry.getInstance( info['path'].split(".")[0]).get_locale_module() t = gettext.translation('messages', resource_filename(mod, "locale"), fallback=True, languages=[locale]) res[name]['doc'] = t.gettext(info['doc']) return res
def shutdown(self, force=False): """ In case of HTTP connections, this command will shut down the node you're currently logged in. ================= ========================== Parameter Description ================= ========================== force force global shut down ================= ========================== ``Return``: True when shutting down """ self.log.debug("received shutdown signal - waiting for threads to terminate") PluginRegistry.getInstance('HTTPService').stop() return True
def process(self, all_props, key, value, objectType, attribute, comp=None): errors = [] index = PluginRegistry.getInstance("ObjectIndex") factory = ObjectFactory.getInstance() query = {attribute: ""} if factory.isBaseType(objectType): query["_type"] = objectType else: query["extension"] = objectType for val in value: if val in all_props[key]['value']: # do not check existing values continue in_creation = False for obj in index.currently_in_creation: if hasattr(obj, attribute) and val == getattr(obj, attribute) and objectType == obj.get_type(): # this object has been created but is not in the DB yet in_creation = True break if in_creation is True: continue query[attribute] = val if not len(index.search(query, {'dn': 1})): errors.append(dict(index=value.index(val), detail=N_("no '%(type)s' object with '%(attribute)s' property matching '%(value)s' found"), type=objectType, attribute=attribute, value=val)) return len(errors) == 0, errors
def get_missing_containers(self, new_dn, base_dn, base_type, result=[]): if new_dn == base_dn: return result self.__log.debug("collect missing containers for new object '%s' starting from '%s' (%s)" % (new_dn, base_dn, base_type)) rel_dn = new_dn[0:-len(base_dn)-1] parts = rel_dn.split(",") if len(parts) < 0: return result part = parts[-1] check_dn = "%s,%s" % (",".join(parts[-1:]), base_dn) index = PluginRegistry.getInstance("ObjectIndex") object_types = self.__factory.getObjectTypes() for sub_base in object_types[base_type]['container']: if 'FixedRDN' in object_types[sub_base]['backend_attrs'] and object_types[sub_base]['backend_attrs']['FixedRDN'] == part: base_type = sub_base break res = index.search({'dn': check_dn}, {'_type': 1}) if len(res) == 0: # create container result.append((base_type, base_dn)) if len(parts) > 1: return self.get_missing_containers(new_dn, check_dn, base_type, result=result) else: return result
def getUserDetails(self, userid): index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ '_type': 'User', 'uid': userid }, { 'sn': 1, 'givenName': 1, 'cn': 1, 'dn': 1, '_uuid': 1, '_last_changed': 1 }) if len(res) == 0: raise GOsaException(C.make_error("UNKNOWN_USER", target=userid)) cache_path = self.env.config.get('user.image-path', default="/var/lib/gosa/images") icon = "@Ligature/user" if os.path.exists( os.path.join(cache_path, res[0]['_uuid'], "jpegPhoto", "0", "64.jpg")): icon = "/images/%s/jpegPhoto/0/64.jpg?c=%s" % ( res[0]['_uuid'], res[0]["_last_changed"]) return ({ 'sn': res[0]['sn'][0], 'givenName': res[0]['givenName'][0], 'dn': res[0]['dn'], 'uuid': res[0]['_uuid'], 'icon': icon, 'cn': res[0]['cn'][0] })
def serve(self): self.mqtt.get_client().add_subscription('%s/#' % self.subtopic) self.mqtt.set_subscription_callback(self.handle_request) self.__command_registry = PluginRegistry.getInstance('CommandRegistry') self.log.info( "MQTT RPC service started, listening on subtopic '%s/#'" % self.subtopic)