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))
Beispiel #2
0
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))
Beispiel #3
0
    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)
Beispiel #4
0
    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))
Beispiel #5
0
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)))
Beispiel #6
0
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))
Beispiel #7
0
    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))
Beispiel #8
0
    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)
Beispiel #9
0
    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
Beispiel #10
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
    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
Beispiel #13
0
    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)
Beispiel #14
0
    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)
Beispiel #15
0
    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)