Skip to content

Commit

Permalink
feat: sync user claims from idp (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
revant authored Jul 15, 2024
1 parent c74298a commit 7940d2f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 6 deletions.
25 changes: 20 additions & 5 deletions castlecraft/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,7 @@ def validate_bearer_with_introspection(token, idp):
if idp.fetch_user_info:
if not idp.profile_endpoint:
return
r = requests.get(
idp.profile_endpoint,
headers={"Authorization": f"Bearer {token}"},
)
user_data = r.json()
user_data = request_user_info(token, idp)

user = create_and_save_user(user_data, idp)
email = user.email
Expand Down Expand Up @@ -369,3 +365,22 @@ def delete_cached_bearer_token(token: str):

def delete_cached_jwt(email: str):
frappe.cache().delete_key(f"cc_jwt|{email}")


def request_user_info(token, idp=None):
if not idp:
idp = get_enabled_idp()
r = requests.get(
idp.profile_endpoint,
headers={"Authorization": f"Bearer {token}"},
)
return r.json()


def get_userinfo_from_idp(token, idp=None):
if not idp:
idp = get_enabled_idp()
if idp.authorization_type == "Introspection":
return request_user_info(token, idp)
elif idp.authorization_type == "JWT Verification":
return validate_signature(token, idp)
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class CFEUserClaim(Document):

def has_permission(doc, user=None):
user = user or frappe.session.user
return doc.user == user
return doc.user == user or "System Manager" in frappe.get_roles()


def get_permission_query_conditions(user):
Expand Down
47 changes: 47 additions & 0 deletions castlecraft/services/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from frappe.exceptions import DoesNotExistError
from frappe.oauth import get_userinfo

from castlecraft.auth import get_enabled_idp, get_userinfo_from_idp
from castlecraft.utils.format import respond_error

from castlecraft.auth import ( # isort: skip
Expand Down Expand Up @@ -55,3 +56,49 @@ def back_channel_logout(logout_token=None):
except Exception:
frappe.log_error(traceback.format_exc(), error_string)
respond_error(error_string, 400)


@frappe.whitelist(methods=["POST"])
def sync_claims():
"""
Sync user claims from Identity Provider
Method: POST
Parameters: None
Path: /api/method/castlecraft.services.oauth2.sync_claims
Error: 403 or 417
Response: CFE User Claim
"""

authorization_header = frappe.get_request_header( # noqa: E501
"Authorization", ""
).split(" ")

if len(authorization_header) == 2:
token = authorization_header[1]
idp = get_enabled_idp()
idp_user_claims = get_userinfo_from_idp(token, idp)
idp_claim_map = [field.claim for field in idp.user_fields]
claims = []
for claim in idp_claim_map:
claims.append(
{
"claim": claim,
"value": idp_user_claims.get(claim),
}
)

user = frappe.get_doc("User", frappe.session.user)
user_claim = None
try:
user_claim = frappe.get_doc("CFE User Claim", user.name)
except DoesNotExistError:
user_claim = frappe.get_doc({"doctype": "CFE User Claim"})
user_claim.set("claims", claims)
user_claim.save(ignore_permissions=True)
return user_claim.as_dict()

0 comments on commit 7940d2f

Please sign in to comment.