Skip to content

Commit

Permalink
add route to generate auth token from logged in cloud users
Browse files Browse the repository at this point in the history
  • Loading branch information
MarconLP committed Nov 16, 2023
1 parent 820e6a7 commit 219e592
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
19 changes: 19 additions & 0 deletions posthog/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,25 @@ def redirect_to_site(request):
return redirect("{}#__posthog={}".format(app_url, state))


@authenticate_secondarily
def redirect_to_website(request):
team = request.user.team
app_url = request.GET.get("appUrl") or (team.app_urls and team.app_urls[0])

if not app_url:
return HttpResponse(status=404)

if not team or not urllib.parse.urlparse(app_url).hostname in ['localhost', 'posthog.com']:
return HttpResponse(f"Can only redirect to a permitted domain.", status=403)
params = { "jwt": "random_auth_token" }

# pass the empty string as the safe param so that `//` is encoded correctly.
# see https://github.com/PostHog/posthog/issues/9671
userData = urllib.parse.quote(json.dumps(params), safe="")

return redirect("{}?userData={}&redirect={}".format('http://localhost:8001/auth', userData, app_url))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.


@require_http_methods(["POST"])
@authenticate_secondarily
def test_slack_webhook(request):
Expand Down
13 changes: 13 additions & 0 deletions posthog/templates/authorize_and_link.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends 'layout.html' %}

{% block content %}
<form class="form-signin" method="post" action="/login">
Do you want to login on <strong>{{ domain }}</strong> using your PostHog Cloud ({{ email}}) account?
<br /><br />
<a href='/api/user/redirect_to_website/?appUrl={{ redirect_url }}' class="btn btn-lg btn-primary btn-block"
type="submit">
Authorize
<strong>{{ domain }}</strong>
</a>
</form>
{% endblock %}
46 changes: 46 additions & 0 deletions posthog/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,50 @@ def authorize_and_redirect(request: HttpRequest) -> HttpResponse:
)


def link_and_redirect(request: HttpRequest) -> HttpResponse:
if not request.GET.get("redirect"):
return HttpResponse("You need to pass a url to ?redirect=", status=400)
if not request.META.get("HTTP_REFERER"):
return HttpResponse('You need to make a request that includes the "Referer" header.', status=400)

current_team = cast(User, request.user).team
referer_url = urlparse(request.META["HTTP_REFERER"])
redirect_url = urlparse(request.GET["redirect"])

print(redirect_url.hostname)
if not current_team or not redirect_url.hostname in ['localhost', 'posthog.com']:
return HttpResponse(f"Can only redirect to a permitted domain.", status=403)

if referer_url.hostname != redirect_url.hostname:
return HttpResponse(
f"Can only redirect to the same domain as the referer: {referer_url.hostname}",
status=403,
)

if referer_url.scheme != redirect_url.scheme:
return HttpResponse(
f"Can only redirect to the same scheme as the referer: {referer_url.scheme}",
status=403,
)

if referer_url.port != redirect_url.port:
return HttpResponse(
f"Can only redirect to the same port as the referer: {referer_url.port or 'no port in URL'}",
status=403,
)

return render_template(
"authorize_and_link.html",
request=request,
context={
"email": request.user,
"domain": redirect_url.hostname,
"redirect_url": request.GET["redirect"],
},
)



def opt_slash_path(route: str, view: Callable, name: Optional[str] = None) -> URLPattern:
"""Catches path with or without trailing slash, taking into account query param and hash."""
# Ignoring the type because while name can be optional on re_path, mypy doesn't agree
Expand Down Expand Up @@ -161,6 +205,7 @@ def opt_slash_path(route: str, view: Callable, name: Optional[str] = None) -> UR
path("api/", include(router.urls)),
path("", include(tf_urls)),
opt_slash_path("api/user/redirect_to_site", user.redirect_to_site),
opt_slash_path("api/user/redirect_to_website", user.redirect_to_website),
opt_slash_path("api/user/test_slack_webhook", user.test_slack_webhook),
opt_slash_path("api/prompts/webhook", prompt_webhook),
opt_slash_path("api/early_access_features", early_access_features),
Expand All @@ -174,6 +219,7 @@ def opt_slash_path(route: str, view: Callable, name: Optional[str] = None) -> UR
),
re_path(r"^api.+", api_not_found),
path("authorize_and_redirect/", login_required(authorize_and_redirect)),
path("link_and_redirect/", login_required(link_and_redirect)),
path(
"shared_dashboard/<str:access_token>",
sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"}),
Expand Down

0 comments on commit 219e592

Please sign in to comment.