예제 #1
0
 def setUp(self) -> None:
     super().setUp()
     ObjectManager().run()
     self.app = Application.objects.create(name="test", slug="test")
     self.provider: OAuth2Provider = OAuth2Provider.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         authorization_flow=create_test_flow(),
         redirect_uris="",
         signing_key=create_test_cert(),
     )
     self.provider.property_mappings.set(ScopeMapping.objects.all())
     # Needs to be assigned to an application for iss to be set
     self.app.provider = self.provider
     self.app.save()
     self.user = create_test_admin_user()
     self.token: RefreshToken = RefreshToken.objects.create(
         provider=self.provider,
         user=self.user,
         access_token=generate_id(),
         refresh_token=generate_id(),
         _scope="openid user profile",
         _id_token=json.dumps(asdict(IDToken("foo", "bar"), )),
     )
예제 #2
0
 def test_request_refresh_token(self):
     """test request param"""
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         authorization_flow=create_test_flow(),
         redirect_uris="http://local.invalid",
         signing_key=create_test_cert(),
     )
     header = b64encode(f"{provider.client_id}:{provider.client_secret}".
                        encode()).decode()
     user = create_test_admin_user()
     token: RefreshToken = RefreshToken.objects.create(
         provider=provider,
         user=user,
         refresh_token=generate_id(),
     )
     request = self.factory.post(
         "/",
         data={
             "grant_type": GRANT_TYPE_REFRESH_TOKEN,
             "refresh_token": token.refresh_token,
             "redirect_uri": "http://local.invalid",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
     )
     params = TokenParams.parse(request, provider, provider.client_id,
                                provider.client_secret)
     self.assertEqual(params.provider, provider)
예제 #3
0
    def test_export_validate_import(self):
        """Test export and validate it"""
        flow_slug = generate_id()
        with transaction_rollback():
            login_stage = UserLoginStage.objects.create(name=generate_id())

            flow = Flow.objects.create(
                slug=flow_slug,
                designation=FlowDesignation.AUTHENTICATION,
                name=generate_id(),
                title=generate_id(),
            )
            FlowStageBinding.objects.update_or_create(
                target=flow,
                stage=login_stage,
                order=0,
            )

            exporter = FlowExporter(flow)
            export = exporter.export()
            self.assertEqual(len(export.entries), 3)
            export_json = exporter.export_to_string()

        importer = FlowImporter(export_json)
        self.assertTrue(importer.validate())
        self.assertTrue(importer.apply())

        self.assertTrue(Flow.objects.filter(slug=flow_slug).exists())
예제 #4
0
 def test_refresh_token_revoke(self):
     """test request param"""
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         authorization_flow=create_test_flow(),
         redirect_uris="http://testserver",
         signing_key=create_test_cert(),
     )
     # Needs to be assigned to an application for iss to be set
     self.app.provider = provider
     self.app.save()
     header = b64encode(f"{provider.client_id}:{provider.client_secret}".
                        encode()).decode()
     user = create_test_admin_user()
     token: RefreshToken = RefreshToken.objects.create(
         provider=provider,
         user=user,
         refresh_token=generate_id(),
     )
     # Create initial refresh token
     response = self.client.post(
         reverse("authentik_providers_oauth2:token"),
         data={
             "grant_type": GRANT_TYPE_REFRESH_TOKEN,
             "refresh_token": token.refresh_token,
             "redirect_uri": "http://testserver",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
     )
     new_token: RefreshToken = (RefreshToken.objects.filter(
         user=user).exclude(pk=token.pk).first())
     # Post again with initial token -> get new refresh token
     # and revoke old one
     response = self.client.post(
         reverse("authentik_providers_oauth2:token"),
         data={
             "grant_type": GRANT_TYPE_REFRESH_TOKEN,
             "refresh_token": new_token.refresh_token,
             "redirect_uri": "http://local.invalid",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
     )
     self.assertEqual(response.status_code, 200)
     # Post again with old token, is now revoked and should error
     response = self.client.post(
         reverse("authentik_providers_oauth2:token"),
         data={
             "grant_type": GRANT_TYPE_REFRESH_TOKEN,
             "refresh_token": new_token.refresh_token,
             "redirect_uri": "http://local.invalid",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
     )
     self.assertEqual(response.status_code, 400)
     self.assertTrue(
         Event.objects.filter(
             action=EventAction.SUSPICIOUS_REQUEST).exists())
예제 #5
0
 def test_request_auth_code(self):
     """test request param"""
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         authorization_flow=create_test_flow(),
         redirect_uris="http://testserver",
         signing_key=create_test_cert(),
     )
     header = b64encode(f"{provider.client_id}:{provider.client_secret}".
                        encode()).decode()
     user = create_test_admin_user()
     code = AuthorizationCode.objects.create(code="foobar",
                                             provider=provider,
                                             user=user)
     request = self.factory.post(
         "/",
         data={
             "grant_type": GRANT_TYPE_AUTHORIZATION_CODE,
             "code": code.code,
             "redirect_uri": "http://testserver",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
     )
     params = TokenParams.parse(request, provider, provider.client_id,
                                provider.client_secret)
     self.assertEqual(params.provider, provider)
     with self.assertRaises(TokenError):
         TokenParams.parse(request, provider, provider.client_id,
                           generate_key())
예제 #6
0
 def test_device_challenge_duo(self):
     """Test duo"""
     request = self.request_factory.get("/")
     stage = AuthenticatorDuoStage.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         api_hostname="",
     )
     duo_device = DuoDevice.objects.create(
         user=self.user,
         stage=stage,
     )
     duo_mock = MagicMock(auth=MagicMock(
         return_value={
             "result": "allow",
             "status": "allow",
             "status_msg": "Success. Logging you in...",
         }))
     failed_duo_mock = MagicMock(auth=MagicMock(
         return_value={"result": "deny"}))
     with patch(
             "authentik.stages.authenticator_duo.models.AuthenticatorDuoStage.client",
             duo_mock,
     ):
         self.assertEqual(
             duo_device.pk,
             validate_challenge_duo(duo_device.pk, request, self.user))
     with patch(
             "authentik.stages.authenticator_duo.models.AuthenticatorDuoStage.client",
             failed_duo_mock,
     ):
         with self.assertRaises(ValidationError):
             validate_challenge_duo(duo_device.pk, request, self.user)
예제 #7
0
 def test_refresh_token_view(self):
     """test request param"""
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         authorization_flow=create_test_flow(),
         redirect_uris="http://local.invalid",
         signing_key=create_test_cert(),
     )
     # Needs to be assigned to an application for iss to be set
     self.app.provider = provider
     self.app.save()
     header = b64encode(f"{provider.client_id}:{provider.client_secret}".
                        encode()).decode()
     user = create_test_admin_user()
     token: RefreshToken = RefreshToken.objects.create(
         provider=provider,
         user=user,
         refresh_token=generate_id(),
     )
     response = self.client.post(
         reverse("authentik_providers_oauth2:token"),
         data={
             "grant_type": GRANT_TYPE_REFRESH_TOKEN,
             "refresh_token": token.refresh_token,
             "redirect_uri": "http://local.invalid",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
         HTTP_ORIGIN="http://local.invalid",
     )
     new_token: RefreshToken = (RefreshToken.objects.filter(
         user=user).exclude(pk=token.pk).first())
     self.assertEqual(response["Access-Control-Allow-Credentials"], "true")
     self.assertEqual(response["Access-Control-Allow-Origin"],
                      "http://local.invalid")
     self.assertJSONEqual(
         response.content.decode(),
         {
             "access_token": new_token.access_token,
             "refresh_token": new_token.refresh_token,
             "token_type": "bearer",
             "expires_in": 2592000,
             "id_token": provider.encode(new_token.id_token.to_dict(), ),
         },
     )
     self.validate_jwt(new_token, provider)
예제 #8
0
    def test_export_validate_import_prompt(self):
        """Test export and validate it"""
        with transaction_rollback():
            # First stage fields
            username_prompt = Prompt.objects.create(field_key="username",
                                                    label="Username",
                                                    order=0,
                                                    type=FieldTypes.TEXT)
            password = Prompt.objects.create(
                field_key="password",
                label="Password",
                order=1,
                type=FieldTypes.PASSWORD,
            )
            password_repeat = Prompt.objects.create(
                field_key="password_repeat",
                label="Password (repeat)",
                order=2,
                type=FieldTypes.PASSWORD,
            )

            # Stages
            first_stage = PromptStage.objects.create(name=generate_id())
            first_stage.fields.set(
                [username_prompt, password, password_repeat])
            first_stage.save()

            flow = Flow.objects.create(
                name=generate_id(),
                slug=generate_id(),
                designation=FlowDesignation.ENROLLMENT,
                title=generate_id(),
            )

            FlowStageBinding.objects.create(target=flow,
                                            stage=first_stage,
                                            order=0)

            exporter = FlowExporter(flow)
            export = exporter.export()
            export_json = dumps(export, cls=DataclassEncoder)

        importer = FlowImporter(export_json)

        self.assertTrue(importer.validate())
        self.assertTrue(importer.apply())
예제 #9
0
def create_test_flow(designation: FlowDesignation = FlowDesignation.STAGE_CONFIGURATION) -> Flow:
    """Generate a flow that can be used for testing"""
    uid = generate_id(10)
    return Flow.objects.create(
        name=uid,
        title=uid,
        slug=slugify(uid),
        designation=designation,
    )
예제 #10
0
def create_test_admin_user(name: Optional[str] = None) -> User:
    """Generate a test-admin user"""
    uid = generate_id(20) if not name else name
    group = Group.objects.create(name=uid, is_superuser=True)
    user: User = User.objects.create(
        username=uid,
        name=uid,
        email=f"{uid}@goauthentik.io",
    )
    user.set_password(uid)
    user.save()
    group.users.add(user)
    return user
예제 #11
0
    def test_export_validate_import_policies(self):
        """Test export and validate it"""
        flow_slug = generate_id()
        stage_name = generate_id()
        with transaction_rollback():
            flow_policy = ExpressionPolicy.objects.create(
                name=generate_id(),
                expression="return True",
            )
            flow = Flow.objects.create(
                slug=flow_slug,
                designation=FlowDesignation.AUTHENTICATION,
                name=generate_id(),
                title=generate_id(),
            )
            PolicyBinding.objects.create(policy=flow_policy,
                                         target=flow,
                                         order=0)

            user_login = UserLoginStage.objects.create(name=stage_name)
            fsb = FlowStageBinding.objects.create(target=flow,
                                                  stage=user_login,
                                                  order=0)
            PolicyBinding.objects.create(policy=flow_policy,
                                         target=fsb,
                                         order=0)

            exporter = FlowExporter(flow)
            export = exporter.export()

            export_json = dumps(export, cls=DataclassEncoder)

        importer = FlowImporter(export_json)
        self.assertTrue(importer.validate())
        self.assertTrue(importer.apply())
        self.assertTrue(
            UserLoginStage.objects.filter(name=stage_name).exists())
        self.assertTrue(Flow.objects.filter(slug=flow_slug).exists())
예제 #12
0
 def test_full_implicit(self):
     """Test full authorization"""
     flow = Flow.objects.create(slug="empty")
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id="test",
         client_secret=generate_key(),
         authorization_flow=flow,
         redirect_uris="http://localhost",
         signing_key=create_test_cert(),
     )
     Application.objects.create(name="app", slug="app", provider=provider)
     state = generate_id()
     user = create_test_admin_user()
     self.client.force_login(user)
     # Step 1, initiate params and get redirect to flow
     self.client.get(
         reverse("authentik_providers_oauth2:authorize"),
         data={
             "response_type": "id_token",
             "client_id": "test",
             "state": state,
             "scope": "openid",
             "redirect_uri": "http://localhost",
         },
     )
     response = self.client.get(
         reverse("authentik_api:flow-executor",
                 kwargs={"flow_slug": flow.slug}), )
     token: RefreshToken = RefreshToken.objects.filter(user=user).first()
     self.assertJSONEqual(
         response.content.decode(),
         {
             "component":
             "xak-flow-redirect",
             "type":
             ChallengeTypes.REDIRECT.value,
             "to":
             (f"http://localhost#access_token={token.access_token}"
              f"&id_token={provider.encode(token.id_token.to_dict())}&token_type=bearer"
              f"&expires_in=60&state={state}"),
         },
     )
     self.validate_jwt(token, provider)
예제 #13
0
 def test_auth_code_view(self):
     """test request param"""
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id=generate_id(),
         client_secret=generate_key(),
         authorization_flow=create_test_flow(),
         redirect_uris="http://local.invalid",
         signing_key=create_test_cert(),
     )
     # Needs to be assigned to an application for iss to be set
     self.app.provider = provider
     self.app.save()
     header = b64encode(f"{provider.client_id}:{provider.client_secret}".
                        encode()).decode()
     user = create_test_admin_user()
     code = AuthorizationCode.objects.create(code="foobar",
                                             provider=provider,
                                             user=user,
                                             is_open_id=True)
     response = self.client.post(
         reverse("authentik_providers_oauth2:token"),
         data={
             "grant_type": GRANT_TYPE_AUTHORIZATION_CODE,
             "code": code.code,
             "redirect_uri": "http://local.invalid",
         },
         HTTP_AUTHORIZATION=f"Basic {header}",
     )
     new_token: RefreshToken = RefreshToken.objects.filter(
         user=user).first()
     self.assertJSONEqual(
         response.content.decode(),
         {
             "access_token": new_token.access_token,
             "refresh_token": new_token.refresh_token,
             "token_type": "bearer",
             "expires_in": 2592000,
             "id_token": provider.encode(new_token.id_token.to_dict(), ),
         },
     )
     self.validate_jwt(new_token, provider)
예제 #14
0
 def test_full_code(self):
     """Test full authorization"""
     flow = Flow.objects.create(slug="empty")
     provider = OAuth2Provider.objects.create(
         name="test",
         client_id="test",
         authorization_flow=flow,
         redirect_uris="foo://localhost",
     )
     Application.objects.create(name="app", slug="app", provider=provider)
     state = generate_id()
     user = create_test_admin_user()
     self.client.force_login(user)
     # Step 1, initiate params and get redirect to flow
     self.client.get(
         reverse("authentik_providers_oauth2:authorize"),
         data={
             "response_type": "code",
             "client_id": "test",
             "state": state,
             "redirect_uri": "foo://localhost",
         },
     )
     response = self.client.get(
         reverse("authentik_api:flow-executor",
                 kwargs={"flow_slug": flow.slug}), )
     code: AuthorizationCode = AuthorizationCode.objects.filter(
         user=user).first()
     self.assertJSONEqual(
         response.content.decode(),
         {
             "component": "xak-flow-redirect",
             "type": ChallengeTypes.REDIRECT.value,
             "to": f"foo://localhost?code={code.code}&state={state}",
         },
     )
예제 #15
0
def default_token_key():
    """Default token key"""
    # We use generate_id since the chars in the key should be easy
    # to use in Emails (for verification) and URLs (for recovery)
    return generate_id(128)
예제 #16
0
def create_test_tenant() -> Tenant:
    """Generate a test tenant, removing all other tenants to make sure this one
    matches."""
    uid = generate_id(20)
    Tenant.objects.all().delete()
    return Tenant.objects.create(domain=uid, default=True)
 def setUp(self) -> None:
     super().setUp()
     self.source: OAuthSource = OAuthSource.objects.create(name="test")
     self.factory = RequestFactory()
     self.identifier = generate_id()
 def setUp(self):
     self.client_id = generate_id()
     self.client_secret = generate_key()
     self.app_slug = generate_id(20)
     super().setUp()
예제 #19
0
 def setUp(self) -> None:
     self.client_id = generate_id()
     self.client_secret = generate_key()
     self.source_slug = "oauth1-test"
     super().setUp()
예제 #20
0
 def setUp(self):
     self.client_id = generate_id()
     self.client_secret = generate_key()
     self.application_slug = "test"
     super().setUp()
예제 #21
0
"""Utility script to generate a config for CI runs"""
from authentik.lib.generators import generate_id
from yaml import safe_dump

with open("local.env.yml", "w") as _config:
    safe_dump({
        "log_level": "debug",
        "secret_key": generate_id(),
    },
              _config,
              default_flow_style=False)