Sharing Settings (ACL Management)

Sharing Settings (ACL Management) in Synapse

Access Control Lists (ACLs) in Synapse determine who can access your data and what actions they can perform. By default, entities inherit permissions from their parent container, but you can create local sharing settings to provide more granular control over access to specific folders and files.

This tutorial demonstrates how to use synapser to manage permissions and sharing settings for your Synapse entities.

Read more about Access Control

Tutorial Purpose

In this tutorial you will:

  1. Retrieve an existing project or create a new one
  2. Create a main folder to set custom sharing settings
  3. Examine current permissions using synGetPermissions() and synGetAcl()
  4. Get ACL for specific principal using synGetAcl()
  5. Set specific permissions using synSetPermissions()
  6. Create a sub-folder with different permissions than its parent
  7. List all ACLs in a hierarchy using synListAcl()
  8. Manage permissions with advanced options
  9. Remove permissions and delete ACLs using synDeletePermissions()

Prerequisites

  • Make sure that you have completed the Installation and Authentication setup.
  • IMPORTANT: You must set a valid PRINCIPAL_ID in the tutorial script before running it. This should be a Synapse user ID or team ID that you want to grant permissions to.
  • You must have a Project created and replace the one used in this tutorial.

Understanding Permission Types

Before we begin, it’s important to understand the different permission types available in Synapse:

  • READ: View entity metadata and download files
  • DOWNLOAD: Download files (requires READ)
  • UPDATE: Modify entity metadata and upload new file versions
  • CREATE: Create new entities within containers
  • DELETE: Delete entities
  • CHANGE_PERMISSIONS: Modify ACL permissions
  • CHANGE_SETTINGS: Modify entity settings
  • MODERATE: Moderate forum discussions (for projects)

Special Principal IDs

  • 273948: All authenticated Synapse users
  • 273949: Public access (anyone on the internet)
  • Specific user ID: Individual Synapse user (e.g., 123456)
  • Team ID: Synapse team

Permission Inheritance and Benefactors

Understanding how permissions work in Synapse is crucial for effective ACL management:

Benefactor Concept

Every entity in Synapse has a benefactor - the entity from which it inherits its permissions. When checking permissions for an entity:

  1. Start at the current entity: Check if it has local sharing settings (its own ACL)
  2. Traverse up the hierarchy: If no local ACL exists, continue checking parent containers
  3. Find the benefactor: The search continues up the tree until an entity with permissions/ACL is found, or until reaching the Project level
  4. Inherit permissions: The entity inherits all permissions from its benefactor

Default Inheritance Behavior

  • New Projects: Become their own benefactor with default permissions
  • New Folders/Files: Initially inherit from their containing Project or parent Folder
  • Local ACLs: When you set local sharing settings, the entity becomes its own benefactor

Applying Permissions to Other Entities

While this tutorial focuses on Folders, you can apply the same permission management functions (synGetPermissions(), synGetAcl(), synSetPermissions(), synListAcl(), and synDeletePermissions()) to other Synapse entities including:

  • Projects: Top-level containers that are typically their own benefactors
  • Files: Individual data files that can have their own sharing settings
  • Tables: Structured data entities with their own permission requirements
  • Views: Query-based entities that can have custom access controls

The inheritance and benefactor concepts apply consistently across all entity types in Synapse.

1. Set Up and Get Project

IMPORTANT: Before running the tutorial, you MUST edit the script to set a valid PRINCIPAL_ID.

library(synapser)

# REQUIRED: Set this to the Synapse user ID or team ID you want to grant permissions to
# Do NOT leave this as NULL - the script will not work properly
PRINCIPAL_ID <- NULL # Replace with actual user/team ID, e.g. 273948L

if (is.null(PRINCIPAL_ID)) {
  stop(
    "You must set PRINCIPAL_ID to a valid Synapse user ID or team ID before running this script. ",
    "Examples: ###### (user ID), 273948 (authenticated users), 273949 (public)"
  )
}

# Helper to print a list of permissions on one line
format_permissions <- function(x) paste(unlist(x), collapse = ", ")

synLogin()

# Step 1: Get or create a project for this tutorial
cat("=== Step 1: Getting project ===\n")
project <- Project(name = "My uniquely named project about Alzheimer's Disease") |> synGet()

2. Create a main folder to set custom sharing settings

# Step 2: Create a main folder to set custom sharing settings
cat("\n=== Step 2: Creating main to set custom permissions ===\n")
main_folder <- Folder(
  name = "Research Data",
  description = "Main folder for research data with custom sharing settings",
  parent_id = project$id
) |> synStore()
cat(sprintf("Created main folder: %s (ID: %s)\n", main_folder$name, main_folder$id))

3. Examine Current Permissions

The synGetPermissions() function returns the permissions that the current user has on an entity

# Step 3: Demonstrate synGetPermissions() - Get current user's permissions
cat("\n=== Step 3: Getting current user's permissions ===\n")
permissions <- main_folder |> synGetPermissions()
cat(sprintf(
  "Current user permissions on main folder: %s\n",
  format_permissions(permissions$access_types)
))

You’ll notice the output looks like:

=== Step 3: Getting current user's permissions ===
Current user permissions on main folder: READ, UPDATE, CREATE, DELETE, DOWNLOAD, MODERATE, CHANGE_PERMISSIONS, CHANGE_SETTINGS

4. Get ACL for Specific Principal

The synGetAcl() function gets the specific permissions for a given principal (user or team):

# Step 4: Demonstrate synGetAcl() - Get ACL for specific principal
cat("\n=== Step 4: Getting ACL for specific principal ===\n")
# First check what permissions the principal currently has (likely inherited from project)
current_acl <- main_folder |> synGetAcl(principal_id = PRINCIPAL_ID, check_benefactor = TRUE)
cat(sprintf(
  "Principal %s current permissions (including inherited): %s\n",
  PRINCIPAL_ID, format_permissions(current_acl)
))

# Check ACL only on the folder itself (not inherited)
folder_only_acl <- main_folder |> synGetAcl(principal_id = PRINCIPAL_ID, check_benefactor = FALSE)
cat(sprintf(
  "Principal %s permissions on folder only: %s\n",
  PRINCIPAL_ID, format_permissions(folder_only_acl)
))

Depending on if you’ve already given permissions to given user/team you may see different results in the output.

You’ll notice the output looks like:

=== Step 4: Getting ACL for specific principal ===
Principal ######## current permissions (including inherited):
Principal ######## permissions on folder only:

5. Set Custom Permissions

Use synSetPermissions() to grant specific permissions to a user or team:

# Step 5: Demonstrate synSetPermissions() - Set specific permissions for the main folder
cat("\n=== Step 5: Setting permissions on main folder ===\n")
main_folder_permissions <- list("READ", "DOWNLOAD")
main_folder |> synSetPermissions(
  principal_id = PRINCIPAL_ID,
  access_type = main_folder_permissions,
  modify_benefactor = FALSE, # Create local ACL for this folder
  overwrite = TRUE
)
cat(sprintf(
  "Set permissions for principal %s on main folder: %s\n",
  PRINCIPAL_ID, format_permissions(main_folder_permissions)
))

# Verify the permissions were set
new_acl <- main_folder |> synGetAcl(principal_id = PRINCIPAL_ID, check_benefactor = FALSE)
cat(sprintf("Verified new permissions: %s\n", format_permissions(new_acl)))

You’ll notice the output looks like:

=== Step 5: Setting permissions on main folder ===
[WARNING] Creating an ACL for entity syn#######, which formerly inherited access control from a benefactor entity, "My uniquely named project about Alzheimer's Disease" (syn########).

Set permissions for principal ####### on main folder: READ, DOWNLOAD
Verified new permissions: DOWNLOAD, READ

6. Create Sub-folder with Different Permissions

Create a sub-folder and give it more restrictive permissions than its parent:

# Step 6: Create a sub-folder with different sharing settings
cat("\n=== Step 6: Creating sub-folder with different permissions ===\n")
sub_folder <- Folder(
  name = "Sensitive Analysis",
  description = "Sub-folder with more restrictive permissions",
  parent_id = main_folder$id
) |> synStore()
cat(sprintf("Created sub-folder: %s (ID: %s)\n", sub_folder$name, sub_folder$id))

# Set more restrictive permissions on the sub-folder
sub_folder_permissions <- list("READ") # More restrictive - only read access
sub_folder |> synSetPermissions(
  principal_id = PRINCIPAL_ID,
  access_type = sub_folder_permissions,
  modify_benefactor = FALSE,
  overwrite = TRUE
)
cat(sprintf(
  "Set more restrictive permissions for principal %s on sub-folder: %s\n",
  PRINCIPAL_ID, format_permissions(sub_folder_permissions)
))

You’ll notice the output looks like:

=== Step 6: Creating sub-folder with different permissions ===
Created sub-folder: Sensitive Analysis (ID: syn#######)
[WARNING] Creating an ACL for entity syn#######, which formerly inherited access control from a benefactor entity, "Research Data" (syn#######).

Set more restrictive permissions for principal ####### on sub-folder: READ

7. List All ACLs

Use synListAcl() to see all the permissions in your hierarchy. By specifying the log_tree = TRUE argument for the function we can get an ascii tree representation of the ACLs on the project. Alternatively you will also be able to loop over the data.

# Step 7: Demonstrate synListAcl() - List all ACLs
cat("\n=== Step 7: Listing ACLs ===\n")

# List ACLs recursively for main folder and all contents
cat("Folder ACL:\n")
recursive_acl_result <- main_folder |> synListAcl(
  recursive = TRUE,
  include_container_content = TRUE,
  log_tree = TRUE # This will also log the tree structure
)
cat(sprintf("Folder (%s) ACL entries:\n", main_folder$id))
for (entity_acl in recursive_acl_result$all_entity_acls) {
  cat(sprintf("\nEntity %s ACL:\n", entity_acl$entity_id))
  for (acl_entry in entity_acl$acl_entries) {
    cat(sprintf(
      "  Principal %s: %s\n",
      acl_entry$principal_id, format_permissions(acl_entry$permissions)
    ))
  }
}

You’ll notice the output looks like:

=== Step 7: Listing ACLs ===
ACL Tree Structure:
🔍 Legend:
  🔒 = No local ACL (inherits from parent)
  🔑 = Local ACL (custom permissions)

└── 🔑 Research Data (syn#######) [Folder]
       └── user_name_1 (#######): CHANGE_PERMISSIONS, DOWNLOAD, CHANGE_SETTINGS, MODERATE, READ, DELETE, CREATE, UPDATE
       └── team_name_1 (#######): DOWNLOAD, READ
    └── 🔑 Sensitive Analysis (syn#######) [Folder]
           └── user_name_1 (#######): CHANGE_PERMISSIONS, UPDATE, READ, DELETE, MODERATE, CHANGE_SETTINGS, DOWNLOAD, CREATE
           └── team_name_1 (#######): READ
Folder (syn#######) ACL entries:

Entity syn####### ACL:
  Principal #######: CHANGE_PERMISSIONS, DOWNLOAD, CHANGE_SETTINGS, MODERATE, READ, DELETE, CREATE, UPDATE
  Principal #######: DOWNLOAD, READ

Entity syn####### ACL:
  Principal #######: CHANGE_PERMISSIONS, UPDATE, READ, DELETE, MODERATE, CHANGE_SETTINGS, DOWNLOAD, CREATE
  Principal #######: READ

8. Advanced Permission Management

Using overwrite = FALSE will allow you to add Permissions Non-destructively.

Note: The default behavior is overwrite = TRUE which will replace the permissions for the given Principal.

# Step 8: Demonstrate additional synSetPermissions() options
cat("\n=== Step 8: Demonstrating additional permission options ===\n")

# Add permissions non-destructively (overwrite = FALSE)
cat("Adding additional permissions non-destructively...\n")
main_folder |> synSetPermissions(
  principal_id = PRINCIPAL_ID,
  access_type = list("UPDATE"), # Add UPDATE permission
  overwrite = FALSE # Don't overwrite existing permissions
)

# Verify the permissions were added
updated_acl <- main_folder |> synGetAcl(principal_id = PRINCIPAL_ID)
cat(sprintf("Updated permissions after adding UPDATE: %s\n", format_permissions(updated_acl)))

You’ll notice the output looks like:

=== Step 8: Demonstrating additional permission options ===
Adding additional permissions non-destructively...
Updated permissions after adding UPDATE: READ, DOWNLOAD, UPDATE

9. Remove Permissions

Remove permissions for a specific principal by setting an empty access type list:

# Step 9: Demonstrate permission removal using synSetPermissions() with an empty list
cat("\n=== Step 9: Removing specific permissions ===\n")
cat(sprintf(
  "Before removal - Principal %s permissions: %s\n",
  PRINCIPAL_ID, format_permissions(main_folder |> synGetAcl(principal_id = PRINCIPAL_ID))
))

# Remove permissions for specific principal by setting an empty access_type
main_folder |> synSetPermissions(
  principal_id = PRINCIPAL_ID,
  access_type = list(), # Empty list removes all permissions for this principal
  overwrite = TRUE
)

removed_acl <- main_folder |> synGetAcl(principal_id = PRINCIPAL_ID)
cat(sprintf(
  "After removal - Principal %s permissions: %s\n",
  PRINCIPAL_ID, format_permissions(removed_acl)
))

You’ll notice the output looks like:

=== Step 9: Removing specific permissions ===
Before removal - Principal ####### permissions: READ, DOWNLOAD, UPDATE
After removal - Principal ####### permissions:

10. Delete Entire ACLs

Use synDeletePermissions() to remove entire ACLs and revert to inheritance:

# Step 10: Demonstrate synDeletePermissions() with dry run
cat("\n=== Step 10: Demonstrating synDeletePermissions() ===\n")

# First, let's set some permissions back so we have something to delete
sub_folder |> synSetPermissions(principal_id = PRINCIPAL_ID, access_type = list("READ", "UPDATE"))
cat("Re-added permissions to sub-folder for demonstration\n")

# Dry run - see what would be deleted without actually deleting
cat("\nDry run - showing what would be deleted:\n")
sub_folder |> synDeletePermissions(dry_run = TRUE, show_acl_details = TRUE)

# Actually delete the permissions (this will make the sub-folder inherit from parent)
cat("\nActually deleting ACL from sub-folder:\n")
sub_folder |> synDeletePermissions(include_self = TRUE)

# Verify inheritance
inherited_acl <- sub_folder |> synGetAcl(principal_id = PRINCIPAL_ID)
cat(sprintf("Sub-folder now inherits permissions: %s\n", format_permissions(inherited_acl)))

You’ll notice the output looks like:

=== Step 10: Demonstrating synDeletePermissions() ===
Re-added permissions to sub-folder for demonstration

Dry run - showing what would be deleted:
=== DRY RUN: Permission Deletion Impact Analysis ===
📊 Summary: 1 entities with local ACLs to delete, 1 entities will change inheritance

🔍 Legend:
  ⚠️  = Local ACL will be deleted
  🚫 = Local ACL will NOT be deleted
  ↗️ = Currently inherits permissions
  🔒 = No local ACL (inherits from parent)
  🔑 = Permission that will be removed
  📍 = New inheritance after deletion

Sensitive Analysis (syn#######) [Folder] ⚠️  WILL DELETE LOCAL ACL → Will inherit from syn#######
├── 🔑 user_name_1 (#######): ['CHANGE_SETTINGS', 'MODERATE', 'DELETE', 'READ', 'DOWNLOAD', 'UPDATE', 'CHANGE_PERMISSIONS', 'CREATE'] → WILL BE REMOVED
└── 🔑 team_name_1 (#######): ['READ', 'UPDATE'] → WILL BE REMOVED
=== End of Dry Run Analysis ===

Actually deleting ACL from sub-folder:
Sub-folder now inherits permissions:

11. Final Overview

Get a complete view of your permission structure:

# Step 11: Final ACL overview
cat("\n=== Step 11: Final ACL overview ===\n")
final_overview <- main_folder |> synListAcl(
  recursive = TRUE, include_container_content = TRUE, log_tree = TRUE
)

You’ll notice the output looks like:

=== Step 11: Final ACL overview ===
ACL Tree Structure:
🔍 Legend:
  🔒 = No local ACL (inherits from parent)
  🔑 = Local ACL (custom permissions)

└── 🔑 Research Data (syn#######) [Folder]
       └── user_name_1 (#######): CHANGE_PERMISSIONS, DOWNLOAD, CHANGE_SETTINGS, MODERATE, READ, DELETE, CREATE, UPDATE

Key Concepts Covered

Inheritance vs Local ACLs

  • Inheritance: Entities inherit permissions from their parent by default
  • Local ACLs: Create specific permissions that override inheritance
  • Benefactor: The entity from which permissions are inherited

Permission Management Functions

  • synGetPermissions(): Get current user’s effective permissions
  • synGetAcl(): Get specific principal’s permissions on an entity
  • synSetPermissions(): Set permissions for a principal
  • synListAcl(): List all ACLs in a hierarchy
  • synDeletePermissions(): Remove ACLs and revert to inheritance

Best Practices

  1. Use inheritance when possible for easier management
  2. Create local ACLs only when you need different permissions than the parent
  3. Use teams for managing group permissions
  4. Test with dry_run = TRUE before deleting permissions
  5. Use synListAcl() to audit your permission structure

Common Use Cases

Research Collaboration

  • Give collaborators READ/DOWNLOAD on data folders
  • Restrict UPDATE/DELETE to data owners
  • Use teams for lab group permissions

Data Sharing

  • Use authenticated users (273948) for internal sharing
  • Use public access (273949) for open data
  • Create different permission levels for different data sensitivity

Hierarchical Access

  • Set broad permissions at project level
  • Override with restrictive permissions for sensitive sub-folders
  • Use synDeletePermissions() to revert to parent permissions when needed