|
|
|
@ -17,58 +17,22 @@ from django.shortcuts import redirect
|
|
|
|
|
from django.urls import reverse
|
|
|
|
|
from django.views import View
|
|
|
|
|
|
|
|
|
|
from konova.sub_settings.sso_settings import SSO_SERVER_BASE, OAUTH_CODE_VERIFIER
|
|
|
|
|
from konova.sub_settings.sso_settings import SSO_SERVER_BASE, OAUTH_CODE_VERIFIER, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET
|
|
|
|
|
from user.models import User
|
|
|
|
|
|
|
|
|
|
OAUTH_CLIENT_ID = "CHANGE_ME"
|
|
|
|
|
OAUTH_CLIENT_SECRET = "CHANGE_ME"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OAuthCallbackView(View):
|
|
|
|
|
"""
|
|
|
|
|
Callback view for a OAuth2.0 authentication token.
|
|
|
|
|
Authentication tokens need to be exchanged for the access token.
|
|
|
|
|
class OAuthLoginView(View):
|
|
|
|
|
"""
|
|
|
|
|
Starts OAuth Login procedure
|
|
|
|
|
-> AnonymousUser is redirected to SSO component using specific parameters
|
|
|
|
|
-> After successful login (in SSO component), user will be redirected to a specific callback url (OAuthCallbackView)
|
|
|
|
|
-> Callback view uses retrieved authorization token to get a proper access token from SSO component
|
|
|
|
|
-> SSO component answers with access token
|
|
|
|
|
-> OAuthCallbackView uses token in Authorization header to access user data of logged-in user in SSO component
|
|
|
|
|
-> OAuthCallbackView creates/updates user
|
|
|
|
|
-> OAuthCallbackView logs in user and redirects to default home view
|
|
|
|
|
|
|
|
|
|
def get(self, request: HttpRequest, *args, **kwargs):
|
|
|
|
|
authentication_code = request.GET.get("code")
|
|
|
|
|
oauth_acces_token_url = f"{SSO_SERVER_BASE}o/token/"
|
|
|
|
|
|
|
|
|
|
next_callback_url = request.build_absolute_uri(
|
|
|
|
|
reverse(
|
|
|
|
|
"oauth-callback"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
params = {
|
|
|
|
|
"grant_type": "authorization_code",
|
|
|
|
|
"code": authentication_code,
|
|
|
|
|
"redirect_uri": next_callback_url,
|
|
|
|
|
"code_verifier": OAUTH_CODE_VERIFIER,
|
|
|
|
|
"client_id": OAUTH_CLIENT_ID,
|
|
|
|
|
"client_secret": OAUTH_CLIENT_SECRET
|
|
|
|
|
}
|
|
|
|
|
access_code_response = requests.post(
|
|
|
|
|
oauth_acces_token_url,
|
|
|
|
|
data=params
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
access_code_response_body = access_code_response.content.decode("utf-8")
|
|
|
|
|
status_code_invalid = access_code_response.status_code != 200
|
|
|
|
|
if status_code_invalid:
|
|
|
|
|
raise RuntimeError(f"OAuth access token could not be fetched: {access_code_response.text}")
|
|
|
|
|
|
|
|
|
|
access_code_response_body = json.loads(access_code_response_body)
|
|
|
|
|
access_token = access_code_response_body.get("access_token")
|
|
|
|
|
if not access_token:
|
|
|
|
|
raise RuntimeError(f"Access token response contained no token: {access_code_response_body}")
|
|
|
|
|
|
|
|
|
|
user = User.oauth_get_user(access_token)
|
|
|
|
|
login(request, user)
|
|
|
|
|
return redirect("home")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OAuthLoginView(View):
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __create_code_challenge(self):
|
|
|
|
|
"""
|
|
|
|
@ -86,7 +50,8 @@ class OAuthLoginView(View):
|
|
|
|
|
return code_verifier, code_challenge
|
|
|
|
|
|
|
|
|
|
def get(self, request: HttpRequest, *args, **kwargs):
|
|
|
|
|
""" Redirects user to OAuth SSO webservice
|
|
|
|
|
"""
|
|
|
|
|
Redirects user to OAuth SSO webservice for credential based login there
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
request ():
|
|
|
|
@ -98,7 +63,6 @@ class OAuthLoginView(View):
|
|
|
|
|
"""
|
|
|
|
|
oauth_authentication_code_url = f"{SSO_SERVER_BASE}o/authorize/"
|
|
|
|
|
code_verifier, code_challenge = self.__create_code_challenge()
|
|
|
|
|
print(code_verifier)
|
|
|
|
|
|
|
|
|
|
urlencode_params = urlencode(
|
|
|
|
|
{
|
|
|
|
@ -115,3 +79,52 @@ class OAuthLoginView(View):
|
|
|
|
|
)
|
|
|
|
|
url = f"{oauth_authentication_code_url}?{urlencode_params}"
|
|
|
|
|
return redirect(url)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OAuthCallbackView(View):
|
|
|
|
|
"""
|
|
|
|
|
Callback view for OAuth2.0 authentication token.
|
|
|
|
|
Authentication tokens will be exchanged for access token.
|
|
|
|
|
Access Token will be used for fetching user data from SSO component.
|
|
|
|
|
User data will be used for creating/updating user data inside this app.
|
|
|
|
|
User will be logged-in and redirected to default home view.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def get(self, request: HttpRequest, *args, **kwargs):
|
|
|
|
|
authentication_code = request.GET.get("code")
|
|
|
|
|
oauth_acces_token_url = f"{SSO_SERVER_BASE}o/token/"
|
|
|
|
|
|
|
|
|
|
next_callback_url = request.build_absolute_uri(
|
|
|
|
|
reverse(
|
|
|
|
|
"oauth-callback"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
params = {
|
|
|
|
|
"grant_type": "authorization_code",
|
|
|
|
|
"code": authentication_code,
|
|
|
|
|
"redirect_uri": next_callback_url,
|
|
|
|
|
"code_verifier": OAUTH_CODE_VERIFIER,
|
|
|
|
|
"client_id": OAUTH_CLIENT_ID,
|
|
|
|
|
"client_secret": OAUTH_CLIENT_SECRET
|
|
|
|
|
}
|
|
|
|
|
access_code_response = requests.post(
|
|
|
|
|
oauth_acces_token_url,
|
|
|
|
|
data=params
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
access_code_response_body = access_code_response.content.decode("utf-8")
|
|
|
|
|
status_code_invalid = access_code_response.status_code != 200
|
|
|
|
|
if status_code_invalid:
|
|
|
|
|
raise RuntimeError(f"OAuth access token could not be fetched: {access_code_response.text}")
|
|
|
|
|
|
|
|
|
|
access_code_response_body = json.loads(access_code_response_body)
|
|
|
|
|
access_token = access_code_response_body.get("access_token")
|
|
|
|
|
if not access_token:
|
|
|
|
|
raise RuntimeError(f"Access token response contained no token: {access_code_response_body}")
|
|
|
|
|
|
|
|
|
|
user = User.oauth_get_user(access_token)
|
|
|
|
|
login(request, user)
|
|
|
|
|
return redirect("home")
|
|
|
|
|
|
|
|
|
|