Merged in feature/consolidate_permissions (pull request #196)

Feature consolidate permissions
This commit is contained in:
Philipp Czora
2019-02-20 14:20:03 +00:00
26 changed files with 243 additions and 87 deletions

View File

@@ -826,7 +826,7 @@
<jetty.maven.version>9.4.14.v20181114</jetty.maven.version> <jetty.maven.version>9.4.14.v20181114</jetty.maven.version>
<!-- security libraries --> <!-- security libraries -->
<ssp.version>1.1.0</ssp.version> <ssp.version>1.2.0</ssp.version>
<shiro.version>1.4.0</shiro.version> <shiro.version>1.4.0</shiro.version>
<!-- repository libraries --> <!-- repository libraries -->

View File

@@ -22,7 +22,8 @@ import com.github.sdorra.ssp.StaticPermissions;
@StaticPermissions( @StaticPermissions(
value = "configuration", value = "configuration",
permissions = {"read", "write"}, permissions = {"read", "write"},
globalPermissions = {"list"} globalPermissions = {"list"},
custom = true, customGlobal = true
) )
public interface Configuration extends PermissionObject { public interface Configuration extends PermissionObject {
} }

View File

@@ -61,7 +61,11 @@ import java.util.List;
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
@StaticPermissions(value = "group", globalPermissions = {"create", "list", "autocomplete"}) @StaticPermissions(
value = "group",
globalPermissions = {"create", "list", "autocomplete"},
custom = true, customGlobal = true
)
@XmlRootElement(name = "groups") @XmlRootElement(name = "groups")
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class Group extends BasicPropertiesAware public class Group extends BasicPropertiesAware

View File

@@ -61,7 +61,8 @@ import java.util.List;
value = "plugin", value = "plugin",
generatedClass = "PluginPermissions", generatedClass = "PluginPermissions",
permissions = {}, permissions = {},
globalPermissions = { "read", "manage" } globalPermissions = { "read", "manage" },
custom = true, customGlobal = true
) )
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "plugin-information") @XmlRootElement(name = "plugin-information")

View File

@@ -62,7 +62,8 @@ import java.util.Set;
*/ */
@StaticPermissions( @StaticPermissions(
value = "repository", value = "repository",
permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"} permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"},
custom = true, customGlobal = true
) )
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "repositories") @XmlRootElement(name = "repositories")

View File

@@ -6,7 +6,8 @@ import com.github.sdorra.ssp.StaticPermissions;
@StaticPermissions( @StaticPermissions(
value = "permission", value = "permission",
permissions = {}, permissions = {},
globalPermissions = {"list", "read", "assign"} globalPermissions = {"list", "read", "assign"},
custom = true, customGlobal = true
) )
public interface Permission extends PermissionObject { public interface Permission extends PermissionObject {
} }

View File

@@ -59,7 +59,9 @@ import java.security.Principal;
@StaticPermissions( @StaticPermissions(
value = "user", value = "user",
globalPermissions = {"create", "list", "autocomplete"}, globalPermissions = {"create", "list", "autocomplete"},
permissions = {"read", "modify", "delete", "changePassword"}) permissions = {"read", "modify", "delete", "changePassword"},
custom = true, customGlobal = true
)
@XmlRootElement(name = "users") @XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject, ReducedModelObject public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject, ReducedModelObject

View File

@@ -34,10 +34,10 @@
<permissions> <permissions>
<permission> <permission>
<value>configuration:read:git</value> <value>configuration:read,write:git</value>
</permission> </permission>
<permission> <permission>
<value>configuration:write:git</value> <value>repository:git:*</value>
</permission> </permission>
</permissions> </permissions>

View File

@@ -0,0 +1,7 @@
<repository-permissions>
<verbs>
<verb>git</verb>
</verbs>
<roles>
</roles>
</repository-permissions>

View File

@@ -39,18 +39,28 @@
}, },
"permissions" : { "permissions" : {
"configuration": { "configuration": {
"read": { "read,write": {
"git": { "git": {
"displayName": "Git Konfiguration lesen", "displayName": "Git Konfiguration ändern",
"description": "Darf die git Konfiguration lesen."
}
},
"write": {
"git": {
"displayName": "Git Konfiguration schreiben",
"description": "Darf die git Konfiguration verändern." "description": "Darf die git Konfiguration verändern."
} }
} }
},
"repository": {
"git": {
"*": {
"displayName": "Repository-spezifische Git Konfiguration ändern",
"description": "Darf die git Konfiguration für alle Repositories verändern."
}
}
}
},
"verbs": {
"repository": {
"git": {
"displayName": "Git konfigurieren",
"description": "Darf die git Konfiguration für dieses Repository verändern."
}
} }
} }
} }

View File

@@ -39,18 +39,28 @@
}, },
"permissions" : { "permissions" : {
"configuration": { "configuration": {
"read": { "read,write": {
"git": { "git": {
"displayName": "Read git configuration", "displayName": "Modify git configuration",
"description": "May read the git configuration"
}
},
"write": {
"git": {
"displayName": "Write git configuration",
"description": "May change the git configuration" "description": "May change the git configuration"
} }
} }
},
"repository": {
"git": {
"*": {
"displayName": "Modify repository specific git configuration",
"description": "May change the git configuration for repositories"
}
}
}
},
"verbs": {
"repository": {
"git": {
"displayName": "configure Git",
"description": "May change the git configuration for this repository"
}
} }
} }
} }

View File

@@ -34,10 +34,10 @@
<permissions> <permissions>
<permission> <permission>
<value>configuration:read:hg</value> <value>configuration:read,write:hg</value>
</permission> </permission>
<permission> <permission>
<value>configuration:write:hg</value> <value>repository:hg:*</value>
</permission> </permission>
</permissions> </permissions>

View File

@@ -0,0 +1,7 @@
<repository-permissions>
<verbs>
<verb>hg</verb>
</verbs>
<roles>
</roles>
</repository-permissions>

View File

@@ -31,18 +31,28 @@
}, },
"permissions" : { "permissions" : {
"configuration": { "configuration": {
"read": { "read,write": {
"hg": { "hg": {
"displayName": "Mercurial Konfiguration lesen", "displayName": "Mercurial Konfiguration ändern",
"description": "Darf die Mercurial Konfiguration lesen"
}
},
"write": {
"hg": {
"displayName": "Mercurial Konfiguration schreiben",
"description": "Darf die Mercurial Konfiguration verändern" "description": "Darf die Mercurial Konfiguration verändern"
} }
} }
},
"repository": {
"hg": {
"*": {
"displayName": "Repository-spezifische Mercurial Konfiguration ändern",
"description": "Darf die Mercurial Konfiguration für alle Repositories verändern."
}
}
}
},
"verbs": {
"repository": {
"hg": {
"displayName": "Mercurial konfigurieren",
"description": "Darf die Mercurial Konfiguration für dieses Repository verändern."
}
} }
} }
} }

View File

@@ -31,18 +31,28 @@
}, },
"permissions" : { "permissions" : {
"configuration": { "configuration": {
"read": { "read,write": {
"hg": { "hg": {
"displayName": "Read Mercurial configuration", "displayName": "Modify Mercurial configuration",
"description": "May read the Mercurial configuration"
}
},
"write": {
"hg": {
"displayName": "Write Mercurial configuration",
"description": "May change the Mercurial configuration" "description": "May change the Mercurial configuration"
} }
} }
},
"repository": {
"hg": {
"*": {
"displayName": "Modify repository specific Mercurial configuration",
"description": "May change the Mercurial configuration for repositories"
}
}
}
},
"verbs": {
"repository": {
"hg": {
"displayName": "configure Mercurial",
"description": "May change the Mercurial configuration for this repository"
}
} }
} }
} }

View File

@@ -34,10 +34,10 @@
<permissions> <permissions>
<permission> <permission>
<value>configuration:read:svn</value> <value>configuration:read,write:svn</value>
</permission> </permission>
<permission> <permission>
<value>configuration:write:svn</value> <value>repository:svn:*</value>
</permission> </permission>
</permissions> </permissions>

View File

@@ -0,0 +1,7 @@
<repository-permissions>
<verbs>
<verb>svn</verb>
</verbs>
<roles>
</roles>
</repository-permissions>

View File

@@ -25,18 +25,28 @@
}, },
"permissions": { "permissions": {
"configuration": { "configuration": {
"read": { "read,write": {
"svn": { "svn": {
"displayName": "Subversion Konfiguration lesen", "displayName": "Subversion Konfiguration ändern",
"description": "Darf die Subversion Konfiguration lesen"
}
},
"write": {
"svn": {
"displayName": "Subversion Konfiguration schreiben",
"description": "Darf die Subversion Konfiguration verändern" "description": "Darf die Subversion Konfiguration verändern"
} }
} }
},
"repository": {
"svn": {
"*": {
"displayName": "Repository-spezifische Subversion Konfiguration ändern",
"description": "Darf die Subversion Konfiguration für alle Repositories verändern."
}
}
}
},
"verbs": {
"repository": {
"svn": {
"displayName": "Subversion konfigurieren",
"description": "Darf die Subversion Konfiguration für dieses Repository verändern."
}
} }
} }
} }

View File

