Merge branch 'auth-fixes' of gurusainath:makeplane/plane into auth-fixes

This commit is contained in:
guru_sainath 2024-05-14 06:42:40 +05:30
commit 803ce802f1
13 changed files with 322 additions and 148 deletions

View File

@ -100,6 +100,12 @@ class Adapter:
user.save()
Profile.objects.create(user=user)
if not user.is_active:
raise AuthenticationException(
AUTHENTICATION_ERROR_CODES["USER_ACCOUNT_DEACTIVATED"],
error_message="USER_ACCOUNT_DEACTIVATED",
)
# Update user details
user.last_login_medium = self.provider
user.last_active = timezone.now()

View File

@ -4,6 +4,9 @@ AUTHENTICATION_ERROR_CODES = {
"INVALID_EMAIL": 5005,
"EMAIL_REQUIRED": 5010,
"SIGNUP_DISABLED": 5015,
"MAGIC_LINK_LOGIN_DISABLED": 5016,
"PASSWORD_LOGIN_DISABLED": 5018,
"USER_ACCOUNT_DEACTIVATED": 5019,
# Password strength
"INVALID_PASSWORD": 5020,
"SMTP_NOT_CONFIGURED": 5025,

View File

@ -1,3 +1,6 @@
# Python imports
import os
# Module imports
from plane.authentication.adapter.credential import CredentialAdapter
from plane.db.models import User
@ -5,6 +8,7 @@ from plane.authentication.adapter.error import (
AUTHENTICATION_ERROR_CODES,
AuthenticationException,
)
from plane.license.utils.instance_value import get_configuration_value
class EmailProvider(CredentialAdapter):
@ -23,6 +27,21 @@ class EmailProvider(CredentialAdapter):
self.code = code
self.is_signup = is_signup
(ENABLE_EMAIL_PASSWORD,) = get_configuration_value(
[
{
"key": "ENABLE_EMAIL_PASSWORD",
"default": os.environ.get("ENABLE_EMAIL_PASSWORD"),
},
]
)
if ENABLE_EMAIL_PASSWORD == "0":
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["ENABLE_EMAIL_PASSWORD"],
error_message="ENABLE_EMAIL_PASSWORD",
)
def set_user_data(self):
if self.is_signup:
# Check if the user already exists

View File

@ -26,23 +26,20 @@ class MagicCodeProvider(CredentialAdapter):
code=None,
):
(EMAIL_HOST, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD) = (
get_configuration_value(
[
{
"key": "EMAIL_HOST",
"default": os.environ.get("EMAIL_HOST"),
},
{
"key": "EMAIL_HOST_USER",
"default": os.environ.get("EMAIL_HOST_USER"),
},
{
"key": "EMAIL_HOST_PASSWORD",
"default": os.environ.get("EMAIL_HOST_PASSWORD"),
},
]
)
(
EMAIL_HOST,
ENABLE_MAGIC_LINK_LOGIN,
) = get_configuration_value(
[
{
"key": "EMAIL_HOST",
"default": os.environ.get("EMAIL_HOST"),
},
{
"key": "ENABLE_MAGIC_LINK_LOGIN",
"default": os.environ.get("ENABLE_MAGIC_LINK_LOGIN", "1"),
},
]
)
if not (EMAIL_HOST):
@ -52,6 +49,15 @@ class MagicCodeProvider(CredentialAdapter):
payload={"email": str(self.key)},
)
if ENABLE_MAGIC_LINK_LOGIN == "0":
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"MAGIC_LINK_LOGIN_DISABLED"
],
error_message="MAGIC_LINK_LOGIN_DISABLED",
payload={"email": str(self.key)},
)
super().__init__(request, self.provider)
self.key = key
self.code = code

View File

@ -24,62 +24,59 @@ class EmailCheckSignUpEndpoint(APIView):
]
def post(self, request):
# Check instance configuration
instance = Instance.objects.first()
if instance is None or not instance.is_setup_done:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"INSTANCE_NOT_CONFIGURED"
],
error_message="INSTANCE_NOT_CONFIGURED",
)
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
)
email = request.data.get("email", False)
# Return error if email is not present
if not email:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
error_message="EMAIL_REQUIRED",
)
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
)
# Validate email
try:
# Check instance configuration
instance = Instance.objects.first()
if instance is None or not instance.is_setup_done:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"INSTANCE_NOT_CONFIGURED"
],
error_message="INSTANCE_NOT_CONFIGURED",
)
email = request.data.get("email", False)
# Return error if email is not present
if not email:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
error_message="EMAIL_REQUIRED",
)
# Validate email
validate_email(email)
existing_user = User.objects.filter(email=email).first()
if existing_user:
# check if the account is the deactivated
if not existing_user.is_active:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ALREADY_EXIST"
],
error_message="USER_ALREADY_EXIST",
)
return Response(
{"status": True},
status=status.HTTP_200_OK,
)
except ValidationError:
exc = AuthenticationException(
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
error_message="INVALID_EMAIL",
)
except AuthenticationException as e:
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
e.get_error_dict(), status=status.HTTP_400_BAD_REQUEST
)
existing_user = User.objects.filter(email=email).first()
if existing_user:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_ALREADY_EXIST"],
error_message="USER_ALREADY_EXIST",
)
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
)
return Response(
{"status": True},
status=status.HTTP_200_OK,
)
class EmailCheckSignInEndpoint(APIView):
@ -88,61 +85,59 @@ class EmailCheckSignInEndpoint(APIView):
]
def post(self, request):
# Check instance configuration
instance = Instance.objects.first()
if instance is None or not instance.is_setup_done:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"INSTANCE_NOT_CONFIGURED"
],
error_message="INSTANCE_NOT_CONFIGURED",
)
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
)
email = request.data.get("email", False)
# Return error if email is not present
if not email:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
error_message="EMAIL_REQUIRED",
)
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
)
# Validate email
try:
# Check instance configuration
instance = Instance.objects.first()
if instance is None or not instance.is_setup_done:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"INSTANCE_NOT_CONFIGURED"
],
error_message="INSTANCE_NOT_CONFIGURED",
)
email = request.data.get("email", False)
# Return error if email is not present
if not email:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
error_message="EMAIL_REQUIRED",
)
# Validate email
validate_email(email)
existing_user = User.objects.filter(email=email).first()
# If existing user
if existing_user:
# Raise different exception when user is not active
if not existing_user.is_active:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
return Response(
{
"status": True,
"is_password_autoset": existing_user.is_password_autoset,
},
status=status.HTTP_200_OK,
)
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
error_message="USER_DOES_NOT_EXIST",
)
except ValidationError:
exc = AuthenticationException(
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
error_message="INVALID_EMAIL",
)
except AuthenticationException as e:
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
e.get_error_dict(), status=status.HTTP_400_BAD_REQUEST
)
existing_user = User.objects.filter(email=email).first()
if existing_user:
return Response(
{
"status": True,
"is_password_autoset": existing_user.is_password_autoset,
},
status=status.HTTP_200_OK,
)
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
error_message="USER_DOES_NOT_EXIST",
)
return Response(
exc.get_error_dict(),
status=status.HTTP_400_BAD_REQUEST,
)

View File

@ -90,7 +90,9 @@ class SignInAuthEndpoint(View):
)
return HttpResponseRedirect(url)
if not User.objects.filter(email=email).exists():
existing_user = User.objects.filter(email=email).first()
if not existing_user:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
error_message="USER_DOES_NOT_EXIST",
@ -105,6 +107,22 @@ class SignInAuthEndpoint(View):
)
return HttpResponseRedirect(url)
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_app=True),
"sign-in?" + urlencode(params),
)
return HttpResponseRedirect(url)
try:
provider = EmailProvider(
request=request, key=email, code=password, is_signup=False
@ -197,7 +215,26 @@ class SignUpAuthEndpoint(View):
)
return HttpResponseRedirect(url)
if User.objects.filter(email=email).exists():
existing_user = User.objects.filter(email=email).first()
if existing_user:
# Existing User
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_app=True),
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_ALREADY_EXIST"],
error_message="USER_ALREADY_EXIST",

View File

@ -95,7 +95,26 @@ class MagicSignInEndpoint(View):
)
return HttpResponseRedirect(url)
if not User.objects.filter(email=email).exists():
# Existing User
existing_user = User.objects.filter(email=email).first()
if not existing_user:
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_app=True),
"sign-in?" + urlencode(params),
)
return HttpResponseRedirect(url)
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
error_message="USER_DOES_NOT_EXIST",
@ -167,8 +186,25 @@ class MagicSignUpEndpoint(View):
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
# Existing user
existing_user = User.objects.filter(email=email).first()
if not existing_user:
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_app=True),
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
if User.objects.filter(email=email).exists():
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_ALREADY_EXIST"],
error_message="USER_ALREADY_EXIST",

View File

@ -63,23 +63,13 @@ class ForgotPasswordEndpoint(APIView):
status=status.HTTP_400_BAD_REQUEST,
)
(EMAIL_HOST, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD) = (
get_configuration_value(
[
{
"key": "EMAIL_HOST",
"default": os.environ.get("EMAIL_HOST"),
},
{
"key": "EMAIL_HOST_USER",
"default": os.environ.get("EMAIL_HOST_USER"),
},
{
"key": "EMAIL_HOST_PASSWORD",
"default": os.environ.get("EMAIL_HOST_PASSWORD"),
},
]
)
(EMAIL_HOST,) = get_configuration_value(
[
{
"key": "EMAIL_HOST",
"default": os.environ.get("EMAIL_HOST"),
},
]
)
if not (EMAIL_HOST):

View File

@ -68,6 +68,17 @@ class EmailCheckEndpoint(APIView):
# If existing user
if existing_user:
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
return Response(
exc.get_error_dict(), status=status.HTTP_400_BAD_REQUEST
)
return Response(
{
"existing": True,

View File

@ -83,7 +83,10 @@ class SignInAuthSpaceEndpoint(View):
)
return HttpResponseRedirect(url)
if not User.objects.filter(email=email).exists():
# Existing User
existing_user = User.objects.filter(email=email).first()
if not existing_user:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
error_message="USER_DOES_NOT_EXIST",
@ -98,6 +101,22 @@ class SignInAuthSpaceEndpoint(View):
)
return HttpResponseRedirect(url)
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_space=True),
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
try:
provider = EmailProvider(
request=request, key=email, code=password, is_signup=False
@ -185,7 +204,26 @@ class SignUpAuthSpaceEndpoint(View):
)
return HttpResponseRedirect(url)
if User.objects.filter(email=email).exists():
# Existing User
existing_user = User.objects.filter(email=email).first()
if existing_user:
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_space=True),
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_ALREADY_EXIST"],
error_message="USER_ALREADY_EXIST",

View File

@ -90,11 +90,14 @@ class MagicSignInSpaceEndpoint(View):
)
return HttpResponseRedirect(url)
if not User.objects.filter(email=email).exists():
params = {
"error_code": "USER_DOES_NOT_EXIST",
"error_message": "User could not be found with the given email.",
}
existing_user = User.objects.filter(email=email).first()
if not existing_user:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
error_message="USER_DOES_NOT_EXIST",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
@ -103,6 +106,22 @@ class MagicSignInSpaceEndpoint(View):
)
return HttpResponseRedirect(url)
# Active User
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_space=True),
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
try:
provider = MagicCodeProvider(
request=request, key=f"magic_{email}", code=code
@ -155,8 +174,25 @@ class MagicSignUpSpaceEndpoint(View):
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
# Existing User
existing_user = User.objects.filter(email=email).first()
if existing_user:
if not existing_user.is_active:
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES[
"USER_ACCOUNT_DEACTIVATED"
],
error_message="USER_ACCOUNT_DEACTIVATED",
)
params = exc.get_error_dict()
if next_path:
params["next_path"] = str(next_path)
url = urljoin(
base_host(request=request, is_space=True),
"?" + urlencode(params),
)
return HttpResponseRedirect(url)
if User.objects.filter(email=email).exists():
exc = AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["USER_ALREADY_EXIST"],
error_message="USER_ALREADY_EXIST",

View File

@ -1,6 +1,3 @@
# Python imports
from urllib.parse import urlencode, urljoin
# Django imports
from django.views import View
from django.contrib.auth import logout

View File

@ -26,7 +26,7 @@ http {
}
location /god-mode/ {
proxy_pass http://admin:3000/god-mode/;
proxy_pass http://admin:3001/god-mode/;
}
location /api/ {
@ -39,7 +39,7 @@ http {
location /spaces/ {
rewrite ^/spaces/?$ /spaces/login break;
proxy_pass http://space:4000/spaces/;
proxy_pass http://space:3002/spaces/;
}
location /${BUCKET_NAME}/ {