Commit 8cdc102c authored by Jonathan Schaeffer's avatar Jonathan Schaeffer
Browse files

black

parent e43b852e
......@@ -13,12 +13,12 @@ from version import __version__
application = Flask(__name__)
if os.getenv('RUNMODE') == 'production':
if os.getenv("RUNMODE") == "production":
application.logger.setLevel(logging.INFO)
else:
application.logger.setLevel(logging.DEBUG)
# Loglevel can be overrinden by LOGLEVEL env var :
if os.getenv('DEBUG') == 'true':
if os.getenv("DEBUG") == "true":
application.logger.setLevel(logging.DEBUG)
application.config.from_object(Configurator)
......@@ -27,24 +27,30 @@ def wsshash(login, password):
"""
Compute a hash suitable for the IRIS wss stack.
"""
return md5(("%s:FDSN:%s"%(login,password)).encode()).hexdigest()
return md5(("%s:FDSN:%s" % (login, password)).encode()).hexdigest()
def verify_token_signature(data, gpg_homedir):
# First we verify the signature
gpg = gnupg.GPG(gnupghome=gpg_homedir)
verified = gpg.verify(data)
if not verified: raise ValueError("Signature could not be verified!")
if not verified:
raise ValueError("Signature could not be verified!")
return True
def parse_input_data(data):
# Then we get the token :
token = re.search(r'{(?P<token>.*)}',str(data)).groupdict()['token']
token = re.search(r"{(?P<token>.*)}", str(data)).groupdict()["token"]
application.logger.debug(token)
d = dict([i for i in kv.split(':',1)] for kv in token.replace('"','').replace(' ','').split(','))
d = dict(
[i for i in kv.split(":", 1)]
for kv in token.replace('"', "").replace(" ", "").split(",")
)
# Add the sha1 of the token to put in the credentials db
d['shortSha1'] = sha1(token.encode()).hexdigest()[0:8]
if 'givenName' not in d:
d['givenName'] = d.get('cn', 'null')
d["shortSha1"] = sha1(token.encode()).hexdigest()[0:8]
if "givenName" not in d:
d["givenName"] = d.get("cn", "null")
application.logger.debug("Transformed to dictionary : %s", d)
return d
......@@ -56,11 +62,11 @@ def register_privileges(login, tokendict):
- For each fdsn reference, insert the privilege in the access table if not already there
"""
authorizations = []
for em in tokendict['memberof'].split(';'):
application.logger.debug("EPOS membership: "+em)
if em in application.config['EPOS_FDSN_MAP']:
for em in tokendict["memberof"].split(";"):
application.logger.debug("EPOS membership: " + em)
if em in application.config["EPOS_FDSN_MAP"]:
application.logger.debug(" ... is in epos fdsn map")
authorizations.append(application.config['EPOS_FDSN_MAP'][em])
authorizations.append(application.config["EPOS_FDSN_MAP"][em])
# Now get localy defined autorizations, from email adress
# 1. Chercher tous les users ayant cet email dans la table resifAuth.users
......@@ -72,49 +78,71 @@ def register_privileges(login, tokendict):
#
# Step 1 :
permanent_logins = []
with psycopg2.connect(dbname= application.config['RESIFAUTH_PGDATABASE'],
port = application.config['RESIFAUTH_PGPORT'],
host = application.config['RESIFAUTH_PGHOST'],
user= application.config['RESIFAUTH_PGUSER'],
password = application.config['RESIFAUTH_PGPASSWORD']) as conn:
with psycopg2.connect(
dbname=application.config["RESIFAUTH_PGDATABASE"],
port=application.config["RESIFAUTH_PGPORT"],
host=application.config["RESIFAUTH_PGHOST"],
user=application.config["RESIFAUTH_PGUSER"],
password=application.config["RESIFAUTH_PGPASSWORD"],
) as conn:
cur = conn.cursor()
application.logger.debug("Connected to users database")
cur.execute("select login from users where email=%s and expires_at is null", (tokendict['mail'],))
cur.execute(
"select login from users where email=%s and expires_at is null",
(tokendict["mail"],),
)
for l in cur:
application.logger.debug("Found an account corresponding to %s: %s", tokendict['mail'], l[0])
application.logger.debug(
"Found an account corresponding to %s: %s", tokendict["mail"], l[0]
)
permanent_logins.append(l[0])
# Step 2
# Maintenant, on enregistre les authorizations
try:
conn = psycopg2.connect(dbname= application.config['RESIFINV_PGDATABASE'],
port = application.config['RESIFINV_PGPORT'],
host = application.config['RESIFINV_PGHOST'],
user= application.config['RESIFINV_PGUSER'],
password = application.config['RESIFINV_PGPASSWORD'])
conn = psycopg2.connect(
dbname=application.config["RESIFINV_PGDATABASE"],
port=application.config["RESIFINV_PGPORT"],
host=application.config["RESIFINV_PGHOST"],
user=application.config["RESIFINV_PGUSER"],
password=application.config["RESIFINV_PGPASSWORD"],
)
cur = conn.cursor()
application.logger.debug("Connected to resifinv database")
except Exception as e:
application.logger.error("Unable to connect to database %s as %s@%s:%s", application.config['RESIFINV_PGDATABASE'],
application.config['RESIFINV_PGUSER'],
application.config['RESIFINV_PGHOST'],
application.config['RESIFINV_PGPORT'])
application.logger.error(
"Unable to connect to database %s as %s@%s:%s",
application.config["RESIFINV_PGDATABASE"],
application.config["RESIFINV_PGUSER"],
application.config["RESIFINV_PGHOST"],
application.config["RESIFINV_PGPORT"],
)
raise e
for l in permanent_logins:
application.logger.debug("Searching for privileges on login %s", l)
cur.execute("select network_id, network, start_year, end_year from resif_users where name=%s", (l,))
cur.execute(
"select network_id, network, start_year, end_year from resif_users where name=%s",
(l,),
)
for ref in cur:
authorizations.append({'networkid': ref[0], 'networkcode': ref[1], 'startyear': ref[2], 'endyear': ref[3] })
authorizations.append(
{
"networkid": ref[0],
"networkcode": ref[1],
"startyear": ref[2],
"endyear": ref[3],
}
)
if len(authorizations) == 0:
application.logger.debug("No membership for user %s", login)
return
application.logger.debug("FDSN authorizations: %s"%(authorizations))
application.logger.debug("FDSN authorizations: %s" % (authorizations))
# Get the network id
for ref in authorizations:
ref['login'] = login
ref['expires_at'] = datetime.datetime.now()+datetime.timedelta(days=1)
ref["login"] = login
ref["expires_at"] = datetime.datetime.now() + datetime.timedelta(days=1)
application.logger.info(ref)
sql_request = "select network_id from networks where start_year=%(startyear)s and end_year=%(endyear)s and network=%(networkcode)s"
try:
......@@ -126,16 +154,24 @@ def register_privileges(login, tokendict):
application.logger.info(cur.mogrify(sql_request, ref))
application.logger.error("%d networks found for %s", cur.rowcount, ref)
raise NameError(f"{cur.rowcount} networks found for {ref}")
ref['networkid'] = cur.fetchone()[0]
application.logger.info("Inserting tupple in %s.eida_temp_users: %s", application.config['RESIFINV_PGDATABASE'], ref)
cur.execute("""
ref["networkid"] = cur.fetchone()[0]
application.logger.info(
"Inserting tupple in %s.eida_temp_users: %s",
application.config["RESIFINV_PGDATABASE"],
ref,
)
cur.execute(
"""
INSERT INTO eida_temp_users (network_id, network, start_year, end_year, name, expires_at)
VALUES (%(networkid)s, %(networkcode)s, %(startyear)s, %(endyear)s, %(login)s, %(expires_at)s)
ON CONFLICT DO NOTHING;
""", ref)
""",
ref,
)
conn.commit()
conn.close()
def get_login_password(tokendict):
"""
Try to read the token's mail. If it exists and a valid credential already exists in the database, return this tuple
......@@ -146,39 +182,73 @@ def get_login_password(tokendict):
login = ""
password = ""
try:
conn = psycopg2.connect(dbname= application.config['RESIFAUTH_PGDATABASE'],
port = application.config['RESIFAUTH_PGPORT'],
host = application.config['RESIFAUTH_PGHOST'],
user= application.config['RESIFAUTH_PGUSER'],
password = application.config['RESIFAUTH_PGPASSWORD'])
conn = psycopg2.connect(
dbname=application.config["RESIFAUTH_PGDATABASE"],
port=application.config["RESIFAUTH_PGPORT"],
host=application.config["RESIFAUTH_PGHOST"],
user=application.config["RESIFAUTH_PGUSER"],
password=application.config["RESIFAUTH_PGPASSWORD"],
)
cur = conn.cursor()
application.logger.debug("Connected to users database")
cur.execute("select user_index,login from users where email=%s and expires_at between now()+'1 hour' and now()+'26 hours'", (tokendict['mail'],))
cur.execute(
"select user_index,login from users where email=%s and expires_at between now()+'1 hour' and now()+'26 hours'",
(tokendict["mail"],),
)
application.logger.debug(cur.mogrify("select user_index,login from users where email=%s and expires_at between now()+'1 hour' and now()+'26 hours'", (tokendict['mail'],)))
application.logger.debug(
cur.mogrify(
"select user_index,login from users where email=%s and expires_at between now()+'1 hour' and now()+'26 hours'",
(tokendict["mail"],),
)
)
if cur.rowcount != 0:
(uid, login) = cur.fetchone()
application.logger.debug("Found a temporary account corresponding to %s: %s", tokendict['mail'], uid)
cur.execute("select password_hash from credentials where user_index=%s", (uid,))
application.logger.debug(
"Found a temporary account corresponding to %s: %s",
tokendict["mail"],
uid,
)
cur.execute(
"select password_hash from credentials where user_index=%s", (uid,)
)
if cur.rowcount != 0:
password = cur.fetchone()[0]
application.logger.debug("Found correspondig password also: %s", password)
application.logger.debug(
"Found correspondig password also: %s", password
)
# If not found, compute a random login and password
if not login or not password:
application.logger.debug("No existing user found. Create a new one")
login = ''.join(random.choices(string.ascii_uppercase + string.digits, k=14))
password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=14))
expiration_time = datetime.datetime.now()+datetime.timedelta(days=1)
login = "".join(
random.choices(string.ascii_uppercase + string.digits, k=14)
)
password = "".join(
random.choices(string.ascii_uppercase + string.digits, k=14)
)
expiration_time = datetime.datetime.now() + datetime.timedelta(days=1)
# Register login in authentication database
cur.execute("""
cur.execute(
"""
INSERT INTO users VALUES (DEFAULT, %(login)s, %(sn)s, %(givenName)s, %(mail)s, %(expires_at)s);
""",
{'login': login, 'givenName': tokendict['givenName'], 'sn': tokendict['sn'], 'mail': tokendict['mail'], 'expires_at': expiration_time }
{
"login": login,
"givenName": tokendict["givenName"],
"sn": tokendict["sn"],
"mail": tokendict["mail"],
"expires_at": expiration_time,
},
)
cur.execute("""
cur.execute(
"""
INSERT INTO credentials (user_index, password_hash, ws_hash, expires_at) VALUES (CURRVAL('users_user_index_seq'), %(password)s, %(wsshash)s, %(expires_at)s);
""",
{'wsshash': wsshash(login, password), 'expires_at': expiration_time, 'password': password }
{
"wsshash": wsshash(login, password),
"expires_at": expiration_time,
"password": password,
},
)
conn.commit()
conn.close()
......@@ -189,11 +259,21 @@ def get_login_password(tokendict):
return (login, password)
@application.route("/version", methods=['GET'])
@application.route("/version", methods=["GET"])
def version():
return Response("Version %s running in %s mode. Contact %s."%(__version__, application.config['ENVIRONMENT'], application.config['SUPPORT_EMAIL']), status=200)
return Response(
"Version %s running in %s mode. Contact %s."
% (
__version__,
application.config["ENVIRONMENT"],
application.config["SUPPORT_EMAIL"],
),
status=200,
)
@application.route("/cleanup", methods=['GET'])
@application.route("/cleanup", methods=["GET"])
def cleanup():
"""
Clean old temporary logins and passwords in both databases.
......@@ -201,11 +281,13 @@ def cleanup():
application.logger.info("Cleaning up expired temporary accounts")
rows_deleted = 0
try:
conn = psycopg2.connect(dbname= application.config['RESIFAUTH_PGDATABASE'],
port = application.config['RESIFAUTH_PGPORT'],
host = application.config['RESIFAUTH_PGHOST'],
user= application.config['RESIFAUTH_PGUSER'],
password = application.config['RESIFAUTH_PGPASSWORD'])
conn = psycopg2.connect(
dbname=application.config["RESIFAUTH_PGDATABASE"],
port=application.config["RESIFAUTH_PGPORT"],
host=application.config["RESIFAUTH_PGHOST"],
user=application.config["RESIFAUTH_PGUSER"],
password=application.config["RESIFAUTH_PGPASSWORD"],
)
cur = conn.cursor()
application.logger.debug("Connected to users database")
cur.execute("delete from users where expires_at < now();")
......@@ -217,11 +299,13 @@ def cleanup():
raise e
try:
conn = psycopg2.connect(dbname= application.config['RESIFINV_PGDATABASE'],
port = application.config['RESIFINV_PGPORT'],
host = application.config['RESIFINV_PGHOST'],
user= application.config['RESIFINV_PGUSER'],
password = application.config['RESIFINV_PGPASSWORD'])
conn = psycopg2.connect(
dbname=application.config["RESIFINV_PGDATABASE"],
port=application.config["RESIFINV_PGPORT"],
host=application.config["RESIFINV_PGHOST"],
user=application.config["RESIFINV_PGUSER"],
password=application.config["RESIFINV_PGPASSWORD"],
)
cur = conn.cursor()
application.logger.debug("Connected to privlieges database")
application.logger.debug("Deleting from privileges database")
......@@ -231,37 +315,47 @@ def cleanup():
except Exception as e:
application.logger.error(e.pgerror)
raise e
return Response("Deleted %d expired accounts."%(rows_deleted), status=200)
return Response("Deleted %d expired accounts." % (rows_deleted), status=200)
@application.route("/", methods=['POST'])
@application.route("/", methods=["POST"])
def auth():
login = ''
password = ''
login = ""
password = ""
application.logger.debug(request.mimetype)
data = request.get_data()
application.logger.debug("Data: %s", data)
try:
verify_token_signature(data, application.config['GNUPG_HOMEDIR'])
verify_token_signature(data, application.config["GNUPG_HOMEDIR"])
tokendict = parse_input_data(data)
application.logger.info("Token signature OK: %s"%str(tokendict))
application.logger.info("Token signature OK: %s" % str(tokendict))
except ValueError as e:
application.logger.info("Token signature could not be checked: %s"%str(data))
application.logger.info("Token signature could not be checked: %s" % str(data))
return Response(str(e), status=415)
# Now we have a dictionary corresponding to the token's content.
# Verify validity
expiration_ts= datetime.datetime.strptime(tokendict['valid_until'], '%Y-%m-%dT%H:%M:%S.%fZ')
expiration_ts = datetime.datetime.strptime(
tokendict["valid_until"], "%Y-%m-%dT%H:%M:%S.%fZ"
)
if (expiration_ts - datetime.datetime.now()).total_seconds() < 0:
application.logger.info("Token is expired")
return Response('Token is expired. Please generate a new one at https://geofon.gfz-potsdam.de/eas/', status=400)
return Response(
"Token is expired. Please generate a new one at https://geofon.gfz-potsdam.de/eas/",
status=400,
)
application.logger.info("Token is valid")
(login, password) = get_login_password(tokendict)
if login and password:
register_privileges(login, tokendict)
return "%s:%s"%(login, password)
return "%s:%s" % (login, password)
else:
return Response("Internal server error. Contact %s"%(application.config['SUPPORT_EMAIL']), status=500)
return Response(
"Internal server error. Contact %s" % (application.config["SUPPORT_EMAIL"]),
status=500,
)
if __name__ == "__main__":
application.logger.info("Running in %s mode"%(application.config['ENVIRONMENT']))
application.run(host='0.0.0.0')
application.logger.info("Running in %s mode" % (application.config["ENVIRONMENT"]))
application.run(host="0.0.0.0")
Supports Markdown
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