Skip to content

Commit

Permalink
✨ feat(big-bear-casaos-user-management): Add user management system (#27
Browse files Browse the repository at this point in the history
)

* ✨ feat(big-bear-casaos-user-management): Add user management system

This commit introduces a new user management system for the BigBearCasaOS project. The key changes include:

- Added a Dockerfile to build a Docker image for the user management system
- Created a Docker Compose file to easily deploy the user management service
- Implemented a Flask-based web application to manage user accounts
- Added an HTML template for the user management interface
- Configured environment variables for the admin username and password
- Granted the container extended privileges and capabilities for system integration

These changes enable the CasaOS platform to manage user accounts and roles, improving the overall security and usability of the system.

* 🔧 feat(user-management): Enhance user management service configuration

Modify the Docker Compose configuration for the CasaOS user management service:

- Expose port 5000 on the host and map it to the container
- Mount the cgroup filesystem in read-only mode for system resource monitoring
- Persist the CasaOS database files to retain data across container restarts
- Mount systemd's runtime directory for integration with the host system
- Provide access to the D-Bus system bus for communication with host services
- Set the Flask application entry point and production environment
- Specify the admin username and password for the service
- Grant the container extended privileges and the SYS_ADMIN capability
- Disable the default seccomp security profile to allow unrestricted system calls
- Rename the service from "big-bear-casaos-user-manager" to "big-bear-casaos-user-management" for consistency
  • Loading branch information
dragonfire1119 authored Nov 20, 2024
1 parent 4d04b80 commit c4d10f0
Show file tree
Hide file tree
Showing 9 changed files with 508 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: "Build and release for big-bear-casaos-user-management"

on:
push:
branches:
- main
paths:
- "big-bear-casaos-user-management/**"

jobs:
create:
name: "Creates the newest release by version"
runs-on: "ubuntu-latest"

steps:
- name: Checkout project
uses: actions/[email protected]

# New step to read the VERSION file and set the version as an output
- name: Get the version
id: get_version
run: echo "big_bear_casaos_user_management_version=$(cat big-bear-casaos-user-management/VERSION)" >> $GITHUB_ENV

- name: Set up QEMU
uses: docker/setup-qemu-action@master
with:
platforms: all

