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://'))
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://")
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
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
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
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
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')