2
0
mirror of https://github.com/frappe/frappe.git synced 2024-06-12 18:32:23 +00:00

feat: Limit OAuth Client by roles

This commit is contained in:
Ankush Menat 2024-04-29 12:09:26 +05:30
parent 926c888374
commit ae4eb87458
11 changed files with 95 additions and 8 deletions

View File

@ -280,7 +280,7 @@ frappe.ui.form.on("User", {
frm.set_df_property("enabled", "read_only", 0);
}
if (frappe.session.user !== "Administrator") {
if (frm.doc.name !== "Administrator") {
frm.toggle_enable("email", frm.is_new());
}
},

View File

@ -157,7 +157,7 @@ class User(Document):
self.password_strength_test()
if self.name not in STANDARD_USERS:
self.validate_email_type(self.email)
self.email = self.name
self.validate_email_type(self.name)
self.add_system_manager_role()
self.move_role_profile_name_to_role_profiles()

View File

@ -9,6 +9,7 @@
"client_id",
"app_name",
"user",
"allowed_roles",
"cb_1",
"client_secret",
"skip_authorization",
@ -114,10 +115,16 @@
"in_standard_filter": 1,
"label": "Response Type",
"options": "Code\nToken"
},
{
"fieldname": "allowed_roles",
"fieldtype": "Table MultiSelect",
"label": "Allowed Roles",
"options": "OAuth Client Role"
}
],
"links": [],
"modified": "2024-03-23 16:03:32.679227",
"modified": "2024-04-29 12:07:07.946980",
"modified_by": "Administrator",
"module": "Integrations",
"name": "OAuth Client",
@ -141,4 +148,4 @@
"states": [],
"title_field": "app_name",
"track_changes": 1
}
}

View File

@ -4,6 +4,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.permissions import SYSTEM_USER_ROLE
class OAuthClient(Document):
@ -13,8 +14,10 @@ class OAuthClient(Document):
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.integrations.doctype.oauth_client_role.oauth_client_role import OAuthClientRole
from frappe.types import DF
allowed_roles: DF.TableMultiSelect[OAuthClientRole]
app_name: DF.Data
client_id: DF.Data | None
client_secret: DF.Data | None
@ -32,6 +35,7 @@ class OAuthClient(Document):
if not self.client_secret:
self.client_secret = frappe.generate_hash(length=10)
self.validate_grant_and_response()
self.add_default_role()
def validate_grant_and_response(self):
if (
@ -45,3 +49,12 @@ class OAuthClient(Document):
"Combination of Grant Type (<code>{0}</code>) and Response Type (<code>{1}</code>) not allowed"
).format(self.grant_type, self.response_type)
)
def add_default_role(self):
if not self.allowed_roles:
self.append("allowed_roles", {"role": SYSTEM_USER_ROLE})
def user_has_allowed_role(self) -> bool:
"""Returns true if session user is allowed to use this client."""
allowed_roles = {d.role for d in self.allowed_roles}
return bool(allowed_roles & set(frappe.get_roles()))

View File

@ -0,0 +1,11 @@
import frappe
def execute():
"""Set default allowed role in OAuth Client"""
for client in frappe.get_all("OAuth Client", pluck="name"):
doc = frappe.get_doc("OAuth Client", client)
if doc.allowed_roles:
continue
row = doc.append("allowed_roles", {"role": "All"}) # Current default
row.db_insert()

View File

@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2024-04-29 12:08:19.459404",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"role"
],
"fields": [
{
"fieldname": "role",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Role",
"options": "Role"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-04-29 12:16:48.018031",
"modified_by": "Administrator",
"module": "Integrations",
"name": "OAuth Client Role",
"owner": "Administrator",
"permissions": [],
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@ -0,0 +1,23 @@
# Copyright (c) 2024, Frappe Technologies and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class OAuthClientRole(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
role: DF.Link | None
# end: auto-generated types
pass

View File

@ -20,10 +20,11 @@ class OAuthWebRequestValidator(RequestValidator):
# Simple validity check, does client exist? Not banned?
cli_id = frappe.db.get_value("OAuth Client", {"name": client_id})
if cli_id:
request.client = frappe.get_doc("OAuth Client", client_id).as_dict()
return True
else:
return False
client = frappe.get_doc("OAuth Client", client_id)
if client.user_has_allowed_role():
request.client = client.as_dict()
return True
return False
def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs):
# Is the client allowed to use the supplied redirect_uri? i.e. has

View File

@ -236,3 +236,4 @@ frappe.patches.v15_0.migrate_role_profile_to_table_multi_select
frappe.patches.v15_0.migrate_session_data
frappe.custom.doctype.property_setter.patches.remove_invalid_fetch_from_expressions
frappe.patches.v16_0.switch_default_sort_order
frappe.integrations.doctype.oauth_client.patches.set_default_allowed_role_in_oauth_client