Commit 0c88652c authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Fixed problems with user migration.

parent d380506d
Pipeline #43922 passed with stages
in 24 minutes and 56 seconds
......@@ -36,6 +36,7 @@ authenticated user information for authorization or otherwise.
from flask import g, request
from flask_restplus import abort, Resource, fields
from flask_httpauth import HTTPBasicAuth
from datetime import datetime
from nomad import config, processing, files, utils, coe_repo
from nomad.coe_repo import User, LoginException
......@@ -71,6 +72,8 @@ def verify_password(username_or_token, password):
else:
try:
g.user = User.verify_user_password(username_or_token, password)
except LoginException:
return False
except Exception as e:
utils.get_logger(__name__).error('could not verify password', exc_info=e)
return False
......@@ -141,7 +144,8 @@ user_model = api.model('User', {
'password': fields.String(description='The bcrypt 2y-indented password for initial and changed password'),
'token': fields.String(
description='The access token that authenticates the user with the API. '
'User the HTTP header "X-Token" to provide it in API requests.')
'User the HTTP header "X-Token" to provide it in API requests.'),
'created': fields.DateTime(dt_format='iso8601', description='The create date for the user.')
})
......@@ -194,6 +198,7 @@ class UserResource(Resource):
user = coe_repo.User.create_user(
email=data['email'], password=data.get('password', None), crypted=True,
first_name=data['first_name'], last_name=data['last_name'],
created=data.get('created', datetime.now()),
affiliation=data.get('affiliation', None), token=data.get('token', None),
user_id=data.get('user_id', None))
......
......@@ -68,7 +68,7 @@ def integrationtests():
assert len(search.results) <= search.pagination.total
finally:
print('delete the upload again')
client.uploads.delete_upload(upload_id=upload.upload_id)
client.uploads.delete_upload(upload_id=upload.upload_id).response()
while upload.process_running:
upload = client.uploads.get_upload(upload_id=upload.upload_id).response().result
......
......@@ -23,7 +23,7 @@ from nomad.files import ArchiveBasedStagingUploadFiles
from nomad.parsing import parser_dict, LocalBackend, match_parser
from nomad.normalizing import normalizers
from .main import cli, nomad_url
from .main import cli, get_nomad_url
class CalcProcReproduction:
......@@ -55,7 +55,7 @@ class CalcProcReproduction:
# download with request, since bravado does not support streaming
# TODO currently only downloads mainfile
self.logger.info('Downloading calc.')
req = requests.get('%s/raw/%s/%s' % (nomad_url, self.upload_id, os.path.dirname(self.mainfile)), stream=True)
req = requests.get('%s/raw/%s/%s' % (get_nomad_url(), self.upload_id, os.path.dirname(self.mainfile)), stream=True)
with open(local_path, 'wb') as f:
for chunk in req.iter_content(chunk_size=1024):
f.write(chunk)
......@@ -139,7 +139,7 @@ class CalcProcReproduction:
help='Override existing local calculation data.')
def local(archive_id, **kwargs):
utils.configure_logging()
utils.get_logger(__name__).info('Using %s' % nomad_url)
utils.get_logger(__name__).info('Using %s' % get_nomad_url())
with CalcProcReproduction(archive_id, **kwargs) as local:
backend = local.parse()
local.normalize_all(parser_backend=backend)
......
......@@ -21,30 +21,40 @@ from bravado.requests_client import RequestsClient
from bravado.client import SwaggerClient
from urllib.parse import urlparse
from nomad import config, utils
from nomad import config, utils, infrastructure
default_url = 'http://%s:%d/%s' % (config.services.api_host, config.services.api_port, config.services.api_base_path.strip('/'))
nomad_url = os.environ.get('NOMAD_URL', default_url)
user = os.environ.get('NOMAD_USER', 'leonard.hofstadter@nomad-fairdi.tests.de')
pw = os.environ.get('NOMAD_PASSWORD', 'password')
_default_url = 'http://%s:%d/%s' % (config.services.api_host, config.services.api_port, config.services.api_base_path.strip('/'))
_nomad_url = os.environ.get('NOMAD_URL', _default_url)
_user = os.environ.get('NOMAD_USER', 'leonard.hofstadter@nomad-fairdi.tests.de')
_pw = os.environ.get('NOMAD_PASSWORD', 'password')
def get_nomad_url():
return _nomad_url
def create_client():
return _create_client()
def _create_client(user: str = user, password: str = pw):
def _create_client(*args, **kwargs):
return __create_client(*args, **kwargs)
def __create_client(user: str = _user, password: str = _pw):
""" A factory method to create the client. """
host = urlparse(nomad_url).netloc.split(':')[0]
host = urlparse(_nomad_url).netloc.split(':')[0]
http_client = RequestsClient()
if user is not None:
http_client.set_basic_auth(host, user, pw)
http_client.set_basic_auth(host, user, password)
client = SwaggerClient.from_url(
'%s/swagger.json' % nomad_url,
'%s/swagger.json' % _nomad_url,
http_client=http_client)
utils.get_logger(__name__).info('created bravado client', user=user)
return client
......@@ -55,33 +65,39 @@ def handle_common_errors(func):
except requests.exceptions.ConnectionError:
click.echo(
'\nCould not connect to nomad at %s. '
'Check connection and url.' % nomad_url)
'Check connection and url.' % _nomad_url)
sys.exit(0)
return wrapper
@click.group()
@click.option('-n', '--url', default=nomad_url, help='The URL where nomad is running "%s".' % nomad_url)
@click.option('-n', '--url', default=_nomad_url, help='The URL where nomad is running "%s".' % _nomad_url)
@click.option('-u', '--user', default=None, help='the user name to login, default no login.')
@click.option('-w', '--password', default=None, help='the password use to login.')
@click.option('-w', '--password', default=_pw, help='the password use to login.')
@click.option('-v', '--verbose', help='sets log level to debug', is_flag=True)
def cli(url: str, verbose: bool, user: str, password: str):
if verbose:
config.console_log_level = logging.DEBUG
config.console_log_level = logging.INFO
else:
config.console_log_level = logging.WARNING
config.service = os.environ.get('NOMAD_SERVICE', 'client')
infrastructure.setup_logging()
logger = utils.get_logger(__name__)
utils.get_logger(__name__).info('Used nomad is %s' % url)
logger.info('Used nomad is %s' % url)
logger.info('Used user is %s' % user)
global nomad_url
nomad_url = url
global _nomad_url
_nomad_url = url
global create_client
global _create_client
def create_client(): # pylint: disable=W0612
def _create_client(*args, **kwargs): # pylint: disable=W0612
if user is not None:
return _create_client(user=user, password=password)
logger.info('create client', user=user)
return __create_client(user=user, password=password)
else:
return _create_client()
logger.info('create anonymous client')
return __create_client()
......@@ -14,7 +14,7 @@
from typing import Dict
from passlib.hash import bcrypt
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime
from sqlalchemy.orm import relationship
import datetime
import jwt
......@@ -65,6 +65,7 @@ class User(Base): # type: ignore
last_name = Column(String, name='lastname')
affiliation = relationship('Affiliation', lazy='joined')
password = Column(String)
created = Column(DateTime)
_token_chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
......@@ -247,6 +248,6 @@ def admin_user():
Its password is part of :mod:`nomad.config`.
"""
repo_db = infrastructure.repository_db
admin = repo_db.query(User).filter_by(user_id=1).first()
admin = repo_db.query(User).filter_by(user_id=0).first()
assert admin, 'Admin user does not exist.'
return admin
......@@ -1154,9 +1154,9 @@ INSERT INTO public.pragma VALUES ('4.59');
--
-- Data for Name: sessions; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO public.sessions VALUES ('leonard', 3, '2100-12-17 09:00:00+00', NULL, NULL);
INSERT INTO public.sessions VALUES ('sheldon', 2, '2100-12-17 09:00:00+00', NULL, NULL);
INSERT INTO public.sessions VALUES ('leonard', 2, '2100-12-17 09:00:00+00', NULL, NULL);
INSERT INTO public.sessions VALUES ('sheldon', 1, '2100-12-17 09:00:00+00', NULL, NULL);
INSERT INTO public.sessions VALUES ('admin', 0, '2100-12-17 09:00:00+00', NULL, NULL);
--
......@@ -1238,16 +1238,16 @@ SELECT pg_catalog.setval('public.uploads_upload_id_seq', 1, false);
-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO public.users VALUES (1, 'admin', 'admin', 'admin', 'admin', NULL, NULL, NULL);
INSERT INTO public.users VALUES (2, 'Sheldon', 'Cooper', 'sheldon.cooper', 'sheldon.cooper@nomad-fairdi.tests.de', NULL, '$2y$12$jths1LQPsLofuBQ3evVIluhQeQ/BZfbdTSZHFcPGdcNmHz2WvDj.y', NULL);
INSERT INTO public.users VALUES (3, 'Leonard', 'Hofstadter', 'leonard.hofstadter', 'leonard.hofstadter@nomad-fairdi.tests.de', NULL, '$2y$12$jths1LQPsLofuBQ3evVIluhQeQ/BZfbdTSZHFcPGdcNmHz2WvDj.y', NULL);
INSERT INTO public.users VALUES (0, 'admin', 'admin', 'admin', 'admin', NULL, NULL, NULL);
INSERT INTO public.users VALUES (1, 'Sheldon', 'Cooper', 'sheldon.cooper', 'sheldon.cooper@nomad-fairdi.tests.de', NULL, '$2y$12$jths1LQPsLofuBQ3evVIluhQeQ/BZfbdTSZHFcPGdcNmHz2WvDj.y', NULL);
INSERT INTO public.users VALUES (2, 'Leonard', 'Hofstadter', 'leonard.hofstadter', 'leonard.hofstadter@nomad-fairdi.tests.de', NULL, '$2y$12$jths1LQPsLofuBQ3evVIluhQeQ/BZfbdTSZHFcPGdcNmHz2WvDj.y', NULL);
--
-- Name: users_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('public.users_user_id_seq', 4, true);
SELECT pg_catalog.setval('public.users_user_id_seq', 3, true);
--
......
......@@ -35,7 +35,7 @@ from email.mime.text import MIMEText
from nomad import config, utils
logger = utils.get_logger(__name__)
logger = None
elastic_client = None
""" The elastic search client. """
......@@ -65,6 +65,10 @@ def setup():
def setup_logging():
utils.configure_logging()
global logger
logger = utils.get_logger(__name__)
logger.info(
'setup logging',
logstash=config.logstash.enabled,
......@@ -169,7 +173,7 @@ def sqlalchemy_repository_db(exists: bool = False, readonly: bool = True, **kwar
with repository_db_connection(dbname=dbname) as conn:
with conn.cursor() as cur:
cur.execute(
"UPDATE public.users SET password='%s' WHERE user_id=1;" %
"UPDATE public.users SET password='%s' WHERE user_id=0;" %
bcrypt.encrypt(config.services.admin_password, ident='2y'))
def no_flush():
......
......@@ -191,7 +191,8 @@ class NomadCOEMigration:
email=source_user.email,
first_name=source_user.first_name,
last_name=source_user.last_name,
password=source_user.password
password=source_user.password,
created=source_user.created
)
try:
......@@ -206,6 +207,7 @@ class NomadCOEMigration:
try:
self.client.auth.create_user(payload=create_user_payload).response()
self.logger.info('copied user', user_id=source_user.user_id)
except HTTPBadRequest as e:
self.logger.error('could not create user due to bad data', exc_info=e, user_id=source_user.user_id)
......
......@@ -269,8 +269,8 @@ def postgres(postgres_infra):
""" Provides a clean coe repository db per function. Clears db before test. """
# do not wonder, this will not setback the id counters
postgres_infra.execute('TRUNCATE uploads CASCADE;')
postgres_infra.execute('DELETE FROM sessions WHERE user_id >= 4;')
postgres_infra.execute('DELETE FROM users WHERE user_id >= 4;')
postgres_infra.execute('DELETE FROM sessions WHERE user_id >= 3;')
postgres_infra.execute('DELETE FROM users WHERE user_id >= 3;')
yield postgres_infra
......
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