Example #1
0
def authorized(  # pylint: disable=too-many-return-statements
        identifier: str, jwt: JwtManager, action: List[str]) -> bool:
    """Assert that the user is authorized to create filings against the business identifier."""
    # if they are registry staff, they are always authorized
    if not action or not identifier or not jwt:
        return False

    if jwt.validate_roles([STAFF_ROLE]) \
            or jwt.validate_roles([SYSTEM_ROLE]) \
            or jwt.validate_roles([COLIN_SVC_ROLE]):
        return True

    if jwt.has_one_of_roles([BASIC_USER, PUBLIC_USER]):

        # if the action is create_comment or courtOrder/registrarsNotation/registrarsOrder filings
        # disallow - only staff are allowed
        staff_only_actions = [
            'add_comment', 'court_order', 'registrars_notation',
            'registrars_order'
        ]
        if any(elem in action for elem in staff_only_actions):
            return False

        template_url = current_app.config.get('AUTH_SVC_URL')
        auth_url = template_url.format(**vars())

        token = jwt.get_token_auth_header()
        headers = {'Authorization': 'Bearer ' + token}
        try:
            http = Session()
            retries = Retry(total=5,
                            backoff_factor=0.1,
                            status_forcelist=[500, 502, 503, 504])
            http.mount('http://', HTTPAdapter(max_retries=retries))
            rv = http.get(url=auth_url, headers=headers)

            if rv.status_code != HTTPStatus.OK \
                    or not rv.json().get('roles'):
                return False

            if all(elem.lower() in rv.json().get('roles') for elem in action):
                return True

        except (
                exceptions.ConnectionError,  # pylint: disable=broad-except
                exceptions.Timeout,
                ValueError,
                Exception) as err:
            current_app.logger.error(
                f'template_url {template_url}, svc:{auth_url}')
            current_app.logger.error(
                f'Authorization connection failure for {identifier}, using svc:{auth_url}',
                err)
            return False

    return False
Example #2
0
def jwt(app):
    def get_roles(a_dict):
        return a_dict['realm_access']['roles']

    app.config['JWT_ROLE_CALLBACK'] = get_roles

    jwt = JwtManager()
    jwt.init_app(app)

    return jwt
Example #3
0
    def _create_invoice(business: Business,
                        filing: Filing,
                        filing_types: list,
                        user_jwt: JwtManager) \
            -> Tuple[int, dict, int]:
        """Create the invoice for the filing submission.

        Returns: {
            int: the paymentToken (id), or None
            dict: a dict of errors, or None
            int: the HTTPStatus error code, or None
        }
        """
        payment_svc_url = current_app.config.get('PAYMENT_SVC_URL')
        mailing_address = business.mailing_address.one_or_none()

        payload = {
            'paymentInfo': {'methodOfPayment': 'CC'},
            'businessInfo': {
                'businessIdentifier': f'{business.identifier}',
                'corpType': f'{business.identifier[:-7]}',
                'businessName': f'{business.legal_name}',
                'contactInfo': {'city': mailing_address.city,
                                'postalCode': mailing_address.postal_code,
                                'province': mailing_address.region,
                                'addressLine1': mailing_address.street,
                                'country': mailing_address.country}
            },
            'filingInfo': {
                'filingTypes': filing_types
            }
        }

        if user_jwt.validate_roles([STAFF_ROLE]):
            routing_slip_number = get_str(filing.filing_json, 'filing/header/routingSlipNumber')
            if routing_slip_number:
                payload['accountInfo'] = {'routingSlip': routing_slip_number}
        try:
            token = user_jwt.get_token_auth_header()
            headers = {'Authorization': 'Bearer ' + token}
            rv = requests.post(url=payment_svc_url,
                               json=payload,
                               headers=headers,
                               timeout=20.0)
        except (exceptions.ConnectionError, exceptions.Timeout) as err:
            current_app.logger.error(f'Payment connection failure for {business.identifier}: filing:{filing.id}', err)
            return {'message': 'unable to create invoice for payment.'}, HTTPStatus.PAYMENT_REQUIRED

        if rv.status_code == HTTPStatus.OK or rv.status_code == HTTPStatus.CREATED:
            pid = rv.json().get('id')
            filing.payment_token = pid
            filing.save()
            return None, None
        return {'message': 'unable to create invoice for payment.'}, HTTPStatus.PAYMENT_REQUIRED
