- Published on
Casbin OpenResty Example
A simple example of OpenResty application with RBAC using Casbin (Lua)
This is a very simple example of an application using the OpenResty stack with RBAC authorization using Casbin. This is a sample so it isn't secure or anything but it is more of an example template to help integrate Casbin in your OR applications.
The full source code is at casbin-openresty-example.
Installing Casbin
If you haven't installed OpenResty yet, you can do that here. This assumes that your installation is at /usr/bin/openresty
, if not you may need to change the relative paths accordingly.
You also need to install LuaRocks first if you haven't, you can do so by:
wget https://luarocks.org/releases/luarocks-3.3.1.tar.gz
tar zxpf luarocks-3.3.1.tar.gz
cd luarocks-3.3.1
./configure --prefix=/usr/local/openresty/luajit \
--with-lua=/usr/local/openresty/luajit/ \
--lua-suffix=jit-2.1.0-beta3 \
--with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1
sudo make
sudo make install
And then to install the dependencies - GCC and PCRE:
sudo apt update
sudo apt install gcc libpcre3 libpcre3-dev
Finally, you can install the latest released version of Casbin by:
sudo /usr/local/openresty/luajit/bin/luarocks install casbin
This should install Casbin (Lua) and all it's dependencies.
Creating example Casbin model file and policy file
We will use the basic RBAC model and policy files for this example. So, creating a example
directory by:
mkdir example
And creating a rbac_model.conf
in the example
directory with the following model:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
Also, creating a rbac_policy.csv
in the example
directory with the following policy:
p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin
Creating nginx.conf
Then, we will create 3 more directories in the project - conf, logs and lua by:
mkdir conf logs lua
Then in the conf directory create a nginx.conf config file for the Nginx server by:
vim conf/nginx.conf
which will contain this:
worker_processes 1;
events {
worker_connections 1024;
}
http {
init_by_lua_block {
local Enforcer = require("casbin")
-- Initialize a new enforcer at server start
e = Enforcer:new("example/rbac_model.conf", "example/rbac_policy.csv")
}
lua_package_path "$prefix/lua/?.lua;;";
server {
listen 8080 reuseport;
location / {
default_type text/plain;
content_by_lua_block {
}
}
}
}
Here the block init_by_lua_block
will run only at the server start (or reload) which is:
local Enforcer = require("casbin")
-- Initialize a new enforcer at server start
e = Enforcer:new("example/rbac_model.conf", "example/rbac_policy.csv")
Here, we create a new Casbin Enforcer e
which is defined globally.
Creating app.lua
Then we create a lua file as app.lua
by:
vim lua/app.lua
which will contain this:
local M = {}
function M.check(e)
local req = ngx.var.request_uri
for usr, obj, act in req:gmatch("/(%w+)%?obj=(%w+)&act=(%w+)") do
-- If pattern matches, shows the request and enforce result
ngx.say("Request:\t", "User:"..usr.."\t", "Object:"..obj.."\t", "Action:"..act)
ngx.say("Result = ", e:enforce(usr, obj, act))
break
end
end
return M
and add the following code in content_by_lua_block
to nginx.conf:
local app = require("app")
-- Check at every request
app.check(e)
Usage
You can then start the server by:
sudo openresty -p $PWD/
And fetch the page with
curl http://127.0.0.1:8080/
So what this does is, when you send request with curl http://127.0.0.1:8080/alice?obj=data1&act=read
, it will match usr = alice
, obj = data1
and act = read
and send the parameters to e:enforce(usr, obj, act)
which will return the enforce result.
For example, if you send a curl request as:
curl http://127.0.0.1:8080/alice?obj=data2&act=read
Since, alice
has a role as data2_admin
, it can acces the data2
object with read
and write
actions as defined in policy. So this will output in:
Request: User:alice Object:data2 Action:read
Result = true
And if you send the curl request as:
curl http://127.0.0.1:8080/bob?obj=data1&act=write
Since bob
has no policy in data1
object, it will output in:
Request: User:bob Object:data1 Action:write
Result = false
The full source code is at casbin-openresty-example.