Group based HTTP basic authentication using Nginx and MySQL with help of Lua
Recently I moved from Apache to Nginx on one of my servers due to increase in traffic. But I was using HTTP Basic authentication with group based authorization on Apache in this manner:
1 2 3 4 5 6 7 8 |
<Location /foo> AuthType Basic AuthName Restricted AuthBasicProvider file AuthUserFile /etc/apache2/htpasswd AuthGroupFile /etc/apache2/groups Require group somegroup </Location> |
1 2 3 4 |
location ~ ^/restricted { set $user_group 'somegroup'; access_by_lua_file '/etc/nginx/authenticate.lua'; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
-- basic configuration of the script local cookie_domain = ".yourdomain.com" local db_username = "dbuser" local db_password = "dbpasswrod" local db_socket = "/tmp/mysql.sock" local db_name = "dbname" -- end configuration local session = require "resty.session".open{ cookie = { domain = cookie_domain } } local remote_password if ngx.var.http_authorization then local tmp = ngx.var.http_authorization tmp = tmp:sub(tmp:find(' ')+1) tmp = ngx.decode_base64(tmp) remote_password = tmp:sub(tmp:find(':')+1) end function authentication_prompt() session.data.valid_user = false session.data.user_group = nil session:save() ngx.header.www_authenticate = 'Basic realm="Restricted"' ngx.exit(401) end function authenticate(user, password, group) local mysql = require "resty.mysql" local db, err, errno, sqlstate, res, ok db = mysql:new() if not db then ngx.log(ngx.ERR, "Failed to create mysql object") ngx.exit(500) end db:set_timeout(2000) ok, err, errno, sqlstate = db:connect{ path = db_socket, database = db_name, user = db_username, password = db_password } if not ok then ngx.log(ngx.ERR, "Unable to connect to database: ", err, ": ", errno, " ", sqlstate) ngx.exit(500) end user = ngx.quote_sql_str(user) password = ngx.quote_sql_str(password) local query = "select 1 from http_users where username = %s and password = SHA2(%s, 224) and (find_in_set('superadmin', groups) > 0 or find_in_set('%s', groups) > 0)" query = string.format(query, user, password, group); res, err, errno, sqlstate = db:query(query) if res and res[1] then session.data.valid_user = true session.data.user_group = group session:save() else authentication_prompt() end end if session.present and (session.data.valid_user and session.data.user_group == ngx.var.user_group) then return elseif ngx.var.remote_user and remote_password then authenticate(ngx.var.remote_user, remote_password, ngx.var.user_group) else authentication_prompt() end |
The group authentication script looks for users and groups in a table called http_users. Since this […]
Nginx and Metalog
Metalog is an easily configurable system logger daemon which can be substituted for standard syslogd and klogd. It has one limitation though, that you cannot log to remote machines. It’s very easy to configure Nginx to use Syslog (Metalog, in my case).