Loading Pipfile +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [packages] common-package = {editable = true, path = "./src", extras=["postgres"]} common-package = {editable = true, path = "./src", extras=["postgres", "auth"]} [dev-packages] pytest = "*" Loading Pipfile.lock +135 −3 Original line number Diff line number Diff line { "_meta": { "hash": { "sha256": "60a6ef5959e2629d74698e56684b1b0c2b112e18139d87434d9b2880fffa6e8c" "sha256": "922232563aac6a98fd205d2e8d58fe224641137d160bedd3c171f4d0f4b78b40" }, "pipfile-spec": 6, "requires": { Loading @@ -16,6 +16,22 @@ ] }, "default": { "blinker": { "hashes": [ "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01", "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83" ], "markers": "python_version >= '3.8'", "version": "==1.8.2" }, "click": { "hashes": [ "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" ], "markers": "python_version >= '3.7'", "version": "==8.1.7" }, "colorama": { "hashes": [ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", Loading @@ -27,6 +43,7 @@ "common-package": { "editable": true, "extras": [ "auth", "postgres" ], "path": "./src" Loading @@ -38,6 +55,105 @@ ], "version": "==0.9.1" }, "flask": { "hashes": [ "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3", "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842" ], "version": "==3.0.3" }, "itsdangerous": { "hashes": [ "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" ], "markers": "python_version >= '3.8'", "version": "==2.2.0" }, "jinja2": { "hashes": [ "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", "version": "==3.1.4" }, "ldap3": { "hashes": [ "sha256:2bc966556fc4d4fa9f445a1c31dc484ee81d44a51ab0e2d0fd05b62cac75daa6", "sha256:5630d1383e09ba94839e253e013f1aa1a2cf7a547628ba1265cb7b9a844b5687", "sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70", "sha256:5ab7febc00689181375de40c396dcad4f2659cd260fc5e94c508b6d77c17e9d5", "sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f" ], "version": "==2.9.1" }, "markupsafe": { "hashes": [ "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", "version": "==2.1.5" }, "numpy": { "hashes": [ "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", Loading Loading @@ -188,6 +304,14 @@ ], "version": "==2.9.9" }, "pyasn1": { "hashes": [ "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473" ], "markers": "python_version >= '3.8'", "version": "==0.6.0" }, "pygments": { "hashes": [ "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", Loading @@ -201,7 +325,7 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, "pytz": { Loading @@ -224,7 +348,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "sqlalchemy": { Loading Loading @@ -297,6 +421,14 @@ ], "markers": "python_version >= '2'", "version": "==2024.1" }, "werkzeug": { "hashes": [ "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" ], "markers": "python_version >= '3.8'", "version": "==3.0.3" } }, "develop": { Loading src/common/auth.py +0 −202 Original line number Diff line number Diff line Loading @@ -4,20 +4,14 @@ from urllib.parse import urlparse, urlencode import hashlib import os from common.mail import send_email from common.env import check_environment as ce from common.database import Database try: from onelogin.saml2.auth import OneLogin_Saml2_Auth from ldap3 import Server, Connection, ALL, SUBTREE from ldap3.core.exceptions import LDAPException, LDAPBindError from flask import jsonify except ImportError: import sys from common.logz import create_logger log = create_logger() log.warn("To use this module, install common-package[auth] extra.") sys.exit(1) Loading Loading @@ -66,75 +60,6 @@ def authenticate_ldap_user(uid, password): return connection.entries[0] def authenticate_saml_user( request_scheme: str, request_host: str, request_url: str, request_method: str, request_args: dict, request_form: dict, success_handler: Callable = lambda _: None, failure_handler: Callable = lambda _: None, saml_path: str = None, logger=None, ): """ Handles SAML authentication by processing the necessary components extracted from a web request. Parameters: - request_scheme (str): The request scheme ('http' or 'https'). - request_host (str): The request host. - request_url (str): The full URL of the request. - request_method (str): The HTTP method of the request. - request_args (dict): The query parameters of the request as a dictionary. - request_form (dict): The form data of the request as a dictionary. - success_handler (Callable, optional): Function to handle successful SAML authentication. Defaults to a no-op function. - failure_handler (Callable, optional): Function to handle SAML authentication failure. Defaults to a no-op function. - saml_path (str, optional): Custom path for SAML configuration files. If not provided, environment variable 'SAML_PATH' is used. - logger (Logger, optional): Logger object for logging. If not provided, no logging is performed. Returns: - Result of the `success_handler` or `failure_handler` callable depending on the SAML processing outcome. """ url_data = urlparse(request_url) saml_request = { "https": "on" if request_scheme == "https" else "off", "http_host": request_host, "server_port": url_data.port, "script_name": url_data.path, "get_data": request_args, "post_data": request_form, "query_string": urlencode(request_args) if request_method == "GET" else "", } saml_path = saml_path or ce("SAML_PATH") auth = OneLogin_Saml2_Auth(saml_request, custom_base_path=saml_path) try: if "sso" in request_args: return success_handler(auth.login()) elif "slo" in request_args: return success_handler(auth.logout()) elif "acs" in request_args: auth.process_response( request_id=None ) # Assuming request carries all needed info if auth.is_authenticated(): return success_handler(None) # pass user details / attributes else: return failure_handler("SAML authentication failed") else: return failure_handler("No valid SAML action found") except Exception as e: error_msg = f"SAML authentication error: {str(e)}" if logger: logger.error(error_msg) return failure_handler(error_msg) def generate_salt() -> str: return str(os.urandom(32)).replace("\\", "").replace("b", "") Loading @@ -147,130 +72,3 @@ def hash_password( **kwargs: Any, ) -> str: return hash_algorithm(password.encode(), salt.encode(), *args, **kwargs).hex() def login( username: str, password: str, db: str, table_name: str, username_column: str, password_column: str, salt_column: str, ) -> dict: user_data = db.query( f"SELECT {password_column}, {salt_column} FROM {table_name} WHERE {username_column} = '{username}'" ) if len(user_data) == 0: return {"msg": "Username does not exist."}, 401 user_pass, salt = user_data[0] pass_to_check = hash_password(password, salt) if pass_to_check == user_pass: # User authentication successful return {"msg": "Login successful!"} else: return {"msg": "Invalid uid or password"}, 401 def check_username_exists(args, kwargs): return True def register_user( username: str, password: str, confirm_pw: str, first_name: str, last_name: str, email: str, work_sector: str, user_type: str, reason: str, db: Database, table_name: str, username_column: str, password_column: str, salt_column: str, ) -> dict: # Check if username already exists if check_username_exists(username, db, table_name, username_column): return {"msg": "Username already exists."}, 401 # Check if passwords match if password != confirm_pw: return {"msg": "Passwords do not match."}, 401 # Generate salt and hash the password salt = generate_salt() hashed_pw = hash_password(password, salt) try: # Insert user data into the database db.cursor.execute( f"""INSERT INTO {table_name} ({username_column}, first_name, last_name, email, work_sector, user_type, {password_column}, {salt_column}, last_login_date, enabled) VALUES ('{username}', '{first_name}', '{last_name}', '{email}', '{work_sector}', '{user_type}', '{hashed_pw}', '{salt}', CURRENT_TIMESTAMP, false);""" ) db.commit() except Exception as e: return {"msg": "Error registering new user account.", "error": str(e)}, 401 # Send email notification os.environ["EMAIL_RECIPIENTS"] = "plattmw@ornl.gov, burdetteja@ornl.gov" os.environ["EMAIL_SENDER"] = "psplatial@ornl.gov" subject = "PS Platial Account Request" msg = f"{last_name}, {first_name} at {email} has requested a PlanetSense Platial account for the following reason: {reason}." send_email(subject, msg) return { "msg": "Thank you for submitting an account request. Our team will review your request and respond as soon as possible." } def reset_password( username: str, token: str, new_password: str, confirm_new_password: str, db: Database, table_name: str, username_column: str, salt_column: str, password_column: str, ) -> dict: # Retrieve user's salt from the database user_salt = db.query( f"SELECT {salt_column} FROM {table_name} WHERE {username_column} = '{username}';" ) if not user_salt: return {"msg": "Username not found."}, 401 user_salt = str(user_salt[0][0]).replace("b", "") # Validate token token_to_match = db.query( f"SELECT email_reset_code FROM {table_name} WHERE {username_column} = '{username}';" ) if token != token_to_match[0][0]: return {"msg": "Token does not match."}, 401 # Check if passwords match if new_password != confirm_new_password: return {"msg": "Passwords do not match."}, 401 # Generate new hashed password and update in the database new_hashed_pw = hash_password(new_password, user_salt) try: db.cursor.execute( f"UPDATE {table_name} SET {password_column} = '{new_hashed_pw}' WHERE {username_column} = '{username}';" ) db.commit() except Exception as e: return {"msg": "Failed to update password.", "error": str(e)}, 401 return { "msg": "Password updated successfully! Redirecting you back to login page now..." } src/pyproject.toml +1 −5 Original line number Diff line number Diff line Loading @@ -40,10 +40,6 @@ postgres = ["psycopg2-binary==2.9.9"] mssql = ["pymssql==2.2.11"] influx = ["influxdb==5.3.1"] auth = [ "lxml", "xmlsec==1.3.13", "onelogin==2.0.3", "python3_saml==1.14.0", "ldap3==2.9.1", "flask>=2.0.2" ] Loading Loading @@ -80,5 +76,5 @@ Source = "https://code.ornl.gov/nset-utilities/common-package" [tool.setuptools] packages = ['common', 'common.mixins'] packages = ['common', 'common.mixins', 'common.scrapers'] Loading
Pipfile +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [packages] common-package = {editable = true, path = "./src", extras=["postgres"]} common-package = {editable = true, path = "./src", extras=["postgres", "auth"]} [dev-packages] pytest = "*" Loading
Pipfile.lock +135 −3 Original line number Diff line number Diff line { "_meta": { "hash": { "sha256": "60a6ef5959e2629d74698e56684b1b0c2b112e18139d87434d9b2880fffa6e8c" "sha256": "922232563aac6a98fd205d2e8d58fe224641137d160bedd3c171f4d0f4b78b40" }, "pipfile-spec": 6, "requires": { Loading @@ -16,6 +16,22 @@ ] }, "default": { "blinker": { "hashes": [ "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01", "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83" ], "markers": "python_version >= '3.8'", "version": "==1.8.2" }, "click": { "hashes": [ "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" ], "markers": "python_version >= '3.7'", "version": "==8.1.7" }, "colorama": { "hashes": [ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", Loading @@ -27,6 +43,7 @@ "common-package": { "editable": true, "extras": [ "auth", "postgres" ], "path": "./src" Loading @@ -38,6 +55,105 @@ ], "version": "==0.9.1" }, "flask": { "hashes": [ "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3", "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842" ], "version": "==3.0.3" }, "itsdangerous": { "hashes": [ "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" ], "markers": "python_version >= '3.8'", "version": "==2.2.0" }, "jinja2": { "hashes": [ "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", "version": "==3.1.4" }, "ldap3": { "hashes": [ "sha256:2bc966556fc4d4fa9f445a1c31dc484ee81d44a51ab0e2d0fd05b62cac75daa6", "sha256:5630d1383e09ba94839e253e013f1aa1a2cf7a547628ba1265cb7b9a844b5687", "sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70", "sha256:5ab7febc00689181375de40c396dcad4f2659cd260fc5e94c508b6d77c17e9d5", "sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f" ], "version": "==2.9.1" }, "markupsafe": { "hashes": [ "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", "version": "==2.1.5" }, "numpy": { "hashes": [ "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", Loading Loading @@ -188,6 +304,14 @@ ], "version": "==2.9.9" }, "pyasn1": { "hashes": [ "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473" ], "markers": "python_version >= '3.8'", "version": "==0.6.0" }, "pygments": { "hashes": [ "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", Loading @@ -201,7 +325,7 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, "pytz": { Loading @@ -224,7 +348,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "sqlalchemy": { Loading Loading @@ -297,6 +421,14 @@ ], "markers": "python_version >= '2'", "version": "==2024.1" }, "werkzeug": { "hashes": [ "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" ], "markers": "python_version >= '3.8'", "version": "==3.0.3" } }, "develop": { Loading
src/common/auth.py +0 −202 Original line number Diff line number Diff line Loading @@ -4,20 +4,14 @@ from urllib.parse import urlparse, urlencode import hashlib import os from common.mail import send_email from common.env import check_environment as ce from common.database import Database try: from onelogin.saml2.auth import OneLogin_Saml2_Auth from ldap3 import Server, Connection, ALL, SUBTREE from ldap3.core.exceptions import LDAPException, LDAPBindError from flask import jsonify except ImportError: import sys from common.logz import create_logger log = create_logger() log.warn("To use this module, install common-package[auth] extra.") sys.exit(1) Loading Loading @@ -66,75 +60,6 @@ def authenticate_ldap_user(uid, password): return connection.entries[0] def authenticate_saml_user( request_scheme: str, request_host: str, request_url: str, request_method: str, request_args: dict, request_form: dict, success_handler: Callable = lambda _: None, failure_handler: Callable = lambda _: None, saml_path: str = None, logger=None, ): """ Handles SAML authentication by processing the necessary components extracted from a web request. Parameters: - request_scheme (str): The request scheme ('http' or 'https'). - request_host (str): The request host. - request_url (str): The full URL of the request. - request_method (str): The HTTP method of the request. - request_args (dict): The query parameters of the request as a dictionary. - request_form (dict): The form data of the request as a dictionary. - success_handler (Callable, optional): Function to handle successful SAML authentication. Defaults to a no-op function. - failure_handler (Callable, optional): Function to handle SAML authentication failure. Defaults to a no-op function. - saml_path (str, optional): Custom path for SAML configuration files. If not provided, environment variable 'SAML_PATH' is used. - logger (Logger, optional): Logger object for logging. If not provided, no logging is performed. Returns: - Result of the `success_handler` or `failure_handler` callable depending on the SAML processing outcome. """ url_data = urlparse(request_url) saml_request = { "https": "on" if request_scheme == "https" else "off", "http_host": request_host, "server_port": url_data.port, "script_name": url_data.path, "get_data": request_args, "post_data": request_form, "query_string": urlencode(request_args) if request_method == "GET" else "", } saml_path = saml_path or ce("SAML_PATH") auth = OneLogin_Saml2_Auth(saml_request, custom_base_path=saml_path) try: if "sso" in request_args: return success_handler(auth.login()) elif "slo" in request_args: return success_handler(auth.logout()) elif "acs" in request_args: auth.process_response( request_id=None ) # Assuming request carries all needed info if auth.is_authenticated(): return success_handler(None) # pass user details / attributes else: return failure_handler("SAML authentication failed") else: return failure_handler("No valid SAML action found") except Exception as e: error_msg = f"SAML authentication error: {str(e)}" if logger: logger.error(error_msg) return failure_handler(error_msg) def generate_salt() -> str: return str(os.urandom(32)).replace("\\", "").replace("b", "") Loading @@ -147,130 +72,3 @@ def hash_password( **kwargs: Any, ) -> str: return hash_algorithm(password.encode(), salt.encode(), *args, **kwargs).hex() def login( username: str, password: str, db: str, table_name: str, username_column: str, password_column: str, salt_column: str, ) -> dict: user_data = db.query( f"SELECT {password_column}, {salt_column} FROM {table_name} WHERE {username_column} = '{username}'" ) if len(user_data) == 0: return {"msg": "Username does not exist."}, 401 user_pass, salt = user_data[0] pass_to_check = hash_password(password, salt) if pass_to_check == user_pass: # User authentication successful return {"msg": "Login successful!"} else: return {"msg": "Invalid uid or password"}, 401 def check_username_exists(args, kwargs): return True def register_user( username: str, password: str, confirm_pw: str, first_name: str, last_name: str, email: str, work_sector: str, user_type: str, reason: str, db: Database, table_name: str, username_column: str, password_column: str, salt_column: str, ) -> dict: # Check if username already exists if check_username_exists(username, db, table_name, username_column): return {"msg": "Username already exists."}, 401 # Check if passwords match if password != confirm_pw: return {"msg": "Passwords do not match."}, 401 # Generate salt and hash the password salt = generate_salt() hashed_pw = hash_password(password, salt) try: # Insert user data into the database db.cursor.execute( f"""INSERT INTO {table_name} ({username_column}, first_name, last_name, email, work_sector, user_type, {password_column}, {salt_column}, last_login_date, enabled) VALUES ('{username}', '{first_name}', '{last_name}', '{email}', '{work_sector}', '{user_type}', '{hashed_pw}', '{salt}', CURRENT_TIMESTAMP, false);""" ) db.commit() except Exception as e: return {"msg": "Error registering new user account.", "error": str(e)}, 401 # Send email notification os.environ["EMAIL_RECIPIENTS"] = "plattmw@ornl.gov, burdetteja@ornl.gov" os.environ["EMAIL_SENDER"] = "psplatial@ornl.gov" subject = "PS Platial Account Request" msg = f"{last_name}, {first_name} at {email} has requested a PlanetSense Platial account for the following reason: {reason}." send_email(subject, msg) return { "msg": "Thank you for submitting an account request. Our team will review your request and respond as soon as possible." } def reset_password( username: str, token: str, new_password: str, confirm_new_password: str, db: Database, table_name: str, username_column: str, salt_column: str, password_column: str, ) -> dict: # Retrieve user's salt from the database user_salt = db.query( f"SELECT {salt_column} FROM {table_name} WHERE {username_column} = '{username}';" ) if not user_salt: return {"msg": "Username not found."}, 401 user_salt = str(user_salt[0][0]).replace("b", "") # Validate token token_to_match = db.query( f"SELECT email_reset_code FROM {table_name} WHERE {username_column} = '{username}';" ) if token != token_to_match[0][0]: return {"msg": "Token does not match."}, 401 # Check if passwords match if new_password != confirm_new_password: return {"msg": "Passwords do not match."}, 401 # Generate new hashed password and update in the database new_hashed_pw = hash_password(new_password, user_salt) try: db.cursor.execute( f"UPDATE {table_name} SET {password_column} = '{new_hashed_pw}' WHERE {username_column} = '{username}';" ) db.commit() except Exception as e: return {"msg": "Failed to update password.", "error": str(e)}, 401 return { "msg": "Password updated successfully! Redirecting you back to login page now..." }
src/pyproject.toml +1 −5 Original line number Diff line number Diff line Loading @@ -40,10 +40,6 @@ postgres = ["psycopg2-binary==2.9.9"] mssql = ["pymssql==2.2.11"] influx = ["influxdb==5.3.1"] auth = [ "lxml", "xmlsec==1.3.13", "onelogin==2.0.3", "python3_saml==1.14.0", "ldap3==2.9.1", "flask>=2.0.2" ] Loading Loading @@ -80,5 +76,5 @@ Source = "https://code.ornl.gov/nset-utilities/common-package" [tool.setuptools] packages = ['common', 'common.mixins'] packages = ['common', 'common.mixins', 'common.scrapers']