sources/plex: allow auth for owner (when identifier of source plex token matches)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
6c3b7c8d3e
commit
6526659b51
|
@ -149,6 +149,7 @@ class SourceFlowManager:
|
||||||
def get_flow(self, **kwargs) -> HttpResponse:
|
def get_flow(self, **kwargs) -> HttpResponse:
|
||||||
"""Get the flow response based on user_matching_mode"""
|
"""Get the flow response based on user_matching_mode"""
|
||||||
action, connection = self.get_action()
|
action, connection = self.get_action()
|
||||||
|
self._logger.debug("get_action() says", action=action, connection=connection)
|
||||||
if connection:
|
if connection:
|
||||||
if action == Action.LINK:
|
if action == Action.LINK:
|
||||||
self._logger.debug("Linking existing user")
|
self._logger.debug("Linking existing user")
|
||||||
|
|
|
@ -4,10 +4,12 @@ from django.shortcuts import get_object_or_404
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.fields import CharField
|
from rest_framework.fields import CharField
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.serializers import ValidationError
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
@ -15,6 +17,7 @@ from authentik.api.decorators import permission_required
|
||||||
from authentik.core.api.sources import SourceSerializer
|
from authentik.core.api.sources import SourceSerializer
|
||||||
from authentik.core.api.utils import PassiveSerializer
|
from authentik.core.api.utils import PassiveSerializer
|
||||||
from authentik.flows.challenge import RedirectChallenge
|
from authentik.flows.challenge import RedirectChallenge
|
||||||
|
from authentik.flows.views import to_stage_response
|
||||||
from authentik.sources.plex.models import PlexSource
|
from authentik.sources.plex.models import PlexSource
|
||||||
from authentik.sources.plex.plex import PlexAuth, PlexSourceFlowManager
|
from authentik.sources.plex.plex import PlexAuth, PlexSourceFlowManager
|
||||||
|
|
||||||
|
@ -51,7 +54,11 @@ class PlexSourceViewSet(ModelViewSet):
|
||||||
@permission_required(None)
|
@permission_required(None)
|
||||||
@swagger_auto_schema(
|
@swagger_auto_schema(
|
||||||
request_body=PlexTokenRedeemSerializer(),
|
request_body=PlexTokenRedeemSerializer(),
|
||||||
responses={200: RedirectChallenge(), 404: "Token not found"},
|
responses={
|
||||||
|
200: RedirectChallenge(),
|
||||||
|
400: "Token not found",
|
||||||
|
403: "Access denied",
|
||||||
|
},
|
||||||
manual_parameters=[
|
manual_parameters=[
|
||||||
openapi.Parameter(
|
openapi.Parameter(
|
||||||
name="slug",
|
name="slug",
|
||||||
|
@ -75,13 +82,15 @@ class PlexSourceViewSet(ModelViewSet):
|
||||||
)
|
)
|
||||||
plex_token = request.data.get("plex_token", None)
|
plex_token = request.data.get("plex_token", None)
|
||||||
if not plex_token:
|
if not plex_token:
|
||||||
raise Http404
|
raise ValidationError("No plex token given")
|
||||||
auth_api = PlexAuth(source, plex_token)
|
auth_api = PlexAuth(source, plex_token)
|
||||||
user_info, identifier = auth_api.get_user_info()
|
user_info, identifier = auth_api.get_user_info()
|
||||||
# Check friendship first, then check server overlay
|
# Check friendship first, then check server overlay
|
||||||
friends_allowed = False
|
friends_allowed = False
|
||||||
|
owner_id = None
|
||||||
if source.allow_friends:
|
if source.allow_friends:
|
||||||
owner_api = PlexAuth(source, source.plex_token)
|
owner_api = PlexAuth(source, source.plex_token)
|
||||||
|
owner_id = owner_api.get_user_info
|
||||||
owner_friends = owner_api.get_friends()
|
owner_friends = owner_api.get_friends()
|
||||||
for friend in owner_friends:
|
for friend in owner_friends:
|
||||||
if int(friend.get("id", "0")) == int(identifier):
|
if int(friend.get("id", "0")) == int(identifier):
|
||||||
|
@ -90,16 +99,18 @@ class PlexSourceViewSet(ModelViewSet):
|
||||||
"allowing user for plex because of friend",
|
"allowing user for plex because of friend",
|
||||||
user=user_info["username"],
|
user=user_info["username"],
|
||||||
)
|
)
|
||||||
if not auth_api.check_server_overlap() or not friends_allowed:
|
servers_allowed = auth_api.check_server_overlap()
|
||||||
LOGGER.warning(
|
owner_allowed = owner_id == identifier
|
||||||
"Denying plex auth because no server overlay and no friends",
|
if any([friends_allowed, servers_allowed, owner_allowed]):
|
||||||
user=user_info["username"],
|
sfm = PlexSourceFlowManager(
|
||||||
|
source=source,
|
||||||
|
request=request,
|
||||||
|
identifier=str(identifier),
|
||||||
|
enroll_info=user_info,
|
||||||
)
|
)
|
||||||
raise Http404
|
return to_stage_response(request, sfm.get_flow(plex_token=plex_token))
|
||||||
sfm = PlexSourceFlowManager(
|
LOGGER.warning(
|
||||||
source=source,
|
"Denying plex auth because no server overlay and no friends and not owner",
|
||||||
request=request,
|
user=user_info["username"],
|
||||||
identifier=str(identifier),
|
|
||||||
enroll_info=user_info,
|
|
||||||
)
|
)
|
||||||
return sfm.get_flow(plex_token=plex_token)
|
raise PermissionDenied("Access denied.")
|
||||||
|
|
|
@ -105,8 +105,8 @@ class PlexSourceFlowManager(SourceFlowManager):
|
||||||
connection_type = PlexSourceConnection
|
connection_type = PlexSourceConnection
|
||||||
|
|
||||||
def update_connection(
|
def update_connection(
|
||||||
self, connection: PlexSourceConnection, plex_token: str
|
self, connection: PlexSourceConnection, **kwargs
|
||||||
) -> PlexSourceConnection:
|
) -> PlexSourceConnection:
|
||||||
"""Set the access_token on the connection"""
|
"""Set the access_token on the connection"""
|
||||||
connection.plex_token = plex_token
|
connection.plex_token = kwargs.get("plex_token")
|
||||||
return connection
|
return connection
|
||||||
|
|
|
@ -13,6 +13,8 @@ import { BaseStage } from "../../stages/base";
|
||||||
import { PlexAPIClient, popupCenterScreen } from "./API";
|
import { PlexAPIClient, popupCenterScreen } from "./API";
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { SourcesApi } from "authentik-api";
|
import { SourcesApi } from "authentik-api";
|
||||||
|
import { showMessage } from "../../../elements/messages/MessageContainer";
|
||||||
|
import { MessageLevel } from "../../../elements/messages/Message";
|
||||||
|
|
||||||
export interface PlexAuthenticationChallenge extends Challenge {
|
export interface PlexAuthenticationChallenge extends Challenge {
|
||||||
|
|
||||||
|
@ -41,8 +43,18 @@ export class PlexLoginInit extends BaseStage {
|
||||||
plexToken: token,
|
plexToken: token,
|
||||||
},
|
},
|
||||||
slug: this.challenge?.slug || "",
|
slug: this.challenge?.slug || "",
|
||||||
}).then(r => {
|
}).then((r) => {
|
||||||
window.location.assign(r.to);
|
window.location.assign(r.to);
|
||||||
|
}).catch((r: Response) => {
|
||||||
|
r.json().then((body: {detail: string}) => {
|
||||||
|
showMessage({
|
||||||
|
level: MessageLevel.error,
|
||||||
|
message: body.detail
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.assign("/");
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue