Exemplo n.º 1
0
    def test_request_full_signed(self):
        """Test full SAML Request/Response flow, fully signed"""
        http_request = self.factory.get("/")
        http_request.user = get_anonymous_user()

        middleware = SessionMiddleware(dummy_get_response)
        middleware.process_request(http_request)
        http_request.session.save()

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        # To get an assertion we need a parsed request (parsed by provider)
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        # Now create a response and convert it to string (provider)
        response_proc = AssertionProcessor(self.provider, http_request,
                                           parsed_request)
        response = response_proc.build_response()

        # Now parse the response (source)
        http_request.POST = QueryDict(mutable=True)
        http_request.POST["SAMLResponse"] = b64encode(
            response.encode()).decode()

        response_parser = ResponseProcessor(self.source)
        response_parser.parse(http_request)
Exemplo n.º 2
0
    def test_request_id_invalid(self):
        """Test generated AuthNRequest with invalid request ID"""
        http_request = self.factory.get("/")
        http_request.user = get_anonymous_user()

        middleware = SessionMiddleware(dummy_get_response)
        middleware.process_request(http_request)
        http_request.session.save()

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        # change the request ID
        http_request.session[SESSION_REQUEST_ID] = "test"
        http_request.session.save()

        # To get an assertion we need a parsed request (parsed by provider)
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        # Now create a response and convert it to string (provider)
        response_proc = AssertionProcessor(self.provider, http_request,
                                           parsed_request)
        response = response_proc.build_response()

        # Now parse the response (source)
        http_request.POST = QueryDict(mutable=True)
        http_request.POST["SAMLResponse"] = b64encode(
            response.encode()).decode()

        response_parser = ResponseProcessor(self.source)

        with self.assertRaises(MismatchedRequestID):
            response_parser.parse(http_request)
Exemplo n.º 3
0
    def test_request_attributes_invalid(self):
        """Test full SAML Request/Response flow, fully signed"""
        user = create_test_admin_user()
        http_request = get_request("/", user=user)

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        # Create invalid PropertyMapping
        scope = SAMLPropertyMapping.objects.create(name="test",
                                                   saml_name="test",
                                                   expression="q")
        self.provider.property_mappings.add(scope)

        # To get an assertion we need a parsed request (parsed by provider)
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        # Now create a response and convert it to string (provider)
        response_proc = AssertionProcessor(self.provider, http_request,
                                           parsed_request)
        self.assertIn(user.username, response_proc.build_response())

        events = Event.objects.filter(action=EventAction.CONFIGURATION_ERROR, )
        self.assertTrue(events.exists())
        self.assertEqual(
            events.first().context["message"],
            "Failed to evaluate property-mapping: name 'q' is not defined",
        )
Exemplo n.º 4
0
    def test_response_schema(self):
        """Test generated AuthNRequest against Schema"""
        http_request = self.factory.get("/")
        http_request.user = get_anonymous_user()

        middleware = SessionMiddleware(dummy_get_response)
        middleware.process_request(http_request)
        http_request.session.save()

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        # To get an assertion we need a parsed request (parsed by provider)
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        # Now create a response and convert it to string (provider)
        response_proc = AssertionProcessor(self.provider, http_request,
                                           parsed_request)
        response = response_proc.build_response()

        metadata = etree.fromstring(response)  # nosec

        schema = etree.XMLSchema(
            etree.parse("xml/saml-schema-protocol-2.0.xsd"))
        self.assertTrue(schema.validate(metadata))
Exemplo n.º 5
0
 def get(self, request: HttpRequest, source_slug: str) -> HttpResponse:
     """Replies with an XHTML SSO Request."""
     source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
     if not source.enabled:
         raise Http404
     relay_state = request.GET.get("next", "")
     auth_n_req = RequestProcessor(source, request, relay_state)
     # If the source is configured for Redirect bindings, we can just redirect there
     if source.binding_type == SAMLBindingTypes.REDIRECT:
         # Parse the initial SSO URL
         sso_url = urlparse(source.sso_url)
         # Parse the querystring into a dict...
         url_kwargs = dict(parse_qsl(sso_url.query))
         # ... and update it with the SAML args
         url_kwargs.update(auth_n_req.build_auth_n_detached())
         # Encode it back into a string
         res = ParseResult(
             scheme=sso_url.scheme,
             netloc=sso_url.netloc,
             path=sso_url.path,
             params=sso_url.params,
             query=urlencode(url_kwargs),
             fragment=sso_url.fragment,
         )
         # and merge it back into a URL
         final_url = urlunparse(res)
         return redirect(final_url)
     # As POST Binding we show a form
     try:
         saml_request = nice64(auth_n_req.build_auth_n())
     except InternalError as exc:
         LOGGER.warning(str(exc))
         return bad_request_message(request, str(exc))
     injected_stages = []
     plan_kwargs = {
         PLAN_CONTEXT_TITLE:
         _("Redirecting to %(app)s..." % {"app": source.name}),
         PLAN_CONTEXT_CONSENT_TITLE:
         _("Redirecting to %(app)s..." % {"app": source.name}),
         PLAN_CONTEXT_ATTRS: {
             "SAMLRequest": saml_request,
             "RelayState": relay_state,
         },
         PLAN_CONTEXT_URL:
         source.sso_url,
     }
     # For just POST we add a consent stage,
     # otherwise we default to POST_AUTO, with direct redirect
     if source.binding_type == SAMLBindingTypes.POST:
         injected_stages.append(in_memory_stage(ConsentStageView))
         plan_kwargs[
             PLAN_CONTEXT_CONSENT_HEADER] = f"Continue to {source.name}"
     injected_stages.append(in_memory_stage(AutosubmitStageView))
     return self.handle_login_flow(
         source,
         *injected_stages,
         **plan_kwargs,
     )
