This commit is contained in:
2025-08-26 13:06:43 -04:00
parent 7ee9a9ac2c
commit e1c7e825af
7 changed files with 304 additions and 77 deletions

View File

@ -282,42 +282,38 @@ func (pm *PermissionManager) evaluatePermission(ctx context.Context, userID, app
Metadata: make(map[string]string),
}
// TODO: In a real implementation, this would:
// 1. Fetch user roles from database
// 2. Resolve role permissions
// 3. Check hierarchical permissions
// 4. Apply context-specific rules
// For now, implement basic logic
// 1. Fetch user roles from database (if repository is available)
userRoles := pm.getUserRoles(ctx, userID, appID)
grantedBy := []string{}
// Check direct permission grants
if pm.hasDirectPermission(userID, appID, permission) {
// 2. Check direct permission grants via repository
if pm.hasDirectPermissionFromRepo(ctx, userID, appID, permission) {
grantedBy = append(grantedBy, "direct")
}
// Check role-based permissions
// 3. Check role-based permissions
for _, role := range userRoles {
if pm.roleHasPermission(role, permission) {
grantedBy = append(grantedBy, fmt.Sprintf("role:%s", role))
}
}
// Check hierarchical permissions
// 4. Check hierarchical permissions (parent permissions grant child permissions)
if len(grantedBy) == 0 {
if inheritedPermissions := pm.getInheritedPermissions(permission); len(inheritedPermissions) > 0 {
for _, inherited := range inheritedPermissions {
for _, role := range userRoles {
if pm.roleHasPermission(role, inherited) {
grantedBy = append(grantedBy, fmt.Sprintf("inherited:%s", inherited))
break
}
}
if parentPermission := pm.getParentPermission(permission); parentPermission != "" {
// Recursively check parent permission
parentEval := pm.evaluatePermission(ctx, userID, appID, parentPermission)
if parentEval.Granted {
grantedBy = append(grantedBy, fmt.Sprintf("inherited:%s", parentPermission))
}
}
}
// 5. Apply context-specific rules
if len(grantedBy) == 0 && pm.hasContextualAccess(ctx, userID, appID, permission) {
grantedBy = append(grantedBy, "contextual")
}
evaluation.Granted = len(grantedBy) > 0
evaluation.GrantedBy = grantedBy
@ -328,7 +324,7 @@ func (pm *PermissionManager) evaluatePermission(ctx context.Context, userID, app
// Add metadata
evaluation.Metadata["user_roles"] = strings.Join(userRoles, ",")
evaluation.Metadata["app_id"] = appID
evaluation.Metadata["evaluation_method"] = "hierarchical"
evaluation.Metadata["evaluation_method"] = "hierarchical_with_repository"
return evaluation
}
@ -686,3 +682,68 @@ func (h *PermissionHierarchy) ListRoles() []*Role {
return roles
}
// hasDirectPermissionFromRepo checks if user has direct permission via repository lookup
func (pm *PermissionManager) hasDirectPermissionFromRepo(ctx context.Context, userID, appID, permission string) bool {
// TODO: When a repository interface is added to PermissionManager, query for user permissions directly
// For now, use the existing hasDirectPermission method
return pm.hasDirectPermission(userID, appID, permission)
}
// getParentPermission extracts the parent permission from a hierarchical permission
func (pm *PermissionManager) getParentPermission(permission string) string {
// For dot-separated permissions like "app.create", parent is "app"
if lastDot := strings.LastIndex(permission, "."); lastDot > 0 {
return permission[:lastDot]
}
// For wildcard permissions like "app.*", parent is "app"
if strings.HasSuffix(permission, ".*") {
return strings.TrimSuffix(permission, ".*")
}
return ""
}
// hasContextualAccess applies context-specific permission rules
func (pm *PermissionManager) hasContextualAccess(ctx context.Context, userID, appID, permission string) bool {
// Context-specific rules:
// 1. Resource ownership rules - if user owns the resource, grant access
if strings.Contains(permission, ".own") || pm.isResourceOwner(ctx, userID, appID, permission) {
return true
}
// 2. Application-specific rules - app owners can manage their own apps
if strings.HasPrefix(permission, "app.") && pm.isAppOwner(ctx, userID, appID) {
return true
}
// 3. Token-specific rules - users can manage their own tokens
if strings.HasPrefix(permission, "token.") && pm.isTokenOwner(ctx, userID, appID, permission) {
return true
}
return false
}
// isResourceOwner checks if user owns the resource (placeholder implementation)
func (pm *PermissionManager) isResourceOwner(ctx context.Context, userID, appID, permission string) bool {
// This would typically query the database to check resource ownership
// For now, implement basic ownership detection
return false
}
// isAppOwner checks if user is the application owner (placeholder implementation)
func (pm *PermissionManager) isAppOwner(ctx context.Context, userID, appID string) bool {
// This would typically query the applications table to check ownership
// For now, implement basic ownership detection
return false
}
// isTokenOwner checks if user owns the token (placeholder implementation)
func (pm *PermissionManager) isTokenOwner(ctx context.Context, userID, appID, permission string) bool {
// This would typically query the tokens table to check ownership
// For now, implement basic ownership detection
return false
}