@@ -25,18 +25,28 @@
}, },
"permissions": { "permissions": {
"configuration": { "configuration": {
"read": { "read,write": {
"svn": { "svn": {
"displayName": "Read Subversion configuration", "displayName": "Modify Subversion configuration",
"description": "May read the Subversion configuration" "description": "May modify the Subversion configuration"
} }
}, }
"write": { },
"svn": { "repository": {
"displayName": "Write Subversion configuration", "svn": {
"description": "May change the Subversion configuration" "*": {
"displayName": "Modify repository specific Subversion configuration",
"description": "May change the Subversion configuration for repositories"
} }
} }
} }
},
"verbs": {
"repository": {
"svn": {
"displayName": "configure Subversion",
"description": "May change the Subversion configuration for this repository"
}
}
} }
} }

View File

@@ -18,6 +18,7 @@ import java.util.Collection;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.util.Collections.unmodifiableCollection; import static java.util.Collections.unmodifiableCollection;
@@ -63,7 +64,7 @@ public class RepositoryPermissionProvider {
RepositoryPermissionsRoot repositoryPermissionsRoot = parsePermissionDescriptor(context, descriptorUrl); RepositoryPermissionsRoot repositoryPermissionsRoot = parsePermissionDescriptor(context, descriptorUrl);
availableVerbs.addAll(repositoryPermissionsRoot.verbs.verbs); availableVerbs.addAll(repositoryPermissionsRoot.verbs.verbs);
availableRoles.addAll(repositoryPermissionsRoot.roles.roles); mergeRolesInto(availableRoles, repositoryPermissionsRoot.roles.roles);
} }
} catch (IOException ex) { } catch (IOException ex) {
logger.error("could not read permission descriptors", ex); logger.error("could not read permission descriptors", ex);
@@ -75,7 +76,22 @@ public class RepositoryPermissionProvider {
return new AvailableRepositoryPermissions(availableVerbs, availableRoles); return new AvailableRepositoryPermissions(availableVerbs, availableRoles);
} }
@SuppressWarnings("unchecked") private static void mergeRolesInto(Collection<RoleDescriptor> targetRoles, List<RoleDescriptor> additionalRoles) {
additionalRoles.forEach(r -> addOrMergeInto(targetRoles, r));
}
private static void addOrMergeInto(Collection<RoleDescriptor> targetRoles, RoleDescriptor additionalRole) {
Optional<RoleDescriptor> existingRole = targetRoles
.stream()
.filter(r -> r.name.equals(additionalRole.name))
.findFirst();
if (existingRole.isPresent()) {
existingRole.get().verbs.verbs.addAll(additionalRole.verbs.verbs);
} else {
targetRoles.add(additionalRole);
}
}
private static RepositoryPermissionsRoot parsePermissionDescriptor(JAXBContext context, URL descriptorUrl) { private static RepositoryPermissionsRoot parsePermissionDescriptor(JAXBContext context, URL descriptorUrl) {
try { try {
RepositoryPermissionsRoot descriptorWrapper = RepositoryPermissionsRoot descriptorWrapper =

View File

@@ -40,7 +40,7 @@
<value>repository:read,pull,push:*</value> <value>repository:read,pull,push:*</value>
</permission> </permission>
<permission> <permission>
<value>repository:*:*</value> <value>repository:*</value>
</permission> </permission>
<permission> <permission>
<value>repository:create</value> <value>repository:create</value>
@@ -51,5 +51,14 @@
<permission> <permission>
<value>group:*</value> <value>group:*</value>
</permission> </permission>
<permission>
<value>configuration:list</value>
</permission>
<permission>
<value>configuration:read,write:global</value>
</permission>
<permission>
<value>configuration:read,write:*</value>
</permission>
</permissions> </permissions>

View File

@@ -7,7 +7,6 @@
<verb>push</verb> <verb>push</verb>
<verb>permissionRead</verb> <verb>permissionRead</verb>
<verb>permissionWrite</verb> <verb>permissionWrite</verb>
<verb>healthCheck</verb>
<verb>*</verb> <verb>*</verb>
</verbs> </verbs>
<roles> <roles>
@@ -26,12 +25,6 @@
<verb>push</verb> <verb>push</verb>
</verbs> </verbs>
</role> </role>
<role>
<name>HEALTH</name>
<verbs>
<verb>healthCheck</verb>
</verbs>
</role>
<role> <role>
<name>OWNER</name> <name>OWNER</name>
<verbs> <verbs>

View File

@@ -14,10 +14,8 @@
} }
}, },
"*": { "*": {
"*": { "displayName": "Alle Repositories besitzen (Owner)",
"displayName": "Alle Repositories besitzen (Owner)", "description": "Darf alle Repositories lesen, klonen, schreiben, konfigurieren und löschen."
"description": "Darf alle Repositories lesen, klonen, schreiben, konfigurieren und löschen."
}
}, },
"create": { "create": {
"displayName": "Repositories erstellen", "displayName": "Repositories erstellen",
@@ -36,6 +34,22 @@
"description": "Darf Gruppen administrieren." "description": "Darf Gruppen administrieren."
} }
}, },
"configuration": {
"list": {
"displayName": "Basis für Administration",
"description": "Voraussetzung für alle anderen Administrationsberechtigungen. Ohne diese Berechtigung wird keine Administrationsansicht gezeigt."
},
"read,write": {
"global": {
"displayName": "zentrale Konfiguration",
"description": "Darf die Konfiguration des SCM-Manager anpassen"
},
"*": {
"displayName": "zentrale + Plugin Konfiguration",
"description": "Darf die Konfiguration des SCM-Manager und aller Plugins anpassen"
}
}
},
"unknown": "Unbekannte Berechtigung" "unknown": "Unbekannte Berechtigung"
}, },
"verbs": { "verbs": {
@@ -68,10 +82,6 @@
"displayName": "Berechtigungen modifizieren", "displayName": "Berechtigungen modifizieren",
"description": "Darf die Berechtigungen des Repository bearbeiten." "description": "Darf die Berechtigungen des Repository bearbeiten."
}, },
"healthCheck": {
"displayName": "Health Check",
"description": "Darf den Repository Health Check ausführen."
},
"*": { "*": {
"displayName": "Alle Repository Rechte", "displayName": "Alle Repository Rechte",
"description": "Darf im Repository Kontext alles ausführen. Dies beinhaltet alle Repository Berechtigungen." "description": "Darf im Repository Kontext alles ausführen. Dies beinhaltet alle Repository Berechtigungen."

View File

@@ -14,10 +14,8 @@
} }
}, },
"*": { "*": {
"*": { "displayName": "Own all repositories",
"displayName": "Own all repositories", "description": "May see, clone, push to, configure and delete all repositories"
"description": "May see, clone, push to, configure and delete all repositories"
}
}, },
"create": { "create": {
"displayName": "Create repositories", "displayName": "Create repositories",
@@ -36,6 +34,22 @@
"description": "May administer all groups" "description": "May administer all groups"
} }
}, },
"configuration": {
"list": {
"displayName": "Basic administration",
"description": "Prerequisite for all other administration permissions. Without this, no configuration will be visible."
},
"read,write": {
"global": {
"displayName": "Administer core",
"description": "May configure core settings of SCM-Manager"
},
"*": {
"displayName": "Administer core and plugins",
"description": "May configure settings of SCM-Manager core and all plugins"
}
}
},
"unknown": "Unknown permission" "unknown": "Unknown permission"
}, },
"verbs": { "verbs": {
@@ -68,10 +82,6 @@
"displayName": "modify permissions", "displayName": "modify permissions",
"description": "May modify the permissions of the repository" "description": "May modify the permissions of the repository"
}, },
"healthCheck": {
"displayName": "health check",
"description": "May run the health check for the repository"
},
"*": { "*": {
"displayName": "overall", "displayName": "overall",
"description": "May change everything for the repository (includes all other permissions)" "description": "May change everything for the repository (includes all other permissions)"

View File

@@ -8,6 +8,7 @@ import sonia.scm.util.ClassLoaders;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@@ -27,6 +28,7 @@ class RepositoryPermissionProviderTest {
repositoryPermissionProvider = new RepositoryPermissionProvider(pluginLoader); repositoryPermissionProvider = new RepositoryPermissionProvider(pluginLoader);
allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields()) allVerbsFromRepositoryClass = Arrays.stream(RepositoryPermissions.class.getDeclaredFields())
.filter(field -> field.getName().startsWith("ACTION_")) .filter(field -> field.getName().startsWith("ACTION_"))
.filter(field -> !field.getName().equals("ACTION_HEALTHCHECK"))
.map(this::getString) .map(this::getString)
.filter(verb -> !"create".equals(verb)) .filter(verb -> !"create".equals(verb))
.toArray(String[]::new); .toArray(String[]::new);
@@ -47,6 +49,18 @@ class RepositoryPermissionProviderTest {
assertThat(repositoryPermissionProvider.availableVerbs()).contains(allVerbsFromRepositoryClass); assertThat(repositoryPermissionProvider.availableVerbs()).contains(allVerbsFromRepositoryClass);
} }
@Test
void shouldMergeRepositoryRoles() {
Collection<String> verbsInMergedRole = repositoryPermissionProvider
.availableRoles()
.stream()
.filter(r -> "READ".equals(r.getName()))
.findFirst()
.get()
.getVerbs();
assertThat(verbsInMergedRole).contains("read", "pull", "test");
}
private String getString(Field field) { private String getString(Field field) {
try { try {
return (String) field.get(null); return (String) field.get(null);

View File

@@ -0,0 +1,13 @@
<repository-permissions>
<verbs>
<verb>test</verb>
</verbs>
<roles>
<role>
<name>READ</name>
<verbs>
<verb>test</verb>
</verbs>
</role>
</roles>
</repository-permissions>