Commit 6b851367 authored by Jonathan Schaeffer's avatar Jonathan Schaeffer
Browse files

Ne pas créer de nouveaux logins si même token

parent b5ef7eb1
...@@ -54,6 +54,26 @@ alter table credentials add column if not exists expires_at timestamp default va ...@@ -54,6 +54,26 @@ alter table credentials add column if not exists expires_at timestamp default va
Table `eida_temp_users` : Table `eida_temp_users` :
``` sql ``` sql
alter table aut_user add column if not exists expires_at timestamp default value null; alter table aut_user add column if not exists expires_at timestamp default value null;
CREATE TABLE public.eida_temp_users (
network text,
start_year integer,
end_year integer,
name text,
network_id bigint DEFAULT 0,
expires_at timestamp without time zone
);
ALTER TABLE ONLY public.eida_temp_users
ADD CONSTRAINT unique_privilege UNIQUE (name, network_id);
ALTER TABLE ONLY public.eida_temp_users
ADD CONSTRAINT eida_temp_users_network_id_fkey FOREIGN KEY (network_id) REFERENCES public.networks(network_id) ON DELETE SET DEFAULT;
GRANT ALL ON TABLE public.eida_temp_users TO eidawsauth;
GRANT SELECT ON TABLE public.eida_temp_users TO resifinv_ro;
``` ```
......
...@@ -4,7 +4,7 @@ import random ...@@ -4,7 +4,7 @@ import random
import string import string
import logging import logging
import os import os
from hashlib import md5 from hashlib import md5, sha1
from flask import Flask, request, Response from flask import Flask, request, Response
import psycopg2 import psycopg2
import gnupg import gnupg
...@@ -44,51 +44,29 @@ def parse_input_data(data): ...@@ -44,51 +44,29 @@ def parse_input_data(data):
token = re.search(r'{(?P<token>.*)}',str(data)).groupdict()['token'] token = re.search(r'{(?P<token>.*)}',str(data)).groupdict()['token']
application.logger.debug(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]
application.logger.debug("Transformed to dictionary : %s", d) application.logger.debug("Transformed to dictionary : %s", d)
return d return d
def register_login(login, password):
"""
- Connects to the AUTHDB
- Generate Login and Password hash
- register in the users table
"""
expiration_time=datetime.datetime.now()+datetime.timedelta(days=1)
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'])
cur = conn.cursor()
application.logger.debug("Connected to users database")
except Exception as e:
application.logger.error("Unable to connect to database %s as %s@%s:%s", application.config['RESIFAUTH_PGDATABASE'],
application.config['RESIFAUTH_PGUSER'],
application.config['RESIFAUTH_PGHOST'],
application.config['RESIFAUTH_PGPORT'])
raise e
cur.execute("""
INSERT INTO users VALUES (DEFAULT, %(login)s, 'Temp', 'EIDA', %(tmpmail)s, %(expires_at)s);
""",
{'login': login, 'tmpmail': "%s@eida"%(login),'expires_at': expiration_time }
)
cur.execute("""
INSERT INTO credentials VALUES (CURRVAL('users_user_index_seq'), NULL, %(wsshash)s, %(expires_at)s);
""",
{'wsshash': wsshash(login, password), 'expires_at': expiration_time }
)
conn.commit()
conn.close()
def register_privileges(login, fdsn_refs): def register_privileges(login, tokendict):
""" """
- Check membership and get FDSN references
- Connect to PRIVILEGEDB - Connect to PRIVILEGEDB
- For each fdsn reference, insert the privilege in the access table - For each fdsn reference, insert the privilege in the access table if not already there
""" """
fdsn_memberships = []
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")
fdsn_memberships.append(application.config['EPOS_FDSN_MAP'][em])
if len(fdsn_memberships) == 0:
return
application.logger.debug("FDSN memberships: %s"%(fdsn_memberships))
try: try:
conn = psycopg2.connect(dbname= application.config['RESIFINV_PGDATABASE'], conn = psycopg2.connect(dbname= application.config['RESIFINV_PGDATABASE'],
port = application.config['RESIFINV_PGPORT'], port = application.config['RESIFINV_PGPORT'],
...@@ -105,7 +83,7 @@ def register_privileges(login, fdsn_refs): ...@@ -105,7 +83,7 @@ def register_privileges(login, fdsn_refs):
raise e raise e
# Get the network id # Get the network id
for ref in fdsn_refs: for ref in fdsn_memberships:
ref['login'] = login ref['login'] = login
ref['expires_at'] = datetime.datetime.now()+datetime.timedelta(days=1) ref['expires_at'] = datetime.datetime.now()+datetime.timedelta(days=1)
application.logger.info(ref) application.logger.info(ref)
...@@ -122,11 +100,62 @@ def register_privileges(login, fdsn_refs): ...@@ -122,11 +100,62 @@ def register_privileges(login, fdsn_refs):
ref['networkid'] = cur.fetchone()[0] ref['networkid'] = cur.fetchone()[0]
application.logger.info("Inserting tupple in %s.eida_temp_users: %s", application.config['RESIFINV_PGDATABASE'], ref) application.logger.info("Inserting tupple in %s.eida_temp_users: %s", application.config['RESIFINV_PGDATABASE'], ref)
cur.execute(""" 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); 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.commit()
conn.close() 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
else, generate a new login/password, register it in the database and return the tupple
"""
# TODO Try to get an existing login/password from the token's short sha1
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'])
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'],))
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", tokendict['mail'])
cur.execute("select ws_hash from credentials where user_index=%s", (uid,))
if cur.rowcount != 0:
password = cur.fetchone()[0]
application.logger.debug("Found correspondig password also")
# 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)
# Register login in authentication database
cur.execute("""
INSERT INTO users VALUES (DEFAULT, %(login)s, %(givenName)s, %(sn)s, %(mail)s, %(expires_at)s);
""",
{'login': login, 'givenName': tokendict['givenName'], 'sn': tokendict['sn'], 'mail': tokendict['mail'], 'expires_at': expiration_time }
)
cur.execute("""
INSERT INTO credentials VALUES (CURRVAL('users_user_index_seq'), NULL, %(wsshash)s, %(expires_at)s);
""",
{'wsshash': wsshash(login, password), 'expires_at': expiration_time }
)
conn.commit()
conn.close()
except psycopg2.Error as e:
application.logger.error(e.pgerror)
raise e
return (login, password)
@application.route("/version", methods=['GET']) @application.route("/version", methods=['GET'])
def version(): def version():
...@@ -141,13 +170,12 @@ def cleanup(): ...@@ -141,13 +170,12 @@ def cleanup():
rows_deleted = 0 rows_deleted = 0
try: try:
conn = psycopg2.connect(dbname= application.config['RESIFAUTH_PGDATABASE'], conn = psycopg2.connect(dbname= application.config['RESIFAUTH_PGDATABASE'],
port = application.config['RESIFAUTH_PGPORT'], port = application.config['RESIFAUTH_PGPORT'],
host = application.config['RESIFAUTH_PGHOST'], host = application.config['RESIFAUTH_PGHOST'],
user= application.config['RESIFAUTH_PGUSER'], user= application.config['RESIFAUTH_PGUSER'],
password = application.config['RESIFAUTH_PGPASSWORD']) password = application.config['RESIFAUTH_PGPASSWORD'])
cur = conn.cursor() cur = conn.cursor()
application.logger.debug("Connected to users database") application.logger.debug("Connected to users database")
cur.execute("delete from credentials where expires_at < now();")
cur.execute("delete from users where expires_at < now();") cur.execute("delete from users where expires_at < now();")
rows_deleted = cur.rowcount rows_deleted = cur.rowcount
conn.commit() conn.commit()
...@@ -158,10 +186,10 @@ def cleanup(): ...@@ -158,10 +186,10 @@ def cleanup():
try: try:
conn = psycopg2.connect(dbname= application.config['RESIFINV_PGDATABASE'], conn = psycopg2.connect(dbname= application.config['RESIFINV_PGDATABASE'],
port = application.config['RESIFINV_PGPORT'], port = application.config['RESIFINV_PGPORT'],
host = application.config['RESIFINV_PGHOST'], host = application.config['RESIFINV_PGHOST'],
user= application.config['RESIFINV_PGUSER'], user= application.config['RESIFINV_PGUSER'],
password = application.config['RESIFINV_PGPASSWORD']) password = application.config['RESIFINV_PGPASSWORD'])
cur = conn.cursor() cur = conn.cursor()
application.logger.debug("Connected to privlieges database") application.logger.debug("Connected to privlieges database")
application.logger.debug("Deleting from privileges database") application.logger.debug("Deleting from privileges database")
...@@ -195,30 +223,12 @@ def auth(): ...@@ -195,30 +223,12 @@ def auth():
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") application.logger.info("Token is valid")
# Compute a random login and password (login, password) = get_login_password(tokendict)
login = ''.join(random.choices(string.ascii_uppercase + string.digits, k=14)) if login and password:
password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=14)) register_privileges(login, tokendict)
return "%s:%s"%(login, password)
# Register login else:
register_login(login, password) return Response('Internal server error. Contact resif-dc@univ-grenoble-alpes.fr', status=500)
# Store in PRIVILEGEDB
# Check membership and get FDSN references
fdsn_memberships = []
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")
fdsn_memberships.append(application.config['EPOS_FDSN_MAP'][em])
if len(fdsn_memberships) > 0:
application.logger.debug("FDSN memberships: %s"%(fdsn_memberships))
try:
register_privileges(login, fdsn_memberships)
except NameError as n:
return "Internal error at RESIF. Please contact resif-dc@univ-grenoble-alpes.fr specifying the URL"
return "%s:%s"%(login, password)
if __name__ == "__main__": if __name__ == "__main__":
application.logger.info("Running in %s mode"%(application.config['ENVIRONMENT'])) application.logger.info("Running in %s mode"%(application.config['ENVIRONMENT']))
......
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