提交 011730f3 编写于 作者: K kohsuke

started implementing the first security realm implementation.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@6087 71c3de6d-444a-0410-be80-ed276b4c234a
上级 5c2ec0d9
......@@ -230,6 +230,8 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node
private transient Set<Label> labelSet;
private transient Set<Label> dynamicLabels = null;
public transient final ServletContext servletContext;
public static Hudson getInstance() {
return theInstance;
}
......@@ -237,6 +239,7 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node
public Hudson(File root, ServletContext context) throws IOException {
this.root = root;
this.servletContext = context;
if(theInstance!=null)
throw new IllegalStateException("second instance");
theInstance = this;
......
......@@ -4,26 +4,30 @@ import com.thoughtworks.xstream.XStream;
import hudson.CopyOnWrite;
import hudson.FeedAdapter;
import hudson.XmlFile;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.export.Exported;
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;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
......@@ -41,6 +45,14 @@ 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.
*/
......@@ -262,6 +274,49 @@ 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.
*/
......
package hudson.security;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.User;
import hudson.util.spring.BeanBuilder;
import net.sf.json.JSONObject;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.kohsuke.stapler.StaplerRequest;
/**
* {@link SecurityRealm} that performs authentication by looking up {@link User}.
*
*
* @author Kohsuke Kawaguchi
*/
public class HudsonPrivateSecurityRealm extends SecurityRealm {
@Override
public AuthenticationManager createAuthenticationManager() {
BeanBuilder builder = new BeanBuilder();
builder.parse(Hudson.getInstance().servletContext.getResourceAsStream("/WEB-INF/security/HudsonPrivateSecurityRealm.groovy"));
return findBean(AuthenticationManager.class,builder.createApplicationContext());
}
public Descriptor<SecurityRealm> getDescriptor() {
return DescriptorImpl.INSTANCE;
}
/**
* {@link UserDetailsService} that loads user information from {@link User} object.
*/
public static final class HudsonUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User u = User.get(username, false);
if(u==null)
throw new UsernameNotFoundException("No such user: "+username);
return u.asUserDetails();
}
}
public static final class DescriptorImpl extends Descriptor<SecurityRealm> {
public static final DescriptorImpl INSTANCE = new DescriptorImpl();
private DescriptorImpl() {
super(HudsonPrivateSecurityRealm.class);
}
public String getDisplayName() {
return "Hudson's own user database";
}
public HudsonPrivateSecurityRealm newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return new HudsonPrivateSecurityRealm();
}
}
}
......@@ -3,6 +3,9 @@ package hudson.security;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import org.acegisecurity.AuthenticationManager;
import org.springframework.context.ApplicationContext;
import java.util.Map;
/**
* Pluggable security realm that connects external user database to Hudson.
......@@ -23,4 +26,24 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
* captured as instance variables of {@link SecurityRealm} implementation.
*/
public abstract AuthenticationManager createAuthenticationManager();
/**
* Picks up the instance of the given type from the spring context.
* If there are multiple beans of the same type or if there are none,
* this method treats that as an {@link IllegalArgumentException}.
*
* This method is intended to be used to pick up a Acegi object from
* spring once the bean definition file is parsed.
*/
protected static <T> T findBean(Class<T> type, ApplicationContext context) {
Map m = context.getBeansOfType(type);
switch(m.size()) {
case 0:
throw new IllegalArgumentException("No beans of "+type+" are defined");
case 1:
return type.cast(m.values().iterator().next());
default:
throw new IllegalArgumentException("Multiple beans of "+type+" are defined: "+m);
}
}
}
/*
Configure Hudson's own user database as the authentication realm.
*/
import org.acegisecurity.providers.ProviderManager
import hudson.security.HudsonPrivateSecurityRealm.HudsonUserDetailsService
authenticationManager(ProviderManager) {
providers = [
// the primary authentication source is Hudson's own user database
bean(DaoAuthenticationProvider) {
userDetailsService = new HudsonUserDetailsService()
},
// this doesn't mean we allow anonymous access.
// we just authenticate anonymous users as such,
// so that later authorization can reject them if so configured
bean(AnonymousAuthenticationProvider) {
key = "anonymous"
}
]
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册