diff --git a/internal/api/v1beta1connect/preferences.go b/internal/api/v1beta1connect/preferences.go index eb3e2451a..c074c2936 100644 --- a/internal/api/v1beta1connect/preferences.go +++ b/internal/api/v1beta1connect/preferences.go @@ -185,12 +185,13 @@ func (h *ConnectHandler) CreateCurrentUserPreferences(ctx context.Context, req * return nil, err } + subjectID, _ := principal.ResolveSubject() var createdPreferences []preference.Preference for _, prefBody := range req.Msg.GetBodies() { pref, err := h.preferenceService.Create(ctx, preference.Preference{ Name: prefBody.GetName(), Value: prefBody.GetValue(), - ResourceID: principal.ID, + ResourceID: subjectID, ResourceType: schema.UserPrincipal, ScopeType: prefBody.GetScopeType(), ScopeID: prefBody.GetScopeId(), @@ -227,8 +228,9 @@ func (h *ConnectHandler) ListCurrentUserPreferences(ctx context.Context, req *co // 1. Scoped DB values (if scope provided) // 2. Global DB values // 3. Trait defaults + subjectID, _ := principal.ResolveSubject() prefs, err := h.preferenceService.LoadUserPreferences(ctx, preference.Filter{ - UserID: principal.ID, + UserID: subjectID, ScopeType: req.Msg.GetScopeType(), ScopeID: req.Msg.GetScopeId(), }) diff --git a/internal/api/v1beta1connect/user.go b/internal/api/v1beta1connect/user.go index eb99b37a9..d5c0b6bc5 100644 --- a/internal/api/v1beta1connect/user.go +++ b/internal/api/v1beta1connect/user.go @@ -343,8 +343,9 @@ func (h *ConnectHandler) UpdateCurrentUser(ctx context.Context, request *connect } } + subjectID, _ := principal.ResolveSubject() updatedUser, err := h.userService.Update(ctx, user.User{ - ID: principal.ID, + ID: subjectID, Title: request.Msg.GetBody().GetTitle(), Avatar: request.Msg.GetBody().GetAvatar(), Name: request.Msg.GetBody().GetName(), diff --git a/pkg/server/connect_interceptors/authorization.go b/pkg/server/connect_interceptors/authorization.go index ff99f49d7..7da16a343 100644 --- a/pkg/server/connect_interceptors/authorization.go +++ b/pkg/server/connect_interceptors/authorization.go @@ -57,6 +57,15 @@ func (a *AuthorizationInterceptor) WrapStreamingHandler(next connect.StreamingHa func (a *AuthorizationInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { + // block PAT from endpoints that require direct user session or are cross-org + if patDeniedEndpoints[req.Spec().Procedure] { + principal, err := a.h.GetLoggedInPrincipal(ctx) + if err == nil && principal.Type == schema.PATPrincipal { + return nil, connect.NewError(connect.CodePermissionDenied, + fmt.Errorf("this operation is not allowed with a personal access token")) + } + } + // check if authorization needs to be skipped if authorizationSkipEndpoints[req.Spec().Procedure] { return next(ctx, req) @@ -143,6 +152,17 @@ var authorizationSkipEndpoints = map[string]bool{ "/raystack.frontier.v1beta1.FrontierService/ListRolesForPAT": true, } +// patDeniedEndpoints lists endpoints that (org scoped) PATs cannot call. Will be called by SDK(UI) +var patDeniedEndpoints = map[string]bool{ + "/raystack.frontier.v1beta1.FrontierService/CreateOrganization": true, + "/raystack.frontier.v1beta1.FrontierService/JoinOrganization": true, + "/raystack.frontier.v1beta1.FrontierService/AcceptOrganizationInvitation": true, + "/raystack.frontier.v1beta1.FrontierService/ListSessions": true, + "/raystack.frontier.v1beta1.FrontierService/PingUserSession": true, + "/raystack.frontier.v1beta1.FrontierService/RevokeSession": true, + "/raystack.frontier.v1beta1.FrontierService/CreateCurrentUserPAT": true, +} + // authorizationValidationMap stores path to validation function var authorizationValidationMap = map[string]func(ctx context.Context, handler *v1beta1connect.ConnectHandler, req connect.AnyRequest) error{ // user