Beispiel #1
0
    def test_blocking_all_uris(self):
        """
        test that the uris will be blocked and unblocked after delay
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # ------------------------------------------------------------------ --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
                            tries=1,
                            resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list("uri://1, uri://2, uri://3, ")

        # ------------------------------------------------------------------ --

        # check that all uris are blocked

        with freeze_time("2012-01-14 12:00:00"):

            # -------------------------------------------------------------- --

            # block all uris

            for uri in res_sched.next():
                res_sched.block(uri, delay=30)

            # -------------------------------------------------------------- --

            # verify that all uris are blocked and none is iterated

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            self.assertTrue(len(uris) == 0)

        # one minute later
        with freeze_time("2012-01-14 12:01:00"):

            # -------------------------------------------------------------- --

            # verify that all uris are un blocked after the delay

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            self.assertTrue('uri://1' in uris)
            self.assertTrue('uri://2' in uris)
            self.assertTrue('uri://3' in uris)

        return
Beispiel #2
0
    def test_blocking_all_uris(self):
        """
        test that the uris will be blocked and unblocked after delay
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # ------------------------------------------------------------------ --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
            tries=1, resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list("uri://1, uri://2, uri://3, ")

        # ------------------------------------------------------------------ --

        # check that all uris are blocked

        with freeze_time("2012-01-14 12:00:00"):

            # -------------------------------------------------------------- --

            # block all uris

            for uri in res_sched.next():
                res_sched.block(uri, delay=30)

            # -------------------------------------------------------------- --

            # verify that all uris are blocked and none is iterated

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            self.assertTrue(len(uris) == 0)

        # one minute later
        with freeze_time("2012-01-14 12:01:00"):

            # -------------------------------------------------------------- --

            # verify that all uris are un blocked after the delay

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            self.assertTrue('uri://1' in uris)
            self.assertTrue('uri://2' in uris)
            self.assertTrue('uri://3' in uris)

        return
Beispiel #3
0
    def test_uris_retry(self):
        """
        test all uris will be n-times tried
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # -------------------------------------------------------------- --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
            tries=3, resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list(
            "bluri://1, bluri://2, bluri://3, ")

        # -------------------------------------------------------------- --

        # check that the retry will be run through all uris n-times

        uris = []
        for uri in res_sched.next():
            uris.append(uri)

        self.assertTrue(len(uris) == 9)

        # -------------------------------------------------------------- --

        # check that every uri is registered in the global registry

        for _key, val in res_sched.resource_registry.registry.items():
            value, b_ind, b_count = val

            self.assertTrue(value is None)
            self.assertTrue(b_ind == 0)
            self.assertTrue(b_count == 0)

        return
Beispiel #4
0
    def test_uris_retry(self):
        """
        test all uris will be n-times tried
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # -------------------------------------------------------------- --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
                            tries=3,
                            resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list("bluri://1, bluri://2, bluri://3, ")

        # -------------------------------------------------------------- --

        # check that the retry will be run through all uris n-times

        uris = []
        for uri in res_sched.next():
            uris.append(uri)

        self.assertTrue(len(uris) == 9)

        # -------------------------------------------------------------- --

        # check that every uri is registered in the global registry

        for _key, val in res_sched.resource_registry.registry.items():
            value, b_ind, b_count = val

            self.assertTrue(value is None)
            self.assertTrue(b_ind == 0 )
            self.assertTrue(b_count == 0)

        return
Beispiel #5
0
    def sendSMS(self, message=None, transactionid=None):
        '''
        send sms

        :param message: the sms submit message - could contain placeholders
         like <otp> or <serial>
        :type message: string

        :return: submitted message
        :rtype: string

        '''

        success = None

        if not message:
            message = "<otp>"

        if not SMSPROVIDER_IMPORTED:
            raise Exception("The SMSProvider could not be imported. Maybe you "
                            "didn't install the package (Debian "
                            "linotp-smsprovider or PyPI SMSProvider)")

        # we require the token owner to get the phone number and the provider
        owner = get_token_owner(self)

        phone = self.get_mobile_number(owner)

        otp = self.getNextOtp()
        serial = self.getSerial()

        if '<otp>' not in message:
            log.error('Message unconfigured: prepending <otp> to message')
            if isinstance(message, basestring):
                message = "<otp> %s" % message
            else:
                message = "<otp> %r" % message

        message = message.replace("<otp>", otp)
        message = message.replace("<serial>", serial)

        if transactionid:
            message = message.replace("<transactionid>", transactionid)

        log.debug("[sendSMS] sending SMS to phone number %s " % phone)

        realm = None
        realms = self.getRealms()
        if realms:
            realm = realms[0]

        # we require the token owner to get the phone number and the provider
        owner = get_token_owner(self)
        if not owner or not owner.login:
            log.warning("[sendSMS] Missing required token owner")

        # ------------------------------------------------------------------ --

        # load providers for the user

        providers = get_provider_from_policy('sms', realm=realm, user=owner)

        # remember if at least one provider could be accessed
        available = False

        res_scheduler = ResourceScheduler(tries=1, uri_list=providers)
        for provider_name in res_scheduler.next():

            sms_provider = loadProvider('sms', provider_name=provider_name)

            if not sms_provider:
                raise Exception('unable to load provider')

            try:

                success = sms_provider.submitMessage(phone, message)

                available = True
                break

            except ProviderNotAvailable as exx:
                log.error('Provider not available %r', provider_name)
                res_scheduler.block(provider_name, delay=30)

        if not available:
            raise AllResourcesUnavailable("unable to connect to any "
                                          "SMSProvider %r" % providers)

        log.debug("[sendSMS] message submitted")

        # # after submit set validity time
        self.setValidUntil()

        # return OTP for selftest purposes
        return success, message
Beispiel #6
0
    def checkOtp(self, anOtpVal, counter, window, options=None):
        '''
        Here we contact the Yubico Cloud server to validate the OtpVal.
        '''

        pparams = {}

        yubico_url = getFromConfig("yubico.url", FALLBACK_YUBICO_URL)

        if yubico_url == DEPRECATED_YUBICO_URL:

            log.warning("Usage of YUBICO_URL %r is deprecated!! ",
                        DEPRECATED_YUBICO_URL)

            # setups with old YUBICO URLS will be broken on yubico side
            # after 3th of February 2019
            third_feb_2019 = datetime.datetime(year=2019, month=2, day=3)

            if datetime.datetime.now() >= third_feb_2019:
                raise Exception("Usage of YUBICO_URL %r is deprecated!! " %
                                DEPRECATED_YUBICO_URL)

        apiId = getFromConfig("yubico.id") or DEFAULT_CLIENT_ID
        apiKey = getFromConfig("yubico.secret") or DEFAULT_API_KEY

        if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:
            log.warning("Usage of default apiKey or apiId not recomended!!")
            log.warning("Please register your own apiKey and apiId at "
                                                        "yubico website !!")
            log.warning("Configure of apiKey and apiId at the "
                                             "linotp manage config menue!!")

        tokenid = self.getFromTokenInfo("yubico.tokenid")
        if len(anOtpVal) < 12:
            log.warning("[checkOtp] The otpval is too short: %r" % anOtpVal)
            return -1

        if anOtpVal[:12] != tokenid:
            log.warning("[checkOtp] the tokenid in the OTP value does "
                        "not match the assigned token!")
            return -1

        timeout = getFromConfig("yubico.timeout")
        if timeout:
            pparams['timeout']= parse_timeout(timeout)

        nonce = binascii.hexlify(os.urandom(20))

        p = urllib.urlencode({
            'nonce': nonce,
            'otp':anOtpVal,
            'id':apiId
        })

        yubico_urls = [x.strip() for x in yubico_url.split(',')]

        res_scheduler = ResourceScheduler(
                        tries=2, uri_list=yubico_urls)


        for uri in res_scheduler.next():

            try:
                URL = "%s?%s" % (uri, p)

                response = requests.get(URL, **pparams)

                if response.ok:
                    return self._check_yubico_response(
                                nonce, apiKey, response.content)

                log.info("Failed to validate yubico request %r", response)

                return -1


            except (Timeout, ConnectTimeout, ReadTimeout,
                    ConnectionError, TooManyRedirects) as exx:

                log.exception('resource %r not available!', uri)

                # mark the url as blocked

                res_scheduler.block(uri, delay=30)

                log.error("[checkOtp] Error getting response from "
                          "Yubico Cloud Server (%r)" % uri)


            except Exception as exx:

                log.exception('unknown exception for uri %r!', uri)

                raise exx

        # ------------------------------------------------------------------ --

        # if we reach here, no resource has been availabel

        log.error('non of the resources %r available!', yubico_urls)

        raise AllResourcesUnavailable('non of the resources %r available!' %
                                      yubico_urls)
Beispiel #7
0
    def test_blocking_counter(self):
        """
        test that if for one entry the blocking counter increments at max of 8

        run a connection timeout simulation by rising an exception for a
        special uri - we have to run many more times as the blocking url
        is not involved in every run. Thus we count the number when it is
        involved and terminate after 10 calls. THe max though should be t 8.
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # -------------------------------------------------------------- --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
            tries=1, resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list(
            "bluri://1, bluri://2, bluri://3, ")

        the_blocked_one = res_sched.uri_list[1]

        # -------------------------------------------------------------- --

        # run the loop

        raise_counter = 0
        i = 0

        while raise_counter < 10:
            i += 1
            with freeze_time(datetime.datetime.utcnow() +
                             datetime.timedelta(minutes=i)):

                try:
                    for uri in res_sched.next():

                        if uri == the_blocked_one:
                            raise DummyException()

                except DummyException:
                    raise_counter += 1
                    res_sched.block(the_blocked_one, 30, immediately=True)

        # -------------------------------------------------------------- --

        # check the result

        for key, val in res_sched.resource_registry.registry.items():
            value, b_ind, b_count = val
            if b_ind == 1:
                assert value is not None
                assert key == the_blocked_one
                assert b_count == 8

            else:
                assert value is None
                assert b_count == 0
                assert b_ind == 0

        return
Beispiel #8
0
    def test_blocking_one_uri(self):
        """
        test that if one entry is blocked it will not be in the iteration list
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # -------------------------------------------------------------- --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
            tries=3, resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list(
            "bluri://1, bluri://2, bluri://3, ")

        the_blocked_one = res_sched.uri_list[1]

        with freeze_time("2012-01-14 12:00:00"):

            # -------------------------------------------------------------- --

            # block the second entry

            res_sched.block(the_blocked_one, 30, immediately=True)

            # -------------------------------------------------------------- --

            # verify that the second entry will not be iterated

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            self.assertTrue(the_blocked_one not in uris)

            # -------------------------------------------------------------- --

            # verify that the retry is done 3 times for the other two

            self.assertTrue(len(uris) == 6)

            # -------------------------------------------------------------- --

            # verify that the blocked one is marked as blocked in the registry

            for key, val in res_sched.resource_registry.registry.items():
                value, b_ind, b_count = val

                if key == the_blocked_one:
                    self.assertTrue(value is not None)
                    self.assertTrue(b_ind == 1)
                    self.assertTrue(b_count == 0)

                else:
                    self.assertTrue(value is None)

        # one minute later

        with freeze_time("2012-01-14 12:01:00"):

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            # -------------------------------------------------------------- --

            # verify that the former blocked one is now not more blocked

            self.assertTrue(the_blocked_one in uris)

            # -------------------------------------------------------------- --

            # verify that the former blocked one is as well unblocked in the
            # registry

            for _key, val in res_sched.resource_registry.registry.items():
                value, _b_ind, _b_count = val
                self.assertTrue(value is None)

        return
Beispiel #9
0
    def _http_push(self, challenge, gda, transactionId):
        """
        push the notification over http by calling the requests POST api

        :param message: the notification message
        :param gda: the global device identifier
        :return: tuple with response status and content / reason
        """

        # ----------------------------------------------------------------- --

        # Challenge Service expectes the following document

        # {"challenge": {
        #    "transactionId": "string",
        #    "gda": "string",
        #    "challenge": "string" }
        # }

        params = {}
        params['transactionId'] = transactionId
        params['gda'] = gda
        params['challenge'] = challenge

        json_challenge = {"challenge": params}

        #
        # using **args for the timeout parameter
        #

        pparams = {}
        if self.timeout:
            pparams['timeout'] = self.timeout

        # submitting the json body requires the correct HTTP headers
        # with contenttype declaration:

        headers = {
            'Content-type': 'application/json',
            'Accept': 'text/plain'}

        if self.proxy:
            pparams['proxies'] = self.proxy

        #
        # we check if the client certificate exists, which is
        # referenced as a filename
        #

        if self.client_cert and os.path.isfile(self.client_cert):
            pparams['cert'] = self.client_cert

        server_cert = self.server_cert
        if server_cert is not None:
            # Session.post() doesn't like unicode values in Session.verify
            if isinstance(server_cert, unicode):
                server_cert = server_cert.encode('utf-8')

            pparams['verify'] = server_cert

        # ------------------------------------------------------------------ --

        # schedule all resources

        res_scheduler = ResourceScheduler(
                                tries=2, uri_list=self.push_server_urls)

        # ------------------------------------------------------------------ --

        # location to preserve the last exception, so we can report this if
        # every resource access failed

        last_exception = None

        # ------------------------------------------------------------------ --

        # iterate through all resources

        for uri in res_scheduler.next():

            try:

                response = requests.post(
                    uri, json=json_challenge, headers=headers, **pparams)

                if not response.ok:
                    result = response.reason
                else:
                    result = response.content

                return response.ok, result

            except (Timeout, ConnectTimeout, ReadTimeout,
                    ConnectionError, TooManyRedirects) as exx:

                log.exception('resource %r not available!', uri)

                # mark the url as blocked

                res_scheduler.block(uri, delay=30)

                # and preserve the exception, so that we are able to raise this
                # when no resources are available at all

                last_exception = exx

        # ------------------------------------------------------------------ --

        # if we reach here, no resource has been availabel

        log.error('non of the resources %r available!', self.push_server_urls)

        if last_exception:
            log.error("Last Exception was %r", exx)
            raise last_exception

        raise AllResourcesUnavailable('non of the resources %r available!' %
                        self.push_server_urls)
Beispiel #10
0
    def test_blocking_counter(self):
        """
        test that if for one entry the blocking counter increments at max of 8

        run a connection timeout simulation by rising an exception for a
        special uri - we have to run many more times as the blocking url
        is not involved in every run. Thus we count the number when it is
        involved and terminate after 10 calls. THe max though should be t 8.
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # -------------------------------------------------------------- --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
            tries=1, resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list(
            "bluri://1, bluri://2, bluri://3, ")

        the_blocked_one = res_sched.uri_list[1]

        # -------------------------------------------------------------- --

        # run the loop

        raise_counter = 0
        i = 0

        while raise_counter < 10:
            i += 1
            with freeze_time(
                datetime.datetime.utcnow() + datetime.timedelta(minutes=i)):

                try:
                    for uri in res_sched.next():

                        if uri == the_blocked_one:
                            raise DummyException()

                except DummyException:
                    raise_counter += 1
                    res_sched.block(the_blocked_one, 30, immediately=True)

        # -------------------------------------------------------------- --

        # check the result

        for key, val in res_sched.resource_registry.registry.items():
            value, b_ind, b_count = val
            if b_ind == 1:
                assert value is not None
                assert key == the_blocked_one
                assert b_count == 8

            else:
                assert value is None
                assert b_count == 0
                assert b_ind == 0

        return
Beispiel #11
0
    def test_blocking_one_uri(self):
        """
        test that if one entry is blocked it will not be in the iteration list
        """

        # -------------------------------------------------------------- --

        # setup a local registry for the test

        DictResourceRegistry.registry = {}

        # -------------------------------------------------------------- --

        # setup the Resource Scheduler

        res_sched = ResourceScheduler(
                            tries=3,
                            resource_registry_class=DictResourceRegistry)

        res_sched.uri_list = string_to_list("bluri://1, bluri://2, bluri://3, ")

        the_blocked_one = res_sched.uri_list[1]

        with freeze_time("2012-01-14 12:00:00"):

            # -------------------------------------------------------------- --

            # block the second entry

            res_sched.block(the_blocked_one, 30, immediately=True)

            # -------------------------------------------------------------- --

            # verify that the second entry will not be iterated

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            self.assertTrue(the_blocked_one not in uris)

            # -------------------------------------------------------------- --

            # verify that the retry is done 3 times for the other two

            self.assertTrue(len(uris) == 6)

            # -------------------------------------------------------------- --

            # verify that the blocked one is marked as blocked in the registry

            for key, val in res_sched.resource_registry.registry.items():
                value, b_ind, b_count = val

                if key == the_blocked_one:
                    self.assertTrue(value is not None)
                    self.assertTrue(b_ind == 1)
                    self.assertTrue(b_count == 0)

                else:
                    self.assertTrue(value is None)

        # one minute later

        with freeze_time("2012-01-14 12:01:00"):

            uris = []
            for uri in res_sched.next():
                uris.append(uri)

            # -------------------------------------------------------------- --

            # verify that the former blocked one is now not more blocked

            self.assertTrue(the_blocked_one in uris)

            # -------------------------------------------------------------- --

            # verify that the former blocked one is as well unblocked in the
            # registry

            for _key, val in res_sched.resource_registry.registry.items():
                value, _b_ind, _b_count = val
                self.assertTrue(value is None)

        return
Beispiel #12
0
    def checkOtp(self, anOtpVal, counter, window, options=None):
        '''
        Here we contact the Yubico Cloud server to validate the OtpVal.
        '''

        pparams = {}

        yubico_url = getFromConfig("yubico.url", FALLBACK_YUBICO_URL)

        if yubico_url == DEPRECATED_YUBICO_URL:

            log.warning("Usage of YUBICO_URL %r is deprecated!! ",
                        DEPRECATED_YUBICO_URL)

            # setups with old YUBICO URLS will be broken on yubico side
            # after 3th of February 2019
            third_feb_2019 = datetime.datetime(year=2019, month=2, day=3)

            if datetime.datetime.now() >= third_feb_2019:
                raise Exception("Usage of YUBICO_URL %r is deprecated!! " %
                                DEPRECATED_YUBICO_URL)

        apiId = getFromConfig("yubico.id") or DEFAULT_CLIENT_ID
        apiKey = getFromConfig("yubico.secret") or DEFAULT_API_KEY

        if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:
            log.warning("Usage of default apiKey or apiId not recomended!!")
            log.warning("Please register your own apiKey and apiId at "
                        "yubico website !!")
            log.warning("Configure of apiKey and apiId at the "
                        "linotp manage config menue!!")

        tokenid = self.getFromTokenInfo("yubico.tokenid")
        if len(anOtpVal) < 12:
            log.warning("[checkOtp] The otpval is too short: %r" % anOtpVal)
            return -1

        if anOtpVal[:12] != tokenid:
            log.warning("[checkOtp] the tokenid in the OTP value does "
                        "not match the assigned token!")
            return -1

        timeout = getFromConfig("yubico.timeout")
        if timeout:
            pparams['timeout'] = parse_timeout(timeout)

        nonce = binascii.hexlify(os.urandom(20))

        p = urllib.urlencode({'nonce': nonce, 'otp': anOtpVal, 'id': apiId})

        yubico_urls = [x.strip() for x in yubico_url.split(',')]

        res_scheduler = ResourceScheduler(tries=2, uri_list=yubico_urls)

        for uri in res_scheduler.next():

            try:
                URL = "%s?%s" % (uri, p)

                response = requests.get(URL, **pparams)

                if response.ok:
                    return self._check_yubico_response(nonce, apiKey,
                                                       response.content)

                log.info("Failed to validate yubico request %r", response)

                return -1

            except (Timeout, ConnectTimeout, ReadTimeout, ConnectionError,
                    TooManyRedirects) as exx:

                log.exception('resource %r not available!', uri)

                # mark the url as blocked

                res_scheduler.block(uri, delay=30)

                log.error("[checkOtp] Error getting response from "
                          "Yubico Cloud Server (%r)" % uri)

            except Exception as exx:

                log.exception('unknown exception for uri %r!', uri)

                raise exx

        # ------------------------------------------------------------------ --

        # if we reach here, no resource has been availabel

        log.error('non of the resources %r available!', yubico_urls)

        raise AllResourcesUnavailable('non of the resources %r available!' %
                                      yubico_urls)