Kaynağa Gözat

feat: option to disable user pass based login (#18000)

* Added checkbox to disable pass login in settings

* Added user_pass disable option in Login page context

* Hide user-pass fields when option disabled

* Added check for social login key and LDAP

* feat: Disable API based usr-pwd login

* style: format with black

* refactor: simpify auth validation

No need for else clause

* refactor: fixup sys setting json and move field

* refactor: sys settings validation

* refactor: simpler imports

* chore: undo unintional changes

* test: add test for disabled user pass

Co-authored-by: Ankush Menat <ankush@frappe.io>
version-14
Nikhil Kothari 2 yıl önce
committed by Ankush Menat
ebeveyn
işleme
7249c179ed
6 değiştirilmiş dosya ile 48 ekleme ve 5 silme
  1. +3
    -0
      frappe/auth.py
  2. +9
    -1
      frappe/core/doctype/system_settings/system_settings.json
  3. +16
    -0
      frappe/core/doctype/system_settings/system_settings.py
  4. +9
    -0
      frappe/tests/test_auth.py
  5. +8
    -3
      frappe/www/login.html
  6. +3
    -1
      frappe/www/login.py

+ 3
- 0
frappe/auth.py Dosyayı Görüntüle

@@ -140,6 +140,9 @@ class LoginManager:
self.set_user_info()

def login(self):
if frappe.get_system_settings("disable_user_pass_login"):
frappe.throw(_("Login with username and password is not allowed."), frappe.AuthenticationError)

# clear cache
frappe.clear_cache(user=frappe.form_dict.get("usr"))
user, pwd = get_cached_user_pass()


+ 9
- 1
frappe/core/doctype/system_settings/system_settings.json Dosyayı Görüntüle

@@ -39,6 +39,7 @@
"deny_multiple_sessions",
"allow_login_using_mobile_number",
"allow_login_using_user_name",
"disable_user_pass_login",
"allow_error_traceback",
"strip_exif_metadata_from_uploaded_images",
"allow_older_web_view_links",
@@ -525,12 +526,19 @@
"fieldname": "email_retry_limit",
"fieldtype": "Int",
"label": "Email Retry Limit"
},
{
"default": "0",
"description": "Make sure to configure a Social Login Key before disabling to prevent lockout",
"fieldname": "disable_user_pass_login",
"fieldtype": "Check",
"label": "Disable Username/Password Login"
}
],
"icon": "fa fa-cog",
"issingle": 1,
"links": [],
"modified": "2022-06-21 13:55:04.796152",
"modified": "2022-09-06 03:16:59.090906",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",


+ 16
- 0
frappe/core/doctype/system_settings/system_settings.py Dosyayı Görüntüle

@@ -43,6 +43,22 @@ class SystemSettings(Document):
):
frappe.flags.update_last_reset_password_date = True

self.validate_user_pass_login()

def validate_user_pass_login(self):
if not self.disable_user_pass_login:
return

social_login_enabled = frappe.db.exists("Social Login Key", {"enable_social_login": 1})
ldap_enabled = frappe.db.get_single_value("LDAP Settings", "enabled")

if not (social_login_enabled or ldap_enabled):
frappe.throw(
_(
"Please enable atleast one Social Login Key or LDAP before disabling username/password based login."
)
)

def on_update(self):
self.set_defaults()



+ 9
- 0
frappe/tests/test_auth.py Dosyayı Görüntüle

@@ -98,6 +98,7 @@ class TestAuth(FrappeTestCase):

def test_deny_multiple_login(self):
self.set_system_settings("deny_multiple_sessions", 1)
self.addCleanup(self.set_system_settings, "deny_multiple_sessions", 0)

first_login = FrappeClient(self.HOST_NAME, self.test_user_email, self.test_user_password)
first_login.get_list("ToDo")
@@ -114,6 +115,14 @@ class TestAuth(FrappeTestCase):
second_login.get_list("ToDo")
third_login.get_list("ToDo")

def test_disable_user_pass_login(self):
FrappeClient(self.HOST_NAME, self.test_user_email, self.test_user_password).get_list("ToDo")
self.set_system_settings("disable_user_pass_login", 1)
self.addCleanup(self.set_system_settings, "disable_user_pass_login", 0)

with self.assertRaises(Exception):
FrappeClient(self.HOST_NAME, self.test_user_email, self.test_user_password).get_list("ToDo")


class TestLoginAttemptTracker(FrappeTestCase):
def test_account_lock(self):


+ 8
- 3
frappe/www/login.html Dosyayı Görüntüle

@@ -1,6 +1,7 @@
{% extends "templates/web.html" %}

{% macro email_login_body() -%}
{% if not disable_user_pass_login %}
<div class="page-card-body">
<div class="form-group">
<label class="form-label sr-only" for="login_email">{{ login_label or _("Email")}}</label>
@@ -38,13 +39,15 @@
</div>

<p class="forgot-password-message">
<a href="#forgot">{{ _("Forgot Password?") }}</a></p>
<a href="#forgot">{{ _("Forgot Password?") }}</a>
</p>
</div>
{% endif %}
<div class="page-card-actions">
{% if not disable_user_pass_login %}
<button class="btn btn-sm btn-primary btn-block btn-login" type="submit">
{{ _("Login") }}</button>
{% endif %}
{% if ldap_settings and ldap_settings.enabled %}
<button class="btn btn-sm btn-default btn-block btn-login btn-ldap-login">
{{ _("Login with LDAP") }}</button>
@@ -83,7 +86,9 @@
{{ email_login_body() }}
</form>
<div class="social-logins text-center">
{% if not disable_user_pass_login or (ldap_settings and ldap_settings.enabled) %}
<p class="text-muted login-divider">{{ _("or") }}</p>
{% endif %}
<div class="social-login-buttons">
{% for provider in provider_logins %}
<div class="login-button-wrapper">


+ 3
- 1
frappe/www/login.py Dosyayı Görüntüle

@@ -7,6 +7,7 @@ from frappe import _
from frappe.auth import LoginManager
from frappe.integrations.doctype.ldap_settings.ldap_settings import LDAPSettings
from frappe.integrations.oauth2_logins import decoder_compat
from frappe.utils import cint
from frappe.utils.html_utils import get_icon_html
from frappe.utils.jinja import guess_is_path
from frappe.utils.oauth import (
@@ -40,7 +41,8 @@ def get_context(context):
context.for_test = "login.html"
context["title"] = "Login"
context["provider_logins"] = []
context["disable_signup"] = frappe.utils.cint(frappe.get_website_settings("disable_signup"))
context["disable_signup"] = cint(frappe.get_website_settings("disable_signup"))
context["disable_user_pass_login"] = cint(frappe.get_system_settings("disable_user_pass_login"))
context["logo"] = frappe.get_website_settings("app_logo") or frappe.get_hooks("app_logo_url")[-1]
context["app_name"] = (
frappe.get_website_settings("app_name") or frappe.get_system_settings("app_name") or _("Frappe")


Yükleniyor…
İptal
Kaydet