|
|
@ -2,127 +2,136 @@ |
|
|
|
# MIT License. See license.txt |
|
|
|
|
|
|
|
from __future__ import unicode_literals |
|
|
|
import frappe |
|
|
|
|
|
|
|
import cgi |
|
|
|
|
|
|
|
import frappe.utils |
|
|
|
from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_via_oauth2, login_via_oauth2_id_token, login_oauth_user as _login_oauth_user, redirect_post_login |
|
|
|
import json |
|
|
|
from frappe import _ |
|
|
|
from frappe.auth import LoginManager |
|
|
|
from frappe.integrations.doctype.ldap_settings.ldap_settings import LDAPSettings |
|
|
|
from frappe.utils.password import get_decrypted_password |
|
|
|
from frappe.utils.html_utils import get_icon_html |
|
|
|
from frappe.integrations.oauth2_logins import decoder_compat |
|
|
|
from frappe.utils.html_utils import get_icon_html |
|
|
|
from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_via_oauth2, login_via_oauth2_id_token, \ |
|
|
|
redirect_post_login |
|
|
|
from frappe.utils.password import get_decrypted_password |
|
|
|
from frappe.website.utils import get_home_page |
|
|
|
import cgi |
|
|
|
|
|
|
|
form = cgi.FieldStorage() |
|
|
|
|
|
|
|
import base64 |
|
|
|
from captcha.image import ImageCaptcha |
|
|
|
import random |
|
|
|
import string |
|
|
|
import frappe |
|
|
|
from frappe import _ |
|
|
|
from frappe.query_builder import Table |
|
|
|
from frappe.utils import cstr, encode |
|
|
|
from cryptography.fernet import Fernet, InvalidToken |
|
|
|
from passlib.hash import pbkdf2_sha256, mysql41 |
|
|
|
from passlib.registry import register_crypt_handler |
|
|
|
from passlib.context import CryptContext |
|
|
|
from pypika.terms import Values |
|
|
|
|
|
|
|
Auth = Table("__Auth") |
|
|
|
|
|
|
|
alpha_num = '' |
|
|
|
no_cache = True |
|
|
|
|
|
|
|
|
|
|
|
def get_context(context): |
|
|
|
redirect_to = frappe.local.request.args.get("redirect-to") |
|
|
|
|
|
|
|
if frappe.session.user != "Guest": |
|
|
|
if not redirect_to: |
|
|
|
if frappe.session.data.user_type=="Website User": |
|
|
|
redirect_to = get_home_page() |
|
|
|
else: |
|
|
|
redirect_to = "/app" |
|
|
|
|
|
|
|
if redirect_to != 'login': |
|
|
|
frappe.local.flags.redirect_location = redirect_to |
|
|
|
raise frappe.Redirect |
|
|
|
|
|
|
|
# get settings from site config |
|
|
|
context.no_header = True |
|
|
|
context.for_test = 'login.html' |
|
|
|
context["title"] = "Login" |
|
|
|
context["provider_logins"] = [] |
|
|
|
context["disable_signup"] = frappe.utils.cint(frappe.db.get_single_value("Website Settings", "disable_signup")) |
|
|
|
context["logo"] = (frappe.db.get_single_value('Website Settings', 'app_logo') or |
|
|
|
frappe.get_hooks("app_logo_url")[-1]) |
|
|
|
context["app_name"] = (frappe.db.get_single_value('Website Settings', 'app_name') or |
|
|
|
frappe.get_system_settings("app_name") or _("Frappe")) |
|
|
|
providers = [i.name for i in frappe.get_all("Social Login Key", filters={"enable_social_login":1}, order_by="name")] |
|
|
|
for provider in providers: |
|
|
|
client_id, base_url = frappe.get_value("Social Login Key", provider, ["client_id", "base_url"]) |
|
|
|
client_secret = get_decrypted_password("Social Login Key", provider, "client_secret") |
|
|
|
provider_name = frappe.get_value("Social Login Key", provider, "provider_name") |
|
|
|
|
|
|
|
icon = None |
|
|
|
icon_url = frappe.get_value("Social Login Key", provider, "icon") |
|
|
|
if icon_url: |
|
|
|
if provider_name != "Custom": |
|
|
|
icon = "<img src='{0}' alt={1}>".format(icon_url, provider_name) |
|
|
|
else: |
|
|
|
icon = get_icon_html(icon_url, small=True) |
|
|
|
|
|
|
|
if (get_oauth_keys(provider) and client_secret and client_id and base_url): |
|
|
|
context.provider_logins.append({ |
|
|
|
"name": provider, |
|
|
|
"provider_name": provider_name, |
|
|
|
"auth_url": get_oauth2_authorize_url(provider, redirect_to), |
|
|
|
"icon": icon |
|
|
|
}) |
|
|
|
context["social_login"] = True |
|
|
|
ldap_settings = LDAPSettings.get_ldap_client_settings() |
|
|
|
context["ldap_settings"] = ldap_settings |
|
|
|
|
|
|
|
login_label = [_("Email")] |
|
|
|
|
|
|
|
if frappe.utils.cint(frappe.get_system_settings("allow_login_using_mobile_number")): |
|
|
|
login_label.append(_("Mobile")) |
|
|
|
|
|
|
|
if frappe.utils.cint(frappe.get_system_settings("allow_login_using_user_name")): |
|
|
|
login_label.append(_("Username")) |
|
|
|
|
|
|
|
context['login_label'] = ' {0} '.format(_('or')).join(login_label) |
|
|
|
|
|
|
|
return context |
|
|
|
redirect_to = frappe.local.request.args.get("redirect-to") |
|
|
|
|
|
|
|
if frappe.session.user != "Guest": |
|
|
|
if not redirect_to: |
|
|
|
if frappe.session.data.user_type == "Website User": |
|
|
|
redirect_to = get_home_page() |
|
|
|
else: |
|
|
|
redirect_to = "/app" |
|
|
|
|
|
|
|
if redirect_to != 'login': |
|
|
|
frappe.local.flags.redirect_location = redirect_to |
|
|
|
raise frappe.Redirect |
|
|
|
|
|
|
|
# get settings from site config |
|
|
|
context.no_header = True |
|
|
|
context.for_test = 'login.html' |
|
|
|
context["title"] = "Login" |
|
|
|
context["provider_logins"] = [] |
|
|
|
context["disable_signup"] = frappe.utils.cint(frappe.db.get_single_value("Website Settings", "disable_signup")) |
|
|
|
context["logo"] = (frappe.db.get_single_value('Website Settings', 'app_logo') or |
|
|
|
frappe.get_hooks("app_logo_url")[-1]) |
|
|
|
context["app_name"] = (frappe.db.get_single_value('Website Settings', 'app_name') or |
|
|
|
frappe.get_system_settings("app_name") or _("Frappe")) |
|
|
|
providers = [i.name for i in |
|
|
|
frappe.get_all("Social Login Key", filters={"enable_social_login": 1}, order_by="name")] |
|
|
|
for provider in providers: |
|
|
|
client_id, base_url = frappe.get_value("Social Login Key", provider, ["client_id", "base_url"]) |
|
|
|
client_secret = get_decrypted_password("Social Login Key", provider, "client_secret") |
|
|
|
provider_name = frappe.get_value("Social Login Key", provider, "provider_name") |
|
|
|
|
|
|
|
icon = None |
|
|
|
icon_url = frappe.get_value("Social Login Key", provider, "icon") |
|
|
|
if icon_url: |
|
|
|
if provider_name != "Custom": |
|
|
|
icon = "<img src='{0}' alt={1}>".format(icon_url, provider_name) |
|
|
|
else: |
|
|
|
icon = get_icon_html(icon_url, small=True) |
|
|
|
|
|
|
|
if (get_oauth_keys(provider) and client_secret and client_id and base_url): |
|
|
|
context.provider_logins.append({ |
|
|
|
"name": provider, |
|
|
|
"provider_name": provider_name, |
|
|
|
"auth_url": get_oauth2_authorize_url(provider, redirect_to), |
|
|
|
"icon": icon |
|
|
|
}) |
|
|
|
context["social_login"] = True |
|
|
|
ldap_settings = LDAPSettings.get_ldap_client_settings() |
|
|
|
context["ldap_settings"] = ldap_settings |
|
|
|
|
|
|
|
login_label = [_("Email")] |
|
|
|
|
|
|
|
if frappe.utils.cint(frappe.get_system_settings("allow_login_using_mobile_number")): |
|
|
|
login_label.append(_("Mobile")) |
|
|
|
|
|
|
|
if frappe.utils.cint(frappe.get_system_settings("allow_login_using_user_name")): |
|
|
|
login_label.append(_("Username")) |
|
|
|
|
|
|
|
context['login_label'] = ' {0} '.format(_('or')).join(login_label) |
|
|
|
|
|
|
|
return context |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_via_google(code, state): |
|
|
|
login_via_oauth2("google", code, state, decoder=decoder_compat) |
|
|
|
login_via_oauth2("google", code, state, decoder=decoder_compat) |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_via_github(code, state): |
|
|
|
login_via_oauth2("github", code, state) |
|
|
|
login_via_oauth2("github", code, state) |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_via_facebook(code, state): |
|
|
|
login_via_oauth2("facebook", code, state, decoder=decoder_compat) |
|
|
|
login_via_oauth2("facebook", code, state, decoder=decoder_compat) |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_via_frappe(code, state): |
|
|
|
login_via_oauth2("frappe", code, state, decoder=decoder_compat) |
|
|
|
login_via_oauth2("frappe", code, state, decoder=decoder_compat) |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_via_office365(code, state): |
|
|
|
login_via_oauth2_id_token("office_365", code, state, decoder=decoder_compat) |
|
|
|
login_via_oauth2_id_token("office_365", code, state, decoder=decoder_compat) |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_via_token(login_token): |
|
|
|
sid = frappe.cache().get_value("login_token:{0}".format(login_token), expires=True) |
|
|
|
if not sid: |
|
|
|
frappe.respond_as_web_page(_("Invalid Request"), _("Invalid Login Token"), http_status_code=417) |
|
|
|
return |
|
|
|
sid = frappe.cache().get_value("login_token:{0}".format(login_token), expires=True) |
|
|
|
if not sid: |
|
|
|
frappe.respond_as_web_page(_("Invalid Request"), _("Invalid Login Token"), http_status_code=417) |
|
|
|
return |
|
|
|
|
|
|
|
frappe.local.form_dict.sid = sid |
|
|
|
frappe.local.login_manager = LoginManager() |
|
|
|
frappe.local.form_dict.sid = sid |
|
|
|
frappe.local.login_manager = LoginManager() |
|
|
|
|
|
|
|
redirect_post_login(desk_user = frappe.db.get_value("User", frappe.session.user, "user_type")=="System User") |
|
|
|
redirect_post_login(desk_user=frappe.db.get_value("User", frappe.session.user, "user_type") == "System User") |
|
|
|
|
|
|
|
|
|
|
|
Temp = form.getvalue('password') |
|
|
@ -131,125 +140,161 @@ Temp = form.getvalue('password') |
|
|
|
###This method called from login.js for password validation(CMS login task) |
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login(login): |
|
|
|
user = frappe.db.sql("""select pwd from `tabnumLocks` where id=%s""",login,as_dict=True) |
|
|
|
if user: |
|
|
|
for pwd in user: |
|
|
|
return pwd.pwd |
|
|
|
user = frappe.db.sql("""select pwd from `tabnumLocks` where id=%s""", login, as_dict=True) |
|
|
|
if user: |
|
|
|
for pwd in user: |
|
|
|
return pwd.pwd |
|
|
|
|
|
|
|
|
|
|
|
###This methed called from user client script(CMS login task) |
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_pwd(login,pwd): |
|
|
|
numlock = frappe.db.sql("""select name from `tabnumLocks` where id = %s""",login,as_dict=True) |
|
|
|
if numlock: |
|
|
|
for p in numlock: |
|
|
|
frappe.db.sql("""update `tabnumLocks` set pwd=%s where name = %s""",(pwd,p.name),as_dict=True) |
|
|
|
else: |
|
|
|
num = frappe.new_doc("numLocks") |
|
|
|
num.id = login |
|
|
|
num.pwd = pwd |
|
|
|
num.save() |
|
|
|
def login_pwd(login, pwd): |
|
|
|
numlock = frappe.db.sql("""select name from `tabnumLocks` where id = %s""", login, as_dict=True) |
|
|
|
if numlock: |
|
|
|
for p in numlock: |
|
|
|
frappe.db.sql("""update `tabnumLocks` set pwd=%s where name = %s""", (pwd, p.name), as_dict=True) |
|
|
|
else: |
|
|
|
num = frappe.new_doc("numLocks") |
|
|
|
num.id = login |
|
|
|
num.pwd = pwd |
|
|
|
num.save() |
|
|
|
|
|
|
|
|
|
|
|
###This method called from templates/includes/login/_login.js |
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def login_user(login): |
|
|
|
user = frappe.db.sql("""select username from `tabUser` where username=%s and enabled = '0'""",(login),as_list=True) |
|
|
|
if user: |
|
|
|
return user |
|
|
|
if not user: |
|
|
|
return 'None' |
|
|
|
user = frappe.db.sql("""select username from `tabUser` where username=%s and enabled = '0'""", (login), |
|
|
|
as_list=True) |
|
|
|
if user: |
|
|
|
return user |
|
|
|
if not user: |
|
|
|
return 'None' |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def create_user(login): |
|
|
|
user = frappe.db.sql("""select username from `tabUser` where username='{0}'""".format(login),as_list=True) |
|
|
|
if not user: |
|
|
|
user = frappe.new_doc("User") |
|
|
|
user.email = login + "@mahindra.com" |
|
|
|
user.first_name = login |
|
|
|
user.username = login |
|
|
|
user.enabled = 0 |
|
|
|
user.pwd = "Mail Sent" |
|
|
|
user.send_welcome_email = 0 |
|
|
|
user.location = "Mahindra" |
|
|
|
role = user.append('roles',{}) |
|
|
|
role.role = "CMS User" |
|
|
|
user.insert(ignore_permissions=True) |
|
|
|
user = frappe.db.sql("""select username from `tabUser` where username='{0}'""".format(login), as_list=True) |
|
|
|
if not user: |
|
|
|
user = frappe.new_doc("User") |
|
|
|
user.email = login + "@mahindra.com" |
|
|
|
user.first_name = login |
|
|
|
user.username = login |
|
|
|
user.enabled = 0 |
|
|
|
user.pwd = "Mail Sent" |
|
|
|
user.send_welcome_email = 0 |
|
|
|
user.location = "Mahindra" |
|
|
|
role = user.append('roles', {}) |
|
|
|
role.role = "CMS User" |
|
|
|
user.insert(ignore_permissions=True) |
|
|
|
|
|
|
|
|
|
|
|
class LegacyPassword(pbkdf2_sha256): |
|
|
|
name = "frappe_legacy" |
|
|
|
ident = "$frappel$" |
|
|
|
name = "frappe_legacy" |
|
|
|
ident = "$frappel$" |
|
|
|
|
|
|
|
def _calc_checksum(self, secret): |
|
|
|
# check if this is a mysql hash |
|
|
|
# it is possible that we will generate a false positive if the users password happens to be 40 hex chars proceeded |
|
|
|
# by an * char, but this seems highly unlikely |
|
|
|
if not (secret[0] == "*" and len(secret) == 41 and all(c in string.hexdigits for c in secret[1:])): |
|
|
|
secret = mysql41.hash(secret + self.salt.decode('utf-8')) |
|
|
|
return super(LegacyPassword, self)._calc_checksum(secret) |
|
|
|
def _calc_checksum(self, secret): |
|
|
|
# check if this is a mysql hash |
|
|
|
# it is possible that we will generate a false positive if the users password happens to be 40 hex chars proceeded |
|
|
|
# by an * char, but this seems highly unlikely |
|
|
|
if not (secret[0] == "*" and len(secret) == 41 and all(c in string.hexdigits for c in secret[1:])): |
|
|
|
secret = mysql41.hash(secret + self.salt.decode('utf-8')) |
|
|
|
return super(LegacyPassword, self)._calc_checksum(secret) |
|
|
|
|
|
|
|
|
|
|
|
register_crypt_handler(LegacyPassword, force=True) |
|
|
|
passlibctx = CryptContext( |
|
|
|
schemes=[ |
|
|
|
"pbkdf2_sha256", |
|
|
|
"argon2", |
|
|
|
"frappe_legacy", |
|
|
|
], |
|
|
|
deprecated=[ |
|
|
|
"frappe_legacy", |
|
|
|
], |
|
|
|
schemes=[ |
|
|
|
"pbkdf2_sha256", |
|
|
|
"argon2", |
|
|
|
"frappe_legacy", |
|
|
|
], |
|
|
|
deprecated=[ |
|
|
|
"frappe_legacy", |
|
|
|
], |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def update_password_mahindra(user, pwd, doctype='User', fieldname='password', logout_all_sessions=True): |
|
|
|
''' |
|
|
|
Update the password for the User |
|
|
|
|
|
|
|
:param user: username |
|
|
|
:param pwd: new password |
|
|
|
:param doctype: doctype name (for encryption) |
|
|
|
:param fieldname: fieldname (in given doctype) (for encryption) |
|
|
|
:param logout_all_session: delete all other session |
|
|
|
''' |
|
|
|
#pwd = "jeci@123" |
|
|
|
hashPwd = passlibctx.hash(pwd) |
|
|
|
query = ( |
|
|
|
frappe.qb.into(Auth) |
|
|
|
.columns(Auth.doctype, Auth.name, Auth.fieldname, Auth.password, Auth.encrypted) |
|
|
|
.insert(doctype, user, fieldname, hashPwd, 0) |
|
|
|
) |
|
|
|
# TODO: Simplify this via aliasing methods in `frappe.qb` |
|
|
|
if frappe.db.db_type == "mariadb": |
|
|
|
query = ( |
|
|
|
query.on_duplicate_key_update(Auth.password, hashPwd) |
|
|
|
.on_duplicate_key_update(Auth.encrypted, 0) |
|
|
|
) |
|
|
|
elif frappe.db.db_type == "postgres": |
|
|
|
query = ( |
|
|
|
query.on_conflict(Auth.doctype, Auth.name, Auth.fieldname) |
|
|
|
.do_update(Auth.password, hashPwd) |
|
|
|
.do_update(Auth.encrypted, 0) |
|
|
|
) |
|
|
|
|
|
|
|
query.run() |
|
|
|
|
|
|
|
# clear all the sessions except current |
|
|
|
if logout_all_sessions: |
|
|
|
from frappe.sessions import clear_sessions |
|
|
|
clear_sessions(user=user, keep_current=True, force=True) |
|
|
|
''' |
|
|
|
Update the password for the User |
|
|
|
|
|
|
|
:param user: username |
|
|
|
:param pwd: new password |
|
|
|
:param doctype: doctype name (for encryption) |
|
|
|
:param fieldname: fieldname (in given doctype) (for encryption) |
|
|
|
:param logout_all_session: delete all other session |
|
|
|
''' |
|
|
|
# pwd = "jeci@123" |
|
|
|
hashPwd = passlibctx.hash(pwd) |
|
|
|
query = ( |
|
|
|
frappe.qb.into(Auth) |
|
|
|
.columns(Auth.doctype, Auth.name, Auth.fieldname, Auth.password, Auth.encrypted) |
|
|
|
.insert(doctype, user, fieldname, hashPwd, 0) |
|
|
|
) |
|
|
|
# TODO: Simplify this via aliasing methods in `frappe.qb` |
|
|
|
if frappe.db.db_type == "mariadb": |
|
|
|
query = ( |
|
|
|
query.on_duplicate_key_update(Auth.password, hashPwd) |
|
|
|
.on_duplicate_key_update(Auth.encrypted, 0) |
|
|
|
) |
|
|
|
elif frappe.db.db_type == "postgres": |
|
|
|
query = ( |
|
|
|
query.on_conflict(Auth.doctype, Auth.name, Auth.fieldname) |
|
|
|
.do_update(Auth.password, hashPwd) |
|
|
|
.do_update(Auth.encrypted, 0) |
|
|
|
) |
|
|
|
|
|
|
|
query.run() |
|
|
|
|
|
|
|
# clear all the sessions except current |
|
|
|
if logout_all_sessions: |
|
|
|
from frappe.sessions import clear_sessions |
|
|
|
clear_sessions(user=user, keep_current=True, force=True) |
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def create_captcha_image(numbers=''): |
|
|
|
import base64 |
|
|
|
from captcha.image import ImageCaptcha |
|
|
|
# Create an image instance of the given size |
|
|
|
image = ImageCaptcha(width = 450, height = 70) |
|
|
|
# generate the image of the given text and convert to base64 |
|
|
|
separator=' ' |
|
|
|
numbers=separator.join(numbers) |
|
|
|
dataStr = image.generate(numbers).read() |
|
|
|
data = str(base64.b64encode(dataStr)) |
|
|
|
return data[2:-1] |
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def get_user_doc_name(email=''): |
|
|
|
name=frappe.db.get_value('User', {'email': email}, ['name']) |
|
|
|
return name |
|
|
|
name = frappe.db.get_value('User', {'email': email}, ['name']) |
|
|
|
return name |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def create_captcha_image(uid): |
|
|
|
numbers = '' |
|
|
|
# initializing size of string |
|
|
|
N = 6 |
|
|
|
# using random.choices() |
|
|
|
# generating random strings |
|
|
|
numbers = ''.join(random.choices('123456789123456789abcdefghijklmnpqrstuvwxyz', k=N)) |
|
|
|
# set the value to check |
|
|
|
|
|
|
|
# alpha_num=numbers |
|
|
|
captcha_doc = frappe.new_doc('Captcha Validation') |
|
|
|
captcha_doc.uid = uid |
|
|
|
captcha_doc.captcha_text = numbers |
|
|
|
captcha_doc.insert(ignore_permissions=True) |
|
|
|
captcha_doc.save() |
|
|
|
# frappe.msgprint('changed '+str(alpha_num)) |
|
|
|
numbers = ' ' + numbers + '' |
|
|
|
# Create an image instance of the given size |
|
|
|
image = ImageCaptcha(width=450, height=70) |
|
|
|
# generate the image of the given text and convert to base64 |
|
|
|
separator = ' ' |
|
|
|
numbers = separator.join(numbers) |
|
|
|
dataStr = image.generate(numbers).read() |
|
|
|
data = str(base64.b64encode(dataStr)) |
|
|
|
|
|
|
|
return data[2:-1] |
|
|
|
|
|
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) |
|
|
|
def check_captcha(captcha_input, uid1): |
|
|
|
validate_captcha = frappe.get_doc('Captcha Validation', {'uid': uid1}) |
|
|
|
if captcha_input == validate_captcha.captcha_text: |
|
|
|
validate_captcha.delete(ignore_permissions=True) |
|
|
|
return True |
|
|
|
|
|
|
|
else: |
|
|
|
validate_captcha.delete(ignore_permissions=True) |
|
|
|
return False |
|
|
|