def can_set_new_secret(self, account_id, client_id): """Whether account_id can set a new sipSecret on client_id. """ if self.is_superuser(account_id): return True if self._is_voip_admin(account_id): return True # We allow resetting a secret to the owner of client_id. # # The test goes like this: find voip_address to which client_id is # bound. Compare it to account_id's owner_id. For non-personal # accounts this test is bound to fail. acc = Factory.get("Account")(self._db) acc.find(account_id) client = VoipClient(self._db) client.find(client_id) address = VoipAddress(self._db) address.find(client.voip_address_id) if address.owner_entity_id == acc.owner_id: return True raise PermissionDenied("Account id=%d cannot change sipSecret of " "voip_client id=%d" % (account_id, client_id))
def generate_voip_clients(sink, addr_id2dn, *args): vc = VoipClient(db) const = Factory.get("Constants")() sink.write(container_entry_string('VOIP_CLIENT')) for entry in vc.list_voip_attributes(*args): voip_address_id = entry.pop("voip_address_id") if voip_address_id not in addr_id2dn: logger.debug("voip client %s refers to voip_address %s, but the " "latter is not in the cache. Has %s been recently " "created?", repr(entry), voip_address_id, voip_address_id) continue entry['objectClass'] = ['top', 'sipClient'] entry['sipVoipAddressDN'] = addr_id2dn[voip_address_id] if entry["sipClientType"] == text_type(const.voip_client_type_softphone): attr = "uid" assert attr in entry elif entry["sipClientType"] == text_type(const.voip_client_type_hardphone): attr = "sipMacAddress" assert "uid" not in entry else: logger.warn("Aiee! Unknown voip_client type: %s (entry: %s)", entry["sipClientType"], repr(entry)) continue dn = "{}={},{}".format(attr, entry[attr], ldapconf('VOIP_CLIENT', 'dn', None)) sink.write(entry_string(dn, entry))
def voip_address_delete(self, operator, designation): """Delete a voip_address from Cerebrum. This is useful as a precursor to removing a service. """ self.ba.can_alter_voip_address(operator.get_entity_id()) address = self._get_voip_address(designation) # Without this check users risk seeing an internal error, rather than # a detailed error message. client = VoipClient(self.db) clients = list(client.search(voip_address_id=address.entity_id)) if clients: raise CerebrumError("Won't delete address id=%s: " "it has %d voip_client(s)" % (address.entity_id, len(clients))) address_id = address.entity_id owner = address.get_owner() address.delete() return "OK, deleted voip_address id=%s (owned by %s id=%s)" % ( address_id, text_type(self.const.EntityType(owner.entity_type)), owner.entity_id)
def generate_voip_clients(sink, addr_id2dn, encoding, *args): db = Factory.get("Database")() vc = VoipClient(db) const = Factory.get("Constants")() sink.write(container_entry_string("VOIP_CLIENT")) for entry in vc.list_voip_attributes(*args): voip_address_id = entry.pop("voip_address_id") if voip_address_id not in addr_id2dn: logger.debug( "voip client %s refers to voip_address %s, but the " "latter is not in the cache. Has %s been recently " "created?", repr(entry), voip_address_id, voip_address_id, ) continue entry["objectClass"] = ["top", "sipClient"] entry["sipVoipAddressDN"] = addr_id2dn[voip_address_id] if entry["sipClientType"] == str(const.voip_client_type_softphone): attr = "uid" assert attr in entry elif entry["sipClientType"] == str(const.voip_client_type_hardphone): attr = "sipMacAddress" assert "uid" not in entry else: logger.warn("Aiee! Unknown voip_client type: %s (entry: %s)", entry["sipClientType"], repr(entry)) continue dn = "%s=%s,%s" % (attr, entry[attr], ldapconf("VOIP_CLIENT", "dn", None)) sink.write(entry_string(object2encoding(dn, encoding), object2encoding(entry, encoding)))
def generate_voip_clients(sink, addr_id2dn, *args): vc = VoipClient(db) const = Factory.get("Constants")() sink.write(container_entry_string('VOIP_CLIENT')) for entry in vc.list_voip_attributes(*args): voip_address_id = entry.pop("voip_address_id") if voip_address_id not in addr_id2dn: logger.debug( "voip client %s refers to voip_address %s, but the " "latter is not in the cache. Has %s been recently " "created?", repr(entry), voip_address_id, voip_address_id) continue entry['objectClass'] = ['top', 'sipClient'] entry['sipVoipAddressDN'] = addr_id2dn[voip_address_id] if entry["sipClientType"] == text_type( const.voip_client_type_softphone): attr = "uid" assert attr in entry elif entry["sipClientType"] == text_type( const.voip_client_type_hardphone): attr = "sipMacAddress" assert "uid" not in entry else: logger.warn("Aiee! Unknown voip_client type: %s (entry: %s)", entry["sipClientType"], repr(entry)) continue dn = "{}={},{}".format(attr, entry[attr], ldapconf('VOIP_CLIENT', 'dn', None)) sink.write(entry_string(dn, entry))
def _get_voip_client(self, designation): """Locate a voip_client by designation. Possible interpretations of designation are: + entity_id + mac address """ # Don't use _human_repr2id here, since it does not like ':' being part # of the identifier (which mac addresses definitely have) client = VoipClient(self.db) if (isinstance(designation, (int, long)) or isinstance(designation, str) and designation.isdigit()): try: client.find(int(designation)) return client except Errors.NotFoundError: pass # Try to look up by mac address try: client.clear() client.find_by_mac_address(designation) return client except (Errors.NotFoundError, AssertionError): pass raise CerebrumError("Could not uniquely determine voip_client " "from designation %s" % str(designation))
def voip_client_new(self, operator, owner_designation, client_type, mac_address, client_info, sip_enabled=True): """Create a new voip_client. If the owner (be it voip_service or person) does NOT have a voip_address, create that as well. """ self.ba.can_create_voip_client(operator.get_entity_id()) # Find the owner first... owner = self._get_voip_owner(owner_designation) if isinstance(sip_enabled, (str, unicode)): sip_enabled = self._get_boolean(sip_enabled) # Does that mac_address point to something? try: self._get_voip_client(mac_address) except CerebrumError: pass else: # As _get_voip_client raises CerebrumError, we can't # just raise that in the try clause. raise CerebrumError("Mac address %r is already bound to a " "voip_client." % mac_address) # Check that info/type_code make sense... ct = self._get_constant(client_type, self.const.VoipClientTypeCode) ci = self._get_constant(client_info, self.const.VoipClientInfoCode) if not ((ct == self.const.voip_client_type_softphone and not mac_address) or (ct == self.const.voip_client_type_hardphone and mac_address)): raise CerebrumError("Hardphones must have mac; softphones must " "not: %s -> %s" % (text_type(ct), mac_address)) # get/create an address for that owner already... address = self._get_or_create_voip_address( owner.entity_id, with_softphone=(ct == self.const.voip_client_type_softphone)) client = VoipClient(self.db) client.populate(address.entity_id, ct, sip_enabled, mac_address, ci) client.write_db() client.set_auth_data(self.const.voip_auth_sip_secret, client.generate_sip_secret()) return "OK, created voipClient %s, id=%s" % (text_type(ct), client.entity_id)
def voip_address_info(self, operator, designation): """Display information about ... ? The spec says 'all attributes': uname, cn, all URIs, e-mail, etc. @param designation: uid, id, fnr -- some way of identifying the proper voip-address. FIXME: Should be split designation into key:value, where key is one of (uname, cn, phone, entity_id/id) and value is the string interpreted according to the meaning of the first key. """ address = self._get_voip_address(designation) owner = address.get_owner() # find the clients client = VoipClient(self.db) client_ids = sorted([ text_type(x["entity_id"]) for x in client.search(voip_address_id=address.entity_id) ]) attrs = address.get_voip_attributes() result = { "entity_id": address.entity_id, "owner_entity_id": owner.entity_id, "owner_entity_type": text_type(self.const.EntityType(owner.entity_type)), "cn": attrs["cn"], "sip_uri": attrs["voipSipUri"], "sip_primary_uri": attrs["voipSipPrimaryUri"], "e164_uri": attrs["voipE164Uri"], "extension_uri": attrs["voipExtensionUri"], "traits": self._typeset_traits(address.get_traits()), "clients": client_ids, } return result
def _get_voip_client(self, designation): """Locate a voip_client by designation. Possible interpretations of designation are: + entity_id + mac address """ # Don't use _human_repr2id here, since it does not like ':' being part # of the identifier (which mac addresses definitely have) client = VoipClient(self.db) if (isinstance(designation, (int, long)) or isinstance(designation, text_type) and designation.isdigit()): try: client.find(int(designation)) return client except Errors.NotFoundError: pass # Try to look up by mac address try: client.clear() client.find_by_mac_address(designation) return client except (Errors.NotFoundError, AssertionError): pass raise CerebrumError("Could not uniquely determine voip_client " "from designation %r" % designation)
def voip_address_info(self, operator, designation): """Display information about ... ? The spec says 'all attributes': uname, cn, all URIs, e-mail, etc. @param designation: uid, id, fnr -- some way of identifying the proper voip-address. FIXME: Should be split designation into key:value, where key is one of (uname, cn, phone, entity_id/id) and value is the string interpreted according to the meaning of the first key. """ address = self._get_voip_address(designation) owner = address.get_owner() # find the clients client = VoipClient(self.db) client_ids = sorted( [text_type(x["entity_id"]) for x in client.search(voip_address_id=address.entity_id)]) attrs = address.get_voip_attributes() result = { "entity_id": address.entity_id, "owner_entity_id": owner.entity_id, "owner_entity_type": text_type(self.const.EntityType(owner.entity_type)), "cn": attrs["cn"], "sip_uri": attrs["voipSipUri"], "sip_primary_uri": attrs["voipSipPrimaryUri"], "e164_uri": attrs["voipE164Uri"], "extension_uri": attrs["voipExtensionUri"], "traits": self._typeset_traits(address.get_traits()), "clients": client_ids, } return result
def _create_default_softphone_client(self, voip_address_id): """Help function to create default softphone client for all addresses and services. """ # # If it exists, we are done... client = VoipClient(self.db) if client.search(voip_address_id=voip_address_id, client_type=self.const.voip_client_type_softphone): return client.populate( voip_address_id, self.const.voip_client_type_softphone, True, # sip_enabled by default None, # softphones don't have MACs self.const.voip_client_info_softphone) client.write_db() client.set_auth_data(self.const.voip_auth_sip_secret, client.generate_sip_secret()) self.logger.debug( "Automatically generated softphone " "client id=%s for address %s", client.entity_id, voip_address_id)
def voip_address_delete(self, operator, designation): """Delete a voip_address from Cerebrum. This is useful as a precursor to removing a service. """ self.ba.can_alter_voip_address(operator.get_entity_id()) address = self._get_voip_address(designation) # Without this check users risk seeing an internal error, rather than # a detailed error message. client = VoipClient(self.db) clients = list(client.search(voip_address_id=address.entity_id)) if clients: raise CerebrumError("Won't delete address id=%s: " "it has %d voip_client(s)" % (address.entity_id, len(clients))) address_id = address.entity_id owner = address.get_owner() address.delete() return "OK, deleted voip_address id=%s (owned by %s id=%s)" % ( address_id, self.const.EntityType( owner.entity_type), owner.entity_id)
def _create_default_softphone_client(self, voip_address_id): """Help function to create default softphone client for all addresses and services. """ # # If it exists, we are done... client = VoipClient(self.db) if client.search(voip_address_id=voip_address_id, client_type=self.const.voip_client_type_softphone): return client.populate(voip_address_id, self.const.voip_client_type_softphone, True, # sip_enabled by default None, # softphones don't have MACs self.const.voip_client_info_softphone) client.write_db() client.set_auth_data(self.const.voip_auth_sip_secret, client.generate_sip_secret()) self.logger.debug("Automatically generated softphone " "client id=%s for address %s", client.entity_id, voip_address_id)