New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initialize/merge policy from CSV to GoRM adapter #972
Comments
@tangyang9464 @closetool @sagilio |
@TJM Line 285 in 833f1af
SavePolicy https://github.com/casbin/gorm-adapter/blob/7b3bc27c2b301e05607450cdf68aad047507943f/adapter.go#L508 So you may better use |
We also tried to use this:
... but then we couldn't save, because it said we couldn't save a filtered policy :( I was hoping to use the built in methods for parsing the CSV policies instead of parsing it myself and looping through the Add* operation. That is why I asked, I had more or less come to the same conclusion, but was hoping I was just missing something. ~tommy |
FYI, for anyone else that stumbles here through search, here is what I ended up doing. I wrote some helper functions to test the existence (enforcer.HasXXX) before attempting to add (enforcer.AddXXX) to tame database errors. I could have probably done "variadic" but actually preferred to have named arguments. package middleware
import (
"github.com/casbin/casbin/v2"
log "github.com/sirupsen/logrus"
)
// AddUserToRole will assign a user to a role (userGroup) if they are not already assigned
func AddUserToRole(user, role string) (result bool, err error) {
return addUserToRole(getEnforcer(), user, role)
}
func addUserToRole(e *casbin.Enforcer, user, role string) (result bool, err error) {
if !e.HasGroupingPolicy(user, role) {
log.WithFields(log.Fields{
"user": user,
"role": role,
}).Info("Add user to role.")
result, err = e.AddGroupingPolicy(user, role)
if err != nil {
log.WithFields(log.Fields{
"user": user,
"role": role,
}).Error("Error adding user to role: " + err.Error())
}
} else {
log.WithFields(log.Fields{
"user": user,
"role": role,
}).Debug("User was already assigned the role.")
}
return
}
// AddResourceToGroup will add a resource object (path target) to a resource group if it does not exist already.
func AddResourceToGroup(resource, group string) (result bool, err error) {
return addResourceToGroup(getEnforcer(), resource, group)
}
func addResourceToGroup(e *casbin.Enforcer, resource, group string) (result bool, err error) {
if !e.HasNamedGroupingPolicy("g2", resource, group) {
log.WithFields(log.Fields{
"resource": resource,
"group": group,
}).Infof("Add resource to group")
result, err = e.AddNamedGroupingPolicy("g2", resource, group)
if err != nil {
log.WithFields(log.Fields{
"resource": resource,
"group": group,
}).Error("Error adding resource to group: " + err.Error())
}
} else {
log.WithFields(log.Fields{
"resource": resource,
"group": group,
}).Debug("Reource already found in group.")
}
return
}
// AddPolicy will add a policy to the enforcer if it does not exist.
func AddPolicy(subject, object, action string) (result bool, err error) {
return addPolicy(getEnforcer(), subject, object, action)
}
func addPolicy(e *casbin.Enforcer, subject, object, action string) (result bool, err error) {
if !e.HasPolicy(subject, object, action) {
log.WithFields(log.Fields{
"subject": subject,
"object": object,
"action": action,
}).Info("Add policy")
result, err = e.AddPolicy(subject, object, action)
if err != nil {
log.WithFields(log.Fields{
"subject": subject,
"object": object,
"action": action,
}).Error("Error adding policy: " + err.Error())
}
} else {
log.WithFields(log.Fields{
"subject": subject,
"object": object,
"action": action,
}).Debug("Policy was found")
}
return
} Then I have an "initEnforcer" function that is called at startup to initialize the database enforcer with the results of the CSV enforcer policy files... // initEnforcer will initialize the enforcer with default policies, mostly for first run
// or if an upgrade provides new features or policies. It will also add initial admins.
func initEnforcer(e *casbin.Enforcer) {
log.Info("Initializing RBAC enforcer...")
args := config.GetArgs()
for _, user := range args.InitAdmins {
_, err := addUserToRole(e, user, "admin")
if err != nil {
log.Error("Error addUserToRole: " + err.Error())
}
}
for _, user := range args.InitUsers {
_, err := addUserToRole(e, user, "user")
if err != nil {
log.Error("Error addUserToRole: " + err.Error())
}
}
if args.DBType != "sqlite" && args.DBType != "sqlite3" {
log.Warn("DUE TO SQLITE ISSUES (id column) - SKIPPING INIT - as it would be pointless.")
// Read Policy from CSV
csvEnforcer, err := casbin.NewEnforcer(casbinConfig, casbinPolicy)
if err != nil {
log.Fatal("Failed to load initial policies from CSV")
}
// Process "p" objects (policies)
for _, p := range csvEnforcer.GetPolicy() {
_, err := addPolicy(e, p[0], p[1], p[2])
if err != nil {
log.Error("Error addPolicy: " + err.Error())
}
}
// Process "g" objects (groups/roles)
for _, g := range csvEnforcer.GetGroupingPolicy() {
_, err := addResourceToGroup(e, g[0], g[1])
if err != nil {
log.Error("Error addResourceToGroup: " + err.Error())
}
}
// Process "g2" objects (resource groups)
for _, g2 := range csvEnforcer.GetNamedGroupingPolicy("g2") {
_, err := addResourceToGroup(e, g2[0], g2[1])
if err != nil {
log.Error("Error addResourceToGroup: " + err.Error())
}
}
}
if args.DebugAuth {
fmt.Printf("\n\n*** initEnforcer Results\n")
fmt.Printf("*** - Roles (User Groups): %+v\n", e.GetGroupingPolicy())
fmt.Printf("*** - Resource Groups: %+v\n", e.GetNamedGroupingPolicy("g2"))
fmt.Printf("*** - Policies: %+v\n", e.GetPolicy())
fmt.Printf("*** END initEnforcer Results\n\n")
log.Info("initEnforer: Done!")
}
} NOTE: I preferred to keep the CSV file, which I have to use when using sqlite as a database (another issue). I could have just used an array of strings or whatever to initialize these, but we already had the CSV from developing. |
Want to prioritize this issue? Try:
What's your scenario? What do you want to achieve?
I am trying to use the gorm adapter with casbin. I would like to be able to "initialize" the data in the database using a CSV policy file that would be distributed in the container with my code. I can sorta make it work by using "NewEnforcer" with the file, then setting enforcer.SetAdapter ... then SavePolicy, but that overwrites the policy in the database (not ok).
I would like to load from CSV, then load from the database, then save? (I think)
Your model:
Your policy:
Your request(s):
This takes a couple runs to reproduce...
The first time through I either add the role ("g", "tommy@company.com", "admin") through code or insert it directly in the database. When the application starts, it mostly seems to overwrite whatever is in the database with the file...
I have also tried "enforcer.LoadPolicy()" after setting the adapter, but that appears to overwrite anything that was loaded from the file with what is in the database. In the event that I add a new feature and want to add a new "g2" I need to be able to add those to an existing database. (test this by uncommenting the "water" lines in the policy and restart.
createEnforcer
:The text was updated successfully, but these errors were encountered: