providers/oauth2: fix manual device code entry (#12017)

* providers/oauth2: fix manual device code entry

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make code input a char field to prevent leading 0s from being cut off

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2024-11-13 21:45:16 +01:00
committed by GitHub
parent 74171e0b5a
commit cf6c3c6d3f
3 changed files with 82 additions and 4 deletions

View File

@ -3,6 +3,7 @@
from urllib.parse import urlencode
from django.urls import reverse
from rest_framework.test import APIClient
from authentik.core.models import Application, Group
from authentik.core.tests.utils import create_test_admin_user, create_test_brand, create_test_flow
@ -34,7 +35,10 @@ class TesOAuth2DeviceInit(OAuthTestCase):
self.brand.flow_device_code = self.device_flow
self.brand.save()
def test_device_init(self):
self.api_client = APIClient()
self.api_client.force_login(self.user)
def test_device_init_get(self):
"""Test device init"""
res = self.client.get(reverse("authentik_providers_oauth2_root:device-login"))
self.assertEqual(res.status_code, 302)
@ -48,6 +52,76 @@ class TesOAuth2DeviceInit(OAuthTestCase):
),
)
def test_device_init_post(self):
"""Test device init"""
res = self.api_client.get(reverse("authentik_providers_oauth2_root:device-login"))
self.assertEqual(res.status_code, 302)
self.assertEqual(
res.url,
reverse(
"authentik_core:if-flow",
kwargs={
"flow_slug": self.device_flow.slug,
},
),
)
res = self.api_client.get(
reverse(
"authentik_api:flow-executor",
kwargs={
"flow_slug": self.device_flow.slug,
},
),
)
self.assertEqual(res.status_code, 200)
self.assertJSONEqual(
res.content,
{
"component": "ak-provider-oauth2-device-code",
"flow_info": {
"background": "/static/dist/assets/images/flow_background.jpg",
"cancel_url": "/flows/-/cancel/",
"layout": "stacked",
"title": self.device_flow.title,
},
},
)
provider = OAuth2Provider.objects.create(
name=generate_id(),
authorization_flow=create_test_flow(),
)
Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider)
token = DeviceToken.objects.create(
provider=provider,
)
res = self.api_client.post(
reverse(
"authentik_api:flow-executor",
kwargs={
"flow_slug": self.device_flow.slug,
},
),
data={
"component": "ak-provider-oauth2-device-code",
"code": token.user_code,
},
)
self.assertEqual(res.status_code, 200)
self.assertJSONEqual(
res.content,
{
"component": "xak-flow-redirect",
"to": reverse(
"authentik_core:if-flow",
kwargs={
"flow_slug": provider.authorization_flow.slug,
},
),
},
)
def test_no_flow(self):
"""Test no flow"""
self.brand.flow_device_code = None

View File

@ -5,7 +5,7 @@ from typing import Any
from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, IntegerField
from rest_framework.fields import CharField
from structlog.stdlib import get_logger
from authentik.brands.models import Brand
@ -47,6 +47,9 @@ class CodeValidatorView(PolicyAccessView):
self.provider = self.token.provider
self.application = self.token.provider.application
def post(self, request: HttpRequest, *args, **kwargs):
return self.get(request, *args, **kwargs)
def get(self, request: HttpRequest, *args, **kwargs):
scope_descriptions = UserInfoView().get_scope_descriptions(self.token.scope, self.provider)
planner = FlowPlanner(self.provider.authorization_flow)
@ -122,7 +125,7 @@ class OAuthDeviceCodeChallenge(Challenge):
class OAuthDeviceCodeChallengeResponse(ChallengeResponse):
"""Response that includes the user-entered device code"""
code = IntegerField()
code = CharField()
component = CharField(default="ak-provider-oauth2-device-code")
def validate_code(self, code: int) -> HttpResponse | None:

View File

@ -44957,7 +44957,8 @@ components:
minLength: 1
default: ak-provider-oauth2-device-code
code:
type: integer
type: string
minLength: 1
required:
- code
OAuthDeviceCodeFinishChallenge: