예제 #1
0
    def test_protocol_id(self, mocked_get_secret_key, mocked_get_public_key,
                         mocked_get_dh_secret_key):
        """
        test if pairing urls get generated with correct custom protocol ids
        """

        mocked_get_secret_key.return_value = 'X' * 64
        mocked_get_dh_secret_key.return_value = 'X' * 64
        mocked_get_public_key.return_value = 'X' * 32

        with patch.dict(config):

            # if configuration entry is not present,
            # protocol id should be lseqr

            if 'mobile_app_protocol_id' in config:
                del config['mobile_app_protocol_id']

            url = generate_pairing_url(token_type='qr',
                                       partition=1,
                                       serial='QRfoo',
                                       callback_url='foo')

            self.assertTrue(url.startswith('lseqr://'))

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

        with patch.dict(config, {'mobile_app_protocol_id': 'yolo'}):

            url = generate_pairing_url(token_type='qr',
                                       partition=1,
                                       serial='QRfoo',
                                       callback_url='foo')

            self.assertTrue(url.startswith('yolo://'))
예제 #2
0
    def test_protocol_id(
        self,
        mocked_get_secret_key,
        mocked_get_public_key,
        mocked_get_dh_secret_key,
    ):
        """
        test if pairing urls get generated with correct custom protocol ids
        """

        mocked_get_secret_key.return_value = b"X" * 64
        mocked_get_dh_secret_key.return_value = b"X" * 64
        mocked_get_public_key.return_value = b"X" * 32

        with patch.dict(config):

            # if configuration entry is not present,
            # protocol id should be lseqr

            if "mobile_app_protocol_id" in config:
                del config["mobile_app_protocol_id"]

            url = generate_pairing_url(
                token_type="qr",
                partition=1,
                serial="QRfoo",
                callback_url="foo",
            )

            assert url.startswith("lseqr://")

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

        with patch.dict(config, {"mobile_app_protocol_id": "yolo"}):

            url = generate_pairing_url(
                token_type="qr",
                partition=1,
                serial="QRfoo",
                callback_url="foo",
            )

            assert url.startswith("yolo://")
예제 #3
0
    def getInitDetail(self, params, user=None):

        """
        returns initialization details in the enrollment process
        (gets called after update method). used here to pass the
        pairing url to the user

        :param params: parameters provided by the client

        :param user: (unused)

        :raises TokenStateError: If token state is not 'initialized'

        :returns: a dict consisting of a 'pairing_url' entry, containing
            the pairing url and a 'pushtoken_pairing_url' entry containing
            a data structure used in the manage frontend in the enrollment
            process
        """

        _ = context['translate']
        response_detail = {}

        self.ensure_state('initialized')

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

        # collect data used for generating the pairing url

        serial = self.getSerial()

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

        owner = get_token_owner(self)
        if owner and owner.login and owner.realm:
            realms = [owner.realm]
        else:
            realms = self.getRealms()

        # it is guaranteed, that cb_url has a value
        # because we checked it in the update method

        cb_url = get_single_auth_policy('pushtoken_pairing_callback_url',
                                        user=owner, realms=realms)

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

        partition = self.getFromTokenInfo('partition')

        # FIXME: certificate usage

        pairing_url = generate_pairing_url(token_type='push',
                                           partition=partition,
                                           serial=serial,
                                           callback_url=cb_url,
                                           use_cert=False)

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

        self.addToInfo('pairing_url', pairing_url)
        response_detail['pairing_url'] = pairing_url

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

        # add response tabs (used in the manage view on enrollment)

        response_detail['lse_qr_url'] = {
            'description': _('Pairing URL'),
            'img': create_img(pairing_url, width=250),
            'order': 0,
            'value': pairing_url}

        response_detail['serial'] = self.getSerial()

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

        self.change_state('unpaired')

        return response_detail
