sources/oauth: add patreon type (#5452)
* Models Update to include Patreon as Social Sign On Signed-off-by: DerGardine <julian.burgschweiger@gmail.com> Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add tests, use vanity as username Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: DerGardine <julian.burgschweiger@gmail.com> Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
0ae53b1ce8
commit
a2994218e4
|
@ -12,12 +12,13 @@ AUTHENTIK_SOURCES_OAUTH_TYPES = [
|
||||||
"authentik.sources.oauth.types.facebook",
|
"authentik.sources.oauth.types.facebook",
|
||||||
"authentik.sources.oauth.types.github",
|
"authentik.sources.oauth.types.github",
|
||||||
"authentik.sources.oauth.types.google",
|
"authentik.sources.oauth.types.google",
|
||||||
|
"authentik.sources.oauth.types.mailcow",
|
||||||
"authentik.sources.oauth.types.oidc",
|
"authentik.sources.oauth.types.oidc",
|
||||||
"authentik.sources.oauth.types.okta",
|
"authentik.sources.oauth.types.okta",
|
||||||
|
"authentik.sources.oauth.types.patreon",
|
||||||
"authentik.sources.oauth.types.reddit",
|
"authentik.sources.oauth.types.reddit",
|
||||||
"authentik.sources.oauth.types.twitter",
|
|
||||||
"authentik.sources.oauth.types.mailcow",
|
|
||||||
"authentik.sources.oauth.types.twitch",
|
"authentik.sources.oauth.types.twitch",
|
||||||
|
"authentik.sources.oauth.types.twitter",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,15 @@ class DiscordOAuthSource(OAuthSource):
|
||||||
verbose_name_plural = _("Discord OAuth Sources")
|
verbose_name_plural = _("Discord OAuth Sources")
|
||||||
|
|
||||||
|
|
||||||
|
class PatreonOAuthSource(OAuthSource):
|
||||||
|
"""Social Login using Patreon."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
verbose_name = _("Patreon OAuth Source")
|
||||||
|
verbose_name_plural = _("Patreon OAuth Sources")
|
||||||
|
|
||||||
|
|
||||||
class GoogleOAuthSource(OAuthSource):
|
class GoogleOAuthSource(OAuthSource):
|
||||||
"""Social Login using Google or Google Workspace (GSuite)."""
|
"""Social Login using Google or Google Workspace (GSuite)."""
|
||||||
|
|
||||||
|
|
67
authentik/sources/oauth/tests/test_type_patreon.py
Normal file
67
authentik/sources/oauth/tests/test_type_patreon.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
"""Patreon Type tests"""
|
||||||
|
from django.test import RequestFactory, TestCase
|
||||||
|
|
||||||
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
|
from authentik.sources.oauth.types.patreon import PatreonOAuthCallback
|
||||||
|
|
||||||
|
PATREON_USER = {
|
||||||
|
"data": {
|
||||||
|
"attributes": {
|
||||||
|
"about": None,
|
||||||
|
"created": "2017-10-20T21:36:23+00:00",
|
||||||
|
"discord_id": None,
|
||||||
|
"email": "corgi@example.com",
|
||||||
|
"facebook": None,
|
||||||
|
"facebook_id": None,
|
||||||
|
"first_name": "Corgi",
|
||||||
|
"full_name": "Corgi The Dev",
|
||||||
|
"gender": 0,
|
||||||
|
"has_password": True,
|
||||||
|
"image_url": "https://c8.patreon.com/2/400/0000000",
|
||||||
|
"is_deleted": False,
|
||||||
|
"is_email_verified": False,
|
||||||
|
"is_nuked": False,
|
||||||
|
"is_suspended": False,
|
||||||
|
"last_name": "The Dev",
|
||||||
|
"social_connections": {
|
||||||
|
"deviantart": None,
|
||||||
|
"discord": None,
|
||||||
|
"facebook": None,
|
||||||
|
"reddit": None,
|
||||||
|
"spotify": None,
|
||||||
|
"twitch": None,
|
||||||
|
"twitter": None,
|
||||||
|
"youtube": None,
|
||||||
|
},
|
||||||
|
"thumb_url": "https://c8.patreon.com/2/100/0000000",
|
||||||
|
"twitch": None,
|
||||||
|
"twitter": None,
|
||||||
|
"url": "https://www.patreon.com/corgithedev",
|
||||||
|
"vanity": "corgithedev",
|
||||||
|
"youtube": None,
|
||||||
|
},
|
||||||
|
"id": "0000000",
|
||||||
|
"relationships": {"pledges": {"data": []}},
|
||||||
|
"type": "user",
|
||||||
|
},
|
||||||
|
"links": {"self": "https://www.patreon.com/api/user/0000000"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestTypePatreon(TestCase):
|
||||||
|
"""OAuth Source tests"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.source = OAuthSource.objects.create(
|
||||||
|
name="test",
|
||||||
|
slug="test",
|
||||||
|
provider_type="Patreon",
|
||||||
|
)
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
|
||||||
|
def test_enroll_context(self):
|
||||||
|
"""Test Patreon Enrollment context"""
|
||||||
|
ak_context = PatreonOAuthCallback().get_user_enroll_context(PATREON_USER)
|
||||||
|
self.assertEqual(ak_context["username"], PATREON_USER["data"]["attributes"]["vanity"])
|
||||||
|
self.assertEqual(ak_context["email"], PATREON_USER["data"]["attributes"]["email"])
|
||||||
|
self.assertEqual(ak_context["name"], PATREON_USER["data"]["attributes"]["full_name"])
|
50
authentik/sources/oauth/types/patreon.py
Normal file
50
authentik/sources/oauth/types/patreon.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
"""Patreon OAuth Views"""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
|
||||||
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
|
from authentik.sources.oauth.types.registry import SourceType, registry
|
||||||
|
from authentik.sources.oauth.views.callback import OAuthCallback
|
||||||
|
from authentik.sources.oauth.views.redirect import OAuthRedirect
|
||||||
|
|
||||||
|
|
||||||
|
class PatreonOAuthRedirect(OAuthRedirect):
|
||||||
|
"""Patreon OAuth2 Redirect"""
|
||||||
|
|
||||||
|
def get_additional_parameters(self, source: OAuthSource): # pragma: no cover
|
||||||
|
return {
|
||||||
|
"scope": ["openid", "email", "profile"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PatreonOAuthCallback(OAuthCallback):
|
||||||
|
"""Patreon OAuth2 Callback"""
|
||||||
|
|
||||||
|
client_class: UserprofileHeaderAuthClient
|
||||||
|
|
||||||
|
def get_user_id(self, info: dict[str, str]) -> str:
|
||||||
|
return info.get("data", {}).get("id")
|
||||||
|
|
||||||
|
def get_user_enroll_context(
|
||||||
|
self,
|
||||||
|
info: dict[str, Any],
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"username": info.get("data", {}).get("attributes", {}).get("vanity"),
|
||||||
|
"email": info.get("data", {}).get("attributes", {}).get("email"),
|
||||||
|
"name": info.get("data", {}).get("attributes", {}).get("full_name"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@registry.register()
|
||||||
|
class PatreonType(SourceType):
|
||||||
|
"""OpenIDConnect Type definition"""
|
||||||
|
|
||||||
|
callback_view = PatreonOAuthCallback
|
||||||
|
redirect_view = PatreonOAuthRedirect
|
||||||
|
name = "Patreon"
|
||||||
|
slug = "patreon"
|
||||||
|
|
||||||
|
authorization_url = "https://www.patreon.com/oauth2/authorize"
|
||||||
|
access_token_url = "https://www.patreon.com/api/oauth2/token" # nosec
|
||||||
|
profile_url = "https://www.patreon.com/api/oauth2/api/current_user"
|
6
web/authentik/sources/patreon.svg
Normal file
6
web/authentik/sources/patreon.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="256px" height="247px" viewBox="0 0 256 247" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||||
|
<g>
|
||||||
|
<path d="M45.1355837,0 L45.1355837,246.35001 L0,246.35001 L0,0 L45.1355837,0 Z M163.657111,0 C214.65668,0 256,41.3433196 256,92.3428889 C256,143.342458 214.65668,184.685778 163.657111,184.685778 C112.657542,184.685778 71.3142222,143.342458 71.3142222,92.3428889 C71.3142222,41.3433196 112.657542,0 163.657111,0 Z" fill="#FF424D"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 587 B |
Reference in a new issue