Skip to content

Commit

Permalink
Upload files.
Browse files Browse the repository at this point in the history
  • Loading branch information
Duarte Mortágua committed Jul 31, 2023
0 parents commit 6892687
Show file tree
Hide file tree
Showing 31 changed files with 1,268 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Duarte Mortágua

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# vpn-idp

This repository includes a VPN solution based on WireGuard that implements user authentication using OAuth2.0 and IdPs. The solution was proposed in my MSc thesis:

- D. Mortágua, "Authentication in VPNs and 802.1X networks with Identity Providers," M.S. thesis, Department of Electronics, Telecommunications and Informatics, University of Aveiro, Aveiro, 2023. [Online]. Available: soon

A PDF containing the dissertation presentation is present in both modules.

### Author
[Duarte Mortágua](mailto:[email protected])
2 changes: 2 additions & 0 deletions vpn-idp-client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv
.env
34 changes: 34 additions & 0 deletions vpn-idp-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# vpn-idp-client

## Introduction

VPN Client that authenticates with a VPN Server using external IdPs.

This repository integrates part of the VPN solution proposed in my MSc thesis:

- D. Mortágua, "Authentication in VPNs and 802.1X networks with Identity Providers," M.S. thesis, Department of Electronics, Telecommunications and Informatics, University of Aveiro, Aveiro, 2023. [Online]. Available: soon.

### TL;DR:

This work presents a streamlined VPN solution that utilizes external IdPs for client user authentication and leverages the OAuth 2.0 authorization process for WireGuard key negotiation, ensuring that only authenticated peers can establish a VPN connection.

This piece of code implements the VPN Client module. The ```presentation.pdf``` file includes a brief explanaition of the architecture and communication implemented.

## Installation:
Set up the python environment by running:
```
python3 -m venv venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
```

You need to set up the following environment variables (```.env``` file in root directory):
``````
VPN_SERVER_URL=<your_vpn_server_url>
VPN_CLIENT_WG_PUB_KEY=<your_vpn_client_wireguard_pub_key>
``````

Finally, run the client:
```
python3 client.py
```
100 changes: 100 additions & 0 deletions vpn-idp-client/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import threading
import time
import webbrowser
import socket
import os
from flask import Flask, redirect, request
import logging
from dotenv import load_dotenv

load_dotenv()

