Skip to content

Commit

Permalink
Make permissions matrix-auth-3.0+ compatible
Browse files Browse the repository at this point in the history
by adding support to explicitly assign permissions to groups or users.

With https://github.com/jenkinsci/matrix-auth-plugin/releases/tag/matrix-auth-3.0 ambiguous permissions will show a warning.
  • Loading branch information
eva-mueller-coremedia committed Aug 25, 2024
1 parent e8d87c1 commit 280e1f2
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 30 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ the common pattern in this situation is to copy jobs to create new ones, these "
diverging from their original "template" and consequently it becomes difficult to maintain consistency between these
jobs.

The Job DSL plugin attempts to solve this problem by allowing jobs to be defined in a programmatic form in a human
readable file. Writing such a file is feasible without being a Jenkins expert as the configuration from the web UI
The Job DSL plugin attempts to solve this problem by allowing jobs to be defined in a programmatic form in a human-readable file. Writing such a file is feasible without being a Jenkins expert as the configuration from the web UI
translates intuitively into code.

![configuration form](docs/images/pipeline.png)
Expand Down Expand Up @@ -113,10 +112,7 @@ generated at runtime by introspecting the plugins that have been installed.
Jenkins saves the configuration of each job in a XML file. The Job DSL plugin is in principle a generator for these XML
files, translating the DSL code into XML. If a configuration option is not available in the high-level DSL, it is
possible to generate the XML directly using a
[Configure Block](https://github.com/jenkinsci/job-dsl-plugin/wiki/The-Configure-Block). Use the
[Job DSL Playground](http://job-dsl.herokuapp.com/) to create and test your configure blocks. Please note that the
playground only supports the DSL API that is available in the online
[API Reference](https://jenkinsci.github.io/job-dsl-plugin/).
[Configure Block](https://github.com/jenkinsci/job-dsl-plugin/wiki/The-Configure-Block).

Find the complete documentation on the [Wiki](https://github.com/jenkinsci/job-dsl-plugin/wiki).

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
// gives permission for the special authenticated group to create jobs in the folder
// gives permission to create jobs in the folder
folder('example-1') {
authorization {
permission('hudson.model.Item.Create:authenticated')
// requires matrix-auth > 3.0
permission('GROUP:hudson.model.Item.Create:group1')
permission('USER:hudson.model.Item.Create:user1')
groupPermission('hudson.model.Item.Create', 'group2')
userPermission('hudson.model.Item.Create', 'user2')
}
}

// gives discover permission for the special anonymous user
// gives discover permission
folder('example-2') {
authorization {
permission('hudson.model.Item.Discover', 'anonymous')
// requires matrix-auth > 3.0
permission('USER:hudson.model.Item.Discover:anonymous')
userPermission('hudson.model.Item.Discover', 'anonymous')
}
}

// gives all permissions to the special anonymous user
// gives all permissions
folder('example-3') {
authorization {
permissionAll('anonymous')
// requires matrix-auth > 3.0
userPermissionAll('user1')
groupPermissionAll('group1')
}
}

// gives the hudson.model.Item.Discover and hudson.model.Item.Create permission to jill
// gives the hudson.model.Item.Discover and hudson.model.Item.Create permissions
folder('example-4') {
authorization {
permissions('jill', [
'hudson.model.Item.Create',
'hudson.model.Item.Discover'
])
// requires matrix-auth > 3.0
userPermissions('user1', [
'hudson.model.Item.Create',
'hudson.model.Item.Discover'
])
groupPermissions('group1', [
'hudson.model.Item.Create',
'hudson.model.Item.Discover'
])
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,50 @@
// add a permission for the special authenticated group to see the workspace of the job
// add group permissions to see the workspace of the job
job('example-1') {
authorization {
permission('hudson.model.Item.Workspace:authenticated')
// requires matrix-auth > 3.0
permission('GROUP:hudson.model.Item.Workspace:group1')
groupPermission('hudson.model.Item.Workspace', 'group2')
}
}

// adds the build permission for the special anonymous user
// adds the build permission to users
job('example-2') {
authorization {
permission('hudson.model.Item.Build', 'anonymous')
// requires matrix-auth > 3.0
permission('USER:hudson.model.Item.Build:user1')
userPermission('hudson.model.Item.Build', 'user2')
}
}

// add all permissions for user joe, blocking inheritance of the global
// add all permissions to users or groups, blocking inheritance of the global
// authorization matrix
job('example-3') {
authorization {
permissionAll('joe')
blocksInheritance()
// requires matrix-auth > 3.0
userPermissionAll('user1')
groupPermissionAll('group1')
}
}

// gives the hudson.model.Item.Discover and hudson.model.Item.Create permission to jill
// gives the hudson.model.Item.Discover and hudson.model.Item.Create permission to user resp. groups
job('example-4') {
authorization {
permissions('jill', [
'hudson.model.Item.Create',
'hudson.model.Item.Discover'
])
// requires matrix-auth > 3.0
userPermissions('user1', [
'hudson.model.Item.Create',
'hudson.model.Item.Discover'
])
groupPermissions('group1', [
'hudson.model.Item.Create',
'hudson.model.Item.Discover'
])
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// add a permission for the special authenticated group to see the workspace of the job
// add permission to see the workspace of the job
job('example-1') {
authorization {
permission('hudson.model.Item.Workspace:authenticated')
// requires matrix-auth > 3.0
permission('GROUP:hudson.model.Item.Workspace:group1')
groupPermission('hudson.model.Item.Workspace', 'group2')
}
}

// adds the build permission for the special anonymous user
// adds the build permission to users
job('example-2') {
authorization {
permission('hudson.model.Item.Build', 'anonymous')
// requires matrix-auth > 3.0
permission('USER:hudson.model.Item.Workspace:user1')
userPermission('hudson.model.Item.Workspace', 'user2')
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// add all permissions for user joe
job('example') {
// add all permissions
job('example-1') {
authorization {
permissionAll('joe')
// requires matrix-auth > 3.0
userPermissionAll('user1')
groupPermissionAll('group1')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package javaposse.jobdsl.dsl.helpers

import javaposse.jobdsl.dsl.AbstractContext
import javaposse.jobdsl.dsl.JobManagement
import javaposse.jobdsl.dsl.RequiresPlugin

import static javaposse.jobdsl.dsl.Preconditions.checkArgument
import static javaposse.jobdsl.dsl.Preconditions.checkNotNullOrEmpty
Expand All @@ -11,6 +12,10 @@ import static javaposse.jobdsl.dsl.Preconditions.checkNotNullOrEmpty
*/
class AuthorizationContext extends AbstractContext {
private final String authorizationMatrixPropertyClassName
private final enum AuthType {
GROUP,
USER;
}
Set<String> permissions = new LinkedHashSet<String>()

AuthorizationContext(JobManagement jobManagement, String authorizationMatrixPropertyClassName) {
Expand All @@ -27,18 +32,56 @@ class AuthorizationContext extends AbstractContext {
}
}

/**
* Adds all available permissions for the user.
*
* @since 1.88
*/
@RequiresPlugin(id = 'matrix-auth', minimumVersion = '3.0')
void userPermissionAll(String userName) {
availablePermissions.each {
addAuthTypedPermission(AuthType.USER, it, userName)
}
}

/**
* Adds all available permissions for the group.
*
* @since 1.88
*/
@RequiresPlugin(id = 'matrix-auth', minimumVersion = '3.0')
void groupPermissionAll(String groupName) {
availablePermissions.each {
addAuthTypedPermission(AuthType.GROUP, it, groupName)
}
}

/**
* Adds a specific permission.
*
* @param permission a permission string in {@code '<permission>:<user>'} format, e.g.
* {@code 'hudson.model.Item.Create:authenticated'}
* @param permission a permission string in {@code '[USER:|GROUP:]<permission>:<user>'} format, e.g.
* {@code '[USER:|GROUP:]hudson.model.Item.Create:authenticated'}
*/
void permission(String permission) {
checkNotNullOrEmpty(permission, 'permission must not be null or empty')
checkArgument(permission.contains(':'), 'permission must be <permission>:<user>')
checkArgument(permission.contains(':'), 'permission must be [USER:|GROUP:]<permission>:<user>')

String[] permissionAndUser = permission.split(':', 2)
this.permission(permissionAndUser[0], permissionAndUser[1])
String[] permissionParts = permission.split(':', 3)
String prefix = permissionParts[0]
if (permissionParts.size() == 3) {
List<String> authTypes = AuthType.values()*.toString()
checkArgument(authTypes.contains(prefix),
"Prefix must be ${authTypes.join(' or ')}")
}
if (permissionParts.size() == 2) {
this.permission(permissionParts[0], permissionParts[1])
} else if (prefix == AuthType.USER.toString()) {
jobManagement.requireMinimumPluginVersion('matrix-auth', '3.0')
this.userPermission(permissionParts[1], permissionParts[2])
} else if (prefix == AuthType.GROUP.toString()) {
jobManagement.requireMinimumPluginVersion('matrix-auth', '3.0')
this.groupPermission(permissionParts[1], permissionParts[2])
}
}

/**
Expand All @@ -52,6 +95,34 @@ class AuthorizationContext extends AbstractContext {
addPermission(permission, user)
}

/**
* Adds a specific permission, but breaks apart the permission from the user name.
*
* @since 1.88
*/
@RequiresPlugin(id = 'matrix-auth', minimumVersion = '3.0')
void userPermission(String permission, String userName) {
checkArgument(
availablePermissions.contains(permission),
"permission must be one of ${availablePermissions.join(',')}"
)
addAuthTypedPermission(AuthType.USER, permission, userName)
}

/**
* Adds a specific permission, but breaks apart the permission from the group name.
*
* @since 1.88
*/
@RequiresPlugin(id = 'matrix-auth', minimumVersion = '3.0')
void groupPermission(String permission, String groupName) {
checkArgument(
availablePermissions.contains(permission),
"permission must be one of ${availablePermissions.join(',')}"
)
addAuthTypedPermission(AuthType.GROUP, permission, groupName)
}

/**
* Adds a set of permissions for a user.
*
Expand All @@ -63,10 +134,37 @@ class AuthorizationContext extends AbstractContext {
}
}

/**
* Adds a set of permissions for a user.
*
* @since 1.88
*/
void userPermissions(String userName, Iterable<String> permissionsList) {
permissionsList.each {
this.addAuthTypedPermission(AuthType.USER, it, userName)
}
}

/**
* Adds a set of permissions for a group.
*
* @since 1.88
*/
void groupPermissions(String groupName, Iterable<String> permissionsList) {
permissionsList.each {
this.addAuthTypedPermission(AuthType.GROUP, it, groupName)
}
}

protected void addPermission(String permission, String user) {
permissions << "${permission}:${user}".toString()
}

@RequiresPlugin(id = 'matrix-auth', minimumVersion = '3.0')
protected void addAuthTypedPermission(AuthType authType, String permission, String user) {
permissions << "${authType.toString()}:${permission}:${user}".toString()
}

protected Set<String> getAvailablePermissions() {
jobManagement.getPermissions(authorizationMatrixPropertyClassName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,23 +98,50 @@ class FolderSpec extends Specification {
when:
folder.authorization {
permission('hudson.model.Item.Build:jill')
permission('USER:hudson.model.Item.Build:andi')
permission('GROUP:hudson.model.Item.Build:admin')
permission('hudson.model.Item.Configure', 'jack')
userPermission('hudson.model.Item.Configure', 'foo')
groupPermission('hudson.model.Item.Configure', 'bar')
permissionAll('anonymous')
userPermissionAll('alex')
groupPermissionAll('devs')
permissions('janice', [
'hudson.model.Item.Build',
'hudson.model.Item.Configure'
])
userPermissions('pedro', [
'hudson.model.Item.Build',
'hudson.model.Item.Configure'
])
groupPermissions('tanya', [
'hudson.model.Item.Build',
'hudson.model.Item.Configure'
])
}

then:
NodeList permissions = folder.node.properties[0]."$propertyName"[0].permission
permissions.size() == 6
permissions[0].text() == 'hudson.model.Item.Build:jill'
permissions[1].text() == 'hudson.model.Item.Configure:jack'
permissions[2].text() == 'hudson.model.Item.Build:anonymous'
permissions[3].text() == 'hudson.model.Item.Configure:anonymous'
permissions[4].text() == 'hudson.model.Item.Build:janice'
permissions[5].text() == 'hudson.model.Item.Configure:janice'
permissions.size() == 18
int index = -1
permissions[++index].text() == 'hudson.model.Item.Build:jill'
permissions[++index].text() == 'USER:hudson.model.Item.Build:andi'
permissions[++index].text() == 'GROUP:hudson.model.Item.Build:admin'
permissions[++index].text() == 'hudson.model.Item.Configure:jack'
permissions[++index].text() == 'USER:hudson.model.Item.Configure:foo'
permissions[++index].text() == 'GROUP:hudson.model.Item.Configure:bar'
permissions[++index].text() == 'hudson.model.Item.Build:anonymous'
permissions[++index].text() == 'hudson.model.Item.Configure:anonymous'
permissions[++index].text() == 'USER:hudson.model.Item.Build:alex'
permissions[++index].text() == 'USER:hudson.model.Item.Configure:alex'
permissions[++index].text() == 'GROUP:hudson.model.Item.Build:devs'
permissions[++index].text() == 'GROUP:hudson.model.Item.Configure:devs'
permissions[++index].text() == 'hudson.model.Item.Build:janice'
permissions[++index].text() == 'hudson.model.Item.Configure:janice'
permissions[++index].text() == 'USER:hudson.model.Item.Build:pedro'
permissions[++index].text() == 'USER:hudson.model.Item.Configure:pedro'
permissions[++index].text() == 'GROUP:hudson.model.Item.Build:tanya'
permissions[++index].text() == 'GROUP:hudson.model.Item.Configure:tanya'
}

def 'call properties'() {
Expand Down
Loading

0 comments on commit 280e1f2

Please sign in to comment.