VMAUTH: Difference between revisions
From STEMX365-WIKI
				
				
				Jump to navigationJump to search
				
				
| No edit summary | No edit summary | ||
| Line 1: | Line 1: | ||
| =VM AUTH= | =VM AUTH= | ||
| ==Bind VM Usage to Online Authentication using a Flask-based API server== | |||
| ===Step 1: Flask API Server (STEMX365 Side)=== | |||
| <pre> | |||
| # vm_auth_server.py | |||
| from flask import Flask, request, jsonify | |||
| from werkzeug.security import check_password_hash | |||
| app = Flask(__name__) | |||
| # Dummy database (use real DB in prod) | |||
| users = { | |||
|     "student1@stemx365.org": { | |||
|         "name": "Student One", | |||
|         "password_hash": "pbkdf2:sha256:260000$...your_hash_here..." | |||
|     } | |||
| } | |||
| @app.route("/api/vm-auth", methods=["POST"]) | |||
| def vm_auth(): | |||
|     data = request.json | |||
|     email = data.get("email") | |||
|     password = data.get("password") | |||
|     user = users.get(email) | |||
|     if user and check_password_hash(user["password_hash"], password): | |||
|         return jsonify({"status": "success", "message": "Authenticated"}), 200 | |||
|     else: | |||
|         return jsonify({"status": "error", "message": "Invalid credentials"}), 401 | |||
| if __name__ == "__main__": | |||
|     app.run(host="0.0.0.0", port=5000) | |||
| </pre> | |||
| ===Step 2: VM Startup Script (Ubuntu Side)=== | |||
| <pre> | |||
| #!/bin/bash | |||
| API_URL="https://login.stemx365.org/api/vm-auth" | |||
| MAX_ATTEMPTS=3 | |||
| LOGFILE="/var/log/stemx365_vm_auth.log" | |||
| clear | |||
| echo "🔐 STEMX365 VM Access Authentication" | |||
| for attempt in $(seq 1 $MAX_ATTEMPTS); do | |||
|     read -p "Enter your STEMX365 email: " EMAIL | |||
|     read -s -p "Enter your password: " PASSWORD | |||
|     echo "" | |||
|     # Send request | |||
|     RESPONSE=$(curl -s -X POST $API_URL \ | |||
|         -H "Content-Type: application/json" \ | |||
|         -d "{\"email\":\"$EMAIL\", \"password\":\"$PASSWORD\"}") | |||
|     STATUS=$(echo $RESPONSE | jq -r '.status') | |||
|     if [[ "$STATUS" == "success" ]]; then | |||
|         echo "✅ Access granted. Welcome!" | |||
|         echo "$(date): $EMAIL logged in successfully" >> $LOGFILE | |||
|         exit 0 | |||
|     else | |||
|         echo "❌ Login failed. Attempt $attempt of $MAX_ATTEMPTS." | |||
|     fi | |||
| done | |||
| echo "$(date): $EMAIL failed authentication" >> $LOGFILE | |||
| echo "⚠️ Too many failed attempts. Locking out..." | |||
| sleep 3 | |||
| pkill -KILL -u "$USER"  # logout the session (or use shutdown -h now) | |||
| </pre> | |||
| ===Step 3: Auto-Run Script at Boot=== | |||
| Place the above script in /usr/local/bin/vm_login.sh, make it executable: | |||
| chmod +x /usr/local/bin/vm_login.sh | |||
| Then set it as a required login precondition using one of: | |||
| ====Option A: .bashrc (for single user VM)==== | |||
| # Add to top of ~/.bashrc | |||
| /usr/local/bin/vm_login.sh || exit | |||
| Option B: LightDM autologin greeter (more secure) | |||
| Modify /etc/lightdm/lightdm.conf: | |||
| <pre> | |||
| [SeatDefaults] | |||
| greeter-setup-script=/usr/local/bin/vm_login.sh | |||
| </pre> | |||
| #A **Python Flask server** (runs on your central server) to handle login/authentication and token validation. | #A **Python Flask server** (runs on your central server) to handle login/authentication and token validation. | ||
| #A **bash script** that runs on **each student's VM during boot**, checks their token, and halts if invalid. | #A **bash script** that runs on **each student's VM during boot**, checks their token, and halts if invalid. | ||
Latest revision as of 19:13, 11 April 2025
VM AUTH
Bind VM Usage to Online Authentication using a Flask-based API server
Step 1: Flask API Server (STEMX365 Side)
# vm_auth_server.py
from flask import Flask, request, jsonify
from werkzeug.security import check_password_hash
app = Flask(__name__)
# Dummy database (use real DB in prod)
users = {
    "student1@stemx365.org": {
        "name": "Student One",
        "password_hash": "pbkdf2:sha256:260000$...your_hash_here..."
    }
}
@app.route("/api/vm-auth", methods=["POST"])
def vm_auth():
    data = request.json
    email = data.get("email")
    password = data.get("password")
    user = users.get(email)
    if user and check_password_hash(user["password_hash"], password):
        return jsonify({"status": "success", "message": "Authenticated"}), 200
    else:
        return jsonify({"status": "error", "message": "Invalid credentials"}), 401
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
Step 2: VM Startup Script (Ubuntu Side)
#!/bin/bash
API_URL="https://login.stemx365.org/api/vm-auth"
MAX_ATTEMPTS=3
LOGFILE="/var/log/stemx365_vm_auth.log"
clear
echo "🔐 STEMX365 VM Access Authentication"
for attempt in $(seq 1 $MAX_ATTEMPTS); do
    read -p "Enter your STEMX365 email: " EMAIL
    read -s -p "Enter your password: " PASSWORD
    echo ""
    # Send request
    RESPONSE=$(curl -s -X POST $API_URL \
        -H "Content-Type: application/json" \
        -d "{\"email\":\"$EMAIL\", \"password\":\"$PASSWORD\"}")
    STATUS=$(echo $RESPONSE | jq -r '.status')
    if [[ "$STATUS" == "success" ]]; then
        echo "✅ Access granted. Welcome!"
        echo "$(date): $EMAIL logged in successfully" >> $LOGFILE
        exit 0
    else
        echo "❌ Login failed. Attempt $attempt of $MAX_ATTEMPTS."
    fi
done
echo "$(date): $EMAIL failed authentication" >> $LOGFILE
echo "⚠️ Too many failed attempts. Locking out..."
sleep 3
pkill -KILL -u "$USER"  # logout the session (or use shutdown -h now)
Step 3: Auto-Run Script at Boot
Place the above script in /usr/local/bin/vm_login.sh, make it executable:
chmod +x /usr/local/bin/vm_login.sh
Then set it as a required login precondition using one of:
Option A: .bashrc (for single user VM)
- Add to top of ~/.bashrc
/usr/local/bin/vm_login.sh || exit Option B: LightDM autologin greeter (more secure) Modify /etc/lightdm/lightdm.conf:
[SeatDefaults] greeter-setup-script=/usr/local/bin/vm_login.sh
- A **Python Flask server** (runs on your central server) to handle login/authentication and token validation.
- A **bash script** that runs on **each student's VM during boot**, checks their token, and halts if invalid.
OVERVIEW
Each VM has:
- A file `/etc/stemx365.conf` containing a unique `STUDENT_ID` and `VM_TOKEN`
- On boot, a script will:
- Read this config
- Ping your Flask server to validate the ID+token
- Only continue if authenticated
 
Bash Script for the Student VM (runs on boot)
Save this as `/usr/local/bin/stemx365_boot.sh` and make it executable.
#!/bin/bash
CONFIG_FILE="/etc/stemx365.conf"
API_URL="https://auth.stemx365.org/api/validate"
if [ ! -f "$CONFIG_FILE" ]; then
    echo "Missing configuration. Please contact STEMX365 support."
    exit 1
fi
source "$CONFIG_FILE"
# Check if required variables exist
if [ -z "$STUDENT_ID" ] || [ -z "$VM_TOKEN" ]; then
    echo "Invalid config file. Aborting."
    exit 1
fi
# Call central API to verify
response=$(curl -s -X POST "$API_URL" \
    -H "Content-Type: application/json" \
    -d "{\"student_id\": \"$STUDENT_ID\", \"vm_token\": \"$VM_TOKEN\"}")
if [[ "$response" == *"valid":true* ]]; then
    echo "✅ Welcome, $STUDENT_ID"
else
    echo "❌ Authentication failed. Access denied."
    exit 1
fi
Add this to the crontab or systemd to run on boot:
bash sudo crontab -e @reboot /usr/local/bin/stemx365_boot.sh
2. Config File Example (per VM)
Path: `/etc/stemx365.conf`
bash STUDENT_ID="student123" VM_TOKEN="a1b2c3d4e5f6"
Generate unique `VM_TOKEN`s for each student when creating the VM.
3. Flask Server to Validate Login
Install Flask:
bash pip install flask flask-cors
Save this as `stemx365_auth.py` on your server:
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
# Example: store valid tokens in a dictionary (use DB in production)
valid_tokens = {
    "student123": "a1b2c3d4e5f6",
    "student456": "z9y8x7w6v5"
}
@app.route('/api/validate', methods=['POST'])
def validate():
    data = request.get_json()
    student_id = data.get('student_id')
    token = data.get('vm_token')
    if student_id in valid_tokens and valid_tokens[student_id] == token:
        return jsonify({"valid": True})
    else:
        return jsonify({"valid": False}), 401
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
Run with:
python stemx365_auth.py
💡 In production, put behind NGINX with HTTPS.
Bonus: Generate Unique Tokens for Each VM
A helper Python snippet to generate:
import uuid
def generate_vm_token():
    return uuid.uuid4().hex
print(generate_vm_token())
