Mercurial > prosody-modules
comparison mod_client_certs/mod_client_certs.lua @ 990:17ba2c59d661
mod_client_certs: Updated to match the specification in urn:xmpp:saslcert:1.
| author | Thijs Alkemade <me@thijsalkema.de> |
|---|---|
| date | Mon, 29 Apr 2013 23:32:16 +0200 |
| parents | 88ef66a65b13 |
| children | 1abb8f2a5761 |
comparison
equal
deleted
inserted
replaced
| 989:7c04c5856daa | 990:17ba2c59d661 |
|---|---|
| 4 -- This file is MIT/X11 licensed. | 4 -- This file is MIT/X11 licensed. |
| 5 | 5 |
| 6 local st = require "util.stanza"; | 6 local st = require "util.stanza"; |
| 7 local jid_bare = require "util.jid".bare; | 7 local jid_bare = require "util.jid".bare; |
| 8 local jid_split = require "util.jid".split; | 8 local jid_split = require "util.jid".split; |
| 9 local xmlns_saslcert = "urn:xmpp:saslcert:0"; | 9 local xmlns_saslcert = "urn:xmpp:saslcert:1"; |
| 10 local xmlns_pubkey = "urn:xmpp:tmp:pubkey"; | |
| 11 local dm_load = require "util.datamanager".load; | 10 local dm_load = require "util.datamanager".load; |
| 12 local dm_store = require "util.datamanager".store; | 11 local dm_store = require "util.datamanager".store; |
| 13 local dm_table = "client_certs"; | 12 local dm_table = "client_certs"; |
| 14 local x509 = require "ssl.x509"; | 13 local x509 = require "ssl.x509"; |
| 15 local id_on_xmppAddr = "1.3.6.1.5.5.7.8.5"; | 14 local id_on_xmppAddr = "1.3.6.1.5.5.7.8.5"; |
| 60 break; | 59 break; |
| 61 end | 60 end |
| 62 end | 61 end |
| 63 | 62 |
| 64 if not found then | 63 if not found then |
| 65 return nil, "This certificate is has no valid id-on-xmppAddr field."; | 64 return nil, "This certificate has no valid id-on-xmppAddr field."; |
| 66 end | 65 end |
| 67 end | 66 end |
| 68 | 67 |
| 69 local certs = dm_load(username, module.host, dm_table) or {}; | 68 local certs = dm_load(username, module.host, dm_table) or {}; |
| 70 | 69 |
| 71 info.pem = cert:pem(); | 70 info.pem = cert:pem(); |
| 72 local digest = cert:digest(digest_algo); | 71 local digest = cert:digest(digest_algo); |
| 73 info.digest = digest; | 72 info.digest = digest; |
| 74 certs[info.id] = info; | 73 certs[info.name] = info; |
| 75 | 74 |
| 76 dm_store(username, module.host, dm_table, certs); | 75 dm_store(username, module.host, dm_table, certs); |
| 77 return true | 76 return true |
| 78 end | 77 end |
| 79 | 78 |
| 116 | 115 |
| 117 local reply = st.reply(stanza):tag("items", { xmlns = xmlns_saslcert }); | 116 local reply = st.reply(stanza):tag("items", { xmlns = xmlns_saslcert }); |
| 118 local certs = dm_load(origin.username, module.host, dm_table) or {}; | 117 local certs = dm_load(origin.username, module.host, dm_table) or {}; |
| 119 | 118 |
| 120 for digest,info in pairs(certs) do | 119 for digest,info in pairs(certs) do |
| 121 reply:tag("item", { id = info.id }) | 120 reply:tag("item") |
| 122 :tag("name"):text(info.name):up() | 121 :tag("name"):text(info.name):up() |
| 123 :tag("keyinfo", { xmlns = xmlns_pubkey }):tag("name"):text(info["key_name"]):up() | |
| 124 :tag("x509cert"):text(info.x509cert) | 122 :tag("x509cert"):text(info.x509cert) |
| 125 :up(); | 123 :up(); |
| 126 end | 124 end |
| 127 | 125 |
| 128 origin.send(reply); | 126 origin.send(reply); |
| 134 local origin, stanza = event.origin, event.stanza; | 132 local origin, stanza = event.origin, event.stanza; |
| 135 if stanza.attr.type == "set" then | 133 if stanza.attr.type == "set" then |
| 136 | 134 |
| 137 local append = stanza:get_child("append", xmlns_saslcert); | 135 local append = stanza:get_child("append", xmlns_saslcert); |
| 138 local name = append:get_child_text("name", xmlns_saslcert); | 136 local name = append:get_child_text("name", xmlns_saslcert); |
| 139 local key_info = append:get_child("keyinfo", xmlns_pubkey); | 137 local x509cert = append:get_child_text("x509cert", xmlns_saslcert); |
| 140 | 138 |
| 141 if not key_info or not name then | 139 if not x509cert or not name then |
| 142 origin.send(st.error_reply(stanza, "cancel", "bad-request", "Missing fields.")); -- cancel? not modify? | 140 origin.send(st.error_reply(stanza, "cancel", "bad-request", "Missing fields.")); -- cancel? not modify? |
| 143 return true | 141 return true |
| 144 end | 142 end |
| 145 | 143 |
| 146 local id = key_info:get_child_text("name", xmlns_pubkey); | 144 local can_manage = append:get_child("no-cert-management", xmlns_saslcert) ~= nil; |
| 147 local x509cert = key_info:get_child_text("x509cert", xmlns_pubkey); | 145 x509cert = x509cert:gsub("^%s*(.-)%s*$", "%1"); |
| 148 | |
| 149 if not id or not x509cert then | |
| 150 origin.send(st.error_reply(stanza, "cancel", "bad-request", "No certificate found.")); | |
| 151 return true | |
| 152 end | |
| 153 | |
| 154 local can_manage = key_info:get_child("no-cert-management", xmlns_saslcert) ~= nil; | |
| 155 local x509cert = key_info:get_child_text("x509cert"):gsub("^%s*(.-)%s*$", "%1"); | |
| 156 | 146 |
| 157 local cert = x509.cert_from_pem( | 147 local cert = x509.cert_from_pem( |
| 158 "-----BEGIN CERTIFICATE-----\n" | 148 "-----BEGIN CERTIFICATE-----\n" |
| 159 .. x509cert .. | 149 .. x509cert .. |
| 160 "\n-----END CERTIFICATE-----\n"); | 150 "\n-----END CERTIFICATE-----\n"); |
| 164 origin.send(st.error_reply(stanza, "modify", "not-acceptable", "Could not parse X.509 certificate")); | 154 origin.send(st.error_reply(stanza, "modify", "not-acceptable", "Could not parse X.509 certificate")); |
| 165 return true; | 155 return true; |
| 166 end | 156 end |
| 167 | 157 |
| 168 local ok, err = enable_cert(origin.username, cert, { | 158 local ok, err = enable_cert(origin.username, cert, { |
| 169 id = id, | |
| 170 name = name, | 159 name = name, |
| 171 x509cert = x509cert, | 160 x509cert = x509cert, |
| 172 no_cert_management = can_manage, | 161 no_cert_management = can_manage, |
| 173 }); | 162 }); |
| 174 | 163 |
| 190 local origin, stanza = event.origin, event.stanza; | 179 local origin, stanza = event.origin, event.stanza; |
| 191 if stanza.attr.type == "set" then | 180 if stanza.attr.type == "set" then |
| 192 local disable = stanza.tags[1]; | 181 local disable = stanza.tags[1]; |
| 193 module:log("debug", "%s disabled a certificate", origin.full_jid); | 182 module:log("debug", "%s disabled a certificate", origin.full_jid); |
| 194 | 183 |
| 195 local item = disable:get_child("item"); | 184 local name = disable:get_child_text("name"); |
| 196 local name = item and item.attr.id; | |
| 197 | 185 |
| 198 if not name then | 186 if not name then |
| 199 origin.send(st.error_reply(stanza, "cancel", "bad-request", "No key specified.")); | 187 origin.send(st.error_reply(stanza, "cancel", "bad-request", "No key specified.")); |
| 200 return true | 188 return true |
| 201 end | 189 end |
| 273 }; | 261 }; |
| 274 | 262 |
| 275 local certs = dm_load(jid_split(data.from), module.host, dm_table) or {}; | 263 local certs = dm_load(jid_split(data.from), module.host, dm_table) or {}; |
| 276 | 264 |
| 277 for digest, info in pairs(certs) do | 265 for digest, info in pairs(certs) do |
| 278 list_layout[#list_layout + 1] = { name = info.id, type = "text-multi", label = info.name, value = info.x509cert }; | 266 list_layout[#list_layout + 1] = { name = info.name, type = "text-multi", label = info.name, value = info.x509cert }; |
| 279 end | 267 end |
| 280 | 268 |
| 281 return { status = "completed", result = list_layout }; | 269 return { status = "completed", result = list_layout }; |
| 282 else | 270 else |
| 283 local layout = dataforms_new { | 271 local layout = dataforms_new { |
| 295 | 283 |
| 296 local certs = dm_load(jid_split(data.from), module.host, dm_table) or {}; | 284 local certs = dm_load(jid_split(data.from), module.host, dm_table) or {}; |
| 297 | 285 |
| 298 local values = {}; | 286 local values = {}; |
| 299 for digest, info in pairs(certs) do | 287 for digest, info in pairs(certs) do |
| 300 values[#values + 1] = { label = info.name, value = info.id }; | 288 values[#values + 1] = { label = info.name, value = info.name }; |
| 301 end | 289 end |
| 302 | 290 |
| 303 return { status = "executing", form = { layout = layout, values = { cert = values } }, actions = { "prev", "next", "complete" } }, | 291 return { status = "executing", form = { layout = layout, values = { cert = values } }, actions = { "prev", "next", "complete" } }, |
| 304 { subcmd = subcmd }; | 292 { subcmd = subcmd }; |
| 305 end | 293 end |
| 322 if not cert then | 310 if not cert then |
| 323 return { status = "completed", error = { message = "Could not parse X.509 certificate" } }; | 311 return { status = "completed", error = { message = "Could not parse X.509 certificate" } }; |
| 324 end | 312 end |
| 325 | 313 |
| 326 local ok, err = enable_cert(jid_split(data.from), cert, { | 314 local ok, err = enable_cert(jid_split(data.from), cert, { |
| 327 id = cert:digest(digest_algo), | |
| 328 name = name, | 315 name = name, |
| 329 x509cert = x509cert, | 316 x509cert = x509cert, |
| 330 no_cert_management = not fields.manage | 317 no_cert_management = not fields.manage |
| 331 }); | 318 }); |
| 332 | 319 |
