def authenticate(devices, params, facet, check_only): """ Interactively authenticates a AuthenticateRequest using an attached U2F device. """ for device in devices[:]: try: device.open() except: devices.remove(device) try: prompted = False while devices: removed = [] for device in devices: try: return u2f.authenticate(device, params, facet, check_only) except exc.APDUError as e: if e.code == APDU_USE_NOT_SATISFIED: if check_only: sys.stderr.write('\nCorrect U2F device present!\n') sys.exit(0) if not prompted: sys.stderr.write('\nTouch the flashing U2F device ' 'to authenticate...\n') prompted = True else: removed.append(device) except exc.DeviceError: removed.append(device) devices = [d for d in devices if d not in removed] for d in removed: d.close() time.sleep(0.25) finally: for device in devices: device.close() sys.stderr.write('\nThe required U2F device is not present!\n') sys.exit(1)
def __handle_result(self, response): """ Handle the results of the different login steps (login, 2FA, U2F) and process with the next required step until the login process succeeds or fails. """ try: print(response) result_code = int(response['state']) if result_code == AUTH_FAILED: print(_("Login of user '%s' failed") % self.__username) sys.exit(1) elif result_code == AUTH_OTP_REQUIRED: key = input(_("OTP-Passkey: ")) return self.__handle_result(self.proxy.verify(key)) elif result_code == AUTH_U2F_REQUIRED and 'u2f_data' in response: for device in u2f.list_devices(): with device as dev: data = loads(response['u2f_data']) print(data) print(_("Please touch the flashing U2F device now.")) for request in data['authenticateRequests']: data = u2f.authenticate(device, request, request['appId']) res = self.proxy.verify(data) if 'counter' in res and 'touch' in res: return True return False elif result_code == AUTH_SUCCESS: return True except Exception as e: print(e) sys.exit(1) return False
def _get_u2f_response(self, reqs): """ Authenticates against yubikey with all the sign requests """ # if U2F enrolled, requests will look like # [ # { # "appId": "https://api-12345678.duosecurity.com", # "challenge": "shfdsjkaKJDGHFSKgfesgfieo2382", # "keyHandle": "fjdskabghpferwuipgt4iuytr23g4uyiawhbiu", # "sessionId": "jrt43uiq9tpgh43qu9gbhw3juipgtbw3", # "version": "U2F_V2" # }, # { ... } # ] _ = input( 'Please ensure your security key is plugged in and hit enter...') devices = get_u2f_devices() if not devices: raise IOError('no U2F devices found') LOG.info('U2F requests: %s', reqs) try: prompted = False valid_pairs = [] removed = [] # enumerate valid pairs of device: request for device in devices: LOG.debug('trying device %s', device) remove = True for request in reqs: try: return u2f.authenticate(device, json.dumps(request), request['appId']) except exc.APDUError as e: #pylint: disable=invalid-name if e.code == APDU_USE_NOT_SATISFIED: valid_pairs.append({ 'device': device, 'request': request }) LOG.debug('device %s just needs a little push', device) remove = False if not prompted: print('Please tap your security key...') prompted = True elif e.code == APDU_WRONG_DATA: LOG.debug('device/request mismatch') else: LOG.error('device %s has other problems: %s', device, e) except exc.DeviceError: LOG.error('DeviceError') if remove: LOG.debug('removing device %s', device) removed.append(device) for dev in removed: dev.close() time.sleep(0.5) # now loop only over the valid pairs while valid_pairs: for pair in valid_pairs: device, request = pair['device'], pair['request'] try: return u2f.authenticate(device, json.dumps(request), request['appId']) except exc.APDUError as e: #pylint: disable=invalid-name if e.code == APDU_USE_NOT_SATISFIED: # can't imagine getting here, but I'll leave it in if not prompted: print('Please tap your security key...') prompted = True elif e.code == APDU_WRONG_DATA: LOG.debug('device/request mismatch') valid_pairs.remove(pair) else: LOG.error('device %s has other problems: %s', device, e) time.sleep(0.25) finally: for device in devices: device.close() answer = input('No registered U2F device found, retry? [Y/n]') if answer in ('Y', 'y', ''): return self._get_u2f_response(reqs) raise RuntimeWarning('No registered U2F device found')
def _verify_single_factor(self, factor): """ Verifies a single MFA factor """ req_data = { "stateToken": self.state_token } self.logger.debug(factor) if factor['factorType'] == 'token:software:totp': if self.totp_token: self.logger.debug("Using TOTP token from command line arg") req_data['answer'] = self.totp_token else: req_data['answer'] = input('Enter MFA verification code: ') post_url = factor['_links']['verify']['href'] resp = requests.post(post_url, json=req_data) resp_json = resp.json() if 'status' in resp_json: if resp_json['status'] == "SUCCESS": return resp_json['sessionToken'] elif resp_json['status'] == "MFA_CHALLENGE" and factor['factorType'] !='u2f': print("Waiting for push verification...") while True: resp = requests.post( resp_json['_links']['next']['href'], json=req_data) resp_json = resp.json() if resp_json['status'] == 'SUCCESS': return resp_json['sessionToken'] elif resp_json['factorResult'] == 'TIMEOUT': print("Verification timed out") sys.exit(1) elif resp_json['factorResult'] == 'REJECTED': print("Verification was rejected") sys.exit(1) else: time.sleep(0.5) if factor['factorType'] == 'u2f': devices = u2f.list_devices() if len(devices) == 0: self.logger.warning("No U2F device found") sys.exit(1) challenge = dict() challenge['appId'] = resp_json['_embedded']['factor']['profile']['appId'] challenge['version'] = resp_json['_embedded']['factor']['profile']['version'] challenge['keyHandle'] = resp_json['_embedded']['factor']['profile']['credentialId'] challenge['challenge'] = resp_json['_embedded']['factor']['_embedded']['challenge']['nonce'] print("Please touch your U2F device...") auth_response = None while not auth_response: for device in devices: with device as dev: try: auth_response = u2f.authenticate(dev, challenge, resp_json['_embedded']['factor']['profile']['appId'] ) req_data.update(auth_response) resp = requests.post(resp_json['_links']['next']['href'], json=req_data) resp_json = resp.json() if resp_json['status'] == 'SUCCESS': return resp_json['sessionToken'] elif resp_json['factorResult'] == 'TIMEOUT': self.logger.warning("Verification timed out") sys.exit(1) elif resp_json['factorResult'] == 'REJECTED': self.logger.warning("Verification was rejected") sys.exit(1) except exc.APDUError as ex: if ex.code == APDU_WRONG_DATA: devices.remove(device) time.sleep(0.1) elif resp.status_code != 200: self.logger.error(resp_json['errorSummary']) sys.exit(1) else: self.logger.error(resp_json) sys.exit(1) return None
}).text) if bindres == 'true': print 'Success reg' else: print 'Fail reg' sys.stdout.flush() sign = json.loads( requests.get("http://localhost:8081/sign").text) key = sign['registeredKeys'][0] for i in key: sign[i] = key[i] print 'Auth: press button . . . ' sys.stdout.flush() auth = u2f.authenticate(device, sign, facet) auth['signatureData'] = auth['signatureData'].replace('1', '2') print auth authres = (requests.post("http://localhost:8081/verify", data={ 'data': json.dumps(auth) }).text) try: authres = json.loads(authres) assert (authres['counter'] > 0) print 'Success auth' except: print 'Fail auth' except: print 'skip'