Пример #1
0
class ServiceProviderMetadataDbLoader(object):
    """Loads metadata from the configured database"""
    def __init__(self, conf):
        self._provider = DatabaseSPProvider(conf)

    def get(self, entity_id):
        metadata = self._provider.get(entity_id)
        if metadata is None:
            raise MetadataNotFoundError(entity_id)
        return ServiceProviderMetadata(metadata)

    def all(self):
        return self._provider.all().keys()
Пример #2
0
    def _setup_managers(self):
        if not self._config.database_admin_interface:
            return

        self.app.config['FLASK_ADMIN_SWATCH'] = 'cerulean'
        self.admin = Admin(
            self.app,
            name='Ambiente di test SPID - Interfaccia di amministrazione',
            template_mode='bootstrap3')
        self.user_manager.register_admin(self.admin)
        if 'db' in self._config.metadata:
            self.sp_metadata_manager = DatabaseSPProvider(
                self._config.metadata['db'])
            self.sp_metadata_manager.register_admin(self.admin)
Пример #3
0
class ServiceProviderMetadataDbLoader:
    """Loads metadata from the configured database"""
    def __init__(self, conf):
        self._provider = DatabaseSPProvider(conf)

    def load(self, entity_id):
        metadata = self._provider.get(entity_id)
        if metadata is None:
            raise MetadataNotFoundError(entity_id)
        return ServiceProviderMetadata(metadata, self, 'db')

    def load_all(self):
        """
        Returns a dict containing all 'db' ServerProviderMetadata loaded,
        indexed by entityId."""
        return {
            entity_id: ServiceProviderMetadata(xml, self, 'db')
            for (entity_id, xml) in self._provider.all().items()
        }