Example #4
0
def authorized(identifier: str, jwt: JwtManager) -> bool:  # pylint: disable=too-many-return-statements
    """Verify the user is authorized to submit the request by inspecting the web token.

    The gateway has already verified the JWT with the OIDC service.
    """
    if not jwt:
        return False

    # Could call the auth api here to check the token roles (/api/v1/orgs/{account_id}/authorizations),
    # but JWTManager.validate_roles does the same thing.

    # All users including staff must have the PPR role.
    if not jwt.validate_roles([PPR_ROLE]):
        return False

    # Account ID (idenfifier) is required if not staff.
    if identifier and identifier.strip() != '':
        return True

    # Remove when all staff changes made.
    if jwt.validate_roles([STAFF_ROLE]):
        return True


#        template_url = current_app.config.get('AUTH_SVC_URL')
#        auth_url = template_url.format(**vars())

#        token = jwt.get_token_auth_header()
#        headers = {'Authorization': 'Bearer ' + token}
#        try:
#            http = Session()
#            retries = Retry(total=5,
#                            backoff_factor=0.1,
#                            status_forcelist=[500, 502, 503, 504])
#            http.mount('http://', HTTPAdapter(max_retries=retries))
#            rv = http.get(url=auth_url, headers=headers)

#           if rv.status_code != HTTPStatus.OK \
#                    or not rv.json().get('roles'):
#                return False

#            if all(elem.lower() in rv.json().get('roles') for elem in action):
#                return True

#        except (exceptions.ConnectionError,  # pylint: disable=broad-except
#                exceptions.Timeout,
#                ValueError,
#                Exception) as err:
#            current_app.logger.error(f'template_url {template_url}, svc:{auth_url}')
#            current_app.logger.error(f'Authorization connection failure for {identifier}, using svc:{auth_url}', err)
#            return False

    return False
Example #5
0
def has_roles(jwt: JwtManager, roles: List[str]) -> bool:
    """Assert the users JWT has the required role(s).

    Assumes the JWT is already validated.
    """
    if jwt.validate_roles(roles):
        return True
    return False
Example #6
0
File: authz.py Project: bcgov/fwben
def authorized(identifier: str, jwt: JwtManager) -> bool:
    """Assert that the user is authorized to create filings against the business identifier."""
    # if they are registry staff, they are always authorized
    if jwt.validate_roles([STAFF_ROLE]):
        return True

    if jwt.validate_roles([COLIN_SVC_ROLE]):
        return True

    token = g.jwt_oidc_token_info
    username = token.get('username', None)

    if username and jwt.validate_roles(
        [BASIC_USER]) and identifier.upper() == username.upper():
        return True

    return False
Example #7
0
def is_staff(jwt: JwtManager) -> bool:  # pylint: disable=too-many-return-statements
    """Return True if the user has the BC Registries staff role."""
    if not jwt:
        return False
    if jwt.validate_roles([STAFF_ROLE]):
        return True

    return False
Example #8
0
def authorized_token(  # pylint: disable=too-many-return-statements
        identifier: str, jwt: JwtManager, action: List[str]) -> bool:
    """Assert that the user is authorized to submit API requests for a particular action."""
    if not action or not identifier or not jwt:
        return False

    # All users including staff must have the PPR role.
    if not jwt.validate_roles([PPR_ROLE]):
        return False

    if jwt.has_one_of_roles([BASIC_USER, PRO_DATA_USER]):

        template_url = current_app.config.get('AUTH_SVC_URL')
        auth_url = template_url.format(**vars())

        token = jwt.get_token_auth_header()
        headers = {'Authorization': 'Bearer ' + token}
        try:
            http = Session()
            retries = Retry(total=5,
                            backoff_factor=0.1,
                            status_forcelist=[500, 502, 503, 504])
            http.mount('http://', HTTPAdapter(max_retries=retries))
            rv = http.get(url=auth_url, headers=headers)

            if rv.status_code != HTTPStatus.OK \
                    or not rv.json().get('roles'):
                return False

            if all(elem.lower() in rv.json().get('roles') for elem in action):
                return True

        except (
                exceptions.ConnectionError,  # pylint: disable=broad-except
                exceptions.Timeout,
                ValueError,
                Exception) as err:
            current_app.logger.error(
                f'template_url {template_url}, svc:{auth_url}')
            current_app.logger.error(
                f'Authorization connection failure for {identifier}, using svc:{auth_url}',
                err)
            return False

    return False