Exemplo n.º 6
0
    def test_signed_valid(self):
        """Test generated AuthNRequest with valid signature"""
        http_request = get_request("/")

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()
        # Now we check the ID and signature
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        self.assertEqual(parsed_request.id, request_proc.request_id)
        self.assertEqual(parsed_request.relay_state, "test_state")
Exemplo n.º 7
0
    def test_request_schema(self):
        """Test generated AuthNRequest against Schema"""
        http_request = get_request("/")

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        metadata = etree.fromstring(request)  # nosec

        schema = etree.XMLSchema(
            etree.parse("xml/saml-schema-protocol-2.0.xsd"))  # nosec
        self.assertTrue(schema.validate(metadata))
Exemplo n.º 8
0
    def test_signed_valid(self):
        """Test generated AuthNRequest with valid signature"""
        http_request = self.factory.get("/")

        middleware = SessionMiddleware(dummy_get_response)
        middleware.process_request(http_request)
        http_request.session.save()

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()
        # Now we check the ID and signature
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        self.assertEqual(parsed_request.id, request_proc.request_id)
        self.assertEqual(parsed_request.relay_state, "test_state")
Exemplo n.º 9
0
    def test_request_attributes(self):
        """Test full SAML Request/Response flow, fully signed"""
        user = create_test_admin_user()
        http_request = get_request("/", user=user)

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        # To get an assertion we need a parsed request (parsed by provider)
        parsed_request = AuthNRequestParser(self.provider).parse(
            b64encode(request.encode()).decode(), "test_state")
        # Now create a response and convert it to string (provider)
        response_proc = AssertionProcessor(self.provider, http_request,
                                           parsed_request)
        self.assertIn(user.username, response_proc.build_response())
Exemplo n.º 10
0
    def test_signed_valid_detached(self):
        """Test generated AuthNRequest with valid signature (detached)"""
        http_request = get_request("/")

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        params = request_proc.build_auth_n_detached()
        # Now we check the ID and signature
        parsed_request = AuthNRequestParser(self.provider).parse_detached(
            params["SAMLRequest"],
            params["RelayState"],
            params["Signature"],
            params["SigAlg"],
        )
        self.assertEqual(parsed_request.id, request_proc.request_id)
        self.assertEqual(parsed_request.relay_state, "test_state")
Exemplo n.º 11
0
    def test_request_schema(self):
        """Test generated AuthNRequest against Schema"""
        http_request = self.factory.get("/")

        middleware = SessionMiddleware(dummy_get_response)
        middleware.process_request(http_request)
        http_request.session.save()

        # First create an AuthNRequest
        request_proc = RequestProcessor(self.source, http_request,
                                        "test_state")
        request = request_proc.build_auth_n()

        metadata = etree.fromstring(request)  # nosec

        schema = etree.XMLSchema(
            etree.parse("xml/saml-schema-protocol-2.0.xsd"))  # nosec
        self.assertTrue(schema.validate(metadata))
Exemplo n.º 12
0
 def get(self, request: HttpRequest, source_slug: str) -> HttpResponse:
     """Replies with an XHTML SSO Request."""
     source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
     if not source.enabled:
         raise Http404
     relay_state = request.GET.get("next", "")
     auth_n_req = RequestProcessor(source, request, relay_state)
     # If the source is configured for Redirect bindings, we can just redirect there
     if source.binding_type == SAMLBindingTypes.REDIRECT:
         url_args = urlencode(auth_n_req.build_auth_n_detached())
         return redirect(f"{source.sso_url}?{url_args}")
     # As POST Binding we show a form
     saml_request = nice64(auth_n_req.build_auth_n())
     injected_stages = []
     plan_kwargs = {
         PLAN_CONTEXT_TITLE: _("Redirecting to %(app)s..." % {"app": source.name}),
         PLAN_CONTEXT_CONSENT_TITLE: _(
             "Redirecting to %(app)s..." % {"app": source.name}
         ),
         PLAN_CONTEXT_ATTRS: {
             "SAMLRequest": saml_request,
             "RelayState": relay_state,
         },
         PLAN_CONTEXT_URL: source.sso_url,
     }
     # For just POST we add a consent stage,
     # otherwise we default to POST_AUTO, with direct redirect
     if source.binding_type == SAMLBindingTypes.POST:
         injected_stages.append(in_memory_stage(ConsentStageView))
         plan_kwargs[PLAN_CONTEXT_CONSENT_HEADER] = f"Continue to {source.name}"
     injected_stages.append(in_memory_stage(AutosubmitStageView))
     return self.handle_login_flow(
         source,
         *injected_stages,
         **plan_kwargs,
     )