Skip to content
Permalink
Browse files

Merge pull request #4 from imod/unprotected-status

[FIXED JENKINS-17798] expose build badge via unprotected URL, but with new Permission
  • Loading branch information
jglick committed May 31, 2013
2 parents 11843c7 + 5c6c161 commit 3a6e78d3e0a4127e990b2cb39b2d9ab1faa2c71e
@@ -3,7 +3,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.424</version>
<version>1.480.3</version>
</parent>

<artifactId>embeddable-build-status</artifactId>
@@ -15,16 +15,11 @@
*/
@Extension
public class BadgeActionFactory extends TransientProjectActionFactory {
private final StatusImage[] images;

private final ImageResolver iconResolver;

public BadgeActionFactory() throws IOException {
images = new StatusImage[] {
new StatusImage("failure.png"),
new StatusImage("unstable.png"),
new StatusImage("success.png"),
new StatusImage("running.png"),
new StatusImage("unknown.png")
};
iconResolver = new ImageResolver();
}

@Override
@@ -33,20 +28,7 @@ public BadgeActionFactory() throws IOException {
}

public StatusImage getImage(BallColor color) {
if (color.isAnimated())
return images[3];

switch (color) {
case RED:
case ABORTED:
return images[0];
case YELLOW:
return images[1];
case BLUE:
return images[2];
default:
return images[4];
}
return iconResolver.getImage(color);
}

}
@@ -0,0 +1,62 @@
/*
* The MIT License
*
* Copyright 2013 Kohsuke Kawaguchi, Dominik Bartholdi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.badge;

import hudson.model.BallColor;

import java.io.IOException;

public class ImageResolver {

private final StatusImage[] images;

public ImageResolver() throws IOException{
images = new StatusImage[] {
new StatusImage("failure.png"),
new StatusImage("unstable.png"),
new StatusImage("success.png"),
new StatusImage("running.png"),
new StatusImage("unknown.png")
};
}

public StatusImage getImage(BallColor color) {
if (color.isAnimated())
return images[3];

switch (color) {
case RED:
case ABORTED:
return images[0];
case YELLOW:
return images[1];
case BLUE:
return images[2];
default:
return images[4];
}
}


}
@@ -0,0 +1,45 @@
/*
* The MIT License
*
* Copyright 2013 Dominik Bartholdi.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.badge;

import hudson.Plugin;

/**
* This plugin implementation only exists to force the loading of the permission in an early enough stage (see also JENKINS-4172).
* If the permission is not loaded early enough, Jenkins fails to load
* permissions from config.
*
* @author Dominik Bartholdi (imod)
*/
public class PluginImpl extends Plugin {

@Override
public void start() throws Exception {
//
// As a work around, force loading of this permission so that by the time we start loading ACLs,
// we have this instance already registered, thereby avoiding a lookup.
PublicBadgeAction.VIEW_STATUS.toString();
}

}
@@ -0,0 +1,110 @@
/*
* The MIT License
*
* Copyright 2013 Dominik Bartholdi.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.badge;

import hudson.Extension;
import hudson.model.Item;
import hudson.model.UnprotectedRootAction;
import hudson.model.AbstractProject;
import hudson.security.ACL;
import hudson.security.Permission;
import hudson.security.PermissionScope;
import hudson.util.HttpResponses;

import java.io.IOException;

import javax.servlet.ServletException;

import jenkins.model.Jenkins;

import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

/**
* Exposes the build status badge via unprotected URL.
*
* The status of a job can be checked like this:
*
* <li>http://localhost:8080/buildstatus/icon?job=[JOBNAME] <li>e.g. http://localhost:8080/buildstatus/icon?job=free1 <br/>
* <br/>
* Even though the URL is unprotected, the user does still need the 'ViewStatus' permission on the given Job. If you want the status icons to be public readable/accessible, just grant the 'ViewStatus'
* permission globally to 'anonymous'.
*
* @author Dominik Bartholdi (imod)
*/
@Extension
public class PublicBadgeAction implements UnprotectedRootAction {

final public static Permission VIEW_STATUS = new Permission(Item.PERMISSIONS, "ViewStatus", Messages._ViewStatus_Permission(), Item.READ, PermissionScope.ITEM);

private final ImageResolver iconResolver;

public PublicBadgeAction() throws IOException {
iconResolver = new ImageResolver();
}

public String getUrlName() {
return "buildStatus";
}

public String getIconFileName() {
return null;
}

public String getDisplayName() {
return null;
}

/**
* Serves the badge image.
*/
public HttpResponse doIcon(StaplerRequest req, StaplerResponse rsp, @QueryParameter String job) throws IOException, ServletException {
AbstractProject<?, ?> project = getProject(job, req, rsp);
return iconResolver.getImage(project.getIconColor());
}

private AbstractProject<?, ?> getProject(String job, StaplerRequest req, StaplerResponse rsp) throws IOException, HttpResponses.HttpResponseException {
AbstractProject<?, ?> p;

// as the user might have ViewStatus permission only (e.g. as anonymous) we get get the project impersonate and check for permission after getting the project
SecurityContext orig = ACL.impersonate(ACL.SYSTEM);
try {
p = Jenkins.getInstance().getItemByFullName(job, AbstractProject.class);
} finally {
SecurityContextHolder.setContext(orig);
}

// check if user has permission to view the status
if(p == null || !(p.hasPermission(VIEW_STATUS))){
throw HttpResponses.notFound();
}

return p;
}

}
@@ -6,7 +6,7 @@ def st = namespace("jelly:stapler")
l.layout {
l.main_panel {
h2(_("Embeddable Build Status Icon"))
p(_("blurb"))
p(raw(_("blurb")))
raw("""
<p>
</p>
@@ -32,22 +32,40 @@ l.layout {

def base = "${app.rootUrl}${my.project.url}";
def badge = base + "badge/icon"

def fullJobName = h.escape(my.project.fullName);
def publicbadge = "${app.rootUrl}buildStatus/icon?job=${fullJobName}";
h3 {
text(_("Image"))
img(id:"badge",src:badge)
}
b {text(_("protected"))}
input(type:"text",value:badge,class:"select-all")
b {text(_("unprotected"))}
input(type:"text",value:publicbadge,class:"select-all")

h3(_("Markdown"))
b {text(_("protected"))}
input(type:"text",value:"[![Build Status](${badge})](${base})",class:"select-all")
b {text(_("unprotected"))}
input(type:"text",value:"[![Build Status](${publicbadge})](${base})",class:"select-all")

h3(_("HTML"))
b {text(_("protected"))}
input(type:"text",value:"<a href='${base}'><img src='${badge}'></a>",class:"select-all")
b {text(_("unprotected"))}
input(type:"text",value:"<a href='${base}'><img src='${publicbadge}'></a>",class:"select-all")

h3(_("Confluence"))
b {text(_("protected"))}
input(type:"text",value:"[!${badge}!|${base}]",class:"select-all")
b {text(_("unprotected"))}
input(type:"text",value:"[!${publicbadge}!|${base}]",class:"select-all")

h3(_("XWiki"))
b {text(_("protected"))}
input(type:"text",value:"[[image:${badge}>>${base}||target='__new']]",class:"select-all")
b {text(_("unprotected"))}
input(type:"text",value:"[[image:${publicbadge}>>${base}||target='__new']]",class:"select-all")
}
}
@@ -1,3 +1,9 @@
blurb=Jenkins exposes the current status of your build as an image in a fixed URL. \
You can put this URL into other sites (such as GitHub README) so that people \
can see the current state of the build.
can see the current state of the build. <br>There are two URLs available for inclusion: <br> \
<ul> \
<li><b>protected</b> exposes the badge to users having at least 'Read' permission on the job</li> \
<li><b>unprotected</b> exposes the badge to users having at least 'ViewStatus' permission on the job</li> \
</ul> \
If you want the status icons to be public readable/accessible, just grant the 'ViewStatus' permission globally to 'anonymous'.

@@ -1 +1,2 @@
BadgeAction.DisplayName=Embeddable Build Status
BadgeAction.DisplayName=Embeddable Build Status
ViewStatus.Permission=This permission grants the ability to view the build status via embeddable build status plugin.

0 comments on commit 3a6e78d

Please sign in to comment.
You can’t perform that action at this time.