Metadata-Version: 2.4
Name: allsafe-auth
Version: 1.1.7
Summary: A complete authentication library including TOTP, HOTP, Active Directory, and more.
Author: Daniel Destaw
Author-email: daniel@allsafe.com
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pycryptodome>=3.0.0
Requires-Dist: python-ldap>=3.4.0
Requires-Dist: ldap3>=2.9
Requires-Dist: qrcode>=8.2
Requires-Dist: Pillow>=11.2.1
Requires-Dist: cryptography>=39.0
Requires-Dist: bcrypt>=4.0.1
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

🎉 **complete authentication system** using `allsafe-auth`, integrating:

- 🔐 **Active Directory (LDAP) Authentication**
- 🔐 **HOTP / TOTP Multi-Factor Authentication**
- 🖼️ **QR Code Generation for MFA Setup**
- 🧑‍💼 **User Listing from AD**
- 🌐 **Django Inertia.js Integration**

---

## ✅ Summary of All Functionality

Here's a clean breakdown of what you have and how to use it.

---

## 🔐 1. TOTP — Generate QR Code for MFA Setup

### 📄 File: `examples/generate_hotp_qr.py`

```python
from allsafe_auth.authentication.totp import TOTP
from allsafe_auth.utils.qr_code_generator import QRCodeGenerator

if __name__ == "__main__":
    secret_key = "JBSWY3DPEHPK3PXP"
    account_name = "allsafe@example.com"
    issuer_name = "allsafe"
    qr_filename = "totp_qr_code.png"

    totp = TOTP(secret_key)
    print(f"Current TOTP: {totp.generate()}")

    uri = QRCodeGenerator.generate_uri(issuer_name, account_name, secret_key)
    QRCodeGenerator.save_to_file(uri, qr_filename)


```

> This generates a QR code that can be scanned with apps like Google Authenticator or Authy to set up **HOTP-based MFA**.

---

## 🔐 2. TOTP — Verify One-Time Password

### 📄 File: `examples/verify_totp_simple.py`

```python
from allsafe_auth.authentication.totp import TOTP

if __name__ == "__main__":
    secret_key = "JBSWY3DPEHPK3PXP"
    totp_verifier = TOTP(secret_key)
    expected_otp = totp_verifier.generate()

    user_otp = input("Enter the OTP from your authenticator app: ")

    if user_otp == expected_otp:
        print("✅ OTP verification successful!")
    else:
        print("❌ OTP verification failed.")
```

> Verifies the TOTP code generated by an authenticator app using the same shared secret.

---

## 🔐 3. Active Directory Authentication + List Users

### 📄 File: `examples/ad_authentication.py`

```python
from allsafe_auth.authentication.active_directory import ActiveDirectoryAuthenticator

# Configuration
AD_SERVER_IP = "10.195.130.34"
AD_DOMAIN = "allsafe.com.et"
AD_SEARCH_BASE = "DC=allsafe,DC=com,DC=et"

ADMIN_USER = "Administrator"
ADMIN_PASS = "password"

ad_auth = ActiveDirectoryAuthenticator(
    server_ip=AD_SERVER_IP,
    domain=AD_DOMAIN,
    search_base=AD_SEARCH_BASE
)

# Test Authentication
username = input("Enter username: ")
password = input("Enter password: ")

user_data = ad_auth.authenticate(username, password)

if user_data:
    print("✅ Login successful!")
    print("User Info:", user_data)
else:
    print("❌ Authentication failed.")

# Test User Listing
users = ad_auth.list_users(ADMIN_USER, ADMIN_PASS)
print(f"\n📄 Found {len(users)} users:")
for user in users:
    print(f" - {user['sAMAccountName'][0]}")
```

> Authenticates against AD and lists all users using admin credentials.

---

## 🔐 4. Combined Flow: AD + TOTP

### 📄 File: `examples/verify_totp_and_ad.py`

