Skip to content

Commit

Permalink
providers/oauth2: fix manual device code entry (#12017)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
BeryJu authored Nov 13, 2024
1 parent 74171e0 commit cf6c3c6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
76 changes: 75 additions & 1 deletion authentik/providers/oauth2/tests/test_device_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -34,7 +35,10 @@ def setUp(self) -> None:
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)
Expand All @@ -48,6 +52,76 @@ def test_device_init(self):
),
)

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
Expand Down
7 changes: 5 additions & 2 deletions authentik/providers/oauth2/views/device_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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
Expand Down Expand Up @@ -47,6 +47,9 @@ def resolve_provider_application(self):
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)
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44957,7 +44957,8 @@ components:
minLength: 1
default: ak-provider-oauth2-device-code
code:
type: integer
type: string
minLength: 1
required:
- code
OAuthDeviceCodeFinishChallenge:
Expand Down

0 comments on commit cf6c3c6

Please sign in to comment.