hivesolutions / appier-extras

Appier on Steroids
http://appier-extras.hive.pt
2 stars 3 forks source link

Two Factor (2FA) authentication #26

Closed joamag closed 5 months ago

joamag commented 6 years ago

Description

Sometimes, it's relevant to increase the security of the authentication process by using 2FA, for instance, with a one-time password.

The additional layer of security can prevent attacks from malicious agents using a brute force password-targeted attack,

Implementation

Some libraries for Python can handle the hardcore work (e.g., pyotp).

Inspiration

Code

OTP Example

According to ChatGPT, this would be a valid implementation for a OTP based approach (eg: Google Authenticator).

import pyotp

def generate_secret():
    # This will generate a fresh secret key
    secret = pyotp.random_base32()
    print(f"Secret key for user: {secret}")
    return secret

def generate_otp(secret):
    # Generate a TOTP object
    totp = pyotp.TOTP(secret)
    return totp.now()  # Generate a OTP based on the current time

def verify_otp(secret, user_input):
    # Verifies user input against the current OTP
    totp = pyotp.TOTP(secret)
    return totp.verify(user_input)

# Usage
user_secret = generate_secret()
otp = generate_otp(user_secret)
print(f"Generated OTP: {otp}")

# Simulate user entering OTP
user_otp_input = input("Enter the OTP: ")
if verify_otp(user_secret, user_otp_input):
    print("OTP is correct!")
else:
    print("Invalid OTP.")

FIDO2 Example

Server side

from fido2.webauthn import PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity
from fido2.server import Fido2Server
from fido2.client import ClientData
from fido2.ctap2 import AttestationObject, AuthenticatorData
from fido2 import cbor

# Setup the relying party information
rp = PublicKeyCredentialRpEntity(name="Example Corp", id="localhost")

# User information (this should be dynamic in production use)
user = PublicKeyCredentialUserEntity(id=b"user_id", name="user@example.com", display_name="User")

# Initialize the server with the relying party details
server = Fido2Server(rp)

# Registration
def register_begin():
    registration_data, state = server.register_begin({
        "id": user.id,
        "name": user.name,
        "displayName": user.display_name,
    })
    return cbor.encode(registration_data), state

def register_complete(client_data, attestation_object, state):
    client_data = ClientData(client_data)
    attestation_obj = AttestationObject(attestation_object)
    auth_data = server.register_complete(state, client_data, attestation_obj)
    return auth_data.credential_data

# Authentication
def authenticate_begin():
    auth_data, state = server.authenticate_begin(user)
    return cbor.encode(auth_data), state

def authenticate_complete(client_data, authenticator_data, state):
    client_data = ClientData(client_data)
    auth_data = AuthenticatorData(authenticator_data)
    server.authenticate_complete(state, user, client_data, auth_data)
    return "Authentication successful!"

Client Side

# Simulate client operations for registration
client_data_json, state = register_begin()
# Normally client_data_json would be used by the client with the user's security key.
# For this example, assume we get the following from the client/security key.
client_data = b"{}"  # Example client data, should be obtained from the security key
attestation_object = b"{}"  # Example attestation object, should be obtained from the security key

# Complete registration
credential_data = register_complete(client_data, attestation_object, state)
print("Registration complete. Credential data:", credential_data)

# Simulate client operations for authentication
auth_data, state = authenticate_begin()
# Again, assume we get the necessary data from the client/security key.
client_data = b"{}"
authenticator_data = b"{}"

# Complete authentication
result = authenticate_complete(client_data, authenticator_data, state)
print(result)