Exemplo n.º 1
0
    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.server.config.entityid
                        },
                    },
                    {
                        'status_code': error_info[0],
                        'status_message': error_info[1]
                    }
                ).to_xml()
                self.app.logger.debug(
                    'Error response: \n{}'.format(response)
                )
                key_file = self.server.config.key_file
                cert_file = self.server.config.cert_file

                pkey = open(key_file, 'rb').read()
                cert = open(cert_file, 'rb').read()
                response = sign_http_post(response, pkey, cert)
                rendered_template = render_template(
                    'form_http_post.html',
                    **{
                        'action': destination,
                        'relay_state': relay_state,
                        'message': response,
                        'message_type': 'SAMLResponse'
                    }
                )
                return rendered_template, 200
        return render_template('403.html'), 403
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
    def _build_failed_response(self, authn_request, destination, key,
                               relay_state):
        """
        Build and return a failed response
        """

        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()
        self.app.logger.debug('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': response,
                'message_type': 'SAMLResponse'
            })
        return rendered_template
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    def login(self):
        """
        Login endpoint (verify user credentials)
        """

        key = from_session('request_key')
        relay_state = from_session('relay_state')
        self.app.logger.debug('Request key: {}'.format(key))
        if key and key in self.ticket:
            authn_request = self.ticket[key]
            sp_id = authn_request.issuer.text
            destination = self.get_destination(authn_request, sp_id)
            authn_context = authn_request.requested_authn_context
            spid_level = authn_context.authn_context_class_ref.text
            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
                    }
                )
                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
                        identity = user['attrs'].copy()
                        self.app.logger.debug(
                            'Unfiltered data: {}'.format(identity)
                        )
                        atcs_idx = getattr(authn_request, 'attribute_consuming_service_index', None)
                        self.app.logger.debug(
                            'AttributeConsumingServiceIndex: {}'.format(
                                atcs_idx
                            )
                        )
                        if atcs_idx:
                            # TODO: Remove this pysaml2 dependency
                            attrs = self.server.wants(sp_id, atcs_idx)
                            required = [el.get('name') for el in attrs.get('required')]
                            optional = [el.get('name') for el in attrs.get('optional')]
                        else:
                            required = []
                            optional = []

                        for k, v in identity.items():
                            if k in self._spid_main_fields:
                                _type = self._spid_attributes['primary'][k]
                            else:
                                _type = self._spid_attributes['secondary'][k]
                            identity[k] = (_type, v)

                        _identity = {}
                        for _key in required:
                            _identity[_key] = identity[_key]
                        for _key in optional:
                            _identity[_key] = identity[_key]

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

                        response_xmlstr = create_response(
                            {
                                'response': {
                                    'attrs': {
                                        'in_response_to': authn_request.id,
                                        'destination': destination
                                    }
                                },
                                'issuer': {
                                    'attrs': {
                                        'name_qualifier': self._config.entity_id,
                                    },
                                    'text': self._config.entity_id
                                },
                                'name_id': {
                                    'attrs': {
                                        'name_qualifier': self._config.entity_id,
                                    }
                                },

                                'subject_confirmation_data': {
                                    'attrs': {
                                        'recipient': destination
                                    }
                                },
                                'audience': {
                                    'text': sp_id
                                },
                                'authn_context_class_ref': {
                                    'text': spid_level
                                }
                            },
                            {
                                'status_code': STATUS_SUCCESS
                            },
                            _identity.copy()
                        ).to_xml()
                        response = sign_http_post(
                            response_xmlstr,
                            self._config.idp_key,
                            self._config.idp_certificate,
                        )
                        self.app.logger.debug(
                            'Response: \n{}'.format(response)
                        )
                        rendered_template = render_template(
                            'form_http_post.html',
                            **{
                                'action': destination,
                                'relay_state': relay_state,
                                'message': response,
                                '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_xmlstr.decode('ascii')
                                ).splitlines(),
                                'attrs': _identity.keys(),
                                'action': '/continue-response',
                                'request_key': key
                            }
                        )
                        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()
                self.app.logger.debug(
                    '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': response,
                        'message_type': 'SAMLResponse'
                    }
                )
                return rendered_template, 200
        return render_template('403.html'), 403