提交 806e33d6 编写于 作者: K kohsuke

making progress on the security realm configuration. Started hooking up GUI.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@6205 71c3de6d-444a-0410-be80-ed276b4c234a
上级 3e229594
......@@ -24,6 +24,7 @@ import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrappers;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.security.SecurityRealm;
import org.apache.commons.jexl.parser.ASTSizeFunction;
import org.apache.commons.jexl.util.Introspector;
import org.kohsuke.stapler.Ancestor;
......@@ -443,6 +444,10 @@ public class Functions {
return BuildWrappers.getFor(project);
}
public static List<Descriptor<SecurityRealm>> getSecurityRealms() {
return SecurityRealm.LIST;
}
public static List<Descriptor<Builder>> getBuilderDescriptors(AbstractProject<?,?> project) {
return filterBuildStepDescriptors(BuildStep.BUILDERS,project);
}
......
......@@ -58,6 +58,8 @@ import hudson.util.HudsonIsLoading;
import hudson.util.MultipartFormDataParser;
import hudson.util.XStream2;
import hudson.widgets.Widget;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.ui.AbstractProcessingFilter;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
......@@ -66,8 +68,6 @@ import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.ui.AbstractProcessingFilter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
......@@ -2080,6 +2080,11 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node
public static boolean parallelLoad = Boolean.getBoolean(Hudson.class.getName()+".parallelLoad");
/**
* True to enable the new security implementation.
*/
public static boolean newSecurity = Boolean.getBoolean("SECURITY");
private static final Logger LOGGER = Logger.getLogger(Hudson.class.getName());
private static final Pattern ICON_SIZE = Pattern.compile("\\d+x\\d+");
......
......@@ -7,11 +7,7 @@ import hudson.XmlFile;
import hudson.model.Descriptor.FormException;
import hudson.scm.ChangeLogSet;
import hudson.util.RunList;
import hudson.util.Scrambler;
import hudson.util.XStream2;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -45,14 +41,6 @@ public class User extends AbstractModelObject {
private volatile String description;
/**
* {@link Scrambler#scramble(String) Scrambled} password.
*
* This field is null if the user object doesn't have its password set,
* in which case no one can login.
*/
private volatile String scrambledPassword;
/**
* List of {@link UserProperty}s configured for this project.
*/
......@@ -274,49 +262,6 @@ public class User extends AbstractModelObject {
return new Api(this);
}
// TODO
private static final GrantedAuthority[] TEST_AUTHORITY = {new GrantedAuthorityImpl("authenticated")};
/**
* Returns the {@link UserDetails} view of the User object.
* <p>
* This interface is implemented by a separate object to avoid having confusing methods
* at the {@link User} class level.
*/
public UserDetails asUserDetails() {
return new UserDetails() {
public GrantedAuthority[] getAuthorities() {
// TODO
return TEST_AUTHORITY;
}
public String getPassword() {
if(scrambledPassword==null) return "not enabled";
return Scrambler.descramble(scrambledPassword);
}
public String getUsername() {
return id;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return scrambledPassword!=null;
}
};
}
/**
* Accepts submission from the configuration page.
*/
......
......@@ -6,6 +6,8 @@ import hudson.model.User;
import hudson.util.spring.BeanBuilder;
import net.sf.json.JSONObject;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
......@@ -29,6 +31,54 @@ public class HudsonPrivateSecurityRealm extends SecurityRealm {
return DescriptorImpl.INSTANCE;
}
// TODO
private static final GrantedAuthority[] TEST_AUTHORITY = {new GrantedAuthorityImpl("authenticated")};
/**
* Returns the {@link UserDetails} view of the User object.
* <p>
* This interface is implemented by a separate object to avoid having confusing methods
* at the {@link User} class level.
*/
private static final class UserDetailsImpl implements UserDetails {
private final User user;
private UserDetailsImpl(User user) {
this.user = user;
}
public GrantedAuthority[] getAuthorities() {
// TODO
return TEST_AUTHORITY;
}
public String getPassword() {
// TODO
return user.getId();
}
public String getUsername() {
return user.getId();
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
// TODO: if password is not set, don't allow login
return true;
}
}
/**
* {@link UserDetailsService} that loads user information from {@link User} object.
*/
......@@ -37,7 +87,7 @@ public class HudsonPrivateSecurityRealm extends SecurityRealm {
User u = User.get(username, false);
if(u==null)
throw new UsernameNotFoundException("No such user: "+username);
return u.asUserDetails();
return new UserDetailsImpl(u);
}
}
......
package hudson.security;
import org.acegisecurity.AuthenticationManager;
import hudson.model.Descriptor;
/**
* {@link SecurityRealm} implementation that uses LDAP for authentication.
*
* @author Kohsuke Kawaguchi
*/
public class LDAPSecurityRealm extends SecurityRealm {
public AuthenticationManager createAuthenticationManager() {
throw new UnsupportedOperationException();
}
public DescriptorImpl getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
private static final class DescriptorImpl extends Descriptor<SecurityRealm> {
private DescriptorImpl() {
super(LDAPSecurityRealm.class);
}
public String getDisplayName() {
return "LDAP";
}
}
}
......@@ -7,6 +7,7 @@ import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.springframework.context.ApplicationContext;
import java.util.List;
import java.util.Map;
/**
......@@ -78,4 +79,12 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
return NO_AUTHENTICATION;
}
}
/**
* All registered instances.
*/
public static final List<Descriptor<SecurityRealm>> LIST = Descriptor.toList(
HudsonPrivateSecurityRealm.DescriptorImpl.INSTANCE,
LDAPSecurityRealm.DESCRIPTOR
);
}
......@@ -22,6 +22,16 @@
</s:entry>
<s:optionalBlock name="use_security" title="Enable security"
checked="${it.useSecurity}" help="/help/system-config/enableSecurity.html">
<j:if test="${app.newSecurity}">
<s:block>
<table style="width:100%">
<s:descriptorRadioList title="Security Realm" varName="realm"
instance="${it.securityRealm}"
descriptors="${h.securityRealms}"/>
</table>
</s:block>
</j:if>
<s:entry title="TCP port for JNLP slave agents"
help="/help/system-config/master-slave/slave-agent-port.html">
<s:radio name="slaveAgentPortType" value="fixed" id="sat.fixed"
......
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="Server" >
<f:textbox name="ldap.server" value="${instance}" />
</f:entry>
</j:jelly>
\ No newline at end of file
<!--
Generate config pages from a list of Descriptors into a section.
Attributes:
title caption for the section (required)
descriptors hudson.model.Descriptor collection to display (required)
instance Current instance that match this. (required)
varName Used as a variable name as well as block name (required)
targetType the type for which descriptors will be configured.
default to ${it.class} (optional)
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<j:set var="targetType" value="${h.defaulted(attrs.targetType,it.class)}"/>
<f:section title="${attrs.title}">
<d:invokeBody />
<j:forEach var="d" items="${descriptors}" varStatus="loop">
<f:radioBlock name="${varName}" help="${d.helpFile}" value="${loop.index}"
title="${d.displayName}" checked="${attrs.instance.descriptor==d}">
<j:set var="descriptor" value="${d}" />
<j:set var="instance" value="${h.ifThenElse(attrs.instance.descriptor==d,attrs.instance,null)}" />
<st:include from="${d}" page="${d.configPage}" optional="true" />
</f:radioBlock>
</j:forEach>
</f:section>
</j:jelly>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册