提交 846889ad 编写于 作者: K kohsuke

adding remember-me service to the mix.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@6761 71c3de6d-444a-0410-be80-ed276b4c234a
上级 2f7c7390
......@@ -40,6 +40,7 @@ import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.security.SecurityMode;
import hudson.security.SecurityRealm;
import hudson.security.SecurityRealm.SecurityComponents;
import hudson.tasks.BuildStep;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrappers;
......@@ -951,7 +952,9 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
public void setSecurityRealm(SecurityRealm securityRealm) {
this.securityRealm = securityRealm;
HudsonFilter.AUTHENTICATION_MANAGER.setManager(securityRealm.createAuthenticationManager());
SecurityComponents sc = securityRealm.createSecurityComponents();
HudsonFilter.AUTHENTICATION_MANAGER.setDelegate(sc.manager);
HudsonFilter.USER_DETAILS_SERVICE_PROXY.setDelegate(sc.userDetails);
}
/**
......
......@@ -16,10 +16,10 @@ import org.acegisecurity.DisabledException;
* @author Kohsuke Kawaguchi
*/
public class AuthenticationManagerProxy implements AuthenticationManager {
private volatile AuthenticationManager manager;
private volatile AuthenticationManager delegate;
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AuthenticationManager m = manager; // fix the reference we are working with
AuthenticationManager m = delegate; // fix the reference we are working with
if(m ==null)
throw new DisabledException("Authentication service is still not ready yet");
......@@ -27,7 +27,7 @@ public class AuthenticationManagerProxy implements AuthenticationManager {
return m.authenticate(authentication);
}
public void setManager(AuthenticationManager manager) {
this.manager = manager;
public void setDelegate(AuthenticationManager manager) {
this.delegate = manager;
}
}
......@@ -4,6 +4,7 @@ import groovy.lang.Binding;
import hudson.model.Hudson;
import hudson.util.spring.BeanBuilder;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.userdetails.UserDetailsService;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.Filter;
......@@ -37,14 +38,22 @@ public class HudsonFilter implements Filter {
private Filter acegi;
/**
* {@link AuthenticationManager} proxy so that the acegi filter chain can be configured
* before {@link Hudson} instance is loaded.
* {@link AuthenticationManager} proxy so that the acegi filter chain can stay the same
* even when security setting is reconfigured.
*/
public static final AuthenticationManagerProxy AUTHENTICATION_MANAGER = new AuthenticationManagerProxy();
/**
* {@link UserDetailsService} proxy so that the acegi filter chain can stay the same
* even when security setting is reconfigured.
*/
public static final UserDetailsServiceProxy USER_DETAILS_SERVICE_PROXY = new UserDetailsServiceProxy();
public void init(FilterConfig filterConfig) throws ServletException {
Binding binding = new Binding();
binding.setVariable("authenticationManager", HudsonFilter.AUTHENTICATION_MANAGER);
binding.setVariable("authenticationManagerProxy", AUTHENTICATION_MANAGER);
binding.setVariable("UserDetailsServiceProxy", USER_DETAILS_SERVICE_PROXY);
binding.setVariable("app", Hudson.getInstance());
BeanBuilder builder = new BeanBuilder();
builder.parse(filterConfig.getServletContext().getResourceAsStream("/WEB-INF/security/SecurityFilters.groovy"),binding);
......
......@@ -9,7 +9,6 @@ import hudson.util.Scrambler;
import hudson.util.Protector;
import hudson.util.spring.BeanBuilder;
import hudson.Util;
import hudson.security.HudsonPrivateSecurityRealm.Details;
import hudson.tasks.Mailer;
import net.sf.json.JSONObject;
import org.acegisecurity.Authentication;
......@@ -24,6 +23,7 @@ import org.acegisecurity.userdetails.UserDetailsService;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.Stapler;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletException;
import java.io.IOException;
......@@ -35,10 +35,13 @@ import java.io.IOException;
*/
public class HudsonPrivateSecurityRealm extends SecurityRealm {
@Override
public AuthenticationManager createAuthenticationManager() {
public SecurityComponents createSecurityComponents() {
BeanBuilder builder = new BeanBuilder();
builder.parse(Hudson.getInstance().servletContext.getResourceAsStream("/WEB-INF/security/HudsonPrivateSecurityRealm.groovy"));
return findBean(AuthenticationManager.class,builder.createApplicationContext());
WebApplicationContext context = builder.createApplicationContext();
return new SecurityComponents(
findBean(AuthenticationManager.class, context),
findBean(UserDetailsService.class, context));
}
public Descriptor<SecurityRealm> getDescriptor() {
......
......@@ -9,11 +9,13 @@ import hudson.util.FormFieldValidator;
import hudson.util.spring.BeanBuilder;
import net.sf.json.JSONObject;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.ldap.search.FilterBasedLdapUserSearch;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.springframework.web.context.WebApplicationContext;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
......@@ -119,13 +121,16 @@ public class LDAPSecurityRealm extends SecurityRealm {
return "ldap://"+server+'/'+rootDN;
}
public AuthenticationManager createAuthenticationManager() {
public SecurityComponents createSecurityComponents() {
Binding binding = new Binding();
binding.setVariable("instance", this);
BeanBuilder builder = new BeanBuilder();
builder.parse(Hudson.getInstance().servletContext.getResourceAsStream("/WEB-INF/security/LDAPBindSecurityRealm.groovy"),binding);
return findBean(AuthenticationManager.class,builder.createApplicationContext());
WebApplicationContext appContext = builder.createApplicationContext();
return new SecurityComponents(
findBean(AuthenticationManager.class, appContext),
findBean(UserDetailsService.class, appContext));
}
public DescriptorImpl getDescriptor() {
......
......@@ -14,8 +14,8 @@ import net.sf.json.JSONObject;
* @author Kohsuke Kawaguchi
*/
public final class LegacySecurityRealm extends SecurityRealm implements AuthenticationManager {
public AuthenticationManager createAuthenticationManager() {
return this;
public SecurityComponents createSecurityComponents() {
return new SecurityComponents(this);
}
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
......
......@@ -7,6 +7,7 @@ import hudson.model.Hudson;
import hudson.util.DescriptorList;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.userdetails.UserDetailsService;
import org.springframework.context.ApplicationContext;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
......@@ -58,7 +59,7 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
* depends on the user configuration), and such configuration is expected to be
* captured as instance variables of {@link SecurityRealm} implementation.
*/
public abstract AuthenticationManager createAuthenticationManager();
public abstract SecurityComponents createSecurityComponents();
/**
* {@inheritDoc}
......@@ -164,12 +165,12 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
public static final SecurityRealm NO_AUTHENTICATION = new None();
private static class None extends SecurityRealm {
public AuthenticationManager createAuthenticationManager() {
return new AuthenticationManager() {
public SecurityComponents createSecurityComponents() {
return new SecurityComponents(new AuthenticationManager() {
public Authentication authenticate(Authentication authentication) {
return authentication;
}
};
});
}
/**
......@@ -188,6 +189,22 @@ public abstract class SecurityRealm implements Describable<SecurityRealm>, Exten
}
}
public static final class SecurityComponents {
public AuthenticationManager manager;
public UserDetailsService userDetails;
public SecurityComponents() {}
public SecurityComponents(AuthenticationManager manager) {
this.manager = manager;
}
public SecurityComponents(AuthenticationManager manager, UserDetailsService userDetails) {
this.manager = manager;
this.userDetails = userDetails;
}
}
/**
* All registered {@link SecurityRealm} implementations.
*/
......
package hudson.security;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
/**
* {@link UserDetailsService} proxy that delegates to another instance.
*
* @author Kohsuke Kawaguchi
*/
public class UserDetailsServiceProxy implements UserDetailsService {
private volatile UserDetailsService delegate;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
UserDetailsService uds = delegate; // fix the reference for concurrency support
if(uds ==null)
throw new UsernameNotFoundException(Messages.UserDetailsServiceProxy_UnableToQuery(username));
return uds.loadUserByUsername(username);
}
public void setDelegate(UserDetailsService core) {
this.delegate = core;
}
}
......@@ -4,5 +4,7 @@ LegacyAuthorizationStrategy.DisplayName=Legacy mode
HudsonPrivateSecurityRealm.Details.DisplayName=Password
UserDetailsServiceProxy.UnableToQuery=Unable to query user information: {0}
# not in use
Permission.Permissions.Title=N/A
......@@ -5,6 +5,7 @@ import org.acegisecurity.providers.ProviderManager
import hudson.security.HudsonPrivateSecurityRealm.HudsonUserDetailsService
import org.acegisecurity.providers.dao.DaoAuthenticationProvider
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider
authenticationManager(ProviderManager) {
......@@ -13,6 +14,11 @@ authenticationManager(ProviderManager) {
bean(DaoAuthenticationProvider) {
userDetailsService = new HudsonUserDetailsService()
},
// these providers apply everywhere
bean(RememberMeAuthenticationProvider) {
key = app.getSecretKey();
},
// 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
......
......@@ -5,6 +5,7 @@ import org.acegisecurity.providers.ldap.authenticator.BindAuthenticator
import org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator
import org.acegisecurity.ldap.DefaultInitialDirContextFactory
import org.acegisecurity.ldap.search.FilterBasedLdapUserSearch
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider
/*
Configure LDAP as the authentication realm.
......@@ -38,6 +39,11 @@ authenticationManager(ProviderManager) {
providers = [
// talk to LDAP
bean(LdapAuthenticationProvider,bindAuthenticator,authoritiesPopulator),
// these providers apply everywhere
bean(RememberMeAuthenticationProvider) {
key = app.getSecretKey();
},
// 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
......
......@@ -14,6 +14,8 @@ import hudson.security.AccessDeniedHandlerImpl
import hudson.security.BasicAuthenticationFilter
import hudson.security.AuthenticationProcessingFilter2
import hudson.security.UnwrapSecurityExceptionFilter
import org.acegisecurity.ui.rememberme.RememberMeProcessingFilter
import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices
// providers that apply to both patterns
def commonProviders(redirectUrl) {
......@@ -39,7 +41,7 @@ filter(ChainedServletFilter) {
},
// allow clients to submit basic authentication credential
bean(BasicProcessingFilter) {
authenticationManager = authenticationManager
authenticationManager = authenticationManagerProxy
// if basic authentication fails (which only happens incorrect basic auth credential is sent),
// respond with 401 with basic auth request, instead of redirecting the user to the login page,
// since users of basic auth tends to be a program and won't see the redirection to the form
......@@ -48,8 +50,14 @@ filter(ChainedServletFilter) {
realmName = "Hudson"
}
},
bean(RememberMeProcessingFilter) {
rememberMeServices = bean(TokenBasedRememberMeServices) {
userDetailsService = userDetailsServiceProxy;
key = app.getSecretKey();
}
},
bean(AuthenticationProcessingFilter2) {
authenticationManager = authenticationManager
authenticationManager = authenticationManagerProxy
authenticationFailureUrl = "/loginError"
defaultTargetUrl = "/"
filterProcessesUrl = "/j_acegi_security_check"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册