from authlib.integrations.flask_client import OAuth from flask import Flask, jsonify, redirect, url_for, request import requests import secrets import os from configparser import ConfigParser from pathlib import Path config = ConfigParser() config.read(Path(__file__).parent / "settings.ini") app = Flask(__name__) # Set a secret key for the Flask app # This is used to encrypt the session cookie # As we don't need to store any session data, we use a random string app.secret_key = secrets.token_hex(32) plesk_url = config["PLESK"].get( "Domain", fallback=os.environ.get("PLESK_DOMAIN")) # Configure Authlib with OIDC provider details # Will use environment variables if values are not set in config oauth = OAuth(app) client_id = config["OIDC"].get( "ClientID", fallback=os.environ.get("OIDC_CLIENT_ID")) client_secret = config["OIDC"].get( "ClientSecret", fallback=os.environ.get("OIDC_CLIENT_SECRET")) token_url = config["OIDC"].get( "TokenURL", fallback=os.environ.get("OIDC_TOKEN_URL")) authorize_url = config["OIDC"].get( "AuthorizeURL", fallback=os.environ.get("OIDC_AUTHORIZE_URL")) jwks_url = config["OIDC"].get( "JWKSURL", fallback=os.environ.get("OIDC_JWKS_URL")) oauth.register( name='oidc', client_id=client_id, client_secret=client_secret, access_token_url=token_url, authorize_url=authorize_url, jwks_uri=jwks_url, client_kwargs={ 'scope': config["OIDC"].get("Scope", fallback="openid profile email"), 'token_endpoint_auth_method': 'client_secret_basic', 'token_placement': 'header' }, ) # Define a route for the "home page" # This will redirect to the OIDC provider's login page @app.route('/') def home(): redirect_uri = url_for('oidc_callback', _external=True) return oauth.oidc.authorize_redirect(redirect_uri) # Define a route for the OIDC provider's callback URL # This will be called after the user has logged in # It will then create a Plesk session for the user and redirect to the Plesk login page @app.route('/oidc/callback') def oidc_callback(): # Get user information from OIDC provider token = oauth.oidc.authorize_access_token() user_info = token["userinfo"] # Display user's preferred_username username = user_info.get('preferred_username') # Get the user's IP address # This needs to be the IP address the Plesk server sees # Check if "SourceIP" is set in config source_ip = config["OIDC"].get("SourceIP", fallback="auto") # If "SourceIP" is set to "auto", get the IP address from the X-Forwarded-For header # If the header is not set, use the remote address as seen by Flask if source_ip == "auto": source_ip = request.headers.get("X-Forwarded-For", request.remote_addr) # If "SourceIP" is set to "public", get the plesklogin host's public IPv4 from ipify.org if source_ip == "public": source_ip = requests.get("https://api.ipify.org").text # Otherwise, just use the value of "SourceIP" as the IP address # Prepare a request to the Plesk API to create a session for the user xml_data = f""" {username} {source_ip} """ headers = { "Content-Type": "text/xml", "HTTP_PRETTY_PRINT": "TRUE", # Hey, it's pretty! } # Add the username and password to the request headers plesk_login = config["PLESK"].get( "Username", fallback=os.environ.get("PLESK_USERNAME")) plesk_password = config["PLESK"].get( "Password", fallback=os.environ.get("PLESK_PASSWORD")) headers["HTTP_AUTH_LOGIN"] = plesk_login headers["HTTP_AUTH_PASSWD"] = plesk_password # If "VerifySSL" is set to "False" in the configuration, disable SSL verification verify = config["PLESK"].getboolean("VerifySSL", fallback=True) response = requests.post( f"https://{plesk_url}/enterprise/control/agent.php", headers=headers, data=xml_data, verify=verify) # Extract the session ID from the response XML or raise an exception if the request failed if response.status_code == 200: response_xml = response.content.decode() # Extract the session ID from the response XML session_id = response_xml.split("")[1].split("")[0] else: print("Error:", response.status_code, response.content.decode()) raise Exception() # Redirect to the Plesk login page with the session ID return redirect(f"https://{plesk_url}/enterprise/rsession_init.php?PLESKSESSID={session_id}") if __name__ == '__main__': app.run(debug=config["FLASK"].getboolean( "Debug", fallback=bool(os.environ.get("FLASK_DEBUG", False))))