def test_user_auth_success_otp(self): """The authentication should be succeeded with OTP.""" from pyotp.totp import TOTP provider = TOTP(self.secret.secret) user = self.backend.authenticate(username=self.users[0].username, password="******", otp_auth=provider.now()) self.assertEqual(user, self.users[0])
def test_user_auth_failure_otp(self): """The authentication should be failed with OTP.""" from pyotp.totp import TOTP provider = TOTP(self.secret.secret) user = self.backend.authenticate( username=self.users[0].username, password="******", otp_auth=str( (int(provider.now()) + 1) % 1000000).zfill(provider.digits)) self.assertIsNone(user)
def totp_verify(request): """ View method for path '/sso/totp/verify' """ #authenticate the request if not _auth_bearer(request): #not authenticated return FORBIDDEN_RESPONSE #get the useremail, idp and totpcode data = json.loads(request.body.decode()) logger.debug("verify totp code.{}".format(data)) user_email = data.get("email") if not user_email: return HttpResponse(content="Email is missint", status=400) idp = data.get("idp") if not idp: return HttpResponse(content="Idp is missint", status=400) totpcode = data.get("totpCode") if not totpcode: return HttpResponse(content="Totp code is missint", status=400) user_totp = models.UserTOTP.objects.filter(email=user_email, idp=idp).first() if not user_totp: #can't find user totp object return HttpResponse( content="User({1}:{0})'s totp secret is missing".format( user_email, idp), status=400) if settings.TOTP_CHECK_LAST_CODE and totpcode == user_totp.last_verified_code: #totpcode is the last checked totp code, return CONFLICT_RESPONSE totp = TOTP(user_totp.secret_key, digits=user_totp.digits, digest=utils.get_digest_function(user_totp.algorithm)[1], name=user_totp.name, issuer=user_totp.issuer, interval=user_totp.timestep) if totp.verify(totpcode, valid_window=settings.TOTP_VALIDWINDOW): #verified user_totp.last_verified_code = totpcode user_totp.last_verified = timezone.now() user_totp.save(update_fields=["last_verified", "last_verified_code"]) logger.debug("Succeed to verify totp code.{}".format(data)) return SUCCEED_RESPONSE else: #verify failed. logger.debug("Failed to verify totp code.{}".format(data)) return CONFLICT_RESPONSE
def enter_totp(self, otp_secret): self.save_screen_shot("ENTER_ONE_TIME_PASS_CODE") if otp_secret is None: raise Exception("REQUIRED_TOTP_SECRET_IS_EMPTY") code = TOTP(otp_secret).now() WebDriverWait(self.driver, self.config.timeout_seconds)\ .until(expected_conditions.element_to_be_clickable((By.ID, GoogleTokenPageElements.TOTPPIN))) self.driver.find_element_by_id(GoogleTokenPageElements.TOTPPIN).send_keys(code) self.driver.find_element_by_id(GoogleTokenPageElements.SUBMIT).click() return True
def generatereq(self): """ Generate strings for authentication. Message format: ( req_num_connection_number (HEX, 2 bytes) + used_remote_listening_port (HEX, 4 bytes) + sha1(cert_pub), pyotp.TOTP(pri_sha1 + ip_in_hex_form + salt), main_pw, # must send in encrypted form to avoid MITM ip_in_hex_form, salt, [cert1, cert2 (only when ptproxy is enabled)] ) """ msg = [""] number_in_hex = "%02X" % min((self.req_num), 255) msg[0] += number_in_hex msg[0] += "%04X" % self.remote_port msg[0] += self.clientpub_sha1 # print(self.clientpub_sha1) # print("======================") if self.ipv6 == "": myip = int2base(self.ip) else: myip = int2base( int( binascii.hexlify( socket.inet_pton(socket.AF_INET6, self.ipv6)), 16)) + "G" salt = binascii.hexlify(os.urandom(16)).decode("ASCII") h = hashlib.sha256() h.update((self.clientpri_sha1 + myip + salt + number_in_hex).encode('utf-8')) msg.append(TOTP(bytes(h.hexdigest(), "UTF-8")).now()) msg.append(binascii.hexlify(self.main_pw).decode("ASCII")) # print(self.main_pw) # print("======================") msg.append(myip) msg.append(salt) if 1 <= self.obfs_level <= 2: certs_byte = urlsafe_b64_short_encode(self.certs_send) msg.extend([certs_byte[:50], certs_byte[50:]]) elif self.obfs_level == 3: msg.append(''.join( [random.choice(ascii_letters) for _ in range(5)])) if Mode == "VPS": req_type = "00" elif Mode == "GAE": req_type = "01" msg.append(req_type + PROTO_VERSION) return '.'.join(msg)
def create_new_user(user_id): user = DATABASE.save_new_user(user_id) qr_code = TOTP(user['secret']).provisioning_uri(user['user_id'], issuer_name=APP_NAME) qr_code_url = f'https://api.qrserver.com/v1/create-qr-code/?size=150x150&data={qr_code}' return { 'user': user['user_id'], 'qr_code': qr_code, 'qr_code_url': qr_code_url, }
def two_factor_input(): if current_user.is_authenticated or 'id' not in session: return redirect(url_for('proute.index')) contributor = Contributor.query.get(session['id']) if contributor is None: return redirect(url_for('proute.index')) form = GetTotp() if form.validate_on_submit(): if TOTP(contributor.totp_key).verify(int(form.totp_code.data), valid_window=5): login_user(contributor, remember=session['remember_me']) flash("Congratulations, you are now logged in!") return redirect(url_for('proute.index')) else: flash("Oops, the pin was wrong") form.totp_code.data = None return render_template('two_factor_input.html', form=form, inst="Code was wrong, try again?") return render_template('two_factor_input.html', form=form, inst="Enter Auth Code")
def get_current_totp_code(totp_key): return TOTP(totp_key).now()
def verify_totp_code(totp_key, totp_code): return TOTP(totp_key).verify(totp_code)
def verify_user_code(user_id, code): user = DATABASE.get_user(user_id) return TOTP(user['secret']).verify(code)
def parse_uri(uri): """ Parses the provisioning URI for the OTP; works for either TOTP or HOTP. See also: https://github.com/google/google-authenticator/wiki/Key-Uri-Format :param uri: the hotp/totp URI to parse :type uri: str :returns: OTP object :rtype: OTP """ # Secret (to be filled in later) secret = None # Data we'll parse to the correct constructor otp_data = {} # Parse with URLlib parsed_uri = urlparse(unquote(uri)) if parsed_uri.scheme != 'otpauth': raise ValueError('Not an otpauth URI') # Parse issuer/accountname info accountinfo_parts = split(':|%3A', parsed_uri.path[1:], maxsplit=1) if len(accountinfo_parts) == 1: otp_data['name'] = accountinfo_parts[0] else: otp_data['issuer'] = accountinfo_parts[0] otp_data['name'] = accountinfo_parts[1] # Parse values for key, value in parse_qsl(parsed_uri.query): if key == 'secret': secret = value elif key == 'issuer': if 'issuer' in otp_data and otp_data[ 'issuer'] is not None and otp_data['issuer'] != value: raise ValueError( 'If issuer is specified in both label and parameters, it should be equal.' ) otp_data['issuer'] = value elif key == 'algorithm': if value == 'SHA1': otp_data['digest'] = hashlib.sha1 elif value == 'SHA256': otp_data['digest'] = hashlib.sha256 elif value == 'SHA512': otp_data['digest'] = hashlib.sha512 else: raise ValueError( 'Invalid value for algorithm, must be SHA1, SHA256 or SHA512' ) elif key == 'digits': digits = int(value) if digits not in [6, 8]: raise ValueError('Digits may only be 6 or 8') otp_data['digits'] = digits elif key == 'period': otp_data['interval'] = value elif key == 'counter': otp_data['initial_count'] = value else: raise ValueError('{} is not a valid parameter'.format(key)) if not secret: raise ValueError('No secret found in URI') # Create objects if parsed_uri.netloc == 'totp': return TOTP(secret, **otp_data) elif parsed_uri.netloc == 'hotp': return HOTP(secret, **otp_data) raise ValueError('Not a supported OTP type')