Exemple #1
0
def create_app():
    """
    Application factory

    This application uses the application factory pattern [1].

    In addition to various routes and commands (registered directly or via blueprints), the app object includes
    instances of important classes such as authentication and metadata records/collections. Application configuration
    is loaded from the `config` class.

    :return:
    """
    app = Flask(__name__)

    app.config.from_object(_create_app_config())
    app.jinja_loader = _create_app_jinja_loader()

    auth = FlaskAzureOauth()
    auth.init_app(app)
    app.auth_token = AppAuthToken(
        session_file_path=app.config["AUTH_SESSION_FILE_PATH"])

    app.repositories = _create_csw_repositories(
        repositories_config=app.config["CSW_SERVERS_CONFIG"])
    app.collections = Collections(config=app.config["COLLECTIONS_CONFIG"])
    app.config["CSW_CLIENTS_CONFIG"]["unpublished"]["client_config"][
        "auth"] = {
            "token": app.auth_token.access_token
        }
    app.config["CSW_CLIENTS_CONFIG"]["published"]["client_config"]["auth"] = {
        "token": app.auth_token.access_token
    }
    app.records = MirrorRepository(
        unpublished_repository_config=app.config["CSW_CLIENTS_CONFIG"]
        ["unpublished"],
        published_repository_config=app.config["CSW_CLIENTS_CONFIG"]
        ["published"],
    )

    app.register_blueprint(record_commands_blueprint)
    app.register_blueprint(collections_commands_blueprint)
    app.register_blueprint(site_commands_blueprint)
    app.register_blueprint(csw_commands_blueprint)
    app.register_blueprint(auth_commands_blueprint)
    app.register_blueprint(seeding_commands_blueprint)

    @app.cli.command("version")
    def version():
        """Show application version."""
        print(f"{app.config['NAME']} version: {app.config['VERSION']}")

    @app.route("/csw/<string:catalogue>", methods=["HEAD", "GET", "POST"])
    @auth(optional=True)
    def csw_catalogue(catalogue: str):
        try:
            return app.repositories[escape(catalogue)].process_request(
                request=request, token=current_token)
        except KeyError:
            return Response(response="Catalogue not found.", status=404)
        except CSWDatabaseNotInitialisedException:
            return Response(response="Catalogue not yet available.",
                            status=500)
        except CSWAuthMissingException:
            return Response(response="Missing authorisation token.",
                            status=401)
        except CSWAuthInsufficientException:
            return Response(response="Insufficient authorisation token.",
                            status=403)

    return app
Exemple #2
0
from http import HTTPStatus

from flask import Flask, request, jsonify

from flask_azure_oauth import FlaskAzureOauth
from tests.utils import TestJwk, TestFlaskAzureOauth

config = {
    "AZURE_OAUTH_TENANCY": "test",
    "AZURE_OAUTH_APPLICATION_ID": "test",
    "AZURE_OAUTH_CLIENT_APPLICATION_IDS": ["test", "test2"],
    "TEST_JWKS": TestJwk(),
}

auth = FlaskAzureOauth()


def create_app():
    app = Flask(__name__)

    # Configure and load provider
    app.config["AZURE_OAUTH_TENANCY"] = config["AZURE_OAUTH_TENANCY"]
    app.config["AZURE_OAUTH_APPLICATION_ID"] = config[
        "AZURE_OAUTH_APPLICATION_ID"]
    app.config["AZURE_OAUTH_CLIENT_APPLICATION_IDS"] = config[
        "AZURE_OAUTH_CLIENT_APPLICATION_IDS"]
    auth.init_app(app)

    @app.route("/meta/auth/introspection")
    @auth()
    def meta_auth_introspection():