예제 #4
0
파일: qrtoken.py 프로젝트: gsnbng/LinOTP
    def getInitDetail(self, params, user=None):

        _ = context['translate']
        response_detail = {}

        param_keys = set(params.keys())
        init_rollout_state_keys = {'type', 'hashlib', 'serial', '::scope::',
                                   'key_size', 'user.login', 'description',
                                   'user.realm', 'session', 'otplen', 'pin',
                                   'resConf', 'user', 'realm', 'qr'}

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

        if param_keys.issubset(init_rollout_state_keys):

            # collect data used for generating the pairing url

            serial = self.getSerial()
            # for qrtoken hashlib is ignored
            hash_algorithm = None
            pub_key = get_qrtoken_public_key()
            otp_pin_length = int(self.getOtpLen())

            owner = get_token_owner(self)
            if owner and owner.login and owner.realm:
                realms = [owner.realm]
                user = owner
            else:
                realms = self.getRealms()

            pairing_policies = ['qrtoken_pairing_callback_url',
                                'qrtoken_pairing_callback_sms']

            # it is guaranteed, that either cb_url or cb_sms has a value
            # because we checked it in the update method

            cb_url = get_single_auth_policy(pairing_policies[0],
                                            user=owner, realms=realms)
            cb_sms = get_single_auth_policy(pairing_policies[1],
                                            user=owner, realms=realms)

            cert_id = get_pairing_certificate_id(realms=realms, user=user)

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

            pairing_url = generate_pairing_url('qrtoken',
                                               server_public_key=pub_key,
                                               serial=serial,
                                               callback_url=cb_url,
                                               callback_sms_number=cb_sms,
                                               otp_pin_length=otp_pin_length,
                                               hash_algorithm=hash_algorithm,
                                               cert_id=cert_id)

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

            self.addToInfo('pairing_url', pairing_url)
            response_detail['pairing_url'] = pairing_url

            # create response tabs
            response_detail['lse_qr_url'] = {
                'description': _('QRToken Pairing Url'),
                'img': create_img(pairing_url, width=250),
                'order': 0,
                'value': pairing_url}
            response_detail['lse_qr_cert'] = {
                'description': _('QRToken Certificate'),
                'img': create_img(pairing_url, width=250),
                'order': 1,
                'value': pairing_url}

            response_detail['serial'] = self.getSerial()

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

        else:

            # make sure the call aborts, if request
            # type wasn't recognized

            raise Exception('Unknown request type for token type qr')

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

        self.change_state('pairing_url_sent')

        return response_detail
예제 #5
0
    def getInitDetail(self, params, user=None):

        _ = context['translate']
        response_detail = {}

        param_keys = set(params.keys())
        init_rollout_state_keys = set([
            'type', 'hashlib', 'serial', '::scope::', 'key_size', 'user.login',
            'description', 'user.realm', 'session', 'otplen', 'pin', 'resConf',
            'user', 'realm', 'qr'
        ])

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

        if param_keys.issubset(init_rollout_state_keys):

            # collect data used for generating the pairing url

            serial = self.getSerial()
            # for qrtoken hashlib is ignored
            hash_algorithm = None
            otp_pin_length = int(self.getOtpLen())

            owner = get_token_owner(self)
            if owner and owner.login and owner.realm:
                realms = [owner.realm]
                user = owner
            else:
                realms = self.getRealms()

            pairing_policies = [
                'qrtoken_pairing_callback_url', 'qrtoken_pairing_callback_sms'
            ]

            # it is guaranteed, that either cb_url or cb_sms has a value
            # because we checked it in the update method

            cb_url = get_single_auth_policy(pairing_policies[0],
                                            user=owner,
                                            realms=realms)
            cb_sms = get_single_auth_policy(pairing_policies[1],
                                            user=owner,
                                            realms=realms)

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

            partition = self.getFromTokenInfo('partition')

            # FIXME: certificate usage

            pairing_url = generate_pairing_url(token_type='qr',
                                               partition=partition,
                                               serial=serial,
                                               callback_url=cb_url,
                                               callback_sms_number=cb_sms,
                                               otp_pin_length=otp_pin_length,
                                               hash_algorithm=hash_algorithm,
                                               use_cert=False)

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

            self.addToInfo('pairing_url', pairing_url)
            response_detail['pairing_url'] = pairing_url

            # create response tabs
            response_detail['lse_qr_url'] = {
                'description': _('QRToken Pairing Url'),
                'img': create_img(pairing_url, width=250),
                'order': 0,
                'value': pairing_url
            }
            response_detail['lse_qr_cert'] = {
                'description': _('QRToken Certificate'),
                'img': create_img(pairing_url, width=250),
                'order': 1,
                'value': pairing_url
            }

            response_detail['serial'] = self.getSerial()

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

        else:

            # make sure the call aborts, if request
            # type wasn't recognized

            raise Exception('Unknown request type for token type qr')

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

        self.change_state('pairing_url_sent')

        return response_detail
예제 #6
0
    def getInitDetail(self, params, user=None):

        """
        returns initialization details in the enrollment process
        (gets called after update method). used here to pass the
        pairing url to the user

        :param params: parameters provided by the client

        :param user: (unused)

        :raises TokenStateError: If token state is not 'initialized'

        :returns: a dict consisting of a 'pairing_url' entry, containing
            the pairing url and a 'pushtoken_pairing_url' entry containing
            a data structure used in the manage frontend in the enrollment
            process
        """

        _ = context['translate']
        response_detail = {}

        self.ensure_state('initialized')

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

        # collect data used for generating the pairing url

        serial = self.getSerial()

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

        owner = get_token_owner(self)
        if owner and owner.login and owner.realm:
            realms = [owner.realm]
        else:
            realms = self.getRealms()

        # it is guaranteed, that cb_url has a value
        # because we checked it in the update method

        cb_url = get_single_auth_policy('pushtoken_pairing_callback_url',
                                        user=owner, realms=realms)

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

        partition = self.getFromTokenInfo('partition')

        # FIXME: certificate usage

        pairing_url = generate_pairing_url(token_type='push',
                                           partition=partition,
                                           serial=serial,
                                           callback_url=cb_url,
                                           use_cert=False)

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

        self.addToInfo('pairing_url', pairing_url)
        response_detail['pairing_url'] = pairing_url

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

        # add response tabs (used in the manage view on enrollment)

        response_detail['lse_qr_url'] = {
            'description': _('Pairing URL'),
            'img': create_img(pairing_url, width=250),
            'order': 0,
            'value': pairing_url}

        response_detail['serial'] = self.getSerial()

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

        self.change_state('unpaired')

        return response_detail
예제 #7
0
파일: qrtoken.py 프로젝트: kuffz/LinOTP
    def update(self, params):

        param_keys = set(params.keys())
        init_rollout_state_keys = set(['type', 'hashlib', 'serial',
                                       'key_size', 'user.login',
                                       'user.realm', 'session'])

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

        if param_keys.issubset(init_rollout_state_keys):

            # if param keys are in {'type', 'hashlib'} the token is
            # initialized for the first time. this is e.g. done on the
            # manage web ui. since the token doesn't exist in the database
            # yet, its rollout state must be None (that is: they data for
            # the rollout state doesn't exist yet)

            self.ensure_state(None)

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

            # collect data used for generating the pairing url

            serial = params.get('serial')
            hash_algorithm = params.get('hashlib')
            pub_key = get_qrtoken_public_key()

            cb_url = get_single_auth_policy('qrtoken_pairing_callback_url')
            cb_sms = get_single_auth_policy('qrtoken_pairing_callback_sms')

            # TODO: read from config
            otp_pin_length = None

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

            pairing_url = generate_pairing_url('qrtoken',
                                          server_public_key=pub_key,
                                          serial=serial,
                                          callback_url=cb_url,
                                          callback_sms_number=cb_sms,
                                          otp_pin_length=otp_pin_length,
                                          hash_algorithm=hash_algorithm)

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

            self.addToInfo('pairing_url', pairing_url)

            # we set the the active state of the token to False, because
            # it should not be allowed to use it for validation before the
            # pairing process is done

            self.token.LinOtpIsactive = False

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

            self.change_state('pairing_url_sent')

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

        elif 'pairing_response' in params:

            # if a pairing response is in the parameters, we guess,
            # that the request refers to a token in the state
            # 'pairing_url_sent'

            self.ensure_state('pairing_url_sent')

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

            # adding the user's public key to the token info
            # as well as the user_token_id, which is used to
            # identify the token on the user's side

            self.addToTokenInfo('user_token_id', params['user_token_id'])

            # user public key arrives in the bytes format.
            # we must convert to a string in order to be
            # able to dump it as json in the db

            b64_user_public_key = b64encode(params['user_public_key'])
            self.addToTokenInfo('user_public_key', b64_user_public_key)

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

            # create challenge through the challenge factory

            # add the content type and the challenge data to the params
            # (needed in the createChallenge method)

            params['content_type'] = CONTENT_TYPE_PAIRING
            params['data'] = self.getSerial()

            self.change_state('pairing_response_received')

            success, challenge_dict = Challenges.create_challenge(self, params)

            if not success:
                raise Exception('Unable to create challenge from '
                                'pairing response %s' %
                                params['pairing_response'])

            challenge_url = challenge_dict['message']

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

            self.addToInfo('pairing_challenge_url', challenge_url)

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

            self.change_state('pairing_challenge_sent')