package abac import ( "database/sql" "github.com/google/uuid" _ "github.com/mattn/go-sqlite3" ) type SQLiteStore struct { db *sql.DB } func NewSQLiteStore(dbPath string) (*SQLiteStore, error) { db, err := sql.Open("sqlite3", dbPath) if err != nil { return nil, err } store := &SQLiteStore{db: db} err = store.createTables(db) if err != nil { return nil, err } return store, nil } func (s *SQLiteStore) Close() error { return s.db.Close() } func (s *SQLiteStore) GetUserAttributes(userID string) ([]Attribute, error) { rows, err := s.db.Query(` SELECT a.key, a.value FROM attributes a JOIN user_attributes ua ON a.id = ua.attribute_id WHERE ua.user_id = ?; `, userID) if err != nil { return nil, err } defer rows.Close() var attributes []Attribute for rows.Next() { var attribute Attribute err := rows.Scan(&attribute.Key, &attribute.Value) if err != nil { return nil, err } attributes = append(attributes, attribute) } return attributes, nil } func (s *SQLiteStore) GetResourceAttributes(resourceID string) ([]Attribute, error) { rows, err := s.db.Query(` SELECT a.key, a.value FROM attributes a JOIN resource_attributes ra ON a.id = ra.attribute_id WHERE ra.resource_id = ?; `, resourceID) if err != nil { return nil, err } defer rows.Close() var attributes []Attribute for rows.Next() { var attribute Attribute err := rows.Scan(&attribute.Key, &attribute.Value) if err != nil { return nil, err } attributes = append(attributes, attribute) } return attributes, nil } func newID() string { uuid, err := uuid.NewV7() if err != nil { panic(err) } return uuid.String() } func (s *SQLiteStore) CreatePolicy(effect, action, conditionAttributeKey, conditionAttributeValue string) error { _, err := s.db.Exec(` INSERT INTO policies (id, effect, action, condition_attribute_key, condition_attribute_value) VALUES (?, ?, ?, ?, ?); `, newID(), effect, action, conditionAttributeKey, conditionAttributeValue) return err } func (s *SQLiteStore) createTables(db *sql.DB) error { _, err := db.Exec(` CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, username TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS resources ( id TEXT PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS attributes ( id TEXT PRIMARY KEY, key TEXT NOT NULL, value TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS user_attributes ( user_id TEXT NOT NULL, attribute_id INTEGER NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (attribute_id) REFERENCES attributes(id) ); CREATE TABLE IF NOT EXISTS resource_attributes ( resource_id TEXT NOT NULL, attribute_id TEXT NOT NULL, FOREIGN KEY (resource_id) REFERENCES resources(id), FOREIGN KEY (attribute_id) REFERENCES attributes(id) ); CREATE TABLE IF NOT EXISTS policies ( id TEXT PRIMARY KEY, effect TEXT NOT NULL CHECK(effect IN ('Allow', 'Deny')), action TEXT NOT NULL, condition_attribute_key TEXT, condition_attribute_value TEXT ); `) return err }