首页龙虾技能列表 › User Authentication System — 技能工具

User Authentication System — 技能工具

v0.1.1

[自动翻译] Role-based access control for Greek accounting firms. Login, role hierarchy, per-client permissions, session management, audit logging.

0· 569·0 当前·0 累计
by @satoshistackalotto (Stems)·MIT-0
下载技能包
License
MIT-0
最后更新
2026/2/26
安全扫描
VirusTotal
无害
查看报告
OpenClaw
可疑
medium confidence
The skill's declared purpose and resource requests are mostly coherent, but there are important security and implementation inconsistencies (notably use of salted SHA‑256 for passwords vs test expectations of bcrypt and underspecified TOTP handling) that make this risky to install without further review or changes.
评估建议
This skill looks like it does what it says (a local RBAC/auth system) but contains cryptographic and documentation inconsistencies that matter for security. Before installing: 1) Do not accept SHA‑256 password hashing—require the author to use a modern password KDF (bcrypt, scrypt, or Argon2) with explicit parameters. 2) Ask for details on how salts and TOTP secrets are generated, stored, and protected (secrets should be encrypted at rest and access-limited). 3) Verify that audit logs don't leak...
详细分析 ▾
用途与能力
Name/description (RBAC for Greek accounting firms) align with the requested binaries (openclaw, jq, openssl) and the single env var OPENCLAW_DATA_DIR. Requiring openclaw and a data directory is expected. However, the SKILL.md claims credentials are stored with salted SHA-256 hashes while the included EVALS expectations explicitly require bcrypt hashing — this is an inconsistency between claimed behavior and test expectations and suggests either outdated/insecure crypto choices or a mismatch between documentation and implementation.
指令范围
Instructions are local and file-based under $OPENCLAW_DATA_DIR/auth (no external endpoints), which is consistent with 'fully local' claims. However, the runtime instructions specify storing passwords as salted SHA-256 (fast hash) and using openssl to generate 'SHA-256 TOTP' without describing secure secret storage, iteration count, salt generation, or protection of TOTP secrets. These omissions are security-relevant: SHA‑256 is not an appropriate password KDF by modern standards (should use bcrypt/argon2/scrypt), and 2FA/TOTP secret handling is underspecified. The EVALS.json expectations explicitly call for bcrypt and 'never plaintext', which contradicts SKILL.md; that mismatch is a substantive scope/behavior inconsistency.
安装机制
There is no install spec (instruction-only), so nothing will be downloaded or written beyond creating the data directory and running openclaw commands. This lowers install-time risk. The only package suggestion is using the system package manager to install jq and openssl if missing.
凭证需求
Only OPENCLAW_DATA_DIR is required and is appropriate for a file-based auth system. No API keys, tokens, or unrelated credentials are requested. Small note: examples default OPENCLAW_DATA_DIR to /data which may be a privileged or shared location on some hosts—users should ensure the directory is set to a safe path with correct ownership and permissions.
持久化与权限
always: false and no special privileges are requested. The skill does not request to persist itself or modify other skills. It only writes to its own $OPENCLAW_DATA_DIR subpaths per instructions.
安装前注意事项
  1. Do not accept SHA‑256 password hashing—require the author to use a modern password KDF (bcrypt, scrypt, or Argon
  2. with explicit parameters.
  3. Ask for details on how salts and TOTP secrets are generated, stored, and protected (secrets should be encrypted at rest and access-limited).
  4. Verify that audit logs don't leak credentials or tokens and that file permissions restrict access to the auth directory (chmod 700 is suggested, but confirm ownership).
  5. Confirm the discrepancy between SKILL.md (SHA‑
  6. and the EVALS tests (bcrypt) is resolved — this could be a documentation error or an implementation bug.
  7. Prefer a non-default OPENCLAW_DATA_DIR (avoid using a global /data if that is shared) and review the actual implementation source before trusting it with production accounts. If you cannot obtain satisfactory answers or the owner/repo provenance, treat this as unsafe to deploy for real user accounts.
安全有层次,运行前请审查代码。

License

MIT-0

可自由使用、修改和再分发,无需署名。

运行时依赖

无特殊依赖

版本

latestv0.1.12026/2/21

Minor update for metadata and environment notes. - Added "openclaw" to required bins in metadata. - Included explicit note in metadata: `/data/ in examples refers to $OPENCLAW_DATA_DIR (default: /data/)`.

● 无害

安装命令 点击复制

官方npx clawhub@latest install user-authentication-system
镜像加速npx clawhub@latest install user-authentication-system --registry https://cn.clawhub-mirror.com

技能文档

This skill provides a complete authentication and authorization system for Greek accounting firm operations through OpenClaw. It manages user identities, role-based permissions, per-client access controls, and session security for multi-user accounting environments.

Setup

export OPENCLAW_DATA_DIR="/data"
which jq openssl || sudo apt install jq openssl
mkdir -p $OPENCLAW_DATA_DIR/auth
chmod 700 $OPENCLAW_DATA_DIR/auth

No external auth services. User credentials are stored as salted SHA-256 hashes locally. 2FA uses SHA-256 TOTP generated by openssl.

Core Philosophy

  • Role-Based Access: Hierarchical permissions matching real accounting firm structures
  • Per-Client Authorization: Granular control over which users access which client data
  • Session Security: Secure session management with timeout and device tracking
  • Audit Integration: Every authentication and authorization event logged
  • OpenClaw Artifact Ready: File-based auth suitable for OpenClaw deployment

OpenClaw Commands

User Management

openclaw auth user-create --username "maria.g" --role assistant --full-name "Maria Georgiou" --email "maria@firm.gr"
openclaw auth user-update --username "maria.g" --role accountant --effective-date 2026-03-01
openclaw auth user-deactivate --username "maria.g" --reason "resignation" --revoke-sessions
openclaw auth user-list --active --role assistant --format table
openclaw auth password-reset --username "maria.g" --send-reset-link
openclaw auth password-policy --min-length 12 --require-special --max-age-days 90

Role & Permission Management

openclaw auth role-list --include-permissions
openclaw auth role-create --name "tax_specialist" --base-role accountant --add-permissions "tax_filing,tax_optimization"
openclaw auth assign-clients --username "maria.g" --clients EL123456789,EL987654321
openclaw auth assign-clients --username "maria.g" --all-clients
openclaw auth check-access --username "maria.g" --client EL123456789 --action "view_financials"
openclaw auth access-matrix --all-users --all-clients --format xlsx

Security & Audit

openclaw auth security-log --last-24h --include-failures
openclaw auth failed-logins --threshold 3 --lockout-duration 30m
openclaw auth audit-report --user "maria.g" --period last-30-days
openclaw auth audit-report --client EL123456789 --who-accessed --period last-week
openclaw auth 2fa-enable --username "maria.g" --method totp
openclaw auth sessions-list --active --format table
openclaw auth session-revoke --username "maria.g" --all-devices

File System Architecture

Auth_File_Structure:
  user_data:
    - /data/auth/users/{username}/profile.json
    - /data/auth/users/{username}/credentials.json
    - /data/auth/users/{username}/permissions.json
    - /data/auth/users/{username}/sessions/
    - /data/auth/users/{username}/2fa/

role_definitions: - /data/auth/roles/senior_accountant.json - /data/auth/roles/accountant.json - /data/auth/roles/assistant.json - /data/auth/roles/viewer.json - /data/auth/roles/custom/

access_control: - /data/auth/access/client_assignments.json - /data/auth/access/policies.json - /data/auth/access/ip_whitelist.json

security_logs: - /data/auth/logs/logins/ - /data/auth/logs/access/ - /data/auth/logs/admin/ - /data/auth/logs/security/

Role Hierarchy & Permissions

Role Definitions

Roles:
  senior_accountant:
    description: "Senior accountant - full system access"
    level: 4
    inherits: "accountant"
    permissions:
      - all_client_access
      - user_management
      - role_assignment
      - system_configuration
      - data_export_all
      - compliance_override
      - audit_log_access
      - gdpr_operations
      - billing_management
      - skill_configuration
    client_access: "all"

accountant: description: "Accountant - broad access to assigned clients" level: 3 inherits: "assistant" permissions: - client_data_full_access - tax_filing_submit - tax_optimization - compliance_management - financial_reporting - efka_submissions - banking_reconciliation - deadline_management - client_communication client_access: "assigned_only" restrictions: - cannot_manage_users - cannot_change_system_config

assistant: description: "Accountant assistant - operational access" level: 2 inherits: "viewer" permissions: - document_upload - document_processing - data_entry - email_processing - dashboard_access - basic_reporting - client_data_edit_basic - alert_acknowledgement - ocr_processing client_access: "assigned_only" restrictions: - cannot_submit_tax_filings - cannot_export_sensitive_data - cannot_modify_financial_records

viewer: description: "Read-only access to assigned client data" level: 1 permissions: - dashboard_view - client_data_view - report_view - deadline_view - document_view client_access: "assigned_only" restrictions: - read_only - no_data_modification - no_data_export

Permission Matrix

Permission_Matrix:
  view_dashboard: "viewer"
  configure_dashboard: "accountant"
  view_client_profile: "viewer"
  edit_client_profile: "assistant"
  create_client: "accountant"
  delete_client: "senior_accountant"
  export_client_data: "accountant"
  gdpr_operations: "senior_accountant"
  view_documents: "viewer"
  upload_documents: "assistant"
  process_documents: "assistant"
  delete_documents: "accountant"
  view_financials: "viewer"
  enter_financial_data: "assistant"
  modify_financial_records: "accountant"
  submit_tax_filings: "accountant"
  view_compliance_status: "viewer"
  manage_compliance: "accountant"
  override_compliance: "senior_accountant"
  view_employee_data: "viewer"
  manage_employees: "accountant"
  submit_efka: "accountant"
  view_transactions: "viewer"
  reconcile_transactions: "assistant"
  configure_banking: "accountant"
  manage_users: "senior_accountant"
  manage_roles: "senior_accountant"
  view_audit_logs: "senior_accountant"
  system_configuration: "senior_accountant"

Authentication Engine

Core Authentication

class AuthenticationEngine:
    """Handles user authentication, sessions, and credential management."""

def __init__(self): self.session_timeout = 30 60 # 30 minutes self.idle_timeout = 15 60 # 15 minutes self.max_failed_attempts = 5 self.lockout_duration = 30 60 # 30 minutes

def authenticate(self, username, password, device_info=None): """Authenticate user and create session.""" if self.is_account_locked(username): self.log_auth_event(username, 'login_blocked', 'account_locked') return {'success': False, 'error': 'Account is locked. Contact administrator.'}

user = self.load_user(username) if not user: self.log_auth_event(username, 'login_failed', 'user_not_found') return {'success': False, 'error': 'Invalid credentials'}

if not self.verify_password(password, user['password_hash']): self.record_failed_attempt(username) self.log_auth_event(username, 'login_failed', 'wrong_password') return {'success': False, 'error': 'Invalid credentials'}

if user['status'] != 'active': self.log_auth_event(username, 'login_failed', f'account_{user["status"]}') return {'success': False, 'error': 'Account is not active'}

if user.get('2fa_enabled', False): return {'success': False, 'requires_2fa': True, 'session_pending': self.create_pending_session(username)}

session = self.create_session(username, device_info) self.clear_failed_attempts(username) self.log_auth_event(username, 'login_success', device_info=device_info) return {'success': True, 'session': session, 'user': self.get_user_summary(username)}

def create_session(self, username, device_info=None): """Create a new authenticated session. Security: The raw session token is returned to the user exactly once. Only the salted SHA-256 hash is stored on disk. Validation compares the hash of the incoming token against the stored hash. """ raw_token = generate_secure_token(64) token_hash = hash_session_token(raw_token) # SHA-256 salted hash session = { 'session_id': token_hash, 'username': username, 'created_at': current_timestamp(), 'expires_at': current_timestamp() + self.session_timeout, 'last_activity': current_timestamp(), 'device_info': device_info, 'ip_address': get_request_ip(), 'role': self.get_user_role(username), 'client_access': self.get_user_client_access(username) } session_path = f"/data/auth/users/{username}/sessions/{token_hash}.json" write_json(session_path, session) # Return raw token to user — this is the only time it exists in cleartext session['bearer_token'] = raw_token return session

def validate_session(self, session_id): """Validate an existing session.""" session = self.find_session(session_id) if not session: return {'valid': False, 'reason': 'session_not_found'} if current_timestamp() > session['expires_at']: self.destroy_session(session_id) return {'valid': False, 'reason': 'session_expired'} if current_timestamp() - session['last_activity'] > self.idle_timeout: self.destroy_session(session_id) return {'valid': False, 'reason': 'idle_timeout'} session['last_activity'] = current_timestamp() self.update_session(session) return {'valid': True, 'session': session}

def hash_password(self, password): """Hash password using bcrypt with salt.""" return bcrypt_hash(password, rounds=12)

def validate_password_strength(self, password): """Check password meets policy requirements.""" errors = [] if len(password) < 12: errors.append("Password must be at least 12 characters") if not any(c.isupper() for c in password): errors.append("Must contain uppercase letter") if not any(c.islower() for c in password): errors.append("Must contain lowercase letter") if not any(c.isdigit() for c in password): errors.append("Must contain digit") if not any(c in '!@#$%^&()_+-=' for c in password): errors.append("Must contain special character") return {'valid': len(errors) == 0, 'errors': errors}

Authorization Engine

class AuthorizationEngine:
    """Handles permission checks and access control decisions."""

def __init__(self): self.roles = self.load_roles() self.access_matrix = self.load_access_matrix()

def check_permission(self, session, action, client_vat=None): """Check if user has permission to perform an action.""" username = session['username'] user_role = session['role']

required_role = self.access_matrix.get(action) if not required_role: self.log_authorization(username, action, client_vat, 'denied', 'unknown_action') return {'allowed': False, 'reason': f'Unknown action: {action}'}

user_level = self.roles[user_role]['level'] required_level = self.roles[required_role]['level']

if user_level < required_level: self.log_authorization(username, action, client_vat, 'denied', 'insufficient_role') return {'allowed': False, 'reason': f'Requires {required_role} role (you have {user_role})'}

# Check client-specific access if client_vat: client_access = session.get('client_access', []) if 'all' not in client_access and client_vat not in client_access: self.log_authorization(username, action, client_vat, 'denied', 'no_client_access') return {'allowed': False, 'reason': f'Not authorized for client {AFM}'}

self.log_authorization(username, action, client_vat, 'allowed') return {'allowed': True}

def resolve_permissions(self, role_name): """Resolve all permissions including inherited ones.""" role = self.roles.get(role_name, {}) permissions = set(role.get('permissions', [])) parent = role.get('inherits') if parent: permissions.update(self.resolve_permissions(parent)) return permissions

def get_accessible_clients(self, username): """Get list of clients this user can access.""" assignments = read_json("/data/auth/access/client_assignments.json") user_entry = assignments.get(username, {}) if user_entry.get('all_clients', False): return {'type': 'all', 'clients': 'all'} return {'type': 'specific', 'clients': user_entry.get('clients', [])}

User Management

class UserManager:
    """Manages user lifecycle operations."""

def __init__(self): self.auth_engine = AuthenticationEngine() self.authz_engine = AuthorizationEngine()

def create_user(self, admin_session, user_data): """Create a new user account.""" # Verify admin has permission perm_check = self.authz_engine.check_permission(admin_session, 'manage_users') if not perm_check['allowed']: return {'success': False, 'error': perm_check['reason']}

username = user_data['username']

# Check for duplicate if self.user_exists(username): return {'success': False, 'error': f'Username {username} already exists'}

# Validate role if user_data['role'] not in self.authz_engine.roles: return {'success': False, 'error': f'Invalid role: {user_data["role"]}'}

# Create user profile profile = { 'username': username, 'full_name': user_data['full_name'], 'email': user_data.get('email'), 'role': user_data['role'], 'status': 'active', 'created_at': current_timestamp(), 'created_by': admin_session['username'], 'password_change_required': True, '2fa_enabled': False }

# Generate temporary password temp_password = generate_secure_password() credentials = { 'password_hash': self.auth_engine.hash_password(temp_password), 'password_set_at': current_timestamp(), 'password_change_required': True }

# Create user directory and files user_dir = f"/data/auth/users/{username}" create_directory(user_dir) create_directory(f"{user_dir}/sessions") create_directory(f"{user_dir}/2fa") write_json(f"{user_dir}/profile.json", profile) write_json(f"{user_dir}/credentials.json", credentials) write_json(f"{user_dir}/permissions.json", {'role': user_data['role'], 'custom': []})

# Audit log self.log_admin_action(admin_session['username'], 'user_created', { 'new_user': username, 'role': user_data['role'] })

return { 'success': True, 'username': username, 'temporary_password': temp_password, 'message': f'User {username} created with role {user_data["role"]}. ' f'Password change required on first login.' }

def assign_clients(self, admin_session, username, client_vats): """Assign client access to a user.""" perm_check = self.authz_engine.check_permission(admin_session, 'manage_users') if not perm_check['allowed']: return {'success': False, 'error': perm_check['reason']}

assignments_path = "/data/auth/access/client_assignments.json" assignments = read_json(assignments_path) if file_exists(assignments_path) else {}

if client_vats == 'all': assignments[username] = {'all_clients': True, 'clients': []} else: current = assignments.get(username, {'all_clients': False, 'clients': []}) current['clients'] = list(set(current.get('clients', []) + client_vats)) assignments[username] = current

write_json(assignments_path, assignments)

self.log_admin_action(admin_session['username'], 'clients_assigned', { 'user': username, 'clients': client_vats })

return {'success': True, 'username': username, 'client_access': assignments[username]}

Security Features

File System Permissions (Production Hardening)

The /data/auth/ directory contains sensitive credential and session data. In production, OS-level file permissions must be hardened:

# Restrict the entire auth directory
chmod 700 /data/auth/
chown -R openclaw:openclaw /data/auth/

# Credential files must be read-only to the service user chmod 600 /data/auth/users//credentials.json

# Session files chmod 600 /data/auth/users//sessions/.json

# Role definitions (read by all skills for auth checks, writable only by admin) chmod 644 /data/auth/roles/.json

# Audit logs (append-only in production if OS supports it) chmod 600 /data/auth/logs/*/.json

Note: The OpenClaw agent and all skills share the same file system context. Without OS-level permission restrictions, any skill could read credential hashes. These permissions ensure that only the authentication skill's process can access sensitive auth data.

Account Lockout

Lockout_Policy:
  max_failed_attempts: 5
  lockout_duration: "30 minutes"
  lockout_escalation:
    - "5 failures: 30 minute lockout"
    - "10 failures: 2 hour lockout"
    - "15 failures: account disabled, admin notification"
  notification: "email admin on 3+ consecutive failures"

Two-Factor Authentication

2FA_Configuration:
  methods: ["totp"]
  mandatory_for: ["senior_accountant"]
  optional_for: ["accountant", "assistant"]
  recovery_codes: 10
  totp_settings:
    algorithm: "SHA256"
    digits: 6
    period: 30

Password Policy

Password_Policy:
  min_length: 12
  require_uppercase: true
  require_lowercase: true
  require_digit: true
  require_special: true
  max_age_days: 90
  history_count: 5
  common_password_check: true

IP & Device Security

Security_Controls:
  ip_whitelist:
    enabled: true
    allowed_ranges: ["office_ip_range"]
    action_on_violation: "block_and_alert"

device_tracking: track_devices: true alert_new_device: true max_concurrent_sessions: 3

session_controls: absolute_timeout: "8 hours" idle_timeout: "15 minutes" single_session_per_device: true

Integration with Other Skills

Skill_Integration:
  dashboard_greek_accounting:
    provides: ["user_session", "role_permissions", "accessible_clients"]
    enforces: "dashboard view permissions per user role"

client_data_management: provides: ["access_decisions", "user_identity"] enforces: "per-client data access based on user assignments" integration: "authorization check before every data operation"

greek_compliance_aade: enforces: "only accountant+ can submit filings"

efka_api_integration: enforces: "only accountant+ can submit EFKA data"

all_skills: provides: "user context for audit trail entries" enforces: "role-based action restrictions across all operations"

Audit & Compliance Reporting

Audit Log Structure

Audit_Events:
  authentication:
    - login_success
    - login_failed
    - login_blocked
    - logout
    - session_expired
    - session_revoked
    - 2fa_success
    - 2fa_failed
    - password_changed
    - password_reset

authorization: - access_granted - access_denied - client_access_checked - permission_checked

administration: - user_created - user_updated - user_deactivated - role_changed - clients_assigned - clients_revoked - policy_changed

Audit_Entry_Format: timestamp: "ISO 8601 with timezone" event_type: "category.action" username: "acting user" target: "affected resource" client_vat: "if client-specific" result: "success/failure" details: "additional context" ip_address: "source IP" session_id: "active session"

Success Metrics

A successful authentication system deployment should achieve:

  • Secure Authentication: bcrypt password hashing, optional 2FA, session management
  • Role Hierarchy: Four-level role system matching accounting firm structures
  • Per-Client Access: Granular client data access assignment per user
  • Session Security: Timeout, idle detection, concurrent session limits
  • Complete Audit Trail: Every auth/authz event logged with context
  • Account Protection: Lockout policy, password requirements, brute-force prevention
  • Cross-Skill Enforcement: Authorization integrated into all data operations
  • Admin Tools: User management, access matrix, security reporting
  • GDPR Compatible: Access controls support data protection requirements
  • Scalable: Handle 50+ users across 500+ clients

Remember: The authentication system is the security foundation for the entire Greek accounting platform. Every data access must pass through authorization checks, and every action must leave an audit trail.

数据来源:ClawHub ↗ · 中文优化:龙虾技能库
OpenClaw 技能定制 / 插件定制 / 私有工作流定制

免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制

了解定制服务