Read only view
Extended read and system read permission allow read only access to parts of Jenkins.
The jelly taglib’s in core will render a read only look and feel, if the user only has access to read the view.
This is handled for developers transparently if they are already using one
of the supported views, like the job
configure view.
Enabling permissions that use read-only views
There are 3 permissions currently that interact with read-only views:
-
Overall/SystemRead
-
Agent/ExtendedRead
-
Job/ExtendedRead
They are currently not enabled by default, the easiest way to enable them is to install the Extended read permission plugin v3.2 or above.
Enabling read-only view support
Jelly example:
<!-- configure permissions on a job required for write access -->
<j:set var="readOnlyMode" value="${!it.hasPermission(it.CONFIGURE)}" />
<!-- administrator permissions required for write access -->
<j:set var="readOnlyMode" value="${!app.hasPermission(app.ADMINISTER)}" />
Groovy example:
// configure permissions on a job required for write access
set("readOnlyMode", !it.hasPermission(it.CONFIGURE))
// administrator permissions required for write access
set("readOnlyMode", !app.hasPermission(app.ADMINISTER))
Partial view read-only
It’s also possible to only use read-only mode for part of a view,
This is an example taken from the /configure page showing the
SYSTEM_READ
and MANAGE
permissions working together, non-editable parts of the view
render in a read only manner:
<j:forEach var="descriptor" items="${h.getSortedDescriptorsForGlobalConfigUnclassifiedReadable()}">
<j:set var="editable" value="${h.getSortedDescriptorsForGlobalConfigUnclassified()}"/>
<j:set var="readOnlyMode" value="${!editable.contains(descriptor)}" />
<!-- (unnecessary context removed) -->
<st:include page="${descriptor.globalConfigPage}" from="${descriptor}" />
<!-- (unnecessary context removed) -->
</j:forEach>
Taglib changes required
If you provide your own taglib that isn’t in Jenkins core you may need to make some changes.
Depending on what change is required there are a few different changes you might need to make, here are a few examples.
Rendering plain text instead of a control
We also add a default text when it is empty (N/A in this case):
<j:choose>
<j:when test="${readOnlyMode}">
<j:choose>
<j:when test="${empty(value)}">
<span class="jenkins-not-applicable">N/A</span>
</j:when>
<j:otherwise><pre class="jenkins-readonly">${value}</pre></j:otherwise>
</j:choose>
</j:when>
<j:otherwise>
... your normal default configuration
</j:otherwise>
</j:choose>
Disabling the control
It is preferable to render plain text or some other method that is obvious to the user what is going on (disabled controls aren’t very obvious), but a lot of the javascript and jelly taglibs depend on inputs of specific types being there for rendering, so sometimes it is preferable to just disable the control:
<input type="radio"
checked="${attrs.checked?'true':null}"
disabled="${readOnlyMode?'true':null}"
/>
Allowing access to a view
Normally in Jenkins the layout tag of a page will have a permission attribute which governs which permission is required to access the page.
Jenkins has a concept of 'impliedBy' in it’s permission, which means that each permission is allowed to be automatically granted by another one. Job/ExtendedRead is implied by Job/Configure, which means that requiring Job/ExtendedRead to access a view, will also grant Job/Configure access.
Here are some examples that show what you will need to update the layout tag to:
Requiring the Job/ExtendedRead permission in Jelly:
<l:layout permission="${it.EXTENDED_READ}">
...
</l:layout>
Overall/SystemRead Jelly:
<l:layout permission="${app.SYSTEM_READ}">
...
</l:layout>
Overall/SystemRead Groovy:
l.layout(permission: app.SYSTEM_READ) {
...
}
Removing part of a view
Often it makes sense to remove parts of a view, such as 'Save' or 'Apply' buttons.
For system read the simplest way to do this is to use the l:isAdmin
tag:
isAdmin Jelly:
<l:isAdmin>
</l:isAdmin>
isAdmin Groovy:
l.isAdmin() {
...
}
There’s also a l:hasAdministerOrManage
tag that can be used to check for the Jenkins/Administer or `Jenkins/Manage
permissions.
If those don’t fit, then you can write your own permission check:
hasPermission Jelly:
<j:if test="${it.hasPermission(it.CONFIGURE)">
</j:if>
hasPermission Groovy:
if (!it.hasPermission(it.CONFIGURE)) {
...
}
Server side changes required
Firstly you will need to update any server side permission checks to now check
on load for the Read permission, rather than the Configure or Administer permission.
See Using StaplerProxy
for more information
on this feature.
i.e.
public Object getTarget() {
checkPermission(Jenkins.SYSTEM_READ);
}
Then you will need to review if additional permission checks are required, i.e. any methods that allow saving or sensitive data access should now require the permission that was previously in use.
Searching for 'public .* do' is a good start as web methods normally start with 'do', but you should carefully review to make sure nothing is now exposed that shouldn’t be.
public void doInstallPlugin() {
checkPermission(Jenkins.ADMINISTER);
}