Пример #4
0
class IdpServer:

    ticket = {}
    responses = {}
    challenges = {}
    _binding_mapping = {
        'http-redirect': BINDING_HTTP_REDIRECT,
        'http-post': BINDING_HTTP_POST
    }
    _endpoint_types = ['single_sign_on_service', 'single_logout_service']
    _spid_levels = SPID_LEVELS
    _spid_attributes = SPID_ATTRIBUTES.copy()
    # digitalAddress => PEC
    challenges_timeout = CHALLENGES_TIMEOUT

    def __init__(self, app, conf=None, registry=None, *args, **kwargs):
        """
        :param app: Flask instance
        :param conf: config.Config instance
        :param args:
        :param kwargs:
        """
        # bind Flask app
        self.app = app

        # setup
        self._config = conf or config.params

        app.context_processor(
            # Inject this dict in every template by default.
            lambda: dict(database_ui_enabled=self._config.
                         database_admin_interface))
        app.jinja_env.add_extension('jinja2.ext.loopcontrols')

        self._registry = registry or spmetadata.registry
        self.app.secret_key = 'sosecret'
        self._prepare_server()
        self.sp_metadata_manager = None
        self.user_manager = UserProvider.factory(self._config)
        self._setup_managers()

    def _setup_managers(self):
        if not self._config.database_admin_interface:
            return

        self.app.config['FLASK_ADMIN_SWATCH'] = 'cerulean'
        self.admin = Admin(
            self.app,
            name='Ambiente di test SPID - Interfaccia di amministrazione',
            template_mode='bootstrap3')
        self.user_manager.register_admin(self.admin)
        if 'db' in self._config.metadata:
            self.sp_metadata_manager = DatabaseSPProvider(
                self._config.metadata['db'])
            self.sp_metadata_manager.register_admin(self.admin)

    @property
    def _mode(self):
        return 'https' if self._config.https else 'http'

    def _setup_app_routes(self):
        """
        Setup Flask routes
        """
        # Setup SSO and SLO endpoints
        endpoints = self._config.endpoints
        if endpoints:
            for ep_type in self._endpoint_types:
                _url = endpoints.get(ep_type)
                if _url:
                    for _binding in list(self._binding_mapping.keys()):
                        self.app.add_url_rule(_url,
                                              ep_type,
                                              getattr(self, ep_type),
                                              methods=['GET', 'POST'])
        self.app.add_url_rule('/', 'index', self.index, methods=['GET'])
        self.app.add_url_rule('/login',
                              'login',
                              self.login,
                              methods=['POST', 'GET'])
        # Endpoint for user add action
        self.app.add_url_rule('/users',
                              'users',
                              self.users,
                              methods=['GET', 'POST'])
        self.app.add_url_rule('/continue-response',
                              'continue_response',
                              self.continue_response,
                              methods=['POST'])
        self.app.add_url_rule('/metadata',
                              'metadata',
                              self.metadata,
                              methods=['POST', 'GET'])

    def _prepare_server(self):
        """
        Setup server
        """
        self._setup_app_routes()

    def _verify_spid(self, level, verify=False, **kwargs):
        """
        :param level: integer, SPID level
        :param verify: boolean, if True verify
            spid extra challenge (otp etc.), if False prepare the challenge
        :param kwargs: dictionary, extra arguments
        """
        level = self._spid_levels.index(level)
        logger.info('spid level {} - verifica ({})'.format(level, verify))
        if verify:
            # Verify the challenge
            if level == 2:
                # spid level 2
                otp = kwargs.get('data').get('otp')
                key = kwargs.get('key')
                if key and key not in self.challenges or not otp:
                    return False
                total_seconds = (datetime.now() -
                                 self.challenges[key][1]).total_seconds()
                # Check that opt value is equal and not expired
                _is_expired = total_seconds > self.challenges_timeout
                if self.challenges[key][0] != otp or _is_expired:
                    del self.challenges[key]
                    return False
            return True
        else:
            # Prepare the challenge
            if level == 2:
                # spid level 2
                # very simple otp implementation,
                # while opt is a random 6 digits string
                # with a lifetime setup in the server instance
                key = kwargs.get('key')
                otp = ''.join(random.choice(string.digits) for _ in range(6))
                self.challenges[key] = [otp, datetime.now()]
                extra_challenge = '<span>Otp ({})</span>'\
                    '<input type="text" name="otp" />'.format(
                        otp
                    )
            else:
                extra_challenge = ''
            return extra_challenge

    def unpack_args(self, elems):
        """
        Unpack arguments from request
        """
        return dict([(k, v) for k, v in list(elems.items())])

    def _raise_error(self, msg, extra=None):
        """
        Raise some error using 'abort' function from Flask

        :param msg: string for error type
        :param extra: optional string for error details
        """

        abort(
            Response(
                render_template("error.html", **{
                    'msg': msg,
                    'extra': extra or ""
                }), 200))

    def _store_request(self, authnreq):
        """
        Store authnrequest in a dictionary

        :param authnreq: authentication request string
        """
        logger.info('store_request: {}'.format(authnreq))
        # FIXME: improve this
        from lxml.etree import tostring
        key = sha1(tostring(authnreq._xml_doc)).hexdigest()
        # store the AuthnRequest
        self.ticket[key] = authnreq
        return key

    def _handle_errors(self, xmlstr, errors=None):
        xmlstr = xmlstr if isinstance(xmlstr, str) else xmlstr.decode()
        rendered_error_response = render_template(
            'spid_error.html', **{
                'lines': xmlstr.splitlines(),
                'errors': errors
            })
        return rendered_error_response

    def _parse_message(self, action):
        """
        Parse an AuthnRequest or a LogoutRequest

        :param action: type of request
        """
        method = request.method

        if method == 'GET':
            return self._handle_http_redirect(action)
        elif method == 'POST':
            return self._handle_http_post(action)
        else:
            self._raise_error('I metodi consentiti sono'
                              ' GET (Http-Redirect) o POST (Http-Post)')

    def _handle_http_redirect(self, action):
        # FIXME: replace the following code with a call to a function
        # in the parser.py module after metadata refactoring.
        # The IdpServer class should not
        # be responsible of request parsing, or know anything
        # about request parsing *at all*.
        saml_msg = self.unpack_args(request.args)
        request_data = HTTPRedirectRequestParser(saml_msg).parse()
        deserializer = get_http_redirect_request_deserializer(
            request_data, action)
        saml_tree = deserializer.deserialize()
        certs = self._get_certificates_by_issuer(saml_tree.issuer.text)
        if not certs:
            raise NoCertificateError
        for cert in certs:
            HTTPRedirectSignatureVerifier(cert, request_data).verify()
        return SPIDRequest(request_data, saml_tree)

    def _handle_http_post(self, action):
        # FIXME: replace the following code with a call to a function
        # in the parser.py module after metadata refactoring.
        # The IdpServer class should not
        # be responsible of request parsing, or know anything
        # about request parsing *at all*.
        saml_msg = self.unpack_args(request.form)
        request_data = HTTPPostRequestParser(saml_msg).parse()
        deserializer = get_http_post_request_deserializer(request_data, action)
        saml_tree = deserializer.deserialize()
        certs = self._get_certificates_by_issuer(saml_tree.issuer.text)
        if not certs:
            raise NoCertificateError
        for cert in certs:
            HTTPPostSignatureVerifier(cert, request_data).verify()
        return SPIDRequest(request_data, saml_tree)

    def _get_certificates_by_issuer(self, issuer):
        try:
            return self._registry.get(issuer).certs()
        except KeyError:
            self._raise_error(
                'entity ID {} non registrato, impossibile ricavare'
                ' un certificato valido.'.format(issuer))
        except NoCertificateError:
            self._raise_error(
                'Errore, il metadata associato al Service provider "{}"'
                ' non è provvisto di certificati validi'.format(issuer))

    def single_sign_on_service(self):
        """
        Process Http-Redirect or Http-POST request

        :param request: Flask request object
        """
        try:
            spid_request = self._parse_message(action='login')
            logger.info('AuthnRequest: \n{}'.format(
                spid_request.data.saml_request))
            # Perform login
            key = self._store_request(spid_request.saml_tree)
            session['request_key'] = key
            session['relay_state'] = spid_request.data.relay_state or ''
            return redirect(url_for('login'))
        except RequestParserError as err:
            self._raise_error(err.args[0])
        except SignatureVerificationError as err:
            self._raise_error(err.args[0])
        except UnknownEntityIDError as err:
            self._raise_error(err.args[0])
        except DeserializationError as err:
            return self._handle_errors(err.initial_data, err.details)
        except MetadataLoadError as err:
            self._raise_error('Metadata non disponibile: {}'.format(
                err.args[0]))

    @property
    def _spid_main_fields(self):
        """
        Returns a list of spid main attributes
        """
        return list(self._spid_attributes['primary'].keys())

    @property
    def _spid_secondary_fields(self):
        """
        Returns a list of spid secondary attributes
        """
        return list(self._spid_attributes['secondary'].keys())

    @property
    def _all_attributes(self):
        _dct = self._spid_attributes['primary'].copy()
        _dct.update(self._spid_attributes['secondary'])
        return _dct

    def users(self):
        """
        Add user endpoint
        """
        spid_main_fields = self._spid_main_fields
        spid_secondary_fields = self._spid_secondary_fields
        can_add_user = self._config.can_add_user
        rendered_form = render_template(
            "users.html", **{
                'action': '/users',
                'primary_attributes': spid_main_fields,
                'secondary_attributes': spid_secondary_fields,
                'users': self.user_manager.all(),
                'sp_list': self._registry.all(),
                'can_add_user': can_add_user
            })
        if request.method == 'GET':
            return rendered_form, 200
        elif request.method == 'POST':
            if not can_add_user:
                return render_template('403.html'), 403
            username = request.form.get('username')
            password = request.form.get('password')
            sp = request.form.get('service_provider')
            if not sp:
                sp = None
            if not username or not password:
                abort(400)
            extra = {}
            for spid_field in spid_main_fields:
                spid_value = request.form.get(spid_field)
                if spid_value:
                    extra[spid_field] = spid_value
            for spid_field in spid_secondary_fields:
                spid_value = request.form.get(spid_field)
                if spid_value:
                    extra[spid_field] = spid_value
            if 'fiscalNumber' in extra and not extra[
                    'fiscalNumber'].startswith('TINIT-'):
                extra['fiscalNumber'] = 'TINIT-{}'.format(
                    extra['fiscalNumber'])
            self.user_manager.add(username, password, sp, extra.copy())
        return redirect(url_for('users'))

    def index(self):
        rendered_form = render_template(
            "home.html", **{
                'sp_list': [{
                    "entityID": sp
                } for sp in self._registry.all()],
            })
        return rendered_form, 200

    def get_destination(self, req, sp_id):
        destination = None
        acs_index = getattr(req, 'assertion_consumer_service_index', None)
        protocol_binding = getattr(req, 'protocol_binding', None)
        if acs_index is not None:
            acss = self._registry.get(sp_id).assertion_consumer_service(
                index=acs_index)
            if acss:
                destination = acss[0].get('Location')
            logger.debug('AssertionConsumerServiceIndex Location: {}'.format(
                destination))
        if destination is None:
            destination = getattr(req, 'assertion_consumer_service_url', None)
            if destination is not None and protocol_binding is not None:
                logger.debug(
                    'AssertionConsumerServiceURL: {}'.format(destination))
        return destination

    def _attribute_type(self, attribute_name):
        if attribute_name in self._spid_main_fields:
            _type = self._spid_attributes['primary'][attribute_name]
        else:
            _type = self._spid_attributes['secondary'][attribute_name]
        return _type

    def _filter_attributes(self, identity, required, optional):
        _identity = {}
        sequence = [required, optional]
        for seq in sequence:
            for _key in seq:
                try:
                    _identity[_key] = identity[_key]
                except KeyError:
                    _type = self._attribute_type(_key)
                    if _type == 'date':
                        _default = '1970-01-01'
                    else:
                        _default = ''
                    _identity[_key] = (_type, _default)
        return _identity

    def login(self):
        """
        Login endpoint (verify user credentials)
        """

        key = from_session('request_key')
        relay_state = from_session('relay_state')
        logger.info('Request key: {}'.format(key))
        if key and key in self.ticket:
            authn_request = self.ticket[key]
            sp_id = authn_request.issuer.text.strip()
            destination = self.get_destination(authn_request, sp_id)
            authn_context = authn_request.requested_authn_context
            spid_level = authn_context.authn_context_class_ref.text.strip()
            if request.method == 'GET':
                # inject extra data in form login based on spid level
                extra_challenge = self._verify_spid(level=spid_level,
                                                    **{'key': key})
                rendered_form = render_template(
                    'login.html', **{
                        'action':
                        url_for('login'),
                        'request_key':
                        key,
                        'relay_state':
                        relay_state,
                        'extra_challenge':
                        extra_challenge,
                        'show_response_options':
                        self._config.show_response_options,
                    })
                return rendered_form, 200

            if 'confirm' in request.form:
                # verify optional challenge based on spid level
                verified = self._verify_spid(level=spid_level,
                                             verify=True,
                                             **{
                                                 'key': key,
                                                 'data': request.form
                                             })
                if verified:
                    # verify user credentials
                    user_id, user = self.user_manager.get(
                        request.form['username'], request.form['password'],
                        sp_id)
                    if user_id is not None:
                        # setup response
                        _audience = sp_id
                        _destination = destination
                        _recipient_subj = destination
                        _issuer_text = self._config.entity_id
                        _pkey = self._config.idp_key
                        _cert = self._config.idp_certificate
                        # setup custom response elements (if any)
                        wrong_destination = request.form.get(
                            'wrong_destination', False)
                        if wrong_destination:
                            _destination = '{}wrong/bad/'.format(_destination)
                        wrong_relay_state = request.form.get(
                            'wrong_relay_state', False)
                        if wrong_relay_state:
                            relay_state = '{}wrong'.format(relay_state)
                        wrong_audience = request.form.get(
                            'wrong_audience', False)
                        if wrong_audience:
                            _audience = '{}/wrong/bad/'.format(_audience)
                        wrong_recipient_subj = request.form.get(
                            'wrong_recipient_subj', False)
                        if wrong_recipient_subj:
                            _recipient_subj = 'badrecipient'
                        wrong_issuer = request.form.get('wrong_issuer', False)
                        if wrong_issuer:
                            _issuer_text = 'wrongissuer123'
                        has_assertion = not request.form.get(
                            'no_assertion', False)
                        bad_status_code = request.form.get(
                            'bad_status_code', False)
                        wrong_conditions_notbefore = request.form.get(
                            'wrong_conditions_notbefore')
                        wrong_conditions_notonorafter = request.form.get(
                            'wrong_conditions_notonorafter')
                        wrong_subj_notonorafter = request.form.get(
                            'wrong_subj_notonorafter')
                        wrong_subj_inresponseto = request.form.get(
                            'wrong_subj_inresponseto')
                        custom_spid_level = request.form.get('spid_level')
                        if custom_spid_level:
                            spid_level = self._spid_levels[int(
                                custom_spid_level)]
                        sign_assertion = request.form.get(
                            'sign_assertion', False)
                        sign_message = request.form.get('sign_message', False)

                        custom_private_key = request.form.get('private_key')
                        if custom_private_key:
                            _pkey = bytes(custom_private_key.encode('utf-8'))
                        custom_certificate = request.form.get('certificate')
                        if custom_certificate:
                            _pkey = bytes(custom_certificate.encode('utf-8'))

                        _conditions = {'conditions': {'attrs': {}}}

                        _subj_extra = {}
                        if wrong_subj_inresponseto:
                            _subj_extra[
                                'in_response_to'] = 'inresponsetowron134'

                        if wrong_conditions_notbefore:
                            _conditions['conditions']['attrs'][
                                'not_before'] = wrong_conditions_notbefore + ':00Z'
                        if wrong_conditions_notonorafter:
                            _conditions['conditions']['attrs'][
                                'not_on_or_after'] = wrong_conditions_notonorafter + ':00Z'
                        if wrong_subj_notonorafter:
                            _subj_extra[
                                'not_on_or_after'] = wrong_subj_notonorafter + ':00Z'

                        _status_code = STATUS_AUTHN_FAILED if bad_status_code else STATUS_SUCCESS

                        identity = user['attrs'].copy()
                        logger.debug('Unfiltered data: {}'.format(identity))
                        atcs_idx = getattr(
                            authn_request, 'attribute_consuming_service_index',
                            None)
                        logger.info(
                            'AttributeConsumingServiceIndex: {}'.format(
                                atcs_idx))
                        sp_metadata = self._registry.get(sp_id)
                        required = []
                        optional = []
                        if atcs_idx and sp_metadata:
                            attrs = sp_metadata.attributes(atcs_idx)
                            required = [el for el in attrs.get('required')]
                            optional = [el for el in attrs.get('optional')]

                        for attr_name, val in list(identity.items()):
                            _type = self._attribute_type(attr_name)
                            identity[attr_name] = (_type, val)

                        _identity = self._filter_attributes(
                            identity, required, optional)

                        logger.debug('Filtered data: {}'.format(_identity))

                        _response_data = {
                            'response': {
                                'attrs': {
                                    'in_response_to': authn_request.id,
                                    'destination': _destination
                                }
                            },
                            'issuer': {
                                'attrs': {
                                    'name_qualifier': self._config.entity_id,
                                },
                                'text': _issuer_text
                            },
                            'name_id': {
                                'attrs': {
                                    'name_qualifier': self._config.entity_id,
                                }
                            },
                            'subject_confirmation_data': {
                                'attrs': {
                                    'recipient': _recipient_subj
                                }
                            },
                            'audience': {
                                'text': _audience
                            },
                            'authn_context_class_ref': {
                                'text': spid_level
                            }
                        }

                        _response_data.update(_conditions)
                        if _subj_extra:
                            _response_data['subject_confirmation_data'][
                                'attrs'].update(_subj_extra)

                        response = create_response(
                            _response_data, {'status_code': _status_code},
                            _identity.copy(),
                            has_assertion=has_assertion)
                        response = sign_http_post(response.to_xml(),
                                                  _pkey,
                                                  _cert,
                                                  message=sign_message,
                                                  assertion=sign_assertion)
                        logger.info('Response: \n{}'.format(response))
                        rendered_template = render_template(
                            'form_http_post.html', **{
                                'action':
                                destination,
                                'relay_state':
                                relay_state,
                                'message':
                                base64.b64encode(response).decode('ascii'),
                                'message_type':
                                'SAMLResponse'
                            })
                        self.responses[key] = rendered_template
                        # Setup confirmation page data
                        rendered_response = render_template(
                            'confirm.html', **{
                                'destination_service':
                                sp_id,
                                'lines':
                                escape(response.decode('utf-8')).splitlines(),
                                'attrs':
                                list(_identity.keys()),
                                'action':
                                '/continue-response',
                                'request_key':
                                key,
                                'show_response_options':
                                self._config.show_response_options,
                            })
                        return rendered_response, 200
            elif 'delete' in request.form:
                error_info = get_spid_error(AUTH_NO_CONSENT)
                response = create_error_response(
                    {
                        'response': {
                            'attrs': {
                                'in_response_to': authn_request.id,
                                'destination': destination
                            }
                        },
                        'issuer': {
                            'attrs': {
                                'name_qualifier': self._config.entity_id,
                            },
                            'text': self._config.entity_id
                        },
                    }, {
                        'status_code': error_info[0],
                        'status_message': error_info[1]
                    }).to_xml()
                logger.info('Error response: \n{}'.format(response))
                response = sign_http_post(
                    response,
                    self._config.idp_key,
                    self._config.idp_certificate,
                )
                del self.ticket[key]
                rendered_template = render_template(
                    'form_http_post.html', **{
                        'action': destination,
                        'relay_state': relay_state,
                        'message': base64.b64encode(response).decode('ascii'),
                        'message_type': 'SAMLResponse'
                    })
                return rendered_template, 200
        return render_template('403.html'), 403

    def continue_response(self):
        key = request.form['request_key']
        relay_state = from_session('relay_state')
        if key and key in self.responses:
            _response = self.responses.pop(key)
            auth_req = self.ticket.pop(key)
            if 'confirm' in request.form:
                return _response, 200
            elif 'delete' in request.form:
                destination = self.get_destination(auth_req,
                                                   auth_req.issuer.text)
                error_info = get_spid_error(AUTH_NO_CONSENT)
                response = create_error_response(
                    {
                        'response': {
                            'attrs': {
                                'in_response_to': auth_req.id,
                                'destination': destination
                            }
                        },
                        'issuer': {
                            'attrs': {
                                'name_qualifier': 'something',
                            },
                            'text': self._config.entity_id
                        },
                    }, {
                        'status_code': error_info[0],
                        'status_message': error_info[1]
                    }).to_xml()
                logger.info('Error response: \n{}'.format(response))
                response = sign_http_post(
                    response,
                    self._config.idp_key,
                    self._config.idp_certificate,
                )
                rendered_template = render_template(
                    'form_http_post.html', **{
                        'action': destination,
                        'relay_state': relay_state,
                        'message': base64.b64encode(response).decode('ascii'),
                        'message_type': 'SAMLResponse'
                    })
                return rendered_template, 200
        return render_template('403.html'), 403

    def _sp_single_logout_service(self, issuer_name):
        _slo = None
        try:
            _slo = self._registry.get(issuer_name).single_logout_services[0]
        except Exception:
            pass
        return _slo

    def single_logout_service(self):
        """
        SLO endpoint
        """
        try:
            spid_request = self._parse_message(action='logout')
            issuer_name = spid_request.saml_tree.issuer.text
            _slo = self._sp_single_logout_service(issuer_name)
            if _slo is None:
                self._raise_error(
                    'Impossibile trovare un servizio di'
                    ' Single Logout per il service provider {}'.format(
                        issuer_name))
            response_binding = _slo.get('Binding')
            logger.info('Response binding: \n{}'.format(response_binding))
            destination = _slo.get('Location')
            response = create_logout_response(
                {
                    'logout_response': {
                        'attrs': {
                            'in_response_to': spid_request.saml_tree.id,
                            'destination': destination
                        }
                    },
                    'issuer': {
                        'attrs': {
                            'name_qualifier': 'something',
                        },
                        'text': self._config.entity_id
                    }
                }, {
                    'status_code': STATUS_SUCCESS
                }).to_xml()
            relay_state = spid_request.data.relay_state or ''
            if response_binding == BINDING_HTTP_POST:
                response = sign_http_post(response,
                                          self._config.idp_key,
                                          self._config.idp_certificate,
                                          message=True,
                                          assertion=False)
                rendered_template = render_template(
                    'form_http_post.html', **{
                        'action': destination,
                        'relay_state': relay_state,
                        'message': base64.b64encode(response).decode('ascii'),
                        'message_type': 'SAMLResponse'
                    })
                return rendered_template, 200
            elif response_binding == BINDING_HTTP_REDIRECT:
                query_string = sign_http_redirect(
                    response,
                    self._config.idp_key,
                    relay_state,
                )
                location = '{}?{}'.format(destination, query_string)
                if location:
                    return redirect(location)
        except RequestParserError as err:
            self._raise_error(err.args[0])
        except SignatureVerificationError as err:
            self._raise_error(err.args[0])
        except UnknownEntityIDError as err:
            self._raise_error(err.args[0])
        except DeserializationError as err:
            return self._handle_errors(err.initial_data, err.details)
        except MetadataLoadError as err:
            self._raise_error(err.args[0])
        abort(400)

    def metadata(self):
        cert_file = self._config.idp_certificate_file_path
        with open(cert_file, 'r') as fp:
            cert = fp.readlines()[1:-1]
            cert = ''.join(cert)
        sso_list = []
        slo_list = []
        sso_list.append(
            Sso(binding=BINDING_HTTP_POST,
                location=self._config.absolute_sso_url))
        sso_list.append(
            Sso(binding=BINDING_HTTP_REDIRECT,
                location=self._config.absolute_sso_url))
        slo_list.append(
            Slo(binding=BINDING_HTTP_POST,
                location=self._config.absolute_slo_url))
        slo_list.append(
            Slo(binding=BINDING_HTTP_REDIRECT,
                location=self._config.absolute_slo_url))
        metadata = create_idp_metadata(
            entity_id=self._config.entity_id,
            want_authn_requests_signed='true',
            keys=[Key(use='signing', value=cert)],
            single_sign_on_services=sso_list,
            single_logout_services=slo_list).to_xml()
        return Response(metadata, mimetype='text/xml')

    @property
    def _wsgiconf(self):
        _cnf = {
            'host': self._config.host,
            'port': self._config.port,
            'debug': self._config.debug,
        }
        if self._config.https:
            key = self._config.https_key_file_path
            cert = self._config.https_certificate_file_path
            _cnf['ssl_context'] = (
                cert,
                key,
            )
        return _cnf

    def start(self):
        """
        Start the server instance
        """
        self.app.run(**self._wsgiconf)
Пример #5
0
 def __init__(self, conf):
     self._provider = DatabaseSPProvider(conf)