Example #9
0
def check_auth(business_identifier: str, jwt: JwtManager, **kwargs):
    """Authorize the user for the business entity."""
    bearer_token = jwt.get_token_auth_header() if jwt else None
    auth_url = current_app.config.get(
        'AUTH_API_ENDPOINT') + f'entities/{business_identifier}/authorizations'
    auth_response = RestService.get(auth_url, bearer_token,
                                    AuthHeaderType.BEARER, ContentType.JSON)

    is_authorized: bool = False
    if auth_response:
        roles: list = auth_response.json().get('roles', [])
        if kwargs.get('one_of_roles', None):
            is_authorized = list(set(kwargs.get('one_of_roles'))
                                 & set(roles)) != []
        if kwargs.get('contains_role', None):
            is_authorized = kwargs.get('contains_role') in roles

    if not is_authorized:
        abort(403)
Example #10
0
This module is the API for the Names Examination system

TODO: Fill in a larger description once the API is defined for V1
"""
import config
from namex.utils.logging import setup_logging
setup_logging() ## important to do this first

import os

from .VERSION import __version__
from flask import Flask
from namex.utils.run_version import get_run_version
from flask_jwt_oidc import JwtManager

jwt = JwtManager()

from namex.services.nro import NROServices
nro = NROServices()

from namex.models import db, ma
from namex.resources import api
from namex import models

run_version = get_run_version()


def create_app(run_mode=os.getenv('FLASK_ENV', 'production')):

    app = Flask(__name__)
    app.config.from_object(config.CONFIGURATION[run_mode])
Example #11
0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Bring in the common JWT Manager."""
from functools import wraps
from http import HTTPStatus

from flask import g, request
from flask_jwt_oidc import JwtManager
from jose import jwt as josejwt
from request_api.utils.enums import MinistryTeamWithKeycloackGroup, ProcessingTeamWithKeycloackGroup, IAOTeamWithKeycloackGroup
jwt = (
    JwtManager()
)  # pylint: disable=invalid-name; lower case name as used by convention in most Flask apps


class Auth:
    """Extending JwtManager to include additional functionalities."""

    @classmethod
    def require(cls, f):
        """Validate the Bearer Token."""

        @jwt.requires_auth
        @wraps(f)
        def decorated(*args, **kwargs):
            g.authorization_header = request.headers.get("Authorization", None)
            g.token_info = g.jwt_oidc_token_info
Example #12
0
    def _create_invoice(business: Business,
                        filing: Filing,
                        user_jwt: JwtManager) \
            -> Tuple[int, dict, int]:
        """Create the invoice for the filing submission.

        Returns: {
            int: the paymentToken (id), or None
            dict: a dict of errors, or None
            int: the HTTPStatus error code, or None
        }
        """
        payment_svc_url = current_app.config.get('PAYMENT_SVC_URL')

        filing_types = []
        for k in filing.filing_json['filing'].keys():
            if Filing.FILINGS.get(k, None):
                filing_types.append(
                    {'filing_type_code': Filing.FILINGS[k].get('code')})

        mailing_address = business.mailing_address.one_or_none()

        payload = {
            'payment_info': {
                'method_of_payment': 'CC'
            },
            'business_info': {
                'business_identifier': f'{business.identifier}',
                'corp_type': f'{business.identifier[:-7]}',
                'business_name': f'{business.legal_name}',
                'contact_info': {
                    'city': mailing_address.city,
                    'postal_code': mailing_address.postal_code,
                    'province': mailing_address.region,
                    'address_line_1': mailing_address.street,
                    'country': mailing_address.country
                }
            },
            'filing_info': {
                'filing_types': filing_types
            }
        }

        try:
            token = user_jwt.get_token_auth_header()
            headers = {'Authorization': 'Bearer ' + token}
            rv = requests.post(url=payment_svc_url,
                               json=payload,
                               headers=headers,
                               timeout=5.0)
        except (exceptions.ConnectionError, exceptions.Timeout) as err:
            current_app.logger.error(
                f'Payment connection failure for {business.identifier}: filing:{filing.id}',
                err)
            return {
                'message': 'unable to create invoice for payment.'
            }, HTTPStatus.PAYMENT_REQUIRED

        if rv.status_code == HTTPStatus.OK or rv.status_code == HTTPStatus.CREATED:
            pid = rv.json().get('id')
            filing.payment_token = pid
            filing.save()
            return None, None
        return {
            'message': 'unable to create invoice for payment.'
        }, HTTPStatus.PAYMENT_REQUIRED
Example #13
0
"""Bring in the common JWT Manager and helper functions."""

from functools import wraps
from http import HTTPStatus

from flask import g, request
from flask_jwt_oidc import JwtManager

from ..exceptions import BusinessException

jwt = JwtManager()  # pylint: disable=invalid-name; lower case name as used by convention in most Flask apps


class Auth():
    """Extending JwtManager to include additional functionalities."""
    @classmethod
    def require(cls, f):
        """Validate the Bearer Token."""
        @jwt.requires_auth
        @wraps(f)
        def decorated(*args, **kwargs):
            g.authorization_header = request.headers.get('Authorization', None)
            g.token_info = g.jwt_oidc_token_info

            return f(*args, **kwargs)

        return decorated

    @classmethod
    def has_one_of_roles(cls, roles):
        """Check that at least one of the realm roles are in the token.
Example #14
0
    def _create_invoice(business: Business,  # pylint: disable=too-many-locals
                        filing: Filing,
                        filing_types: list,
                        user_jwt: JwtManager,
                        payment_account_id: str = None) \
            -> Tuple[int, dict, int]:
        """Create the invoice for the filing submission.

        Returns: {
            int: the paymentToken (id), or None
            dict: a dict of errors, or None
            int: the HTTPStatus error code, or None
        }
        """
        payment_svc_url = current_app.config.get('PAYMENT_SVC_URL')

        if filing.filing_type == Filing.FILINGS[
                'incorporationApplication'].get('name'):
            mailing_address = Address.create_address(
                filing.json['filing']['incorporationApplication']['offices']
                ['registeredOffice']['mailingAddress'])
            corp_type = filing.json['filing']['business'].get(
                'legalType', Business.LegalTypes.BCOMP.value)

            try:
                business.legal_name = filing.json['filing'][
                    'incorporationApplication']['nameRequest']['legalName']
            except KeyError:
                business.legal_name = business.identifier

        else:
            mailing_address = business.mailing_address.one_or_none()
            corp_type = business.legal_type if business.legal_type else \
                filing.json['filing']['business'].get('legalType')

        payload = {
            'businessInfo': {
                'businessIdentifier': f'{business.identifier}',
                'corpType': f'{corp_type}',
                'businessName': f'{business.legal_name}',
                'contactInfo': {
                    'city': mailing_address.city,
                    'postalCode': mailing_address.postal_code,
                    'province': mailing_address.region,
                    'addressLine1': mailing_address.street,
                    'country': mailing_address.country
                }
            },
            'filingInfo': {
                'filingTypes': filing_types
            }
        }

        folio_number = filing.json['filing']['header'].get('folioNumber', None)
        if folio_number:
            payload['filingInfo']['folioNumber'] = folio_number

        if user_jwt.validate_roles([STAFF_ROLE]) or \
                user_jwt.validate_roles([SYSTEM_ROLE]):
            account_info = {}
            routing_slip_number = get_str(filing.filing_json,
                                          'filing/header/routingSlipNumber')
            if routing_slip_number:
                account_info['routingSlip'] = routing_slip_number
            bcol_account_number = get_str(filing.filing_json,
                                          'filing/header/bcolAccountNumber')
            if bcol_account_number:
                account_info['bcolAccountNumber'] = bcol_account_number
            dat_number = get_str(filing.filing_json, 'filing/header/datNumber')
            if dat_number:
                account_info['datNumber'] = dat_number

            if account_info:
                payload['accountInfo'] = account_info
        try:
            token = user_jwt.get_token_auth_header()
            headers = {
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            }
            rv = requests.post(url=payment_svc_url,
                               json=payload,
                               headers=headers,
                               timeout=20.0)
        except (exceptions.ConnectionError, exceptions.Timeout) as err:
            current_app.logger.error(
                f'Payment connection failure for {business.identifier}: filing:{filing.id}',
                err)
            return {
                'message': 'unable to create invoice for payment.'
            }, HTTPStatus.PAYMENT_REQUIRED

        if rv.status_code in (HTTPStatus.OK, HTTPStatus.CREATED):
            pid = rv.json().get('id')
            filing.payment_token = pid
            filing.payment_status_code = rv.json().get('statusCode', '')
            filing.payment_account = payment_account_id
            filing.save()
            return {
                'isPaymentActionRequired':
                rv.json().get('isPaymentActionRequired', False)
            }, HTTPStatus.CREATED

        if rv.status_code == HTTPStatus.BAD_REQUEST:
            # Set payment error type used to retrieve error messages from pay-api
            error_type = rv.json().get('type')
            filing.payment_status_code = error_type
            filing.save()

            return {
                'payment_error_type': error_type,
                'message': rv.json().get('detail')
            }, HTTPStatus.PAYMENT_REQUIRED

        return {
            'message': 'unable to create invoice for payment.'
        }, HTTPStatus.PAYMENT_REQUIRED
Example #15
0
    def create_receipt(payment_identifier: str,
                       invoice_identifier: str,
                       filing_data: Tuple[Dict[str, Any]],
                       jwt: JwtManager = None,
                       skip_auth_check: bool = False):
        """Create receipt."""
        current_app.logger.debug('<create receipt initiated',
                                 payment_identifier, invoice_identifier)
        bearer_token = jwt.get_token_auth_header() if jwt else None
        receipt_dict = {
            'templateVars': {
                'lineItems': [],
            },
            'templateName': 'payment_receipt_coops',
            'reportName': 'payment_receipt_coops'
        }
        template_vars = receipt_dict['templateVars']
        template_vars['coopsName'] = filing_data.get('corpName')
        template_vars['filingDateTime'] = filing_data.get('filingDateTime')
        # inovice number not mandatory ;since only one invoice exist for a payment now
        if not invoice_identifier:
            invoice_data = Invoice.find_by_payment_identifier(
                payment_identifier, jwt=jwt,
                skip_auth_check=skip_auth_check).asdict()
        else:
            invoice_data = Invoice.find_by_id(
                invoice_identifier,
                payment_identifier,
                jwt=jwt,
                skip_auth_check=skip_auth_check).asdict()

        template_vars['incorporationNumber'] = invoice_data['created_by']
        template_vars['paymentInvoiceNumber'] = invoice_data['invoice_number']
        if 'receipts' not in invoice_data:
            raise BusinessException(Error.PAY999)

        template_vars['receiptNumber'] = invoice_data['receipts'][0][
            'receipt_number']
        for line_item in invoice_data['line_items']:
            template_vars['lineItems'].append({
                'description':
                line_item['description'],
                'filingFees':
                '{:.2f}'.format(line_item['total'])
            })

        template_vars['lineItems'].append({
            'description':
            'Total',
            'filingFees':
            '{:.2f}'.format(invoice_data['total'])
        })
        current_app.logger.debug('<OAuthService invoked from receipt.py',
                                 current_app.config.get('REPORT_API_BASE_URL'))

        pdf_response = OAuthService.post(
            current_app.config.get('REPORT_API_BASE_URL'), bearer_token,
            AuthHeaderType.BEARER, ContentType.JSON, receipt_dict)
        current_app.logger.debug('<OAuthService responded to receipt.py')

        return pdf_response
Example #16
0
from flask import Flask
from flask_jwt_oidc import JwtManager

import requests
import config

from colin_api.models.filing import Filing
from registry_schemas import validate
from utils.logging import setup_logging

setup_logging(
    os.path.join(os.path.abspath(os.path.dirname(__file__)),
                 'logging.conf'))  # important to do this first

# lower case name as used by convention in most Flask apps
jwt = JwtManager()  # pylint: disable=invalid-name

SENTRY_LOGGING = LoggingIntegration(
    event_level=logging.ERROR  # send errors as events
)
SET_EVENTS_MANUALLY = False


def create_app(run_mode=os.getenv('FLASK_ENV', 'production')):
    """Return a configured Flask App using the Factory method."""
    app = Flask(__name__)
    app.config.from_object(config.CONFIGURATION[run_mode])
    # Configure Sentry
    if app.config.get('SENTRY_DSN', None):
        sentry_sdk.init(dsn=app.config.get('SENTRY_DSN'),
                        integrations=[SENTRY_LOGGING])
Example #17
0
# Copyright © 2019 Province of British Columbia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Auth."""
from flask_jwt_oidc import JwtManager

jwtmanager = JwtManager()