mirror of https://github.com/nucypher/nucypher.git
Add very simple iteration of basic authentication to Porter.
parent
ed17df1be3
commit
5485484e36
|
@ -0,0 +1,12 @@
|
|||
FROM nucypher:latest
|
||||
|
||||
# Update
|
||||
RUN apt update -y && apt upgrade -y
|
||||
|
||||
WORKDIR /code
|
||||
COPY . /code
|
||||
|
||||
# Porter requirements
|
||||
RUN pip3 install .[porter]
|
||||
|
||||
CMD ["/bin/bash"]
|
|
@ -6,7 +6,7 @@ services:
|
|||
image: nucypher:latest
|
||||
build:
|
||||
context: ../../..
|
||||
dockerfile: deploy/docker/Dockerfile
|
||||
dockerfile: deploy/docker/porter/Dockerfile
|
||||
ports:
|
||||
# Default Porter port
|
||||
- "80:9155"
|
||||
|
@ -22,16 +22,37 @@ services:
|
|||
image: nucypher:latest
|
||||
build:
|
||||
context: ../../..
|
||||
dockerfile: deploy/docker/Dockerfile
|
||||
dockerfile: deploy/docker/porter/Dockerfile
|
||||
ports:
|
||||
# Default Porter port
|
||||
- "443:9155"
|
||||
volumes:
|
||||
- .:/code
|
||||
- ~/.local/share/nucypher:/nucypher
|
||||
- "${TLS_DIR}:/etc/porter-tls/"
|
||||
- "${TLS_DIR}:/etc/porter/tls/"
|
||||
command: [ "nucypher", "porter", "run",
|
||||
"--provider", "${WEB3_PROVIDER_URI}",
|
||||
"--network", "${NUCYPHER_NETWORK}",
|
||||
"--tls-key-filepath", "/etc/porter-tls/key.pem",
|
||||
"--tls-certificate-filepath", "/etc/porter-tls/cert.pem"]
|
||||
"--tls-key-filepath", "/etc/porter/tls/key.pem",
|
||||
"--tls-certificate-filepath", "/etc/porter/tls/cert.pem"]
|
||||
|
||||
porter-https-auth:
|
||||
restart: on-failure
|
||||
image: nucypher:latest
|
||||
build:
|
||||
context: ../../..
|
||||
dockerfile: deploy/docker/porter/Dockerfile
|
||||
ports:
|
||||
# Default Porter port
|
||||
- "443:9155"
|
||||
volumes:
|
||||
- .:/code
|
||||
- ~/.local/share/nucypher:/nucypher
|
||||
- "${TLS_DIR}:/etc/porter/tls/"
|
||||
- "${HTPASSWD_FILE}:/etc/porter/auth/htpasswd"
|
||||
command: [ "nucypher", "porter", "run",
|
||||
"--provider", "${WEB3_PROVIDER_URI}",
|
||||
"--network", "${NUCYPHER_NETWORK}",
|
||||
"--tls-key-filepath", "/etc/porter/tls/key.pem",
|
||||
"--tls-certificate-filepath", "/etc/porter/tls/cert.pem",
|
||||
"--basic-auth-filepath", "/etc/porter/auth/htpasswd"]
|
||||
|
|
|
@ -21,7 +21,8 @@ import click
|
|||
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||
from nucypher.characters.lawful import Ursula
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED, PORTER_RUN_MESSAGE
|
||||
from nucypher.cli.literature import BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED, PORTER_RUN_MESSAGE, \
|
||||
BASIC_AUTH_REQUIRES_HTTPS
|
||||
from nucypher.cli.options import (
|
||||
option_network,
|
||||
option_provider_uri,
|
||||
|
@ -96,6 +97,7 @@ def exec_work_order(general_config, porter_uri, ursula, work_order):
|
|||
@click.option('--http-port', help="Porter HTTP/HTTPS port for JSON endpoint", type=NETWORK_PORT, default=Porter.DEFAULT_PORT)
|
||||
@click.option('--tls-certificate-filepath', help="Pre-signed TLS certificate filepath", type=click.Path(dir_okay=False, exists=True, path_type=Path))
|
||||
@click.option('--tls-key-filepath', help="TLS private key filepath", type=click.Path(dir_okay=False, exists=True, path_type=Path))
|
||||
@click.option('--basic-auth-filepath', help="htpasswd filepath for basic authentication", type=click.Path(dir_okay=False, exists=True, resolve_path=True, path_type=Path))
|
||||
@click.option('--dry-run', '-x', help="Execute normally without actually starting Porter", is_flag=True)
|
||||
@click.option('--eager', help="Start learning and scraping the network before starting up other services", is_flag=True, default=True)
|
||||
def run(general_config,
|
||||
|
@ -108,11 +110,24 @@ def run(general_config,
|
|||
http_port,
|
||||
tls_certificate_filepath,
|
||||
tls_key_filepath,
|
||||
basic_auth_filepath,
|
||||
dry_run,
|
||||
eager):
|
||||
"""Start Porter's Web controller."""
|
||||
emitter = setup_emitter(general_config, banner=Porter.BANNER)
|
||||
|
||||
# HTTP/HTTPS
|
||||
if bool(tls_key_filepath) ^ bool(tls_certificate_filepath):
|
||||
raise click.BadOptionUsage(option_name='--tls-key-filepath, --tls-certificate-filepath',
|
||||
message=BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED)
|
||||
|
||||
is_https = (tls_key_filepath and tls_certificate_filepath)
|
||||
|
||||
# check authentication
|
||||
if basic_auth_filepath and not is_https:
|
||||
raise click.BadOptionUsage(option_name='--basic-auth-filepath',
|
||||
message=BASIC_AUTH_REQUIRES_HTTPS)
|
||||
|
||||
if federated_only:
|
||||
if not teacher_uri:
|
||||
raise click.BadOptionUsage(option_name='--teacher',
|
||||
|
@ -157,17 +172,15 @@ def run(general_config,
|
|||
rpc_controller.start()
|
||||
return
|
||||
|
||||
# HTTP/HTTPS
|
||||
if bool(tls_key_filepath) ^ bool(tls_certificate_filepath):
|
||||
raise click.BadOptionUsage(option_name='--tls-key-filepath, --tls-certificate-filepath',
|
||||
message=BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED)
|
||||
|
||||
emitter.message(f"Network: {PORTER.domain.capitalize()}", color='green')
|
||||
if not federated_only:
|
||||
emitter.message(f"Provider: {provider_uri}", color='green')
|
||||
|
||||
controller = PORTER.make_web_controller(crash_on_error=False)
|
||||
http_scheme = "https" if tls_key_filepath and tls_certificate_filepath else "http"
|
||||
if basic_auth_filepath:
|
||||
emitter.message(f"Basic Authentication enabled", color='green')
|
||||
|
||||
controller = PORTER.make_web_controller(htpasswd_filepath=basic_auth_filepath, crash_on_error=False)
|
||||
http_scheme = "https" if is_https else "http"
|
||||
message = PORTER_RUN_MESSAGE.format(http_scheme=http_scheme, http_port=http_port)
|
||||
emitter.message(message, color='green', bold=True)
|
||||
return controller.start(port=http_port,
|
||||
|
|
|
@ -723,3 +723,5 @@ SUCCESSFUL_MANUALLY_SAVE_METADATA = "Successfully saved node metadata to {metada
|
|||
PORTER_RUN_MESSAGE = "Running Porter Web Controller at {http_scheme}://127.0.0.1:{http_port}"
|
||||
|
||||
BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED = "Both --tls-key-filepath and --tls-certificate-filepath must be provided to launch porter with TLS; only one specified"
|
||||
|
||||
BASIC_AUTH_REQUIRES_HTTPS = "Basic authentication can only be used with HTTPS. --tls-key-filepath and --tls-certificate-filepath must also be provided"
|
||||
|
|
|
@ -19,6 +19,7 @@ from typing import List, Optional, Iterable
|
|||
from constant_sorrow.constants import NO_CONTROL_PROTOCOL, NO_BLOCKCHAIN_CONNECTION
|
||||
from eth_typing import ChecksumAddress
|
||||
from flask import request, Response
|
||||
from flask_htpasswd import HtPasswdAuth
|
||||
from umbral.keys import UmbralPublicKey
|
||||
|
||||
from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent
|
||||
|
@ -198,7 +199,7 @@ the Pipe for nucypher network operations
|
|||
self.controller = controller
|
||||
return controller
|
||||
|
||||
def make_web_controller(self, crash_on_error: bool = False):
|
||||
def make_web_controller(self, crash_on_error: bool = False, htpasswd_filepath: str = None):
|
||||
controller = WebController(app_name=self.APP_NAME,
|
||||
crash_on_error=crash_on_error,
|
||||
interface=self._interface_class(porter=self))
|
||||
|
@ -206,6 +207,11 @@ the Pipe for nucypher network operations
|
|||
|
||||
# Register Flask Decorator
|
||||
porter_flask_control = controller.make_control_transport()
|
||||
if htpasswd_filepath:
|
||||
porter_flask_control.config['FLASK_HTPASSWD_PATH'] = htpasswd_filepath
|
||||
# ensure basic auth required for all endpoints
|
||||
porter_flask_control.config['FLASK_AUTH_ALL'] = True
|
||||
_ = HtPasswdAuth(app=porter_flask_control)
|
||||
|
||||
#
|
||||
# Porter Control HTTP Endpoints
|
||||
|
|
4
setup.py
4
setup.py
|
@ -135,6 +135,7 @@ DEPLOY_REQUIRES = [
|
|||
URSULA_REQUIRES = ['prometheus_client', 'sentry-sdk'] # TODO: Consider renaming to 'monitor', etc.
|
||||
ALICE_REQUIRES = ['qrcode']
|
||||
BOB_REQUIRES = ['qrcode']
|
||||
PORTER_REQUIRES = ['flask-htpasswd'] # needed for basic authentication
|
||||
|
||||
EXTRAS = {
|
||||
|
||||
|
@ -146,7 +147,8 @@ EXTRAS = {
|
|||
# User
|
||||
'ursula': URSULA_REQUIRES,
|
||||
'alice': ALICE_REQUIRES,
|
||||
'bob': BOB_REQUIRES
|
||||
'bob': BOB_REQUIRES,
|
||||
'porter': PORTER_REQUIRES
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue