def check_signature(callback_uri): # Extracts data from the posted request (from form of from json data according to the method used by the client) container = request.get_json(False, True, False) if request.mimetype == "application/json" else request.form bitid_uri = container["uri"] signature = container["signature"] address = container["address"] # Checks the address if not bitid.address_valid(address, USE_TESTNET): return (False, None, address, "Address is invalid or not legal") # Checks the bitid uri if not bitid.uri_valid(bitid_uri, callback_uri): return (False, None, address, "BitID URI is invalid or not legal") # Checks the signature if not bitid.signature_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): return (False, None, address, "Signature is incorrect") # Note that the previous 3 steps could also be done in 1 step with following code: # if not bitid.challenge_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): # return (False, "Sorry but something does not match") # Checks the nonce nid = bitid.extract_nonce(bitid_uri) # Tries to retrieve the nonce from db nonce = nonce_db_service.get_nonce_by_nid(nid) if nonce is None: return (False, None, address, "NONCE is illegal") elif nonce.has_expired(): nonce_db_service.delete_nonce(nonce) return (False, None, address, "NONCE has expired") # Everything is ok return (True, nonce, address, "")
def check_signature(callback_uri): # Extracts data from the posted request (from form of from json data according to the method used by the client) container = request.get_json( False, True, False) if request.mimetype == "application/json" else request.form bitid_uri = container["uri"] signature = container["signature"] address = container["address"] # Checks the address if not bitid.address_valid(address, USE_TESTNET): return (False, None, address, "Address is invalid or not legal") # Checks the bitid uri if not bitid.uri_valid(bitid_uri, callback_uri): return (False, None, address, "BitID URI is invalid or not legal") # Checks the signature if not bitid.signature_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): return (False, None, address, "Signature is incorrect") # Note that the previous 3 steps could also be done in 1 step with following code: # if not bitid.challenge_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): # return (False, "Sorry but something does not match") # Checks the nonce nid = bitid.extract_nonce(bitid_uri) # Tries to retrieve the nonce from db nonce = nonce_db_service.get_nonce_by_nid(nid) if nonce is None: return (False, None, address, "NONCE is illegal") elif nonce.has_expired(): nonce_db_service.delete_nonce(nonce) return (False, None, address, "NONCE has expired") # Everything is ok return (True, nonce, address, "")
def authenticate(self, bitid_uri=None, callback_uri=None, signature=None, address=None, errors=[]): if bitid_uri is None or callback_uri is None or signature is None or address is None: errors.append('Invalid parameters') return None # # Let's start by a bunch of validations # use_testnet = getattr(settings, 'BITID_USE_TESTNET', self.USE_TESTNET_DEFAULT) # Checks the address if not bitid.address_valid(address, use_testnet): errors.append("Address is invalid or not legal") return None # Checks the bitid uri if not bitid.uri_valid(bitid_uri, callback_uri): errors.append("BitID URI is invalid or not legal") return None # Checks the signature if not bitid.signature_valid(address, signature, bitid_uri, callback_uri, use_testnet): errors.append("Signature is incorrect") return None # Checks the nonce nid = bitid.extract_nonce(bitid_uri) # Tries to retrieve the nonce from db try: nonce = Nonce.objects.get(nid=nid) except ObjectDoesNotExist: errors.append("NONCE is illegal") return None if nonce.has_expired(): nonce.delete() errors.append("NONCE has expired") return None # # So good so far, everything seems ok # It's time to check if we have a sign out or a sign in # # Checks if a user with the given address has already been registered in db (sign in) try: user = User.objects.get(username=address) except ObjectDoesNotExist: # Here, we have an important check to do in order to avoid flooding of the users db # Let's check for a proof of goodwill (@see pybitid_demo.services.fake_tx_db_service) if not self.goodwill_check(address): errors.append("Address is invalid or not legal") return None # Creates a new user and stores it in db user = User.objects.create_user(username=address) user.save() # To finalize the authentication, let's set the user id in the nonce and update it in db nonce.user = user nonce.save() return user
def test_fail_verification_if_signature_text_doesnt_match(self): bitid_uri = bitid.build_uri(CALLBACK_URI, NONCE) bad_signature = "H4/hhdnxtXHduvCaA+Vnf0TM4UqdljTsbdIfltwx9+w50gg3mxy8WgLSLIiEjTnxbOPW9sNRzEfjibZXnWEpde4=" is_valid = bitid.signature_valid(ADDRESS, bad_signature, bitid_uri, CALLBACK_URI) self.assertFalse(is_valid)
def test_fail_verification_if_invalid_signature(self): bitid_uri = bitid.build_uri(CALLBACK_URI, NONCE) is_valid = bitid.signature_valid(ADDRESS, "garbage", bitid_uri, CALLBACK_URI) self.assertFalse(is_valid)
def test_verify_signature(self): bitid_uri = bitid.build_uri(SEC_CALLBACK_URI, NONCE) is_valid = bitid.signature_valid(ADDRESS, SIGNATURE, bitid_uri, SEC_CALLBACK_URI) self.assertTrue(is_valid)
def callback(): ''' This function validates the response sent by the client about the challenge This is the route called by the bitcoin wallet when the challenge has been signed ''' # Retrieves the callback uri callback_uri = get_callback_uri() # Extracts data from the posted request (from form of from json data according to the method used by the client) container = request.get_json( False, True, False) if request.mimetype == "application/json" else request.form bitid_uri = container["uri"] signature = container["signature"] address = container["address"] # # Let's start by a bunch of validations # # Checks the address if not bitid.address_valid(address, USE_TESTNET): return jsonify(message="Address is invalid or not legal"), 401 # Checks the bitid uri if not bitid.uri_valid(bitid_uri, callback_uri): return jsonify(message="BitID URI is invalid or not legal"), 401 # Checks the signature if not bitid.signature_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): return jsonify(message="Signature is incorrect"), 401 # Note that the previous 3 steps could also be done in 1 step with following code: # if not bitid.challenge_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): # return jsonify(message = "Sorry but something does not match"), 401 # Checks the nonce nid = bitid.extract_nonce(bitid_uri) # Tries to retrieve the nonce from db nonce = nonce_db_service.get_nonce_by_nid(nid) if nonce is None: return jsonify(message="NONCE is illegal"), 401 elif nonce.has_expired(): nonce_db_service.delete_nonce(nonce) return jsonify(message="NONCE has expired"), 401 # # So good so far, everything seems ok # It's time to check if we have a sign out or a sign in # # Checks if a user with the given address has already been registered in db (sign in) user = user_db_service.get_user_by_address(address) # If we have a sign out if user is None: # Here, we have an important check to do in order to avoid flooding of the users db # Let's check for a proof of goodwill (@see pybitid_demo.services.fake_tx_db_service) if not tx_db_service.check_proof_of_goodwill(address): return jsonify(message="Address is invalid or not legal"), 401 else: # Creates a new user and stores it in db user = User(address) if not user_db_service.create_user(user): return jsonify( message="Ooops ! Something went wrong but we work on it" ), 500 # To finalize the authentication, let's set the user id in the nonce and update it in db nonce.uid = user.uid if not nonce_db_service.update_nonce(nonce): return jsonify( message="Ooops ! Something went wrong but we work on it"), 500 # Everything was ok: user is authenticated return jsonify(address=address, nonce=nonce.sid)
def callback(): ''' This function validates the response sent by the client about the challenge This is the route called by the bitcoin wallet when the challenge has been signed ''' # Retrieves the callback uri callback_uri = get_callback_uri() # Extracts data from the posted request (from form of from json data according to the method used by the client) container = request.get_json(False, True, False) if request.mimetype == "application/json" else request.form bitid_uri = container["uri"] signature = container["signature"] address = container["address"] # # Let's start by a bunch of validations # # Checks the address if not bitid.address_valid(address, USE_TESTNET): return jsonify(message = "Address is invalid or not legal"), 401 # Checks the bitid uri if not bitid.uri_valid(bitid_uri, callback_uri): return jsonify(message = "BitID URI is invalid or not legal"), 401 # Checks the signature if not bitid.signature_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): return jsonify(message = "Signature is incorrect"), 401 # Note that the previous 3 steps could also be done in 1 step with following code: # if not bitid.challenge_valid(address, signature, bitid_uri, callback_uri, USE_TESTNET): # return jsonify(message = "Sorry but something does not match"), 401 # Checks the nonce nid = bitid.extract_nonce(bitid_uri) # Tries to retrieve the nonce from db nonce = nonce_db_service.get_nonce_by_nid(nid) if nonce is None: return jsonify(message = "NONCE is illegal"), 401 elif nonce.has_expired(): nonce_db_service.delete_nonce(nonce) return jsonify(message = "NONCE has expired"), 401 # # So good so far, everything seems ok # It's time to check if we have a sign out or a sign in # # Checks if a user with the given address has already been registered in db (sign in) user = user_db_service.get_user_by_address(address) # If we have a sign out if user is None: # Here, we have an important check to do in order to avoid flooding of the users db # Let's check for a proof of goodwill (@see pybitid_demo.services.fake_tx_db_service) if not tx_db_service.check_proof_of_goodwill(address): return jsonify(message = "Address is invalid or not legal"), 401 else: # Creates a new user and stores it in db user = User(address) if not user_db_service.create_user(user): return jsonify(message = "Ooops ! Something went wrong but we work on it"), 500 # To finalize the authentication, let's set the user id in the nonce and update it in db nonce.uid = user.uid if not nonce_db_service.update_nonce(nonce): return jsonify(message = "Ooops ! Something went wrong but we work on it"), 500 # Everything was ok: user is authenticated return jsonify(address = address, nonce = nonce.sid)