Exemple #3
0
def create_app():
    app = Flask(__name__)
    app.config["SECRET_KEY"] = "TPZHP2Ljw82CSXR5BjjfoQ"

    ## Note: If changing between config sets, make sure to update required scopes in routes as well

    ## Config options for 'Flask Azure OAuth Provider - Example App 1' (version 1.0 tokens)
    # app.config["AZURE_OAUTH_TENANCY"] = "d14c529b-5558-4a80-93b6-7655681e55d6"
    # app.config["AZURE_OAUTH_APPLICATION_ID"] = "be76d0cc-26ab-4c07-8bae-ed544224078f"
    # app.config["AZURE_OAUTH_CLIENT_APPLICATION_IDS"] = ["da553d65-9dca-4393-a604-875addd10f13"]
    # app.config["AUTH_CLIENT_ID"] = "da553d65-9dca-4393-a604-875addd10f13"
    # app.config["AUTH_CLIENT_TENANCY"] = "https://login.microsoftonline.com/d14c529b-5558-4a80-93b6-7655681e55d6"
    # app.config["AUTH_CLIENT_SCOPES"] = [
    #     "api://be76d0cc-26ab-4c07-8bae-ed544224078f/BAS.WSF.FlaskOAuthProvider.Examples.Example1.Access"
    # ]

    ## Config options for 'Flask Azure OAuth Provider - Example App 2' (version 2.0 tokens)
    app.config["AZURE_OAUTH_TENANCY"] = "d14c529b-5558-4a80-93b6-7655681e55d6"
    app.config[
        "AZURE_OAUTH_APPLICATION_ID"] = "de40e653-e63b-46e3-80f6-52a39f055bf3"
    app.config["AZURE_OAUTH_CLIENT_APPLICATION_IDS"] = [
        "c5134fdc-f69a-4b80-ad55-66c4d6e5a2b0"
    ]
    app.config["AUTH_CLIENT_ID"] = "c5134fdc-f69a-4b80-ad55-66c4d6e5a2b0"
    app.config["AUTH_CLIENT_SECRET"] = "yq__4pGnY4RQ.Z3w~g_~ZFBF09S_07ergR"
    app.config[
        "AUTH_CLIENT_TENANCY"] = "https://login.microsoftonline.com/d14c529b-5558-4a80-93b6-7655681e55d6"
    app.config["AUTH_CLIENT_SCOPES"] = [
        "api://de40e653-e63b-46e3-80f6-52a39f055bf3/BAS.WSF.FlaskOAuthProvider.Examples.Example2.Access"
    ]

    app.auth = FlaskAzureOauth()
    app.auth.init_app(app)

    @app.route("/auth/sign-in")
    def auth_sign_in():
        session["state"] = str(uuid4())
        auth_url = ConfidentialClientApplication(
            app.config["AUTH_CLIENT_ID"],
            authority=current_app.config["AUTH_CLIENT_TENANCY"],
            client_credential=app.config["AUTH_CLIENT_SECRET"],
        ).get_authorization_request_url(
            scopes=current_app.config["AUTH_CLIENT_SCOPES"],
            state=session.get("state"),
            redirect_uri="http://*****:*****@app.route("/auth/callback")
    def auth_callback():
        if request.args.get("state") != session.get("state"):
            return "Sign-in failed, state doesn't match.", 403
        if request.args.get("error"):
            return request.args.get("error"), 403
        if not request.args.get("code"):
            return "Sign-in failed, no auth code.", 403

        result = ConfidentialClientApplication(
            app.config["AUTH_CLIENT_ID"],
            authority=current_app.config["AUTH_CLIENT_TENANCY"],
            client_credential=app.config["AUTH_CLIENT_SECRET"],
        ).acquire_token_by_authorization_code(
            code=request.args.get("code"),
            scopes=current_app.config["AUTH_CLIENT_SCOPES"],
            redirect_uri="http://*****:*****@app.route("/unprotected")
    def unprotected():
        return "Unprotected resource."

    @app.route("/protected")
    @app.auth()
    def protected():
        return "Protected resource."

    @app.route("/protected-with-single-scope")
    # @app.auth("BAS.WSF.FlaskOAuthProvider.Examples.Example1.Scope1")
    @app.auth("BAS.WSF.FlaskOAuthProvider.Examples.Example2.Scope1")
    def protected_with_scope():
        return "Protected resource requiring single scope."

    @app.route("/protected-with-multiple-scopes")
    # @app.auth("BAS.WSF.FlaskOAuthProvider.Examples.Example1.Scope1 BAS.WSF.FlaskOAuthProvider.Examples.Example1.Scope2")
    @app.auth(
        "BAS.WSF.FlaskOAuthProvider.Examples.Example2.Scope1 BAS.WSF.FlaskOAuthProvider.Examples.Example2.Scope2"
    )
    def protected_with_multiple_scopes():
        return "Protected resource requiring multiple scopes."

    @app.cli.command("access-resource")
    @click.argument(
        "resource",
        type=click.Choice([
            "unprotected", "protected", "protected-with-single-scope",
            "protected-with-multiple-scopes"
        ]),
    )
    @click.option("-t", "--access-token")
    def access_resource(resource, access_token):
        """Simulates a user requesting a resource"""
        if access_token is not None:
            current_app.config["AUTH_TOKEN"] = access_token
        if resource != "unprotected" and "AUTH_TOKEN" not in current_app.config:
            _get_token()

        client_headers = {}
        if "AUTH_TOKEN" in current_app.config:
            client_headers[
                "Authorization"] = f"Bearer {current_app.config['AUTH_TOKEN']}"
        client = current_app.test_client()

        response = client.get(f"/{resource}", headers=client_headers)
        click.echo(f"Response status code: {response.status_code}")
        click.echo(f"Response data: {response.data.decode()}")

    def _get_token():
        auth_client = PublicClientApplication(
            client_id=current_app.config["AUTH_CLIENT_ID"],
            authority=current_app.config["AUTH_CLIENT_TENANCY"])
        auth_flow = auth_client.initiate_device_flow(
            scopes=current_app.config["AUTH_CLIENT_SCOPES"])
        click.pause(
            f"To sign-in, visit 'https://microsoft.com/devicelogin', enter this code '{auth_flow['user_code']}' and then press any key..."
        )
        auth_payload = auth_client.acquire_token_by_device_flow(auth_flow)
        current_app.config["AUTH_TOKEN"] = auth_payload["access_token"]
        click.echo(current_app.config["AUTH_TOKEN"])
        click.echo(f"Ok. Access token set.")

    return app