Mercurial > prosody-modules
comparison mod_auth_dovecot/mod_auth_dovecot.lua @ 268:cfcd4efb0fa4
mod_auth_dovecot: Remove asserts (use logger) and refactor socket code
author | Javier Torres <javitonino@gmail.com> |
---|---|
date | Sat, 30 Oct 2010 23:38:39 +0200 |
parents | 76f3310ec113 |
children | 74846ec9c29f |
comparison
equal
deleted
inserted
replaced
267:76f3310ec113 | 268:cfcd4efb0fa4 |
---|---|
14 local pposix = require "util.pposix"; | 14 local pposix = require "util.pposix"; |
15 | 15 |
16 local prosody = _G.prosody; | 16 local prosody = _G.prosody; |
17 | 17 |
18 function new_default_provider(host) | 18 function new_default_provider(host) |
19 local provider = { name = "dovecot" }; | 19 local provider = { name = "dovecot", c = nil }; |
20 log("debug", "initializing dovecot authentication provider for host '%s'", host); | 20 log("debug", "initializing dovecot authentication provider for host '%s'", host); |
21 | 21 |
22 function provider.test_password(username, password) | 22 -- The following connects to a new socket and send the handshake |
23 log("debug", "test password '%s' for user %s at host %s", password, username, module.host); | 23 function provider.connect(self) |
24 -- Destroy old socket | |
25 if (provider.c ~= nil) then | |
26 provider.c:close(); | |
27 end | |
24 | 28 |
25 c = assert(socket.unix()); | 29 provider.c = socket.unix(); |
26 assert(c:connect("/var/run/dovecot/auth-login")); -- FIXME: Hardcoded is bad | |
27 | 30 |
31 -- Create a connection to dovecot socket | |
32 local socket = "/var/run/dovecot/auth-login"; | |
33 local r, e = provider.c:connect(socket); | |
34 if (not r) then | |
35 log("warn", "error connecting to dovecot socket at '%s'. error was '%s'. check permissions", socket, e); | |
36 return false; | |
37 end | |
38 | |
39 -- Send our handshake | |
28 local pid = pposix.getpid(); | 40 local pid = pposix.getpid(); |
29 | 41 if not provider:send("VERSION\t1\t1\n") then |
30 -- Send our handshake | 42 return false |
31 -- FIXME: Oh no! There are asserts everywhere | 43 end |
32 assert(c:send("VERSION\t1\t1\n")); | 44 if (not provider:send("CPID\t" .. pid .. "\n")) then |
33 assert(c:send("CPID\t" .. pid .. "\n")); | 45 return false |
34 | 46 end |
35 -- Check their handshake | 47 |
48 -- Parse Dovecot's handshake | |
36 local done = false; | 49 local done = false; |
37 while (not done) do | 50 while (not done) do |
38 local l = assert(c:receive()); | 51 local l = provider:receive(); |
52 if (not l) then | |
53 return false; | |
54 end | |
55 | |
39 parts = string.gmatch(l, "[^\t]+"); | 56 parts = string.gmatch(l, "[^\t]+"); |
40 first = parts(); | 57 first = parts(); |
41 if (first == "VERSION") then | 58 if (first == "VERSION") then |
42 assert(parts() == "1"); | 59 -- Version should be 1.1 |
43 assert(parts() == "1"); | 60 local v1 = parts(); |
61 local v2 = parts(); | |
62 | |
63 if (not (v1 == "1" and v2 == "1")) then | |
64 log("warn", "server version is not 1.1. it is %s.%s", v1, v2); | |
65 return false; | |
66 end | |
44 elseif (first == "MECH") then | 67 elseif (first == "MECH") then |
68 -- Mechanisms should include PLAIN | |
45 local ok = false; | 69 local ok = false; |
46 for p in parts do | 70 for p in parts do |
47 if p == "PLAIN" then | 71 if p == "PLAIN" then |
48 ok = true; | 72 ok = true; |
49 end | 73 end |
50 end | 74 end |
51 assert(ok); | 75 if (not ok) then |
76 log("warn", "server doesn't support PLAIN mechanism. It supports '%s'", l); | |
77 return false; | |
78 end | |
52 elseif (first == "DONE") then | 79 elseif (first == "DONE") then |
53 done = true; | 80 done = true; |
54 end | 81 end |
55 end | 82 end |
56 | 83 return true; |
84 end | |
85 | |
86 function provider.send(self, data) | |
87 local r, e = provider.c:send(data); | |
88 if (not r) then | |
89 log("warn", "error sending '%s' to dovecot. error was '%s'", data, e); | |
90 return false; | |
91 end | |
92 return true; | |
93 end | |
94 | |
95 function provider.receive(self) | |
96 local r, e = provider.c:receive(); | |
97 if (not r) then | |
98 log("warn", "error receiving data from dovecot. error was '%s'", socket, e); | |
99 return false; | |
100 end | |
101 return r; | |
102 end | |
103 | |
104 function provider.test_password(username, password) | |
105 log("debug", "test password '%s' for user %s at host %s", password, username, module.host); | |
106 | |
107 if (not provider:connect()) then | |
108 return nil, "Auth failed. Dovecot communications error"; | |
109 end | |
110 | |
57 -- Send auth data | 111 -- Send auth data |
58 username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server | 112 username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server |
59 local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password); | 113 local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password); |
60 local id = "54321"; -- FIXME: probably can just be a fixed value if making one request per connection | 114 local id = "54321"; -- FIXME: probably can just be a fixed value if making one request per connection |
61 assert(c:send("AUTH\t" .. id .. "\tPLAIN\tservice=XMPP\tresp=" .. b64 .. "\n")); | 115 if (not provider:send("AUTH\t" .. id .. "\tPLAIN\tservice=XMPP\tresp=" .. b64 .. "\n")) then |
62 local l = assert(c:receive()); | 116 return nil, "Auth failed. Dovecot communications error"; |
63 assert(c:close()); | 117 end |
118 | |
119 -- Get response | |
120 local l = provider:receive(); | |
121 if (not l) then | |
122 return nil, "Auth failed. Dovecot communications error"; | |
123 end | |
64 local parts = string.gmatch(l, "[^\t]+"); | 124 local parts = string.gmatch(l, "[^\t]+"); |
65 | 125 |
126 -- Check response | |
66 if (parts() == "OK") then | 127 if (parts() == "OK") then |
67 return true; | 128 return true; |
68 else | 129 else |
69 return nil, "Auth failed. Invalid username or password."; | 130 return nil, "Auth failed. Invalid username or password."; |
70 end | 131 end |
71 end | 132 end |
72 | 133 |
73 function provider.get_password(username) | 134 function provider.get_password(username) |
74 return nil, "Cannot get_password in dovecot backend."; | 135 return nil, "Cannot get_password in dovecot backend."; |
75 end | 136 end |
76 | 137 |
77 function provider.set_password(username, password) | 138 function provider.set_password(username, password) |
78 return nil, "Cannot set_password in dovecot backend."; | 139 return nil, "Cannot set_password in dovecot backend."; |
79 end | 140 end |
80 | 141 |
81 function provider.user_exists(username) | 142 function provider.user_exists(username) |
82 --TODO: Send an auth request. If it returns FAIL <id> user=<user> then user exists. | 143 --TODO: Send an auth request. If it returns FAIL <id> user=<user> then user exists. |
83 return nil, "user_exists not yet implemented in dovecot backend."; | 144 return nil, "user_exists not yet implemented in dovecot backend."; |
84 end | 145 end |
85 | 146 |
86 function provider.create_user(username, password) | 147 function provider.create_user(username, password) |
87 return nil, "Cannot create_user in dovecot backend."; | 148 return nil, "Cannot create_user in dovecot backend."; |
88 end | 149 end |
89 | 150 |
90 function provider.get_sasl_handler() | 151 function provider.get_sasl_handler() |
91 local realm = module:get_option("sasl_realm") or module.host; | 152 local realm = module:get_option("sasl_realm") or module.host; |
92 local getpass_authentication_profile = { | 153 local getpass_authentication_profile = { |
93 plain_test = function(username, password, realm) | 154 plain_test = function(username, password, realm) |
94 local prepped_username = nodeprep(username); | 155 local prepped_username = nodeprep(username); |
95 if not prepped_username then | 156 if not prepped_username then |
96 log("debug", "NODEprep failed on username: %s", username); | 157 log("debug", "NODEprep failed on username: %s", username); |
97 return "", nil; | 158 return "", nil; |
98 end | 159 end |
99 return usermanager.test_password(prepped_username, realm, password), true; | 160 return usermanager.test_password(prepped_username, realm, password), true; |
100 end | 161 end |
101 }; | 162 }; |
102 return new_sasl(realm, getpass_authentication_profile); | 163 return new_sasl(realm, getpass_authentication_profile); |
103 end | 164 end |
104 | 165 |
105 return provider; | 166 return provider; |
106 end | 167 end |
107 | 168 |
108 module:add_item("auth-provider", new_default_provider(module.host)); | 169 module:add_item("auth-provider", new_default_provider(module.host)); |
109 | 170 |