comparison mod_auth_sql/mod_auth_sql.lua @ 354:f24998ec7f8d

Implemented basic SQL authentication module. This module implements authentication against plaintext password stored in SQL database. You wil definitely need to edit the Lua code and put a query working with your database. The example query works against jabberd2 database schema. P.S. This module is just some code glued together from other modules. ;-)
author Tomasz Sterna <tomek@xiaoka.com>
date Tue, 12 Apr 2011 00:30:53 +0200
parents
children c2554fee5c21
comparison
equal deleted inserted replaced
353:8ef36af30181 354:f24998ec7f8d
1 -- Simple SQL Authentication module for Prosody IM
2 -- Copyright (C) 2011 Tomasz Sterna <tomek@xiaoka.com>
3 --
4
5 local log = require "util.logger".init("auth_sql");
6 local new_sasl = require "util.sasl".new;
7 local nodeprep = require "util.encodings".stringprep.nodeprep;
8
9 local DBI;
10 local connection;
11 local host,user,store = module.host;
12 local params = module:get_option("sql");
13
14 local resolve_relative_path = require "core.configmanager".resolve_relative_path;
15
16 local function test_connection()
17 if not connection then return nil; end
18 if connection:ping() then
19 return true;
20 else
21 module:log("debug", "Database connection closed");
22 connection = nil;
23 end
24 end
25 local function connect()
26 if not test_connection() then
27 prosody.unlock_globals();
28 local dbh, err = DBI.Connect(
29 params.driver, params.database,
30 params.username, params.password,
31 params.host, params.port
32 );
33 prosody.lock_globals();
34 if not dbh then
35 module:log("debug", "Database connection failed: %s", tostring(err));
36 return nil, err;
37 end
38 module:log("debug", "Successfully connected to database");
39 dbh:autocommit(false); -- don't commit automatically
40 connection = dbh;
41 return connection;
42 end
43 end
44
45 do -- process options to get a db connection
46 DBI = require "DBI";
47
48 params = params or { driver = "SQLite3" };
49
50 if params.driver == "SQLite3" then
51 params.database = resolve_relative_path(prosody.paths.data or ".", params.database or "prosody.sqlite");
52 end
53
54 assert(params.driver and params.database, "Both the SQL driver and the database need to be specified");
55
56 assert(connect());
57 end
58
59 local function getsql(sql, ...)
60 if params.driver == "PostgreSQL" then
61 sql = sql:gsub("`", "\"");
62 end
63 -- do prepared statement stuff
64 local stmt, err = connection:prepare(sql);
65 if not stmt and not test_connection() then error("connection failed"); end
66 if not stmt then module:log("error", "QUERY FAILED: %s %s", err, debug.traceback()); return nil, err; end
67 -- run query
68 local ok, err = stmt:execute(...);
69 if not ok and not test_connection() then error("connection failed"); end
70 if not ok then return nil, err; end
71
72 return stmt;
73 end
74
75 function new_default_provider(host)
76 local provider = { name = "sql" };
77 log("debug", "initializing default authentication provider for host '%s'", host);
78
79 function provider.test_password(username, password)
80 log("debug", "test password '%s' for user %s at host %s", password, username, module.host);
81 return nil, "Password based auth not supported.";
82 end
83
84 function provider.get_password(username)
85 log("debug", "get_password for username '%s' at host '%s'", username, module.host);
86
87 local stmt, err = getsql("SELECT `password` FROM `authreg` WHERE `username`=? AND `realm`=?",
88 username, module.host);
89
90 local password = nil;
91 if stmt ~= nil then
92 for row in stmt:rows(true) do
93 password = row.password;
94 end
95 else
96 log("error", "QUERY ERROR: %s %s", err, debug.traceback());
97 return nil;
98 end
99
100 return password;
101 end
102
103 function provider.set_password(username, password)
104 return nil, "Password based auth not supported.";
105 end
106
107 function provider.user_exists(username)
108 return nil, "User exist check not supported.";
109 end
110
111 function provider.create_user(username, password)
112 return nil, "Account creation/modification not supported.";
113 end
114
115 function provider.get_sasl_handler()
116 local realm = module:get_option("sasl_realm") or module.host;
117 local getpass_authentication_profile = {
118 plain = function(sasl, username, realm)
119 local prepped_username = nodeprep(username);
120 if not prepped_username then
121 log("debug", "NODEprep failed on username: %s", username);
122 return "", nil;
123 end
124 local password = usermanager.get_password(prepped_username, realm);
125 if not password then
126 return "", nil;
127 end
128 return password, true;
129 end
130 };
131 return new_sasl(realm, getpass_authentication_profile);
132 end
133
134 return provider;
135 end
136
137 module:add_item("auth-provider", new_default_provider(module.host));
138