# Logging configuration
logging.basicConfig(
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%d-%m-%Y %H:%M:%S')


# Get environment variables
VPN_SERVER_URL = os.getenv('VPN_SERVER_URL')
VPN_CLIENT_WG_PUB_KEY = os.environ.get('VPN_CLIENT_WG_PUB_KEY')


def initial_logging(port):
logging.info(f"Local server listening on port {port}")
logging.info(f"Launching browser...")
logging.info(f"{VPN_SERVER_URL}/accounts/login/?port={port}")
webbrowser.open(
f"{VPN_SERVER_URL}/accounts/login/?port={port}")


class MyFlaskApp(Flask):
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
if not self.debug or os.getenv('WERKZEUG_RUN_MAIN') == 'true':
with self.app_context():
initial_logging(port)
super(MyFlaskApp, self).run(host=host, port=port,
debug=debug, load_dotenv=load_dotenv, **options)


# Initialize app
app = MyFlaskApp(__name__)

# Find available port
sock = socket.socket()
sock.bind(('', 0))
port = sock.getsockname()[1]
sock.close()


def create_vpn(params):
"""
Simulates the instatiation of a WireGuard VPN connection
based on the parameters recieved from the VPN Server.
"""

if params.get('machine_id'):
logging.info(f"Machine ID: {params.get('machine_id')}")
logging.info(f"Client WG ipv4: {params.get('machine_wg_ipv4_address')}")
logging.info(f"Client WG ipv4 pool: {params.get('machine_wg_ipv4_address_pool')}")
logging.info(f"Client WG pub key: {params.get('machine_wg_pub_key')}")
logging.info(f"Server WG pub key: {params.get('server_wg_pub_key')}")
logging.info(f"Server WG public endpoint: {params.get('server_wg_public_endpoint')}")
logging.info("VPN creation Thread starting (simulation)...")
time.sleep(5)
logging.info("VPN creation Thread finishing.")


@app.route('/login_callback')
def redirect_to_vpn_server():
"""
Redcieves the callback from the IdP callback and redirects it to
the real OAuth2.0 client, aka the VPN Server. If the response
contains a code (Auth Grant flow), it adds the code to the
redirection request.
"""

code = request.args.get("code")
logging.info("Recieved redirect from IdP, redirecting token fragment to the VPN Server...")
if code:
logging.info("Found code, adding it to redirect...")
return redirect(f'{VPN_SERVER_URL}/accounts/login_callback/?code={code}&wg_pub_key={VPN_CLIENT_WG_PUB_KEY}')
return redirect(f'{VPN_SERVER_URL}/accounts/login_callback/?wg_pub_key={VPN_CLIENT_WG_PUB_KEY}')


@app.route('/vpn_parameters')
def recieve_vpn_parameters():
"""
Endpoint where the VPN Server sends the final VPN parameters
upon successful authentication. These parameters allow the client
to initiate the VPN connection.
"""

logging.info("Recieved parameters from browser.")
create_vpn_job = threading.Thread(target=create_vpn, args=(request.args,))
create_vpn_job.start()
return 'Login successful. You can close this window now.'


app.run(host="127.0.0.1", port=port)
Binary file added vpn-idp-client/presentation.pdf
Binary file not shown.
5 changes: 5 additions & 0 deletions vpn-idp-client/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
websockets
flask-sock
flask
requests
python-dotenv
132 changes: 132 additions & 0 deletions vpn-idp-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
*.sql
.vscode/
migrations/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
72 changes: 72 additions & 0 deletions vpn-idp-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# vpn-idp-server

## Introduction

VPN server that allows a VPN client to authenticate via an external Identity Provider, using OAuth2.0, avoiding the usual ID/Password authentication.

This repository integrates part of the VPN solution proposed in my MSc thesis:

- D. Mortágua, "Authentication in VPNs and 802.1X networks with Identity Providers," M.S. thesis, Department of Electronics, Telecommunications and Informatics, University of Aveiro, Aveiro, 2023. [Online]. Available: soon.

## Introduction

### TL;DR:

This work presents a streamlined VPN solution that utilizes external IdPs for client user authentication and leverages the OAuth 2.0 authorization process for WireGuard key negotiation, ensuring that only authenticated peers can establish a VPN connection.

This piece of code implements the VPN Server module. The ```presentation.pdf``` file includes a brief explanaition of the architecture and communication implemented.

## Installation:

Set up the python environment by running:
```
python3 -m venv venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
```

Apply the Django migrations:
```
python3 manage.py makemigrations
python3 manage.py migrate
```

Create the Django admin user:
```
python3 manage.py createsuperuser --username admin
```

As this server acts like a OAuth2.0 client, it needs to hold credentials regarding the supported IdPs (client ID, client secret, etc...). This Django project is ready to hold a sqlite3 table that holds these credentials, according to the model ```IdentityProvider``` in ```accounts/models.py```.

In order to facilitate the import of an IdP, you can set up a OAuth2.0 client (for example, [Google ID](https://developers.google.com/identity/protocols/oauth2)) and import it as a Django fixture.

Example of a fixture file ```fixtures/idps.json``` holding 1 IdP configuration:
```json
[
{
"model": "accounts.identityprovider",
"pk": 1,
"fields": {
"name" : "google",
"type": "auth_code",
"client_id": "********",
"client_secret": "********",
"auth_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"token_endpoint": "https://oauth2.googleapis.com/token",
"scope": "https://www.googleapis.com/auth/userinfo.email",
"response_type": "code",
"redirect_uri": null,
"code_challange_method" : "S256"
}
}
]
```

You can import the fixture file as follows:
```bash
python3 manage.py loaddata fixtures/idps.json --app accounts.IdentityProvider
```
Finally, you can run the server:
```bash
python3 manage.py runserver 127.0.0.1:8000
```
3 changes: 3 additions & 0 deletions vpn-idp-server/accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions vpn-idp-server/accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'accounts'
Loading

0 comments on commit 6892687

Please sign in to comment.