Squashed 'spiffworkflow-backend/' changes from 57ba8e0c8..72049c004

72049c004 added authentication callback endpoint. w/ burnettk, cullerton, jbirddog
1902b785d updated flask-bpmn w/ burnettk cullerton

git-subtree-dir: spiffworkflow-backend
git-subtree-split: 72049c00413ab9aa7d4c65b77247583654c06488
This commit is contained in:
burnettk 2022-10-19 15:17:17 -04:00
parent 9781908243
commit a166df8303
8 changed files with 88 additions and 16 deletions

View File

@ -1,8 +1,8 @@
"""empty message """empty message
Revision ID: b41f0d35641a Revision ID: 3a95e16cf17c
Revises: Revises:
Create Date: 2022-10-18 16:16:23.575571 Create Date: 2022-10-19 12:42:38.086243
""" """
from alembic import op from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'b41f0d35641a' revision = '3a95e16cf17c'
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -137,7 +137,7 @@ def upgrade():
op.create_table('secret', op.create_table('secret',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('key', sa.String(length=50), nullable=False), sa.Column('key', sa.String(length=50), nullable=False),
sa.Column('value', sa.String(length=255), nullable=False), sa.Column('value', sa.Text(), nullable=False),
sa.Column('creator_user_id', sa.Integer(), nullable=False), sa.Column('creator_user_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['creator_user_id'], ['user.id'], ), sa.ForeignKeyConstraint(['creator_user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id'), sa.PrimaryKeyConstraint('id'),

9
poetry.lock generated
View File

@ -639,7 +639,7 @@ werkzeug = "*"
type = "git" type = "git"
url = "https://github.com/sartography/flask-bpmn" url = "https://github.com/sartography/flask-bpmn"
reference = "main" reference = "main"
resolved_reference = "42cebab51fe469ab9dcb45672917d34c1f30987a" resolved_reference = "6e1411dd134955a829bb9f3d59b4af121907cd35"
[[package]] [[package]]
name = "Flask-Cors" name = "Flask-Cors"
@ -1847,8 +1847,8 @@ test = ["pytest"]
[[package]] [[package]]
name = "SpiffWorkflow" name = "SpiffWorkflow"
version = "1.2.0" version = "1.2.1"
description = "A workflow framework and BPMN/DMN Processor" description = ""
category = "main" category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
@ -1858,7 +1858,6 @@ develop = false
celery = "*" celery = "*"
configparser = "*" configparser = "*"
dateparser = "*" dateparser = "*"
importlib-metadata = "<5.0"
lxml = "*" lxml = "*"
pytz = "*" pytz = "*"
@ -1866,7 +1865,7 @@ pytz = "*"
type = "git" type = "git"
url = "https://github.com/sartography/SpiffWorkflow" url = "https://github.com/sartography/SpiffWorkflow"
reference = "main" reference = "main"
resolved_reference = "d9fcd45a384f8376a669cf58677564289d2c661c" resolved_reference = "a094adad8767f82e9c5fa806a46597e066252a72"
[[package]] [[package]]
name = "SQLAlchemy" name = "SQLAlchemy"

View File

@ -951,6 +951,47 @@ paths:
schema: schema:
$ref: "#/components/schemas/ServiceTask" $ref: "#/components/schemas/ServiceTask"
/authentication_callback/{service}/{auth_method}:
parameters:
- name: service
in: path
required: true
description: The name of the service
schema:
type: string
- name: auth_method
in: path
required: true
description: The method
schema:
type: string
- name: response
in: query
required: true
description: The response
schema:
type: string
- name: token
in: query
required: true
description: The response
schema:
type: string
get:
# disable security so we can get the token from query params instead
security: []
tags:
- Authentications
operationId: spiffworkflow_backend.routes.process_api_blueprint.authentication_callback
summary: Callback to backend
responses:
"200":
description: All authentications
content:
application/json:
schema:
$ref: "#/components/schemas/ServiceTask"
/tasks/{process_instance_id}/{task_id}: /tasks/{process_instance_id}/{task_id}:
parameters: parameters:
- name: task_id - name: task_id

View File

@ -16,7 +16,7 @@ class SecretModel(SpiffworkflowBaseDBModel):
__tablename__ = "secret" __tablename__ = "secret"
id: int = db.Column(db.Integer, primary_key=True) id: int = db.Column(db.Integer, primary_key=True)
key: str = db.Column(db.String(50), unique=True, nullable=False) key: str = db.Column(db.String(50), unique=True, nullable=False)
value: str = db.Column(db.String(255), nullable=False) value: str = db.Column(db.Text(), nullable=False)
creator_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=False) creator_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=False)

View File

@ -13,11 +13,13 @@ from typing import Union
import connexion # type: ignore import connexion # type: ignore
import flask.wrappers import flask.wrappers
import jinja2 import jinja2
import werkzeug
from flask import Blueprint from flask import Blueprint
from flask import current_app from flask import current_app
from flask import g from flask import g
from flask import jsonify from flask import jsonify
from flask import make_response from flask import make_response
from flask import redirect
from flask import request from flask import request
from flask.wrappers import Response from flask.wrappers import Response
from flask_bpmn.api.api_error import ApiError from flask_bpmn.api.api_error import ApiError
@ -52,6 +54,7 @@ from spiffworkflow_backend.models.secret_model import SecretModel
from spiffworkflow_backend.models.secret_model import SecretModelSchema from spiffworkflow_backend.models.secret_model import SecretModelSchema
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.routes.user import verify_token
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
from spiffworkflow_backend.services.file_system_service import FileSystemService from spiffworkflow_backend.services.file_system_service import FileSystemService
from spiffworkflow_backend.services.git_service import GitService from spiffworkflow_backend.services.git_service import GitService
@ -780,11 +783,28 @@ def authentication_list() -> flask.wrappers.Response:
response_json = { response_json = {
"results": available_authentications, "results": available_authentications,
"connector_proxy_base_url": current_app.config["CONNECTOR_PROXY_URL"], "connector_proxy_base_url": current_app.config["CONNECTOR_PROXY_URL"],
"redirect_url": f"{current_app.config['SPIFFWORKFLOW_BACKEND_URL']}/v1.0/authentication_callback",
} }
return Response(json.dumps(response_json), status=200, mimetype="application/json") return Response(json.dumps(response_json), status=200, mimetype="application/json")
def authentication_callback(
service: str,
auth_method: str,
) -> werkzeug.wrappers.Response:
"""Authentication_callback."""
verify_token(request.args.get("token"))
response = request.args["response"]
print(f"response: {response}")
SecretService().update_secret(
f"{service}/{auth_method}", response, g.user.id, create_if_not_exists=True
)
return redirect(
f"{current_app.config['SPIFFWORKFLOW_FRONTEND_URL']}/admin/authentications"
)
def process_instance_report_show( def process_instance_report_show(
process_group_id: str, process_group_id: str,
process_model_id: str, process_model_id: str,

View File

@ -69,7 +69,8 @@ class SecretService:
def update_secret( def update_secret(
key: str, key: str,
value: str, value: str,
creator_user_id: Optional[int] = None, creator_user_id: int,
create_if_not_exists: Optional[bool] = False,
) -> None: ) -> None:
"""Does this pass pre commit?""" """Does this pass pre commit?"""
secret_model = SecretModel.query.filter(SecretModel.key == key).first() secret_model = SecretModel.query.filter(SecretModel.key == key).first()
@ -80,16 +81,18 @@ class SecretService:
try: try:
db.session.commit() db.session.commit()
except Exception as e: except Exception as e:
raise ApiError( db.session.rollback()
error_code="update_secret_error", raise e
message=f"There was an error updating the secret with key: {key}, and value: {value}",
) from e
else: else:
raise ApiError( raise ApiError(
error_code="update_secret_error", error_code="update_secret_error",
message=f"User: {creator_user_id} cannot update the secret with key : {key}", message=f"User: {creator_user_id} cannot update the secret with key : {key}",
status_code=401, status_code=401,
) )
elif create_if_not_exists:
SecretService.add_secret(
key=key, value=value, creator_user_id=creator_user_id
)
else: else:
raise ApiError( raise ApiError(
error_code="update_secret_error", error_code="update_secret_error",

View File

@ -90,5 +90,4 @@ class ServiceTaskService:
parsed_response = json.loads(response.text) parsed_response = json.loads(response.text)
return parsed_response return parsed_response
except Exception as exception: except Exception as exception:
current_app.logger.error(exception)
raise ConnectorProxyError(exception.__class__.__name__) from exception raise ConnectorProxyError(exception.__class__.__name__) from exception

View File

@ -1560,6 +1560,16 @@ class TestProcessApi(BaseTest):
assert response.json is not None assert response.json is not None
assert len(response.json["results"]) == 2 assert len(response.json["results"]) == 2
# TODO: test the auth callback endpoint
# def test_can_store_authentication_secret(
# self, app: Flask, client: FlaskClient, with_db_and_bpmn_file_cleanup: None
# ) -> None:
# """Test_can_store_authentication_secret."""
# response = client.get(
# "/v1.0/authentication_callback",
# headers=self.logged_in_headers(user),
# )
# def test_get_process_model(self): # def test_get_process_model(self):
# #
# load_test_spec('random_fact') # load_test_spec('random_fact')