This commit is contained in:
iFargle
2023-02-20 18:47:19 +09:00
parent ef8e7f0644
commit ea3c5b1be6
2 changed files with 98 additions and 58 deletions

View File

@@ -17,7 +17,7 @@ PyYAML = "^6.0"
pyuwsgi = "^2.0.21"
gunicorn = "^20.1.0"
flask-basicauth = "^0.2.0"
flask-providers-oidc = "^1.2.1"
flask-pyoidc = "^3.12.1"
[tool.poetry.dev-dependencies]

154
server.py
View File

@@ -22,50 +22,81 @@ executor = Executor(app)
# Set Authentication type:
########################################################################################
if AUTH_TYPE.lower() == "oidc":
# https://flask-oidc2.readthedocs.io/en/latest/#
# https://gist.github.com/thomasdarimont/145dc9aa857b831ff2eff221b79d179a/
# https://www.authelia.com/integration/openid-connect/introduction/
# https://flask-pyoidc.readthedocs.io/en/latest/
LOG.error("Loading OIDC libraries and configuring app...")
from flask_pyoidc import OIDCAuthentication
from flask_pyoidc.provider_configuration import ProviderConfiguration, ClientMetadata
from flask_pyoidc.user_session import UserSession
DOMAIN_NAME = os.environ["DOMAIN_NAME"]
BASE_PATH = os.environ["SCRIPT_NAME"] if os.environ["SCRIPT_NAME"] != "/" else ""
OIDC_ISSUER = os.environ["OIDC_ISSUER"].replace('"','')
OIDC_SECRET = os.environ["OIDC_CLIENT_SECRET"]
OIDC_CLIENT_ID = os.environ["OIDC_CLIENT_ID"]
# Construct client_secrets.json:
client_secrets = """
{
"web": {
"issuer": \""""+OIDC_ISSUER+"""",
"auth_uri": \""""+OIDC_ISSUER+"""/api/oidc/authorization",
"client_id": \""""+OIDC_CLIENT_ID+"""",
"client_secret": \""""+OIDC_SECRET+"""",
"redirect_uris": [\""""+DOMAIN_NAME+BASE_PATH+"""/oidc_callback"],
"userinfo_uri": \""""+OIDC_ISSUER+"""/api/oidc/userinfo",
"token_uri": \""""+OIDC_ISSUER+"""/api/oidc/token",
"token_introspection_uri": \""""+OIDC_ISSUER+"""/api/oidc/introspection"
REDIRECT_URI = DOMAIN_NAME+BASE_PATH+"/redirect_uri"
app.config.update(
{
'OIDC_REDIRECT_URI': REDIRECT_URI,
'SECRET_KEY': OIDC_SECRET,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=7).total_seconds(),
'DEBUG': DEBUG_STATE
}
}
"""
LOG.error("Secrets")
LOG.error(client_secrets)
with open("/app/instance/secrets.json", "w+") as secrets_json:
secrets_json.write(client_secrets)
app.config.update({
'SECRET_KEY': secrets.token_urlsafe(32),
'TESTING': DEBUG_STATE,
'DEBUG': DEBUG_STATE,
'OIDC_CLIENT_SECRETS': '/app/instance/secrets.json',
'OIDC_ID_TOKEN_COOKIE_SECURE': False,
'OIDC_REQUIRE_VERIFIED_EMAIL': False,
'OIDC_USER_INFO_ENABLED': True,
'OIDC_OPENID_REALM': 'Headscale-WebUI',
'OIDC_SCOPES': ['openid', 'email', 'profile'],
'OIDC_INTROSPECTION_AUTH_METHOD': 'client_secret_post'
})
from flask_oidc import OpenIDConnect
oidc = OpenIDConnect(app)
)
ISSUER = OIDC_ISSUER
CLIENT = OIDC_CLIENT_ID+"@oidc_provider"
OIDC_PROVIDER = 'oidc_provider'
CONFIG = ProviderConfiguration(issuer=ISSUER, client_metadata=ClientMetadata(CLIENT, OIDC_SECRET))
oidc = OIDCAuthentication({OIDC_PROVIDER: CONFIG})
# Testing another OIDC library
# if AUTH_TYPE.lower() == "oidc":
# # https://flask-oidc2.readthedocs.io/en/latest/#
# # https://gist.github.com/thomasdarimont/145dc9aa857b831ff2eff221b79d179a/
# # https://www.authelia.com/integration/openid-connect/introduction/
# LOG.error("Loading OIDC libraries and configuring app...")
#
# DOMAIN_NAME = os.environ["DOMAIN_NAME"]
# BASE_PATH = os.environ["SCRIPT_NAME"] if os.environ["SCRIPT_NAME"] != "/" else ""
# OIDC_ISSUER = os.environ["OIDC_ISSUER"].replace('"','')
# OIDC_SECRET = os.environ["OIDC_CLIENT_SECRET"]
# OIDC_CLIENT_ID = os.environ["OIDC_CLIENT_ID"]
# # Construct client_secrets.json:
# client_secrets = """
# {
# "web": {
# "issuer": \""""+OIDC_ISSUER+"""",
# "auth_uri": \""""+OIDC_ISSUER+"""/api/oidc/authorization",
# "client_id": \""""+OIDC_CLIENT_ID+"""",
# "client_secret": \""""+OIDC_SECRET+"""",
# "redirect_uris": [\""""+DOMAIN_NAME+BASE_PATH+"""/oidc_callback"],
# "userinfo_uri": \""""+OIDC_ISSUER+"""/api/oidc/userinfo",
# "token_uri": \""""+OIDC_ISSUER+"""/api/oidc/token",
# "token_introspection_uri": \""""+OIDC_ISSUER+"""/api/oidc/introspection"
# }
# }
# """
# LOG.error("Secrets")
# LOG.error(client_secrets)
# with open("/app/instance/secrets.json", "w+") as secrets_json:
# secrets_json.write(client_secrets)
#
# app.config.update({
# 'SECRET_KEY': secrets.token_urlsafe(32),
# 'TESTING': DEBUG_STATE,
# 'DEBUG': DEBUG_STATE,
# 'OIDC_CLIENT_SECRETS': '/app/instance/secrets.json',
# 'OIDC_ID_TOKEN_COOKIE_SECURE': False,
# 'OIDC_REQUIRE_VERIFIED_EMAIL': False,
# 'OIDC_USER_INFO_ENABLED': True,
# 'OIDC_OPENID_REALM': 'Headscale-WebUI',
# 'OIDC_SCOPES': ['openid', 'email', 'profile'],
# 'OIDC_INTROSPECTION_AUTH_METHOD': 'client_secret_post'
# })
# from flask_oidc import OpenIDConnect
# oidc = OpenIDConnect(app)
elif AUTH_TYPE.lower() == "basic":
# https://flask-basicauth.readthedocs.io/en/latest/
@@ -81,9 +112,18 @@ elif AUTH_TYPE.lower() == "basic":
########################################################################################
# / pages - User-facing pages
########################################################################################
# Testing OIDC page...
@app.route('/oidctest')
@auth.oidc_auth(OIDC_PROVIDER)
def oidctest_page():
user_session = UserSession(flask.session)
return jsonify(access_token=user_session.access_token,
id_token=user_session.id_token,
userinfo=user_session.userinfo)
@app.route('/')
@app.route('/overview')
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def overview_page():
# Some basic sanity checks:
pass_checks = str(helper.load_checks())
@@ -96,7 +136,7 @@ def overview_page():
)
@app.route('/machines', methods=('GET', 'POST'))
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def machines_page():
# Some basic sanity checks:
pass_checks = str(helper.load_checks())
@@ -111,7 +151,7 @@ def machines_page():
)
@app.route('/users', methods=('GET', 'POST'))
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def users_page():
# Some basic sanity checks:
pass_checks = str(helper.load_checks())
@@ -126,7 +166,7 @@ def users_page():
)
@app.route('/settings', methods=('GET', 'POST'))
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def settings_page():
# Some basic sanity checks:
pass_checks = str(helper.load_checks())
@@ -144,7 +184,7 @@ def settings_page():
)
@app.route('/error')
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def error_page():
if helper.access_checks() == "Pass":
return redirect(url_for('overview_page'))
@@ -162,7 +202,7 @@ def error_page():
########################################################################################
@app.route('/api/test_key', methods=('GET', 'POST'))
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def test_key_page():
api_key = headscale.get_api_key()
url = headscale.get_url()
@@ -199,7 +239,7 @@ def test_key_page():
return message
@app.route('/api/save_key', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def save_key_page():
json_response = request.get_json()
api_key = json_response['api_key']
@@ -224,7 +264,7 @@ def save_key_page():
# Machine API Endpoints
########################################################################################
@app.route('/api/update_route', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def update_route_page():
json_response = request.get_json()
route_id = json_response['route_id']
@@ -235,7 +275,7 @@ def update_route_page():
return headscale.update_route(url, api_key, route_id, current_state)
@app.route('/api/machine_information', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def machine_information_page():
json_response = request.get_json()
machine_id = json_response['id']
@@ -245,7 +285,7 @@ def machine_information_page():
return headscale.get_machine_info(url, api_key, machine_id)
@app.route('/api/delete_machine', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def delete_machine_page():
json_response = request.get_json()
machine_id = json_response['id']
@@ -255,7 +295,7 @@ def delete_machine_page():
return headscale.delete_machine(url, api_key, machine_id)
@app.route('/api/rename_machine', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def rename_machine_page():
json_response = request.get_json()
machine_id = json_response['id']
@@ -266,7 +306,7 @@ def rename_machine_page():
return headscale.rename_machine(url, api_key, machine_id, new_name)
@app.route('/api/move_user', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def move_user_page():
json_response = request.get_json()
machine_id = json_response['id']
@@ -277,7 +317,7 @@ def move_user_page():
return headscale.move_user(url, api_key, machine_id, new_user)
@app.route('/api/set_machine_tags', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def set_machine_tags():
json_response = request.get_json()
machine_id = json_response['id']
@@ -288,7 +328,7 @@ def set_machine_tags():
return headscale.set_machine_tags(url, api_key, machine_id, machine_tags)
@app.route('/api/register_machine', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def register_machine():
json_response = request.get_json()
machine_key = json_response['key']
@@ -302,7 +342,7 @@ def register_machine():
# User API Endpoints
########################################################################################
@app.route('/api/rename_user', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def rename_user_page():
json_response = request.get_json()
old_name = json_response['old_name']
@@ -313,7 +353,7 @@ def rename_user_page():
return headscale.rename_user(url, api_key, old_name, new_name)
@app.route('/api/add_user', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def add_user():
json_response = json.dumps(request.get_json())
url = headscale.get_url()
@@ -322,7 +362,7 @@ def add_user():
return headscale.add_user(url, api_key, json_response)
@app.route('/api/delete_user', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def delete_user():
json_response = request.get_json()
user_name = json_response['name']
@@ -332,7 +372,7 @@ def delete_user():
return headscale.delete_user(url, api_key, user_name)
@app.route('/api/get_users', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def get_users_page():
url = headscale.get_url()
api_key = headscale.get_api_key()
@@ -343,7 +383,7 @@ def get_users_page():
# Pre-Auth Key API Endpoints
########################################################################################
@app.route('/api/add_preauth_key', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def add_preauth_key():
json_response = json.dumps(request.get_json())
url = headscale.get_url()
@@ -352,7 +392,7 @@ def add_preauth_key():
return headscale.add_preauth_key(url, api_key, json_response)
@app.route('/api/expire_preauth_key', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def expire_preauth_key():
json_response = json.dumps(request.get_json())
url = headscale.get_url()
@@ -361,7 +401,7 @@ def expire_preauth_key():
return headscale.expire_preauth_key(url, api_key, json_response)
@app.route('/api/build_preauthkey_table', methods=['POST'])
@oidc.require_login
@oidc.oidc_auth(OIDC_PROVIDER)
def build_preauth_key_table():
json_response = request.get_json()
user_name = json_response['name']