- name: Set up Docker Build
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
platforms: linux/amd64,linux/arm64
context: ./big-bear-casaos-user-management
file: ./big-bear-casaos-user-management/Dockerfile
tags: |
bigbeartechworld/big-bear-casaos-user-management:latest
bigbeartechworld/big-bear-casaos-user-management:${{ env.big_bear_casaos_user_management_version }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ pihole-unbound/build.log
pihole-unbound/build.sh
genmon/build.log
genmon/build.sh
genmon/build.log
genmon/build.sh
big-bear-casaos-user-management/build.log
big-bear-casaos-user-management/build.sh
27 changes: 27 additions & 0 deletions big-bear-casaos-user-management/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM python:3.9-slim

# Install system dependencies (systemd includes systemctl)
RUN apt-get update && \
apt-get install -y systemd sudo && \
rm -rf /var/lib/apt/lists/*

# Create necessary directories
RUN mkdir -p /var/lib/casaos/db

# Set working directory
WORKDIR /app

# Copy all application files
COPY app/ .

# Install Python dependencies
RUN pip install flask flask-wtf

# Create a volume for persistent storage
VOLUME /var/lib/casaos/db

# Expose port for Flask
EXPOSE 5000

# Run Flask app
CMD ["python", "app.py"]
1 change: 1 addition & 0 deletions big-bear-casaos-user-management/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.0.1
71 changes: 71 additions & 0 deletions big-bear-casaos-user-management/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from flask import Flask, render_template, redirect, url_for, flash, request
from user_management import (list_users, add_user, edit_password,
remove_user, reset_database, hash_password)
from functools import wraps
from flask import request, Response
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'

ADMIN_USERNAME = os.environ.get('ADMIN_USERNAME', 'admin')
ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD', 'YOUR_SECURE_PASSWORD')

def check_auth(username, password):
"""Verify admin credentials"""
return username == ADMIN_USERNAME and password == ADMIN_PASSWORD

def authenticate():
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'}
)

def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
return decorated

@app.route('/')
@requires_auth
def index():
users = list_users(return_data=True)
return render_template('index.html', users=users)

@app.route('/add_user', methods=['POST'])
def add_user_route():
username = request.form.get('username')
password = request.form.get('password')
if add_user(username, password):
flash('User added successfully', 'success')
return redirect(url_for('index'))

@app.route('/edit_password', methods=['POST'])
def edit_password_route():
user_id = request.form.get('user_id')
new_password = request.form.get('new_password')
if edit_password(user_id, new_password):
flash('Password updated successfully', 'success')
return redirect(url_for('index'))

@app.route('/remove_user', methods=['POST'])
def remove_user_route():
user_id = request.form.get('user_id')
if remove_user(user_id):
flash('User removed successfully', 'success')
return redirect(url_for('index'))

@app.route('/reset_database', methods=['POST'])
@requires_auth
def reset_database_route():
if reset_database():
flash('Database reset successfully', 'success')
return redirect(url_for('index'))

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
15 changes: 15 additions & 0 deletions big-bear-casaos-user-management/app/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>BigBearCasaOS User Management</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
/>
<!-- Add before closing body tag -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container mt-4">{% block content %}{% endblock %}</div>
</body>
</html>
128 changes: 128 additions & 0 deletions big-bear-casaos-user-management/app/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{% extends "base.html" %} {% block content %}
<h2>BigBearCasaOS User Management</h2>

<!-- User List -->
<div class="card mb-4">
<div class="card-header">Users</div>
<div class="card-body">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Role</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user[0] }}</td>
<td>{{ user[1] }}</td>
<td>{{ user[2] }}</td>
<td>
<button
type="button"
class="btn btn-sm btn-warning"
data-bs-toggle="modal"
data-bs-target="#editModal{{user[0]}}"
>
Edit
</button>
<form
action="{{ url_for('remove_user_route') }}"
method="POST"
style="display: inline"
>
<input type="hidden" name="user_id" value="{{ user[0] }}" />
<button
type="submit"
class="btn btn-sm btn-danger"
onclick="return confirm('Are you sure?')"
>
Remove
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>

<!-- Add this after the table -->
{% for user in users %}
<div class="modal fade" id="editModal{{user[0]}}" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit User: {{user[1]}}</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
></button>
</div>
<form action="{{ url_for('edit_password_route') }}" method="POST">
<div class="modal-body">
<input type="hidden" name="user_id" value="{{user[0]}}" />
<div class="mb-3">
<label>New Password</label>
<input
type="password"
name="new_password"
class="form-control"
required
/>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Close
</button>
<button type="submit" class="btn btn-primary">
Save changes
</button>
</div>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
</div>

<!-- Add User Form -->
<div class="card">
<div class="card-header">Add New User</div>
<div class="card-body">
<form method="POST" action="{{ url_for('add_user_route') }}">
<div class="mb-3">
<label>Username</label>
<input type="text" name="username" class="form-control" required />
</div>
<div class="mb-3">
<label>Password</label>
<input type="password" name="password" class="form-control" required />
</div>
<button type="submit" class="btn btn-primary">Add User</button>
</form>
</div>
</div>

<div class="card mt-4">
<div class="card-header">Database Management</div>
<div class="card-body">
<form
action="{{ url_for('reset_database_route') }}"
method="POST"
onsubmit="return confirm('WARNING: This will delete all users! Are you sure?');"
>
<button type="submit" class="btn btn-danger">Reset Database</button>
</form>
</div>
</div>
{% endblock %}
Loading

0 comments on commit c4d10f0

Please sign in to comment.