-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmulti_user_acl.py
More file actions
217 lines (176 loc) · 7.46 KB
/
multi_user_acl.py
File metadata and controls
217 lines (176 loc) · 7.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/usr/bin/env python3
"""
Multi-User ACL Example for RiceDB
This example demonstrates how to:
1. Manage users (Admin operations)
2. Insert documents with permissions
3. Grant and revoke permissions
4. Search with ACL filtering (User context)
"""
import os
import sys
import time
from dotenv import load_dotenv
# Add the ricedb package to the path
sys.path.insert(0, "../src")
from ricedb import RiceDBClient
load_dotenv()
HOST = os.environ.get("HOST", "localhost")
PORT = int(os.environ.get("PORT", "50051"))
PASSWORD = os.environ.get("PASSWORD", "admin")
SSL = os.environ.get("SSL", "false").lower() == "true"
def print_section(title: str):
"""Print a formatted section header."""
print(f"\n{'=' * 50}")
print(f" {title}")
print("=" * 50)
def print_success(message: str):
"""Print a success message."""
print(f" {message}")
def print_info(message: str):
"""Print an info message."""
print(f" {message}")
def print_error(message: str):
"""Print an error message."""
print(f" {message}")
def main():
print_section("Multi-User ACL Demo for RiceDB")
# Initialize admin client
print_info("Connecting as Admin...")
# ACL Management is typically done via HTTP admin client on port 3000 by default,
# but here we use main port/transport from env
admin_client = RiceDBClient(
HOST, port=PORT, transport="http"
) # Force HTTP for admin ops if needed or use main transport
# Actually most examples use main client. Let's use env config.
# Note: multi_user_acl.py used port=3000 hardcoded.
# If the user sets PORT=50051 (gRPC), we should respect it or use a separate admin port var?
# For simplicity, let's assume HOST/PORT points to the service we want to use.
# But if transport="http" is hardcoded, it expects HTTP port.
# Let's try to infer or just use provided PORT.
# If user provided 50051 (gRPC), force http might fail if it's strictly gRPC port?
# RiceDB usually exposes both?
# Let's trust the env vars. If SSL=true, it might be remote.
# Update: using standard client init
admin_client = RiceDBClient(HOST, port=PORT, transport="http")
admin_client.ssl = SSL
try:
if not admin_client.connect():
print_error("Failed to connect to RiceDB server")
return
# Login as admin (default credentials if not changed)
# In a real scenario, these would come from env vars or secure storage
try:
admin_client.login("admin", PASSWORD)
print_success("Logged in as Admin")
except Exception as e:
print_error(f"Admin login failed: {e}")
print_info("Ensure the server is running and initialized.")
return
# Create users
print_section("1. User Management")
users_config = {
"alice": {"role": "user", "dept": "Finance", "pass": "alice123"},
"bob": {"role": "user", "dept": "Engineering", "pass": "bob123"},
"charlie": {"role": "user", "dept": "Finance", "pass": "charlie123"},
"diana": {"role": "user", "dept": "Engineering", "pass": "diana123"},
}
user_clients = {}
users = {}
for name, info in users_config.items():
print_info(f"Creating user '{name}'...")
try:
# Delete if exists (cleanup from previous runs)
try:
admin_client.delete_user(name)
except:
pass
user_id = admin_client.create_user(name, info["pass"], info["role"])
users[name] = {**info, "id": user_id}
print_success(f"Created {name} (ID: {user_id})")
# Create client for this user
client = RiceDBClient(HOST, port=PORT, transport="http")
client.ssl = SSL
client.connect()
client.login(name, info["pass"])
user_clients[name] = client
except Exception as e:
print_error(f"Failed to create/login {name}: {e}")
# Document 1: Financial Report (Created by Alice)
print_section("2. Creating Documents")
print_info("\nAlice inserting Q4 Budget Report...")
alice_client = user_clients["alice"]
# Alice inserts and grants read access to Charlie (Analyst)
# Note: In the new system, insert makes Alice the owner.
# She then grants permissions to others.
result1 = alice_client.insert(
node_id=1001,
text="Q4 2023 Budget Report - Financial analysis and projections",
metadata={
"title": "Q4 2023 Budget Report",
"type": "Financial Report",
"department": "Finance",
"sensitive": True,
},
)
# Alice grants read to Charlie
alice_client.grant_permission(
1001, users["charlie"]["id"], {"read": True, "write": False, "delete": False}
)
print_success("Document inserted and shared with Charlie")
# Document 2: Technical Spec (Created by Bob)
print_info("\nBob inserting API Documentation...")
bob_client = user_clients["bob"]
result2 = bob_client.insert(
node_id=2001,
text="API v2 Documentation - Endpoints and schemas",
metadata={
"title": "API v2 Documentation",
"type": "Technical Documentation",
"department": "Engineering",
},
)
# Bob grants read to Diana
bob_client.grant_permission(
2001, users["diana"]["id"], {"read": True, "write": False, "delete": False}
)
print_success("Document inserted and shared with Diana")
print_section("3. Testing Permissions")
# Test: Charlie reading Alice's report
print_info("Charlie searching for reports...")
charlie_client = user_clients["charlie"]
results = charlie_client.search("budget report", user_id=users["charlie"]["id"])
found = any(r["id"] == 1001 for r in results)
if found:
print_success("Charlie found the Budget Report")
else:
print_error("Charlie could NOT find the Budget Report")
# Test: Bob reading Alice's report (Should fail)
print_info("Bob searching for reports...")
results = bob_client.search("budget report", user_id=users["bob"]["id"])
found = any(r["id"] == 1001 for r in results)
if not found:
print_success("Bob could NOT find the Budget Report (Correct)")
else:
print_error("Bob found the Budget Report (Unexpected)")
print_section("4. Revoking Permissions")
# Alice revokes Charlie's access
print_info("Alice revoking Charlie's access...")
alice_client.revoke_permission(1001, users["charlie"]["id"])
# Verify
results = charlie_client.search("budget report", user_id=users["charlie"]["id"])
found = any(r["id"] == 1001 for r in results)
if not found:
print_success("Charlie can no longer see the report")
else:
print_error("Charlie can still see the report")
print_section("5. Summary")
print_success("Multi-User ACL Demo completed successfully!")
except Exception as e:
print_error(f"Error during demo: {e}")
finally:
admin_client.disconnect()
for c in user_clients.values():
c.disconnect()
if __name__ == "__main__":
main()