You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We should provide help and support including development efforts to help Glewlwyd integrate with Casbin. We need to communicate with them, know our customer's need and help them with the code.
I suggest putting this in a high priority (than the issues proposed by our own people) because we have been "working behind closed doors" for long (we raise issues by ourselves, then solve them) and this can be the first time for us to show Casbin-Cpp is also useful for others.
I'm available to help improving casbin and/or Glewlwyd to integrate one with another.
Glewlwyd's ACL design is based on the OAuth2 scopes: When a user asks for an access token to Glewlwyd, Glewlwyd checks that the user is allowed to grant those scopes, and asks for new authentication factors if the scopes require it.
For now, the security model of a user is like a flat list, for example, a user object could look like this:
The user model is flexible enough to add other properties, example: address, certificate, picture, you name it. The requirement for any additional property is that the values must be a string or an array of strings. You can add any number of additional properties.
I don't know casbin at all, nor its security model so correct me if I'm wrong.
Casbin is an interface that can be called in one way or another to check a user access level. A program uses casbin to check if a user has access to policies
Casbin doesn't handle authentication, nor user list management
One solution I see for the integration is to create a user backend module, based on the database or ldap module, or both.
This new module would behave as the original, but would also include ACLs properties. Those ACLs can be included as one or multiple additional properties, depending on the need, and therefore be included in the access token as Additional claims in the ID Token or the /userinfo endpoint. This solution is elegant because it doesn't adds another protocol to implement for the client or the resource service. Its main problem is that the client must know all the addition claims available to request the correct ones, or potentially get a huge amount of claims and deals with them.
Another solution is to add a new plugin to handle the interface with the casbin backend. This plugin would have its REST API and would be called to answer more precise questions: "Is this user allowed to read A and write B?". The main problem I see with this solution is that the client and the resource server must implement an interface to the casbin plugin in addition to the OAuth2/OIDC standard. This plugin would also be a duplicate of what already exists in the casbin ecosystem, therefore the benefit is limited. i.e. it's not more or less complicated to ask a casbin interface if "user is allowed to read A and write B?" or ask glewlwyd's casbin plugin the exact same question.
A concern I have is that the plugin would not implement a standard but a dedicated interface. And if the casbin interface changes, the plugin must follow the changes.
I personally don't mind, we all make free software, but since I don't intend to use casbin for myself, I hope we can both develop the plugin and maintain it over the month or years of its life.
@babelouest Your idea that encoding policies to OAuth token is very clever, I once built an OAuth server, I use a database table to store the relation of scope and correspond API, not very convenient and can't be abstracted as a library.
The OAuth scope model is very simple, it's just an ACL, for example, if a token has scope file:read, then this token can access API like getFile or listFile, a regex match can solve this problem. But if the scopes have intersections, we can consider using casbin, because casbin is very good at handling hierarchical or negative permissions.
While thinking about it, I came out with a better idea than updating the existing user backends, instead, I'll add a middleware backend system.
These middleware backends would be placed between glewlwyd core and the user backends and would be able to access and update the user objects. Their possibility would be potentially limitless with the user object.
For example, in the case of casbin, the middleware beckend would do something like this:
// user returned by the user backend{username: "dev",name: "Dave Lopper",email: "dev@example.com",enabled: true,scopes: ["file:read","file:write","mail:read","profile","openid"]}// user updated by the casbin middleware backend{username: "dev",name: "Dave Lopper",email: "dev@example.com",enabled: true,scopes: ["file:read","file:write","mail:read","profile","openid"],roles: ["admin:it","admin:legal","admin:shoes"],// added by the middlewareprofile: ["left","right"]// added by the middleware}
This way will be better and easier to implement and to test, and will allow to use backends and middleware in symbiosis, rather than having an updated backend and having to maintain it in parallel of a similar one.
@hsluoyz sure! Should we create the middleware separately, or include it in glewlwyd's source?
Are there any examples of such middleware(s) to which I can refer? Can this be a viable starting point?
I'll be glad if someone can educate me/drop-in references on how middlewares work in glewlwyd while I try to figure it out since I am not familiar with it enough.
The middleware modules implementation is still a WIP, I'm working on the front-end at the moment, the tests will follow, and the documentation too. But you can start working on a middleware module, based on the mock you mention, that's what it's for.
The front-end must have an update too to integrate the casbin parameter, we can make that when we're sure what parameters will be required for it.
I will be happy to include the casbin middleware module in Glewlwyd's project, assuming we agree on a license.
Feel free to ask questions or challenge the interface if you think it should be changed!
A few tips on the functions definitions to help you start:
/** * Must inclulde at least "glewlwyd-common.h" */#include"glewlwyd-common.h"/** * function executed once when the module file is loaded * can be used to initiate global startup * must return a json_t * object with the module description (see mock return value) */json_t*user_middleware_module_load(structconfig_module*config);
/** * function executed once when the module file is closed * must return G_OK on success, an error value on error */intuser_middleware_module_unload(structconfig_module*config);
/** * function executed when a module instance is initiated * The variable j_parameters will contain the instance parameters * The variable *cls, if used, must be set by the instance and will be passed as parameter for all other module functions, * can be used to keep a structure with the connection to a service or anything useful to the module * must return a json_t * object of the following format: * {result: G_OK} on success * {result: G_ERROR*, error: ["error list in a JSON array of strings"]} on error */json_t*user_middleware_module_init(structconfig_module*config, json_t*j_parameters, void**cls);
/** * function executed when a module instance is closed * the resources contained in cls must be released here * must return G_OK on success, an error value on error */intuser_middleware_module_close(structconfig_module*config, void*cls);
/** * function executed on a user_get_iist * this function will update the j_user_list content accordingly to its requirements, or leave it as is if needed * must return G_OK on success, an error value on error * The whole user_get_list result will be cancelled if an error is returned, so an error value shouldn't be returned if one user has error for example, better off removing this user of the list */intuser_middleware_module_get_list(structconfig_module*config, json_t*j_user_list, void*cls);
/** * function executed on a get_user * this function will update the j_user content accordingly to its requirements, or leave it as is if needed * must return G_OK on success, an error value on error */intuser_middleware_module_get(structconfig_module*config, constchar*username, json_t*j_user, void*cls);
/** * function executed on a get_user_profile, the user_profile is the attributes the user has access to * this function will update the j_user content accordingly to its requirements, or leave it as is if needed * must return G_OK on success, an error value on error */intuser_middleware_module_get_profile(structconfig_module*config, constchar*username, json_t*j_user, void*cls);
/** * function executed before a add_user, set_user or set_user_profile * this function will update the j_user content accordingly to its requirements, or leave it as is if needed * must return G_OK on success, an error value on error */intuser_middleware_module_update(structconfig_module*config, constchar*username, json_t*j_user, void*cls);
/** * function executed before a delete_user * this function will update the j_user content accordingly to its requirements, or leave it as is if needed * must return G_OK on success, an error value on error */intuser_middleware_module_delete(structconfig_module*config, constchar*username, json_t*j_user, void*cls);
We usually use Apache 2.0 license in Casbin main repos. But I think it's OK to follow the https://github.com/babelouest/glewlwyd repo's license (which is GPL 3.0) if we put the middleware code directly into it.
To explain my point of view, I'm open minded with the licences third parties want to use with the modules, that's why the mock modules and the required files to include use MIT license, while the rest of glewlwyd is using GPL3.
Therefore even a closed source license would be possible for a module, although in that case I wouldn't be part of its implementation.
Concerning my glewlwyd repository, I'll include only free-as-in-free-speech and DFSG compliant code, to respect the philosophy. Therefore, Apache 2 license is allowed too, but I might say I prefer GPL3 for my own.
Bottom line, I'm ok with a GPL3 license for the casbin module, but I'm not closed to other compatible license in general ;)
casbin-cpp has not yet been configured to be called within C. This would require developing C wrappers for casbin's intrinsic functions and classes. I'll be working on this next week as well along with benchmarking.
Activity
hsluoyz commentedon May 21, 2021
@EmperorYP7
/cc @xcaptain
EmperorYP7 commentedon May 21, 2021
I'd like to work on this. I still need to get into the weeds of Glewlwyd which might take me a while. So I need @xcaptain's help on this.
babelouest commentedon May 21, 2021
Hello, Glewlwyd's author here!
I'm available to help improving casbin and/or Glewlwyd to integrate one with another.
Glewlwyd's ACL design is based on the OAuth2 scopes: When a user asks for an access token to Glewlwyd, Glewlwyd checks that the user is allowed to grant those scopes, and asks for new authentication factors if the scopes require it.
For now, the security model of a user is like a flat list, for example, a user object could look like this:
The user model is flexible enough to add other properties, example:
address,certificate,picture, you name it. The requirement for any additional property is that the values must be a string or an array of strings. You can add any number of additional properties.I don't know casbin at all, nor its security model so correct me if I'm wrong.
One solution I see for the integration is to create a user backend module, based on the database or ldap module, or both.
This new module would behave as the original, but would also include ACLs properties. Those ACLs can be included as one or multiple additional properties, depending on the need, and therefore be included in the access token as Additional claims in the ID Token or the /userinfo endpoint. This solution is elegant because it doesn't adds another protocol to implement for the client or the resource service. Its main problem is that the client must know all the addition claims available to request the correct ones, or potentially get a huge amount of claims and deals with them.
Another solution is to add a new plugin to handle the interface with the casbin backend. This plugin would have its REST API and would be called to answer more precise questions: "Is this user allowed to read A and write B?". The main problem I see with this solution is that the client and the resource server must implement an interface to the casbin plugin in addition to the OAuth2/OIDC standard. This plugin would also be a duplicate of what already exists in the casbin ecosystem, therefore the benefit is limited. i.e. it's not more or less complicated to ask a casbin interface if "user is allowed to read A and write B?" or ask glewlwyd's casbin plugin the exact same question.
A concern I have is that the plugin would not implement a standard but a dedicated interface. And if the casbin interface changes, the plugin must follow the changes.
I personally don't mind, we all make free software, but since I don't intend to use casbin for myself, I hope we can both develop the plugin and maintain it over the month or years of its life.
xcaptain commentedon May 21, 2021
@babelouest Your idea that encoding policies to OAuth token is very clever, I once built an OAuth server, I use a database table to store the relation of scope and correspond API, not very convenient and can't be abstracted as a library.
The OAuth scope model is very simple, it's just an ACL, for example, if a token has scope
file:read, then this token can access API likegetFileorlistFile, a regex match can solve this problem. But if the scopes have intersections, we can consider using casbin, because casbin is very good at handling hierarchical or negative permissions.babelouest commentedon May 30, 2021
While thinking about it, I came out with a better idea than updating the existing user backends, instead, I'll add a middleware backend system.
These middleware backends would be placed between glewlwyd core and the user backends and would be able to access and update the user objects. Their possibility would be potentially limitless with the user object.
For example, in the case of casbin, the middleware beckend would do something like this:
This way will be better and easier to implement and to test, and will allow to use backends and middleware in symbiosis, rather than having an updated backend and having to maintain it in parallel of a similar one.
hsluoyz commentedon Jun 7, 2021
@EmperorYP7 plz work on this.
EmperorYP7 commentedon Jun 7, 2021
@hsluoyz sure! Should we create the middleware separately, or include it in glewlwyd's source?
Are there any examples of such middleware(s) to which I can refer? Can this be a viable starting point?
I'll be glad if someone can educate me/drop-in references on how middlewares work in glewlwyd while I try to figure it out since I am not familiar with it enough.
babelouest commentedon Jun 7, 2021
@EmperorYP7 ,
The middleware modules implementation is still a WIP, I'm working on the front-end at the moment, the tests will follow, and the documentation too. But you can start working on a middleware module, based on the mock you mention, that's what it's for.
The front-end must have an update too to integrate the casbin parameter, we can make that when we're sure what parameters will be required for it.
I will be happy to include the casbin middleware module in Glewlwyd's project, assuming we agree on a license.
Feel free to ask questions or challenge the interface if you think it should be changed!
A few tips on the functions definitions to help you start:
EmperorYP7 commentedon Jun 7, 2021
Thank you @babelouest. 😄
@hsluoyz I think we should be creating a middleware within glewlwyd's source.
babelouest commentedon Jun 7, 2021
You can also reach me on IRC, libera network, channel #glewlwyd
hsluoyz commentedon Jun 8, 2021
@babelouest @EmperorYP7 thanks for the update! The middleware design looks great :)
We usually use Apache 2.0 license in Casbin main repos. But I think it's OK to follow the https://github.com/babelouest/glewlwyd repo's license (which is GPL 3.0) if we put the middleware code directly into it.
babelouest commentedon Jun 8, 2021
@hsluoyz , no problem for the license.
To explain my point of view, I'm open minded with the licences third parties want to use with the modules, that's why the mock modules and the required files to include use MIT license, while the rest of glewlwyd is using GPL3.
Therefore even a closed source license would be possible for a module, although in that case I wouldn't be part of its implementation.
Concerning my glewlwyd repository, I'll include only
free-as-in-free-speechand DFSG compliant code, to respect the philosophy. Therefore, Apache 2 license is allowed too, but I might say I prefer GPL3 for my own.Bottom line, I'm ok with a GPL3 license for the casbin module, but I'm not closed to other compatible license in general ;)
babelouest commentedon Jun 9, 2021
@EmperorYP7 , the middleware modules management is now ready in the master branch.
EmperorYP7 commentedon Jun 9, 2021
That's great! I am on it. Thanks for the update. 😄
EmperorYP7 commentedon Jun 11, 2021
Quick update:
casbin-cpp has not yet been configured to be called within C. This would require developing C wrappers for casbin's intrinsic functions and classes. I'll be working on this next week as well along with benchmarking.
babelouest commentedon Jun 11, 2021
You may not have to wrap casbin functions: I've written a module in a similar context by adding
extern "C"to the functions that are exported, see https://github.com/babelouest/angharad/blob/master/src/benoic/device-modules/device-zwave.cpp#L514 for example.Something like that:
The Makefile will use
g++instead oggccand the cmake script won't have a difference if I recall correctly.EmperorYP7 commentedon Jun 12, 2021
Thank you so much. Saved me a lot of time! 😄 @babelouest
babelouest commentedon Jun 12, 2021
My pleasure