Authentication, Organizations και ρόλοι
Η υλοποιημένη πολιτική ασφαλείας του Bubllio CRM: memberships, permissions και tenant isolation.
Αυτή η σελίδα περιγράφει την πολιτική ασφαλείας που εφαρμόζεται σήμερα στο Bubllio CRM. Για την προτεινόμενη εξέλιξή της και τη σύγκριση με άλλα CRM, δείτε την έρευνα για το access model.
Authentication και authorization
Το authentication απαντά στο «ποιος κάνει αυτό το request;». Το authorization απαντά στο «τι επιτρέπεται να κάνει αυτός ο χρήστης μέσα σε αυτό το Organization;». Είναι δύο ξεχωριστοί έλεγχοι και απαιτούνται και οι δύο.
Το API χρησιμοποιεί JSON Web Tokens μέσω του DRF SimpleJWT. Τα προστατευμένα endpoints απαιτούν authenticated χρήστη και δέχονται Bearer access token. Εξαιρούνται σκόπιμα τα endpoints του αρχικού setup, της προεπισκόπησης και αποδοχής πρόσκλησης, καθώς και της επαναφοράς password. Το Django admin εξακολουθεί να χρησιμοποιεί session authentication. Τα βασικά REST endpoints είναι /api/v1/auth/token/, /api/v1/auth/token/refresh/, /api/v1/auth/me/ και /api/v1/auth/logout/.
Τα refresh tokens περιστρέφονται και μπαίνουν σε blacklist μετά την περιστροφή. Το logout βάζει σε blacklist το refresh token που υποβάλλεται. Το React frontend αποθηκεύει και τα δύο tokens στο Zustand με persistence στο sessionStorage της ίδιας καρτέλας. Η ανανέωση της σελίδας διατηρεί το session· το logout το καθαρίζει. Επειδή JavaScript στον browser μπορεί να διαβάσει το sessionStorage, παραμένει απαραίτητη η προστασία από XSS.
Μοντέλο membership
Ένας Django user μπορεί να ανήκει σε πολλά Organizations και να έχει διαφορετικό role σε καθένα:
User 1 -> many OrganizationMemberships <- 1 OrganizationΤο OrganizationMembership περιέχει UUID, Organization, User, role και timestamps. Η βάση αποτρέπει διπλό membership για τον ίδιο χρήστη και Organization και επιτρέπει μόνο έναν Owner ανά Organization.
Installation admin μπορεί να δημιουργήσει shared Organization και να ορίσει τον αρχικό business Owner μέσω email. Οι υπόλοιποι χρήστες αποκτούν πρόσβαση μόνο αν αποδεχτούν πρόσκληση από Owner ή Admin του Organization.
Πρέπει να διακρίνουμε τρία διαφορετικά ερωτήματα:
- Installation authority: μπορεί ο λογαριασμός να ρυθμίσει ολόκληρο το deployment ή να δημιουργήσει shared workspaces; Ενεργοί Django superusers μπορούν να κάνουν και τα δύο, αλλά η δημιουργία workspace παραμένει ευθύνη Installation admin.
- Workspace membership: σε ποια Organizations έχει πρόσβαση ο χρήστης και ποιο role έχει σε καθένα; Ο Installation admin δεν αποκτά αυτόματα REST membership σε workspaces που δημιούργησε κάποιος άλλος.
- Record visibility: ποιες εγγραφές βλέπει μέσα σε workspace στο οποίο έχει πρόσβαση; Σήμερα και οι τέσσερις workspace roles βλέπουν όλες τις Companies, Contacts, Automations και το run history του workspace. Δεν υπάρχουν ακόμη περιορισμοί ορατότητας ανά ομάδα, εγγραφή ή πεδίο.
Το Organization είναι workspace και όριο ασφαλείας. Δεν είναι εγγραφή Company του CRM ούτε τμήμα μιας επιχείρησης. Δημιουργήστε ξεχωριστό workspace όταν χρειάζεται διαχωρισμός δεδομένων, membership, διαχείρισης ή SMTP settings. Οι πελάτες της επιχείρησης καταχωρίζονται ως Company μέσα στο κατάλληλο workspace.
Για Organizations που δημιουργήθηκαν πριν από τη migration του membership δεν μπορεί να συναχθεί με ασφάλεια ποιος είναι ο Owner. Μετά την αναβάθμιση υπάρχουσας development database, Django superuser πρέπει να προσθέσει Owner membership μέσω /admin/ πριν αποκτήσει πρόσβαση ένας κανονικός χρήστης. Μην μαντεύετε ownership κατά τη migration.
Roles και capabilities
| Capability | Owner | Admin | Member | Viewer |
|---|---|---|---|---|
| Προβολή Companies, Contacts, Automations και run history | Ναι | Ναι | Ναι | Ναι |
| Δημιουργία Companies και Contacts | Ναι | Ναι | Ναι | Όχι |
| Δημιουργία και δοκιμή Automations | Ναι | Ναι | Όχι | Όχι |
| Προβολή workspace settings και SMTP account metadata | Ναι | Ναι | Ναι | Ναι |
| Αλλαγή workspace settings ή SMTP accounts και αποστολή δοκιμαστικού email | Ναι | Ναι | Όχι | Όχι |
| Προβολή μελών και pending invitations | Ναι | Ναι | Όχι | Όχι |
| Πρόσκληση, αλλαγή ή αφαίρεση Member/Viewer | Ναι | Ναι | Όχι | Όχι |
| Πρόσκληση ή προαγωγή Admin | Ναι | Όχι | Όχι | Όχι |
| Αλλαγή ή αφαίρεση Admin | Ναι | Όχι | Όχι | Όχι |
| Μεταβίβαση ownership | Ναι | Όχι | Όχι | Όχι |
| Διαγραφή Organization | Ναι | Όχι | Όχι | Όχι |
Τα passwords των email accounts κρυπτογραφούνται κατά την αποθήκευση και δεν επιστρέφονται ποτέ από το API. Όλοι οι workspace roles μπορούν να δουν τις ρυθμίσεις του account, εκτός από το password· για αλλαγές απαιτείται Owner ή Admin. Το workspace χρησιμοποιεί το ενεργό default SMTP account για invitations και, αν δεν υπάρχει, το fallback SMTP της εγκατάστασης. Owners και Admins μπορούν επίσης να δουν activity history που περιορίζεται στο tenant τους και να κατεβάσουν JSON export του workspace. Τα endpoints δεν εκθέτουν δεδομένα άλλου workspace, SMTP passwords, authentication secrets ή invitation tokens.
Ο πίνακας περιγράφει τα σημερινά endpoints· δεν υπόσχεται CRUD ανά εγγραφή. Για παράδειγμα, το API μπορεί να δημιουργεί και να εμφανίζει Companies και Contacts, αλλά δεν έχει endpoints για ενημέρωση ή διαγραφή τους. Τα profile και password settings αφορούν τον authenticated χρήστη ανεξάρτητα από τον workspace role.
Τα permissions εκφράζονται ως capabilities στο src/access/permissions.py, ώστε να μη διασπείρονται έλεγχοι role σε κάθε view. Admins μπορούν να προσκαλούν, να ενημερώνουν και να αφαιρούν Members και Viewers. Δεν μπορούν να αλλάξουν άλλον Admin ή Owner. Owners μπορούν να προαγάγουν Member σε Admin και να μεταβιβάσουν ownership. Ο τρέχων Owner δεν αφαιρείται ούτε υποβιβάζεται απευθείας· πρέπει πρώτα να μεταβιβάσει την ιδιοκτησία σε άλλο membership.
Ο ίδιος χρήστης μπορεί να είναι Owner στο workspace A, Viewer στο workspace B και Installation admin ταυτόχρονα. Πρόκειται για ανεξάρτητες αναθέσεις: η αλλαγή workspace δεν μεταφέρει τον role από το ένα στο άλλο.
Δημιουργία workspace και παράδοση στον Owner
Μόνο ενεργός Installation admin μπορεί να δημιουργήσει workspace. Το backend ελέγχει τον κανόνα σε κάθε create request, ώστε ένα stale UI ή token να μην μπορεί να δώσει πρόσβαση. Το GET /api/v1/auth/me/ επιστρέφει το can_create_workspaces για το UI. Η δημιουργία workspace και το resend πρόσκλησης Owner μοιράζονται ημερήσιο throttle.
Δημιουργήστε shared workspace με POST /api/v1/organizations/, στέλνοντας name, slug και owner_email. Αν παραλείψετε το owner_email, ο Installation admin γίνεται απευθείας Owner. Το ίδιο ισχύει αν οριστεί το δικό του email. Διαφορετικά:
- Πρέπει να είναι ρυθμισμένο το fallback SMTP της εγκατάστασης. Ο server δημιουργεί ατομικά το Organization, τα settings του, ένα προσωρινό membership του δημιουργού ως Owner και invitation που συνδέεται με email και λήγει σε επτά ημέρες. Αν αποτύχει η αποστολή, γίνεται rollback όλων των αλλαγών. Η απάντηση περιλαμβάνει
owner_invitation_pending: true. - Μέχρι να γίνει αποδοχή, το workspace δεν εμφανίζεται στις κανονικές λίστες workspaces και σε κανένα membership-scoped CRM/settings endpoint — ούτε για τον προσωρινό δημιουργό. Δεν μπορεί να δεχτεί δεδομένα CRM μέσω REST API.
- Ο υποψήφιος Owner αποδέχεται την πρόσκληση από την υπάρχουσα invitation page. Νέος χρήστης μπορεί να δημιουργήσει account· υπάρχων χρήστης πρέπει να συνδεθεί με το email της πρόσκλησης. Κατά την αποδοχή, αφαιρείται ατομικά το προσωρινό membership του δημιουργού, ορίζεται ο νέος Owner και ανοίγει το workspace.
- Installation admin μπορεί να δει pending workspaces, να ξαναστείλει την πρόσκληση (ακυρώνοντας το προηγούμενο token) ή να ακυρώσει και να διαγράψει το pending workspace:
GET /api/v1/organizations/provisioning/
POST /api/v1/organizations/provisioning/<organization_id>/
DELETE /api/v1/organizations/provisioning/<organization_id>/Μόνο Installation admins βλέπουν ή διαχειρίζονται pending workspaces. Πρόσκληση που δεν έγινε αποδεκτή ή έχει λήξει δεν δίνει πρόσβαση. Ο περιορισμός της βάσης διασφαλίζει ότι υπάρχει το πολύ ένας Owner· το προσωρινό membership διασφαλίζει ότι ένα pending workspace δεν μένει χωρίς Owner. Το owner handoff, η δημιουργία shared workspace, τα resend/cancel actions, οι προσκλήσεις μελών, οι αλλαγές roles και οι αλλαγές email connection καταγράφονται στο read-only WorkspaceAccessEvent log, ορατό στους Installation admins. Τα secrets και τα invitation tokens δεν αποθηκεύονται στο log.
Tenant-scoped routes
Τα resources ενός Organization χρησιμοποιούν το UUID του Organization στο URL:
/api/v1/organizations/<organization_id>/companies/
/api/v1/organizations/<organization_id>/contacts/
/api/v1/organizations/<organization_id>/automations/Ο server βρίσκει το Organization μέσω του membership και του απαιτούμενου capability του authenticated χρήστη. Ο client δεν ορίζει ownership στέλνοντας πεδίο organization στο JSON. Στους serializers των Company, Contact και Automation, το organization είναι read-only.
Κάθε query φιλτράρεται με βάση το Organization που επιλύθηκε. Αν λείπει membership ή capability, συνήθως επιστρέφεται 404 Not Found, ώστε να μη διαρρεύσει αν υπάρχει Organization στο οποίο ο χρήστης δεν έχει πρόσβαση.
Πρόσβαση στα Automations
Ισχύουν τα ίδια όρια πρόσβασης: Members μπορούν να βλέπουν automation rules και run history· Owners και Admins μπορούν να δημιουργούν rules και να εκτελούν χειροκίνητα το action test. Το test εκτελεί πραγματικά την ενέργεια ακόμη και αν το rule είναι inactive. Δεν είναι permission preview ή dry run. Για την τρέχουσα συμπεριφορά, δείτε τα Automations.
Διαχείριση memberships και invitations
Μόνο Owners και Admins μπορούν να εμφανίσουν τη λίστα μελών:
GET /api/v1/organizations/<organization_id>/members/Δεν υποστηρίζεται απευθείας POST στο members endpoint. Για να δημιουργηθεί membership, απαιτείται invitation μέσω email και αποδοχή της.
Owners και Admins προσκαλούν χρήστες με POST /api/v1/organizations/<organization_id>/invitations/, στέλνοντας email και role. Owners μπορούν να προσκαλέσουν admin, member ή viewer· Admins μόνο member ή viewer. Το GET στο ίδιο endpoint επιστρέφει τις 100 πιο πρόσφατες invitations, με status pending, accepted, expired ή revoked και timestamps. Ο server στέλνει το email μέσω του ενεργού default SMTP account του Organization ή μέσω του installation fallback SMTP. Αν κανένα δεν είναι διαθέσιμο ή αποτύχει η αποστολή, επιστρέφεται error και δεν αποθηκεύεται invitation. Νέα πρόσκληση στο ίδιο email ανακαλεί τον προηγούμενο ενεργό σύνδεσμο, διατηρώντας το ιστορικό. Τα invitation και resend requests περιορίζονται συνολικά σε 20 ανά χρήστη την ημέρα.
Οι Owners και Admins μπορούν να ξαναστείλουν ή να ανακαλέσουν invitations με tenant-scoped actions. Το resend δημιουργεί νέο σύνδεσμο επτά ημερών και ανακαλεί κάθε προηγούμενο ενεργό σύνδεσμο για το ίδιο email. Η ανάκληση ακυρώνει αμέσως τον επιλεγμένο σύνδεσμο. Admin δεν μπορεί να ξαναστείλει ή να ανακαλέσει invitation άλλου Admin· αυτή η ενέργεια επιτρέπεται μόνο στον Owner.
POST /api/v1/organizations/<organization_id>/invitations/<invitation_id>/resend/
DELETE /api/v1/organizations/<organization_id>/invitations/<invitation_id>/Τα invitation links περιέχουν τυχαίο token. Αποθηκεύεται μόνο το SHA-256 hash του και το link λήγει σε επτά ημέρες. Το GET /api/v1/invitations/<token>/ εμφανίζει το workspace, το email, το role και την ημερομηνία λήξης της πρόσκλησης. Το POST στο αντίστοιχο accept/ endpoint χρησιμοποιεί το token μία φορά. Υπάρχων χρήστης συνδέεται με το προσκεκλημένο email· νέος χρήστης δίνει username και password και λαμβάνει JWTs. Το email δεν αλλάζει κατά την αποδοχή. Δεν υπάρχει γενικό public signup endpoint. Οι προσκεκλημένοι χρήστες δεν μπορούν να δημιουργήσουν shared Organizations· αυτό επιτρέπεται μόνο σε Installation admins.
Ορίστε το BUBLLIO_APP_URL στο public origin του React app για σωστά links στα emails. Στο local development η προεπιλογή είναι http://127.0.0.1:5173.
Για αλλαγή role:
PATCH /api/v1/organizations/<organization_id>/members/<membership_id>/
Content-Type: application/json
{
"role": "viewer"
}Αν οριστεί role: "owner", η μεταβίβαση γίνεται ατομικά: ο προηγούμενος Owner γίνεται Admin και το επιλεγμένο membership γίνεται Owner.
Για αφαίρεση membership:
DELETE /api/v1/organizations/<organization_id>/members/<membership_id>/Django superusers
Το προαιρετικό first-run setup στα GET/POST /api/v1/setup/ μπορεί να δημιουργήσει τον πρώτο Django superuser και τον πρώτο Owner του Organization. Είναι διαθέσιμο μόνο αν έχει οριστεί BUBLLIO_SETUP_TOKEN, το setup δεν έχει ολοκληρωθεί και οι πίνακες users και Organizations είναι άδειοι. Το POST απαιτεί το server-side token. Μετά την επιτυχή ολοκλήρωση, το setup κλείνει μόνιμα για τη συγκεκριμένη database. Υπάρχουσα εγκατάσταση δεν αποκτά δημόσια διαδρομή δημιουργίας χρηστών. Δείτε το Getting Started.
Ο πρώτος χρήστης γίνεται Installation admin. Οι Installation admins μπορούν να προσκαλέσουν επιπλέον IT admins με ξεχωριστή invitation που συνδέεται με email και λήγει σε επτά ημέρες. Η αποδοχή δίνει Django superuser και staff permissions, αλλά δεν δημιουργεί workspace memberships. Στο API του προϊόντος, ακόμη και superuser βλέπει CRM workspaces μόνο μέσω του OrganizationMembership. Επειδή Django superusers μπορούν να δουν δεδομένα από το /admin/, ο ρόλος προορίζεται μόνο για έμπιστους IT admins και δεν πρέπει να χρησιμοποιείται ως workspace role.
Installation admins δημιουργούν shared Organizations και διαχειρίζονται installation settings. Η δημιουργία workspace δεν ανατίθεται σε απλούς λογαριασμούς. Owners και Admins ενός Organization μπορούν να προσκαλούν άτομα στο δικό τους workspace, αλλά δεν μπορούν να δημιουργούν workspaces ή να δίνουν installation-level access.
Σημαντικός περιορισμός: το REST API απαιτεί membership ακόμη και για Installation admins. Ωστόσο, το Django /admin/ δίνει στους superusers ευρεία πρόσβαση στη database. Μην περιγράφετε τον Installation admin ως τεχνικά αδύνατο να δει δεδομένα άλλων workspaces. Είναι ρόλος υψηλών δικαιωμάτων: δίνεται μόνο σε έμπιστα άτομα και το /admin/ πρέπει να προστατεύεται ανάλογα. Δείτε την έρευνα για το access model.
Οι απλοί χρήστες δεν μπορούν να δημιουργήσουν personal workspaces. Βλέπουν μόνο workspaces στα οποία έχουν πρόσβαση μέσω invitation. Τα υπάρχοντα personal workspaces παραμένουν απομονωμένα και δεν μπορούν να προσκαλέσουν μέλη ή να διαγραφούν από το σημερινό API. Αν απενεργοποιηθεί η σχετική ρύθμιση, σταματά η δημιουργία νέων personal workspaces αλλά δεν αφαιρούνται τα υπάρχοντα.
Μελλοντικές εργασίες ασφάλειας
- Μετάβαση σε HttpOnly cookie για refresh token, αν το deployment χρειάζεται ισχυρότερη προστασία από JavaScript στον browser.
- Υποστήριξη inactive ή suspended memberships.
- Audit coverage για αλλαγές στο προσωπικό profile και login.
- Rate limiting και production HTTPS/security settings.
Django admin ως fallback εργαλείο
Το Django admin είναι εργαλείο διαχείρισης για staff και superusers· δεν είναι dashboard για Owners των Organizations. Μέσω του /admin/, Django superusers μπορούν να επιθεωρούν Organizations, memberships, settings και email accounts, ανεξάρτητα από το REST membership. Στη φόρμα email account, password ζητείται μόνο κατά τη δημιουργία ή αλλαγή. Κρυπτογραφείται πριν αποθηκευτεί και η κρυπτογραφημένη τιμή δεν εμφανίζεται ποτέ ως επεξεργάσιμο πεδίο.
Το API για ρητή δοκιμή email παραμένει διαθέσιμο για Postman ή μελλοντικό frontend:
POST /api/v1/organizations/<organization_id>/email-accounts/<account_id>/test/