提交 cc12964e 编写于 作者: K kohsuke

Matrix security configuration now validates whether the username/password are valid.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@14887 71c3de6d-444a-0410-be80-ed276b4c234a
上级 b2d4be45
......@@ -14,11 +14,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.io.IOException;
import net.sf.json.JSONObject;
import org.acegisecurity.acls.sid.Sid;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.QueryParameter;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
......@@ -26,6 +28,8 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import javax.servlet.ServletException;
/**
* {@link JobProperty} to associate ACL for each project.
*/
......@@ -94,7 +98,6 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> {
}
public static class DescriptorImpl extends JobPropertyDescriptor {
@Override
public JobProperty<?> newInstance(StaplerRequest req,
JSONObject formData) throws FormException {
......@@ -135,6 +138,10 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> {
public boolean showPermission(Permission p) {
return p!=Item.CREATE;
}
public void doCheckName(@QueryParameter String value) throws IOException, ServletException {
GlobalMatrixAuthorizationStrategy.DESCRIPTOR.doCheckName(value);
}
}
private final class AclImpl extends SidACL {
......
......@@ -6,13 +6,17 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.util.FormFieldValidator;
import hudson.Functions;
import net.sf.json.JSONObject;
import org.acegisecurity.Authentication;
import org.acegisecurity.acls.sid.GrantedAuthoritySid;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.acls.sid.Sid;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.QueryParameter;
import org.springframework.dao.DataAccessException;
import javax.servlet.ServletException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
......@@ -21,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.io.IOException;
/**
* Role-based authorization via a matrix.
......@@ -126,7 +131,7 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy {
return DESCRIPTOR;
}
public static final Descriptor<AuthorizationStrategy> DESCRIPTOR = new DescriptorImpl();
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
/**
* Persist {@link GlobalMatrixAuthorizationStrategy} as a list of IDs that
......@@ -216,6 +221,57 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy {
public boolean showPermission(Permission p) {
return true;
}
public void doCheckName(@QueryParameter String value ) throws IOException, ServletException {
final String v = value.substring(1,value.length()-1);
new FormFieldValidator(Hudson.ADMINISTER) {
protected void check() throws IOException, ServletException {
SecurityRealm sr = Hudson.getInstance().getSecurityRealm();
String ev = Functions.escape(v);
if(v.equals("authenticated")) {
// systerm reserved group
respond("<span>"+ makeImg("user.gif") +ev+"</span>");
return;
}
try {
sr.loadUserByUsername(v);
respond("<span>"+ makeImg("person.gif") +ev+"</span>");
return;
} catch (UserMayOrMayNotExistException e) {
// undecidable, meaning the user may exist
respond("<span>"+ev+"</span>");
return;
} catch (UsernameNotFoundException e) {
// fall through next
} catch (DataAccessException e) {
// fall through next
}
try {
sr.loadGroupByGroupname(v);
respond("<span>"+ makeImg("user.gif") +ev+"</span>");
return;
} catch (UserMayOrMayNotExistException e) {
// undecidable, meaning the group may exist
respond("<span>"+ev+"</span>");
return;
} catch (UsernameNotFoundException e) {
// fall through next
} catch (DataAccessException e) {
// fall through next
}
// couldn't find it. it doesn't exit
respond("<span>"+ makeImg("error.gif") +ev+"</span>");
}
}.process();
}
private String makeImg(String gif) {
return String.format("<img src='%s/images/16x16/%s' style='margin-right:0.2em'>", Hudson.RESOURCE_PATH, gif);
}
}
}
......@@ -27,6 +27,7 @@ import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.dao.DataAccessException;
import javax.servlet.ServletException;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
......@@ -61,6 +62,14 @@ public class HudsonPrivateSecurityRealm extends SecurityRealm implements ModelOb
return !disableSignup;
}
/**
* This implementation doesn't support groups.
*/
@Override
public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException {
throw new UsernameNotFoundException(groupname);
}
@Override
public SecurityComponents createSecurityComponents() {
BeanBuilder builder = new BeanBuilder();
......
......@@ -286,6 +286,10 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
public Authentication authenticate(Authentication authentication) {
return authentication;
}
}, new UserDetailsService() {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
throw new UsernameNotFoundException(username);
}
});
}
......@@ -297,6 +301,14 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
return null;
}
/**
* There's no group.
*/
@Override
public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException {
throw new UsernameNotFoundException(groupname);
}
/**
* We don't need any filter for this {@link SecurityRealm}.
*/
......
......@@ -60,7 +60,7 @@
</tr>
<j:forEach var="sid" items="${instance.allSIDs}">
<tr name="[${sid}]">
<tr name="[${sid}]" class="permission-row">
<local:row title="${sid}" sid="${sid}"/>
</tr>
</j:forEach>
......@@ -71,7 +71,7 @@
<!-- template row to be used for adding a new row -->
<j:set var="id" value="${h.generateId()}"/>
<tr id="${id}" style="display:none">
<tr id="${id}" style="display:none" class="permission-row">
<local:row sid="${null}" />
</tr>
</table>
......@@ -120,6 +120,10 @@
return false;
}
e = null; <!-- avoid memory leak -->
},
<!-- validates the name -->
"#${strategyid} TR.permission-row" : function(e) {
FormChecker.delayedCheck("${rootURL}/descriptor/${descriptor.clazz.name}/checkName?value="+encode(e.getAttribute("name")),"GET",e.firstChild);
}
});
</script>
......
......@@ -30,6 +30,7 @@
<st:header name="Expires" value="0" />
<!-- Use st:header here rather than st:contentType because Jetty 5.x appears to ignore the latter. -->
<st:header name="Content-Type" value="text/html;charset=UTF-8" />
<!-- The path starts with a "/" character but does not end with a "/" character. -->
<j:set var="rootURL" value="${request.contextPath}" />
<j:new var="h" className="hudson.Functions" /><!-- instead of JSP functions -->
<j:set var="_" value="${h.configureAutoRefresh(request, response, attrs.norefresh!=null)}"/>
......
......@@ -22,7 +22,19 @@ var FormChecker = {
inProgress : false,
/**
* Schedules a form field check. Executions are serialized to reduce the bandwidth impact.
*
* @param url
* Remote doXYZ URL that performs the check. Query string should include the field value.
* @param method
* HTTP method. GET or POST. I haven't confirmed specifics, but some browsers seem to cache GET requests.
* @param target
* HTML element whose innerHTML will be overwritten when the check is completed.
*/
delayedCheck : function(url, method, target) {
if(url==null || method==null || target==null)
return; // don't know whether we should throw an exception or ignore this. some broken plugins have illegal parameters
this.queue.push({url:url, method:method, target:target});
this.schedule();
},
......@@ -41,8 +53,6 @@ var FormChecker = {
if (this.queue.length == 0) return;
var next = this.queue.shift();
this.inProgress = true;
this.sendRequest(next.url, {
method : next.method,
onComplete : function(x) {
......@@ -51,6 +61,7 @@ var FormChecker = {
FormChecker.schedule();
}
});
this.inProgress = true;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册