providers/oauth2: remove jwt_alg field and set algorithm based on selected keypair, select HS256 when no keypair is selected

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-12-22 22:09:49 +01:00
parent 89696edbee
commit 2f3026084e
26 changed files with 126 additions and 205 deletions

View file

@ -146,7 +146,7 @@ class TestCrypto(APITestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://localhost",
rsa_key=keypair,
signing_key=keypair,
)
response = self.client.get(
reverse(

View file

@ -7,25 +7,18 @@ from rest_framework.fields import CharField
from rest_framework.generics import get_object_or_404
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ValidationError
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import Provider
from authentik.providers.oauth2.models import JWTAlgorithms, OAuth2Provider
from authentik.providers.oauth2.models import OAuth2Provider
class OAuth2ProviderSerializer(ProviderSerializer):
"""OAuth2Provider Serializer"""
def validate_jwt_alg(self, value):
"""Ensure that when RS256 is selected, a certificate-key-pair is selected"""
if self.initial_data.get("rsa_key", None) is None and value == JWTAlgorithms.RS256:
raise ValidationError(_("RS256 requires a Certificate-Key-Pair to be selected."))
return value
class Meta:
model = OAuth2Provider
@ -37,8 +30,7 @@ class OAuth2ProviderSerializer(ProviderSerializer):
"access_code_validity",
"token_validity",
"include_claims_in_id_token",
"jwt_alg",
"rsa_key",
"signing_key",
"redirect_uris",
"sub_mode",
"property_mappings",
@ -73,8 +65,7 @@ class OAuth2ProviderViewSet(UsedByMixin, ModelViewSet):
"access_code_validity",
"token_validity",
"include_claims_in_id_token",
"jwt_alg",
"rsa_key",
"signing_key",
"redirect_uris",
"sub_mode",
"property_mappings",

View file

@ -0,0 +1,22 @@
# Generated by Django 4.0 on 2021-12-22 21:04
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentik_providers_oauth2', '0007_auto_20201016_1107_squashed_0017_alter_oauth2provider_token_validity'),
]
operations = [
migrations.RenameField(
model_name='oauth2provider',
old_name='rsa_key',
new_name='signing_key',
),
migrations.RemoveField(
model_name='oauth2provider',
name='jwt_alg',
),
]

View file

@ -8,6 +8,8 @@ from datetime import datetime
from hashlib import sha256
from typing import Any, Optional, Type
from urllib.parse import urlparse
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from dacite import from_dict
from django.db import models
@ -88,6 +90,7 @@ class JWTAlgorithms(models.TextChoices):
HS256 = "HS256", _("HS256 (Symmetric Encryption)")
RS256 = "RS256", _("RS256 (Asymmetric Encryption)")
EC256 = "EC256", _("EC256 (Asymmetric Encryption)")
class ScopeMapping(PropertyMapping):
@ -145,13 +148,6 @@ class OAuth2Provider(Provider):
verbose_name=_("Client Secret"),
default=generate_key,
)
jwt_alg = models.CharField(
max_length=10,
choices=JWTAlgorithms.choices,
default=JWTAlgorithms.RS256,
verbose_name=_("JWT Algorithm"),
help_text=_(JWTAlgorithms.__doc__),
)
redirect_uris = models.TextField(
default="",
blank=True,
@ -207,7 +203,7 @@ class OAuth2Provider(Provider):
help_text=_(("Configure how the issuer field of the ID Token should be filled.")),
)
rsa_key = models.ForeignKey(
signing_key = models.ForeignKey(
CertificateKeyPair,
verbose_name=_("RSA Key"),
on_delete=models.SET_NULL,
@ -231,29 +227,18 @@ class OAuth2Provider(Provider):
token.access_token = token.create_access_token(user, request)
return token
def get_jwt_key(self) -> str:
"""
Takes a provider and returns the set of keys associated with it.
Returns a list of keys.
"""
if self.jwt_alg == JWTAlgorithms.RS256:
# if the user selected RS256 but didn't select a
# CertificateKeyPair, we fall back to HS256
if not self.rsa_key:
Event.new(
EventAction.CONFIGURATION_ERROR,
provider=self,
message="Provider was configured for RS256, but no key was selected.",
).save()
self.jwt_alg = JWTAlgorithms.HS256
self.save()
else:
return self.rsa_key.key_data
if self.jwt_alg == JWTAlgorithms.HS256:
return self.client_secret
raise Exception("Unsupported key algorithm.")
def get_jwt_key(self) -> tuple[str, str]:
"""Get either the configured certificate or the client secret"""
if not self.signing_key:
# No Certificate at all, assume HS256
return self.client_secret, JWTAlgorithms.HS256
key: CertificateKeyPair = self.signing_key
private_key = key.private_key
if isinstance(private_key, RSAPrivateKey):
return key.key_data, JWTAlgorithms.RS256
if isinstance(private_key, EllipticCurvePrivateKey):
return key.key_data, JWTAlgorithms.EC256
raise Exception(f"Invalid private key type: {type(private_key)}")
def get_issuer(self, request: HttpRequest) -> Optional[str]:
"""Get issuer, based on request"""
@ -293,13 +278,13 @@ class OAuth2Provider(Provider):
def encode(self, payload: dict[str, Any]) -> str:
"""Represent the ID Token as a JSON Web Token (JWT)."""
headers = {}
if self.rsa_key:
headers["kid"] = self.rsa_key.kid
key = self.get_jwt_key()
if self.signing_key:
headers["kid"] = self.signing_key.kid
key, alg = self.get_jwt_key()
# If the provider does not have an RSA Key assigned, it was switched to Symmetric
self.refresh_from_db()
# pyright: reportGeneralTypeIssues=false
return encode(payload, key, algorithm=self.jwt_alg, headers=headers)
return encode(payload, key, algorithm=alg, headers=headers)
class Meta:

View file

@ -1,32 +0,0 @@
"""Test oauth2 provider API"""
from django.urls import reverse
from rest_framework.test import APITestCase
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.providers.oauth2.models import JWTAlgorithms
class TestOAuth2ProviderAPI(APITestCase):
"""Test oauth2 provider API"""
def setUp(self) -> None:
super().setUp()
self.user = create_test_admin_user()
self.client.force_login(self.user)
def test_validate(self):
"""Test OAuth2 Provider validation"""
response = self.client.post(
reverse(
"authentik_api:oauth2provider-list",
),
data={
"name": "test",
"jwt_alg": str(JWTAlgorithms.RS256),
"authorization_flow": create_test_flow().pk,
},
)
self.assertJSONEqual(
response.content.decode(),
{"jwt_alg": ["RS256 requires a Certificate-Key-Pair to be selected."]},
)

View file

@ -218,7 +218,7 @@ class TestAuthorize(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=flow,
redirect_uris="http://localhost",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
Application.objects.create(name="app", slug="app", provider=provider)
state = generate_id()

View file

@ -25,7 +25,7 @@ class TestJWKS(OAuthTestCase):
client_id="test",
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
app = Application.objects.create(name="test", slug="test", provider=provider)
response = self.client.get(

View file

@ -35,7 +35,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://testserver",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
user = create_test_admin_user()
@ -62,7 +62,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://testserver",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
request = self.factory.post(
@ -85,7 +85,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
user = create_test_admin_user()
@ -114,7 +114,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
# Needs to be assigned to an application for iss to be set
self.app.provider = provider
@ -156,7 +156,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
# Needs to be assigned to an application for iss to be set
self.app.provider = provider
@ -205,7 +205,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
user = create_test_admin_user()
@ -250,7 +250,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://testserver",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
# Needs to be assigned to an application for iss to be set
self.app.provider = provider

View file

@ -27,7 +27,7 @@ class TestUserinfo(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="",
rsa_key=create_test_cert(),
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

View file

@ -2,7 +2,7 @@
from django.test import TestCase
from jwt import decode
from authentik.providers.oauth2.models import JWTAlgorithms, OAuth2Provider, RefreshToken
from authentik.providers.oauth2.models import OAuth2Provider, RefreshToken
class OAuthTestCase(TestCase):
@ -19,13 +19,11 @@ class OAuthTestCase(TestCase):
def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider):
"""Validate that all required fields are set"""
key = provider.client_secret
if provider.jwt_alg == JWTAlgorithms.RS256:
key = provider.rsa_key.public_key
key, alg = provider.get_jwt_key()
jwt = decode(
token.access_token,
key,
algorithms=[provider.jwt_alg],
algorithms=[alg],
audience=provider.client_id,
)
id_token = token.id_token.to_dict()

View file

@ -1,7 +1,8 @@
"""authentik OAuth2 JWKS Views"""
from base64 import urlsafe_b64encode
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey, EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404
from django.views import View
@ -25,22 +26,38 @@ class JWKSView(View):
"""Show RSA Key data for Provider"""
application = get_object_or_404(Application, slug=application_slug)
provider: OAuth2Provider = get_object_or_404(OAuth2Provider, pk=application.provider_id)
private_key = provider.signing_key
response_data = {}
if provider.jwt_alg == JWTAlgorithms.RS256 and provider.rsa_key:
public_key: RSAPublicKey = provider.rsa_key.private_key.public_key()
public_numbers = public_key.public_numbers()
response_data["keys"] = [
{
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"kid": provider.rsa_key.kid,
"n": b64_enc(public_numbers.n),
"e": b64_enc(public_numbers.e),
}
]
if private_key:
if isinstance(private_key, RSAPrivateKey):
public_key: RSAPublicKey = private_key.public_key()
public_numbers = public_key.public_numbers()
response_data["keys"] = [
{
"kty": "RSA",
"alg": JWTAlgorithms.RS256,
"use": "sig",
"kid": private_key.kid,
"n": b64_enc(public_numbers.n),
"e": b64_enc(public_numbers.e),
}
]
elif isinstance(private_key, EllipticCurvePrivateKey):
public_key: EllipticCurvePublicKey = private_key.public_key()
public_numbers = public_key.public_numbers()
response_data["keys"] = [
{
"kty": "EC",
"alg": JWTAlgorithms.EC256,
"use": "sig",
"kid": private_key.kid,
"n": b64_enc(public_numbers.n),
"e": b64_enc(public_numbers.e),
}
]
response = JsonResponse(response_data)
response["Access-Control-Allow-Origin"] = "*"

View file

@ -39,6 +39,7 @@ class ProviderInfoView(View):
)
if SCOPE_OPENID not in scopes:
scopes.append(SCOPE_OPENID)
_, supported_alg = provider.get_jwt_key()
return {
"issuer": provider.get_issuer(self.request),
"authorization_endpoint": self.request.build_absolute_uri(
@ -78,7 +79,7 @@ class ProviderInfoView(View):
GRANT_TYPE_REFRESH_TOKEN,
GrantTypes.IMPLICIT,
],
"id_token_signing_alg_values_supported": [provider.jwt_alg],
"id_token_signing_alg_values_supported": [supported_alg],
# See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
"subject_types_supported": ["public"],
"token_endpoint_auth_methods_supported": [

View file

@ -18,7 +18,6 @@ from authentik.providers.oauth2.constants import (
)
from authentik.providers.oauth2.models import (
ClientTypes,
JWTAlgorithms,
OAuth2Provider,
ScopeMapping,
)
@ -128,8 +127,7 @@ class ProxyProvider(OutpostModel, OAuth2Provider):
def set_oauth_defaults(self):
"""Ensure all OAuth2-related settings are correct"""
self.client_type = ClientTypes.CONFIDENTIAL
self.jwt_alg = JWTAlgorithms.HS256
self.rsa_key = None
self.signing_key = None
scopes = ScopeMapping.objects.filter(
scope_name__in=[
SCOPE_OPENID,

View file

@ -10858,15 +10858,6 @@ paths:
- global
- per_provider
description: Configure how the issuer field of the ID Token should be filled.
- in: query
name: jwt_alg
schema:
type: string
title: JWT Algorithm
enum:
- HS256
- RS256
description: Algorithm used to sign the JWT Token
- in: query
name: name
schema:
@ -10902,17 +10893,17 @@ paths:
name: redirect_uris
schema:
type: string
- in: query
name: rsa_key
schema:
type: string
format: uuid
- name: search
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: signing_key
schema:
type: string
format: uuid
- in: query
name: sub_mode
schema:
@ -22221,11 +22212,6 @@ components:
- global
- per_provider
type: string
JwtAlgEnum:
enum:
- HS256
- RS256
type: string
KubernetesServiceConnection:
type: object
description: KubernetesServiceConnection Serializer
@ -23099,15 +23085,11 @@ components:
type: boolean
description: Include User claims from scopes in the id_token, for applications
that don't access the userinfo endpoint.
jwt_alg:
allOf:
- $ref: '#/components/schemas/JwtAlgEnum'
title: JWT Algorithm
description: Algorithm used to sign the JWT Token
rsa_key:
signing_key:
type: string
format: uuid
nullable: true
title: RSA Key
description: Key used to sign the tokens. Only required when JWT Algorithm
is set to RS256.
redirect_uris:
@ -23175,15 +23157,11 @@ components:
type: boolean
description: Include User claims from scopes in the id_token, for applications
that don't access the userinfo endpoint.
jwt_alg:
allOf:
- $ref: '#/components/schemas/JwtAlgEnum'
title: JWT Algorithm
description: Algorithm used to sign the JWT Token
rsa_key:
signing_key:
type: string
format: uuid
nullable: true
title: RSA Key
description: Key used to sign the tokens. Only required when JWT Algorithm
is set to RS256.
redirect_uris:
@ -27509,15 +27487,11 @@ components:
type: boolean
description: Include User claims from scopes in the id_token, for applications
that don't access the userinfo endpoint.
jwt_alg:
allOf:
- $ref: '#/components/schemas/JwtAlgEnum'
title: JWT Algorithm
description: Algorithm used to sign the JWT Token
rsa_key:
signing_key:
type: string
format: uuid
nullable: true
title: RSA Key
description: Key used to sign the tokens. Only required when JWT Algorithm
is set to RS256.
redirect_uris:

View file

@ -81,7 +81,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/",
authorization_flow=authorization_flow,
)
@ -123,7 +123,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
authorization_flow=authorization_flow,
)
@ -178,7 +178,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
authorization_flow=authorization_flow,
)
@ -243,7 +243,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
)
provider.property_mappings.set(
@ -315,7 +315,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
)
provider.property_mappings.set(

View file

@ -80,7 +80,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/",
authorization_flow=authorization_flow,
)
@ -122,7 +122,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/auth/callback",
authorization_flow=authorization_flow,
)
@ -172,7 +172,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/auth/callback",
)
provider.property_mappings.set(
@ -235,7 +235,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/auth/callback",
)
provider.property_mappings.set(

View file

@ -80,7 +80,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/",
authorization_flow=authorization_flow,
)
@ -122,7 +122,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/implicit/",
authorization_flow=authorization_flow,
)
@ -168,7 +168,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/implicit/",
)
provider.property_mappings.set(
@ -228,7 +228,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/implicit/",
)
provider.property_mappings.set(

View file

@ -175,9 +175,9 @@ ${this.instance?.redirectUris}</textarea
${t`If no explicit redirect URIs are specified, any redirect URI is allowed.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`RSA Key`} name="rsaKey">
<ak-form-element-horizontal label=${t`Signing Key`} name="signingKey">
<select class="pf-c-form-control">
<option value="" ?selected=${this.instance?.rsaKey === undefined}>
<option value="" ?selected=${this.instance?.signingKey === undefined}>
---------
</option>
${until(
@ -188,7 +188,7 @@ ${this.instance?.redirectUris}</textarea
})
.then((keys) => {
return keys.results.map((key) => {
let selected = this.instance?.rsaKey === key.pk;
let selected = this.instance?.signingKey === key.pk;
if (keys.results.length === 1) {
selected = true;
}
@ -203,9 +203,7 @@ ${this.instance?.redirectUris}</textarea
html`<option>${t`Loading...`}</option>`,
)}
</select>
<p class="pf-c-form__helper-text">
${t`Key used to sign the tokens. Only required when JWT Algorithm is set to RS256.`}
</p>
<p class="pf-c-form__helper-text">${t`Key used to sign the tokens.`}</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
@ -252,29 +250,6 @@ ${this.instance?.redirectUris}</textarea
${t`(Format: hours=-1;minutes=-2;seconds=-3).`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`JWT Algorithm`}
?required=${true}
name="jwtAlg"
>
<select class="pf-c-form-control">
<option
value=${JwtAlgEnum.Rs256}
?selected=${this.instance?.jwtAlg === JwtAlgEnum.Rs256}
>
${t`RS256 (Asymmetric Encryption)`}
</option>
<option
value=${JwtAlgEnum.Hs256}
?selected=${this.instance?.jwtAlg === JwtAlgEnum.Hs256}
>
${t`HS256 (Symmetric Encryption)`}
</option>
</select>
<p class="pf-c-form__helper-text">
${t`Algorithm used to sign the JWT Tokens.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Scopes`} name="propertyMappings">
<select class="pf-c-form-control" multiple>
${until(

View file

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Redirect URIs: `https://guacamole.company/` (depending on your Tomcat setup, you might have to add `/guacamole/` if the application runs in a subfolder)
- Scopes: OpenID, Email and Profile

View file

@ -7,7 +7,7 @@ title: Budibase
From https://github.com/Budibase/budibase
:::note
Budibase is an open source low-code platform, and the easiest way to build internal tools that improve productivity.
Budibase is an open source low-code platform, and the easiest way to build internal tools that improve productivity.
:::
## Preparation
@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://budibase.company/api/global/auth/oidc/callback`
@ -33,4 +32,4 @@ In Budibase under `Auth` set the following values
- Config URL: `https://authentik.company/application/o/<Slug of the application from above>/.well-known/openid-configuration`
- Client ID: `Client ID from above`
- Client Secret: `Client Secret from above`
- Client Secret: `Client Secret from above`

View file

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://grafana.company/login/generic_oauth`
@ -86,12 +85,12 @@ role_attribute_path = contains(groups[*], 'Grafana Admins') && 'Admin' || contai
In the configuration above you can see an example of a role mapping. Upon login, this configuration looks at the groups of which the current user is a member. If any of the specified group names are found, the user will be granted the resulting role in Grafana.
In the example shown above, one of the specified group names is "Grafana Admins". If the user is a member of this group, they will be granted the "Admin" role in Grafana.
In the example shown above, one of the specified group names is "Grafana Admins". If the user is a member of this group, they will be granted the "Admin" role in Grafana.
If the user is not a member of the "Grafana Admins" group, it moves on to see if the user is a member of the "Grafana Editors" group. If they are, they are granted the "Editor" role. Finally, if the user is not found to be a member of either of these groups, it fails back to granting the "Viewer" role.
```text
contains(groups[*], 'Grafana Admins') && 'Admin' || contains(groups[*], 'Grafana Editors') && 'Editor' || 'Viewer'
^ attribute to search ^ group to search for ^ role to grant ^ or grant "Viewer" role.
^ attribute to search ^ group to search for ^ role to grant ^ or grant "Viewer" role.
```
For more information on group/role mappings, see [Grafana's docs](https://grafana.com/docs/grafana/latest/auth/generic-oauth/#role-mapping).
@ -105,4 +104,4 @@ If you get `user does not belong to org` error when trying to log into grafana f
[users]
auto_assign_org = true
auto_assign_org_id = <id-of-your-default-organization>
```
```

View file

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Redirect URIs: `https://harbor.company/c/oidc/callback`
- Scopes: OpenID, Email and Profile

View file

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://hedgedoc.company/auth/oauth2/callback`

View file

@ -21,7 +21,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://matrix.company/_synapse/client/oidc/callback`

View file

@ -28,7 +28,6 @@ return {
Create an application in authentik. Create an _OAuth2/OpenID Provider_ with the following parameters:
- Client Type: `Public`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email, Profile and the scope you created above
- RSA Key: Select any available key
- Redirect URIs: `https://minio.company/oauth_callback`

View file

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://wekan.company/_oauth/oidc`