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)
Beispiel #2
0
    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
Beispiel #3
0
 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')
Beispiel #4
0
    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
Beispiel #5
0
                                         }).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'