website/integrations: add three more policy-expressions to discord-docs (#5760)
* - Add two policy-examples for syncing discord roles to authentik groups during enrollment or authentication - Add policy to store oauth-info and create an authentik-avatar-attribute during enrollment or authentication * Fix issues and lint - Fixed issue with wrong return during provider-check - Lint using black Signed-off-by: Keyinator <k3yinator@gmail.com> * Fix capitalization and punctuation Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com> Signed-off-by: Keyinator <k3yinator@gmail.com> * Fix documentation link and add explanation to MAPPED_ROLES attribute --------- Signed-off-by: Keyinator <k3yinator@gmail.com> Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
This commit is contained in:
@ -154,3 +154,209 @@ return user_matched
|
||||
```
|
||||
|
||||
Now bind this policy to the chosen enrollment and authentication flows for the Discord OAuth source.
|
||||
|
||||
### Syncing Discord roles to authentik groups
|
||||
|
||||
:::info
|
||||
Ensure that the Discord OAuth source in 'Federation & Social login' has the additional `guilds.members.read` scopes added under the 'Protocol settings'.
|
||||
:::
|
||||
|
||||
Create a new 'Expression Policy' with the content below, adjusting the variables where required.
|
||||
|
||||
#### Sync on enrollment
|
||||
|
||||
```python
|
||||
# To get the role and guild ID numbers for the parameters, open Discord, go to Settings > Advanced and
|
||||
# enable developer mode.
|
||||
# Right-click on the server/guild title and select "Copy ID" to get the guild ID.
|
||||
# Right-click on the server/guild title and select server settings > roles, right click on the role and click
|
||||
# "Copy ID" to get the role ID.
|
||||
|
||||
from authentik.core.models import Group
|
||||
|
||||
GUILD_ID = "<YOUR GUILD ID>"
|
||||
MAPPED_ROLES = {
|
||||
"<Discord Role Id 1>": Group.objects.get_or_create(name="<Authentik Role Name 1>")[0],
|
||||
"<Discord Role Id 2>": Group.objects.get_or_create(name="<Authentik Role Name 2>")[0],
|
||||
# You can add mapped roles by copying the above line and adjusting to your needs
|
||||
}
|
||||
|
||||
# Only change below here if you know what you are doing.
|
||||
GUILD_API_URL = "https://discord.com/api/users/@me/guilds/{guild_id}/member"
|
||||
|
||||
# Ensure flow is only run during OAuth logins via Discord
|
||||
if context["source"].provider_type != "discord":
|
||||
return True
|
||||
|
||||
# Get the user-source connection object from the context, and get the access token
|
||||
connection = context.get("goauthentik.io/sources/connection")
|
||||
if not connection:
|
||||
return False
|
||||
access_token = connection.access_token
|
||||
|
||||
guild_member_info = requests.get(
|
||||
GUILD_API_URL.format(guild_id=GUILD_ID),
|
||||
headers={"Authorization": "Bearer " + access_token},
|
||||
).json()
|
||||
|
||||
# Ensure user is a member of the guild
|
||||
if "code" in guild_member_info:
|
||||
if guild_member_info["code"] == 10004:
|
||||
ak_message("User is not a member of the guild")
|
||||
else:
|
||||
ak_create_event(
|
||||
"discord_error", source=context["source"], code=guild_member_info["code"]
|
||||
)
|
||||
ak_message("Discord API error, try again later.")
|
||||
return False
|
||||
|
||||
# Add all mapped roles the user has in the guild
|
||||
groups_to_add = []
|
||||
for role_id in MAPPED_ROLES:
|
||||
if role_id in guild_member_info["roles"]:
|
||||
groups_to_add.append(MAPPED_ROLES[role_id])
|
||||
|
||||
request.context["flow_plan"].context["groups"] = groups_to_add
|
||||
return True
|
||||
|
||||
```
|
||||
|
||||
Now bind this policy to the chosen enrollment flows for the Discord OAuth source.
|
||||
|
||||
#### Sync on authentication
|
||||
|
||||
```python
|
||||
# To get the role and guild ID numbers for the parameters, open Discord, go to Settings > Advanced and
|
||||
# enable developer mode.
|
||||
# Right-click on the server/guild title and select "Copy ID" to get the guild ID.
|
||||
# Right-click on the server/guild title and select server settings > roles, right click on the role and click
|
||||
# "Copy ID" to get the role ID.
|
||||
|
||||
from authentik.core.models import Group
|
||||
|
||||
GUILD_ID = "<YOUR GUILD ID>"
|
||||
MAPPED_ROLES = {
|
||||
"<Discord Role Id 1>": Group.objects.get_or_create(name="<Authentik Role Name 1>")[0],
|
||||
"<Discord Role Id 2>": Group.objects.get_or_create(name="<Authentik Role Name 2>")[0],
|
||||
# You can add mapped roles by copying the above line and adjusting to your needs
|
||||
}
|
||||
|
||||
# Only change below here if you know what you are doing.
|
||||
GUILD_API_URL = "https://discord.com/api/users/@me/guilds/{guild_id}/member"
|
||||
|
||||
# Ensure flow is only run during OAuth logins via Discord
|
||||
if context["source"].provider_type != "discord":
|
||||
return True
|
||||
|
||||
# Get the user-source connection object from the context, and get the access token
|
||||
connection = context.get("goauthentik.io/sources/connection")
|
||||
if not connection:
|
||||
return False
|
||||
access_token = connection.access_token
|
||||
|
||||
guild_member_info = requests.get(
|
||||
GUILD_API_URL.format(guild_id=GUILD_ID),
|
||||
headers={"Authorization": "Bearer " + access_token},
|
||||
).json()
|
||||
|
||||
# Ensure user is a member of the guild
|
||||
if "code" in guild_member_info:
|
||||
if guild_member_info["code"] == 10004:
|
||||
ak_message("User is not a member of the guild")
|
||||
else:
|
||||
ak_create_event(
|
||||
"discord_error", source=context["source"], code=guild_member_info["code"]
|
||||
)
|
||||
ak_message("Discord API error, try again later.")
|
||||
return False
|
||||
|
||||
# Get the user's current roles and remove all roles we want to remap
|
||||
new_groups = [
|
||||
role for role in request.user.ak_groups.all() if role not in MAPPED_ROLES.values()
|
||||
]
|
||||
|
||||
# Add back mapped roles which the user has in the guild
|
||||
for role_id in MAPPED_ROLES:
|
||||
if role_id in guild_member_info["roles"]:
|
||||
new_groups.append(MAPPED_ROLES[role_id])
|
||||
|
||||
# Update user's groups
|
||||
request.user.ak_groups.set(new_groups)
|
||||
request.user.save()
|
||||
|
||||
return True
|
||||
|
||||
```
|
||||
|
||||
Now bind this policy to the chosen authentication flows for the Discord OAuth source.
|
||||
|
||||
### Store OAuth info in attribute and create avatar attribute from Discord avatar
|
||||
|
||||
:::info
|
||||
Ensure that the Discord OAuth source in 'Federation & Social login' has the additional `guilds.members.read` scopes added under the 'Protocol settings'.
|
||||
:::
|
||||
|
||||
:::info
|
||||
In order to use the created attribute in authentik you will have to set authentik configuration arguments found at: https://docs.goauthentik.io/docs/core/settings#avatars
|
||||
:::
|
||||
|
||||
Create a new 'Expression Policy' with the content below, adjusting the variables where required:
|
||||
|
||||
```python
|
||||
import base64
|
||||
import requests
|
||||
|
||||
AVATAR_SIZE = "64" # Valid values: 16,32,64,128,256,512,1024
|
||||
|
||||
# Only change below here if you know what you are doing.
|
||||
AVATAR_URL = "https://cdn.discordapp.com/avatars/{id}/{avatar}.png?site={avatar_size}"
|
||||
AVATAR_STREAM_CONTENT = "data:image/png;base64,{base64_string}" # Converts base64 image into html syntax useable with authentik's avatar attributes feature
|
||||
|
||||
|
||||
def get_as_base64(url):
|
||||
"""Returns the base64 content of the url"""
|
||||
return base64.b64encode(requests.get(url).content)
|
||||
|
||||
|
||||
def get_avatar_from_avatar_url(url):
|
||||
"""Returns an authentik-avatar-attributes-compatible string from an image url"""
|
||||
cut_url = f"{url}?size=64"
|
||||
return AVATAR_STREAM_CONTENT.format(
|
||||
base64_string=(get_as_base64(cut_url).decode("utf-8"))
|
||||
)
|
||||
|
||||
|
||||
# Ensure flow is only run during OAuth logins via Discord
|
||||
if context["source"].provider_type != "discord":
|
||||
return True
|
||||
|
||||
user = request.user
|
||||
userinfo = request.context["oauth_userinfo"]
|
||||
|
||||
# Assigns the discord attributes to the user
|
||||
user.attributes["discord"] = {
|
||||
"id": userinfo["id"],
|
||||
"username": userinfo["username"],
|
||||
"discriminator": userinfo["discriminator"],
|
||||
"email": userinfo["email"],
|
||||
"avatar": userinfo["avatar"],
|
||||
"avatar_url": (
|
||||
AVATAR_URL.format(
|
||||
id=userinfo["id"], avatar=userinfo["avatar"], avatar_size=AVATAR_SIZE
|
||||
)
|
||||
if userinfo["avatar"]
|
||||
else None
|
||||
),
|
||||
}
|
||||
|
||||
# If the user has an avatar, assign it to the user
|
||||
avatar_url = user.attributes["discord"].get("avatar_url", None)
|
||||
if avatar_url is not None:
|
||||
user.attributes["avatar"] = get_avatar_from_avatar_url(avatar_url)
|
||||
|
||||
user.save()
|
||||
return True
|
||||
|
||||
```
|
||||
|
||||
Now bind this policy to the chosen enrollment and authentication flows for the Discord OAuth source.
|
||||
|
Reference in New Issue
Block a user