Commit 8a5c4880 authored by Julien Muchembled's avatar Julien Muchembled

registry: delete unused accounts and old tokens automatically

Certificates are deleted 30 days after they get invalid,
so that unused prefixes can be reallocated.
parent d7d7b425
#!/usr/bin/python #!/usr/bin/python
import errno, httplib, logging, select, socket import errno, httplib, logging, select, socket, time
from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import BaseHTTPRequestHandler
from SocketServer import ThreadingTCPServer from SocketServer import ThreadingTCPServer
from urlparse import parse_qsl from urlparse import parse_qsl
...@@ -103,8 +103,17 @@ def main(): ...@@ -103,8 +103,17 @@ def main():
if server_list: if server_list:
empty_list = [] empty_list = []
while True: while True:
while True:
next = server._timeout
if next is None:
break
next -= time.time()
if next > 0:
break
server._onTimeout()
try: try:
r = select.select(server_list[:], empty_list, empty_list)[0] r = select.select(server_list[:], empty_list, empty_list,
next)[0]
except select.error as e: except select.error as e:
if e.args[0] != errno.EINTR: if e.args[0] != errno.EINTR:
raise raise
......
import base64, hmac, hashlib, httplib, inspect, logging, mailbox, os, random import base64, hmac, hashlib, httplib, inspect, logging, mailbox, os, random
import select, smtplib, socket, sqlite3, string, struct, threading, time import select, smtplib, socket, sqlite3, string, struct, sys, threading, time
from collections import deque from collections import deque
from datetime import datetime
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from email.mime.text import MIMEText from email.mime.text import MIMEText
from OpenSSL import crypto from OpenSSL import crypto
...@@ -9,6 +10,7 @@ from . import tunnel, utils ...@@ -9,6 +10,7 @@ from . import tunnel, utils
HMAC_HEADER = "Re6stHMAC" HMAC_HEADER = "Re6stHMAC"
RENEW_PERIOD = 30 * 86400 RENEW_PERIOD = 30 * 86400
GRACE_PERIOD = RENEW_PERIOD
class getcallargs(type): class getcallargs(type):
...@@ -77,6 +79,49 @@ class RegistryServer(object): ...@@ -77,6 +79,49 @@ class RegistryServer(object):
logging.info("Network: %s/%u", utils.ipFromBin(self.network), logging.info("Network: %s/%u", utils.ipFromBin(self.network),
len(self.network)) len(self.network))
self._email = self.ca.get_subject().emailAddress self._email = self.ca.get_subject().emailAddress
self._onTimeout()
def _onTimeout(self):
# XXX: Because we use threads to process requests, the statements
# 'self._timeout = 1' below have no effect as long as the
# 'select' call does not return. Ideally, we should interrupt it.
logging.info("Checking if there's any old entry in the database ...")
not_after = None
old = time.time() - GRACE_PERIOD
q = self.db.execute
with self.lock:
with self.db:
q("BEGIN")
for token, x in q("SELECT token, date FROM token"):
if x <= old:
q("DELETE FROM token WHERE token=?", (token,))
elif not_after is None or x < not_after:
not_after = x
for prefix, email, cert in q("SELECT * FROM cert"
" WHERE cert IS NOT NULL"):
try:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
except crypto.Error:
continue
x = utils.notAfter(cert)
if x <= old:
if prefix == self.prefix:
logging.critical("Refuse to delete certificate"
" of main node: wrong clock ?")
sys.exit(1)
logging.info("Delete %s: %s (invalid since %s)",
"certificate requested by '%s'" % email
if email else "anonymous certificate",
", ".join("%s=%s" % x for x in
cert.get_subject().get_components()),
datetime.utcfromtimestamp(x).isoformat())
q("UPDATE cert SET email=null, cert=null WHERE prefix=?",
(prefix,))
elif not_after is None or x < not_after:
not_after = x
# TODO: reduce 'cert' table by merging free slots
# (IOW, do the contrary of _newPrefix)
self._timeout = not_after and not_after + GRACE_PERIOD
def _handle_request(self, request, method, kw): def _handle_request(self, request, method, kw):
m = getattr(self, method) m = getattr(self, method)
...@@ -129,16 +174,18 @@ class RegistryServer(object): ...@@ -129,16 +174,18 @@ class RegistryServer(object):
(client_prefix,)).next()[0] (client_prefix,)).next()[0]
def requestToken(self, email): def requestToken(self, email):
while True: with self.lock:
# Generating token while True:
token = ''.join(random.sample(string.ascii_lowercase, 8)) # Generating token
args = token, email, self.config.prefix_length, int(time.time()) token = ''.join(random.sample(string.ascii_lowercase, 8))
# Updating database args = token, email, self.config.prefix_length, int(time.time())
try: # Updating database
self.db.execute("INSERT INTO token VALUES (?,?,?,?)", args) try:
break self.db.execute("INSERT INTO token VALUES (?,?,?,?)", args)
except sqlite3.IntegrityError: break
pass except sqlite3.IntegrityError:
pass
self._timeout = 1
# Creating and sending email # Creating and sending email
msg = MIMEText('Hello, your token to join re6st network is: %s\n' msg = MIMEText('Hello, your token to join re6st network is: %s\n'
...@@ -219,6 +266,7 @@ class RegistryServer(object): ...@@ -219,6 +266,7 @@ class RegistryServer(object):
cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert) cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
self.db.execute("UPDATE cert SET cert = ? WHERE prefix = ?", self.db.execute("UPDATE cert SET cert = ? WHERE prefix = ?",
(cert, client_prefix)) (cert, client_prefix))
self._timeout = 1
return cert return cert
def renewCertificate(self, cn): def renewCertificate(self, cn):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment