registry.py 3.14 KB
Newer Older
1 2 3 4 5
# -*- coding: utf-8 -*-
from __future__ import absolute_import
"""
Registers and loads Processor classes from settings.
"""
ale's avatar
ale committed
6
import base64
7
import logging
8
import warnings
ale's avatar
ale committed
9
import zlib
10

11
from flask import g
12 13 14 15 16
from importlib import import_module

from . import base
from . import exceptions
from . import xml_render
ale's avatar
ale committed
17
from .app import saml_app
18 19


ale's avatar
ale committed
20
class SSOProcessor(base.Processor):
ale's avatar
ale committed
21
    """SAML processor for the Ruby omniauth saml gem."""
22 23 24

    def _validate_request(self):
        super(SSOProcessor, self)._validate_request()
25 26 27
        #url = self._request_params['ACS_URL']
        #if 'blah' not in url:
        #    raise exceptions.CannotHandleAssertion('ACS is not a supported URL')
28

ale's avatar
ale committed
29 30 31
    def _decode_request(self):
        self._request_xml = zlib.decompress(base64.b64decode(self._saml_request), -15)

ale's avatar
ale committed
32 33 34 35 36
    def _determine_audience(self):
        self._audience = self._request_params.get('ISSUER', None)
        if not self._audience:
            super(SSOProcessor, self)._determine_audience()

37
    def _format_assertion(self):
ale's avatar
ale committed
38 39 40
        # Add attributes that gitlab needs (?).
        self._assertion_params['ATTRIBUTES'] = {
            'name': self._subject,
41
            'email': g.user_email,
ale's avatar
ale committed
42
        }
43 44 45 46
        self._assertion_xml = xml_render.get_assertion_salesforce_xml(self._assertion_params, signed=True)


def get_processor(name, config):
47
    return SSOProcessor(config, name)
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84


def old_get_processor(name, config):
    """
    Get an instance of the processor with config.
    """
    dottedpath = config['processor']

    try:
        dot = dottedpath.rindex('.')
    except ValueError:
        raise exceptions.ImproperlyConfigured('%s isn\'t a processors module' % dottedpath)
    sp_module, sp_classname = dottedpath[:dot], dottedpath[dot+1:]
    try:
        mod = import_module(sp_module)
    except ImportError as exc:
        raise exceptions.ImproperlyConfigured(
            'Error importing processors {0}: "{1}"'.format(sp_module, exc))
    try:
        sp_class = getattr(mod, sp_classname)
    except AttributeError:
        raise exceptions.ImproperlyConfigured(
            'processors module "{0}" does not define a "{1}" class'.format(
                sp_module, sp_classname))

    try:
        instance = sp_class(name=name, config=config)
    except TypeError:
        warnings.warn(
            "the new version of the Processor class expects a 'name' argument "
            "to be passed in. The use of old processors is deprecated and will "
            "be removed in the future.", DeprecationWarning)
        instance = sp_class(config=config)
        instance.name = name
    return instance


85
def find_processor():
86
    """
87
    Returns the Processor instance that is willing to handle the current request.
88
    """
ale's avatar
ale committed
89
    for name, sp_config in saml_app.config['SAML2IDP_REMOTES'].items():
90 91
        proc = get_processor(name, sp_config)
        try:
92
            if proc.can_handle():
93 94 95
                return proc
        except exceptions.CannotHandleAssertion as exc:
            # Log these, but keep looking.
96
            logging.debug('%s %s' % (proc, exc))
97 98 99

    raise exceptions.CannotHandleAssertion(
        'None of the processors in SAML2IDP_REMOTES could handle this request.')