```python
from allsafe_auth.authentication.active_directory import ActiveDirectoryAuthenticator
from allsafe_auth.authentication.totp import TOTP

# AD Config
AD_SERVER_IP = "10.19.13.34"
AD_DOMAIN = "allsafe.com.et"
AD_SEARCH_BASE = "DC=allsafe,DC=com,DC=et"
TOTP_SECRET_KEY = "JBSWY3DPEHPK3PXP"


def main():
    ad_auth = ActiveDirectoryAuthenticator(
        server_ip=AD_SERVER_IP,
        domain=AD_DOMAIN,
        search_base=AD_SEARCH_BASE
    )

    username = input("Enter username: ")
    password = input("Enter password: ")
    totp_code = input("Enter TOTP from your authenticator app: ")

    print("\n[Step 1] Authenticating with Active Directory...")
    user_info = ad_auth.authenticate(username, password)

    if not user_info:
        print("❌ Authentication failed: Invalid username or password.")
        return

    print(f"✅ Successfully authenticated '{username}' via Active Directory.")

    print("\n[Step 2] Verifying TOTP...")
    totp_verifier = TOTP(TOTP_SECRET_KEY)
    expected_otp = totp_verifier.generate()

    if totp_code == expected_otp:
        print("✅ TOTP verification successful!")
        print("🔓 Full access granted.")
    else:
        print("❌ TOTP verification failed.")
        print("🔐 Access denied.")


if __name__ == "__main__":
    main()
```

> Combines both steps:
1. Authenticate via AD
2. Validate TOTP code before granting access

---

## 🌐 5. Django View with Inertia Support

### 📄 File: `views.py` (partial)

```python
from allsafe_auth.authentication.active_directory import ActiveDirectoryAuthenticator
from allsafe_auth.authentication.totp import TOTP
from inertia import render

# AD Config
AD_SERVER_IP = "10.19.13.34"
AD_DOMAIN = "allsafe.com.et"
AD_SEARCH_BASE = "DC=allsafe,DC=com,DC=et"
TOTP_SECRET_KEY = "JBSWY3DPEHPK3PXP"


@csrf_exempt
def ad_totp_login(request):
    if request.method != 'POST':
        return render(request, "logins/login_page", {
            "errors": {"login": "Only POST requests allowed"},
            "old": {}
        })

    try:
        data = json.loads(request.body)
        username = data.get('username')
        password = data.get('password')
        mfa_code = data.get('mfaCode')
        mfa_type = data.get('mfaType', 'authenticator')

        # Step 1: AD Authentication
        ad_auth = ActiveDirectoryAuthenticator(
            server_ip=AD_SERVER_IP,
            domain=AD_DOMAIN,
            search_base=AD_SEARCH_BASE
        )
        user_info = ad_auth.authenticate(username, password)

        if not user_info:
            return render(request, "logins/login_page", {
                "errors": {"login": "Invalid username or password"},
                "old": data
            })

        # Step 2: TOTP Verification
        if mfa_type == 'authenticator':
            totp = TOTP(TOTP_SECRET_KEY)
            expected_otp = totp.generate()

            if mfa_code != expected_otp:
                return render(request, "logins/login_page", {
                    "errors": {"login": "Invalid MFA code"},
                    "old": data
                })

        # Success
        return render(request, "somepage")

    except Exception as e:
        return render(request, "logins/login_page", {
            "errors": {"login": str(e)},
            "old": data
        })
```

> Integrates with your React frontend using Inertia.js and protects `/resource_dashboard`.

---

## 📋 6. Example Output

After running the combined script or using the Django login view:

```
Enter username: daniel.destaw
Enter password: ***********
Enter TOTP from your authenticator app: 359864

[Step 1] Authenticating with Active Directory...
✅ Successfully authenticated 'daniel.destaw' via Active Directory.

[Step 2] Verifying TOTP...
✅ TOTP verification successful!
🔓 Full access granted.
```

And on success, redirects to `/somepage`.

---

## 🧾 7. List All AD Users Using Admin Account

You can also run this inside any script or view:

```python
# Inside main() or a view
users = ad_auth.list_users("Administrator", "password@@")
print(f"\n📄 Found {len(users)} users:")
for user in users:
    print(f" - {user['sAMAccountName'][0]}")
```

Output:
```
📄 Found 5 users:
 - Administrator
 - Guest
 - DefaultAccount
 - krbtgt
 - daniel.destaw
```

---

## ✅ What’s Working?

| Feature | Status |
|--------|--------|
| AD Authentication | ✅ |
| TOTP Verification | ✅ |
| HOTP QR Code Generation | ✅ |
| User Listing from AD | ✅ |
| Django Inertia Integration | ✅ |

---

