提交 27d208b0 编写于 作者: K Kohsuke Kawaguchi

Moving impersonation logic once again.

I think the cleanest place to do this is as a filter of UserDetailsService.

The problem is that SecurityRealm defines loadUserByName method, which AbstractPasswordBasedSecurityRealm overrides
上级 bded790f
......@@ -39,6 +39,7 @@ import hudson.util.RunList;
import hudson.util.XStream2;
import jenkins.model.Jenkins;
import jenkins.model.ModelObjectWithContextMenu;
import jenkins.security.ImpersonatingUserDetailsService;
import jenkins.security.LastGrantedAuthoritiesProperty;
import net.sf.json.JSONObject;
......@@ -262,7 +263,8 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
*/
public Authentication impersonate() throws UsernameNotFoundException {
try {
UserDetails u = Jenkins.getInstance().getSecurityRealm().loadUserByUsername(id);
UserDetails u = new ImpersonatingUserDetailsService(
Jenkins.getInstance().getSecurityRealm().getSecurityComponents().userDetails).loadUserByUsername(id);
return new UsernamePasswordAuthenticationToken(u.getUsername(), "", u.getAuthorities());
} catch (UserMayOrMayNotExistException e) {
// backend can't load information about other users. so use the stored information if available
......@@ -273,12 +275,9 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
// seems like it's in the same boat as UserMayOrMayNotExistException
}
LastGrantedAuthoritiesProperty p = getProperty(LastGrantedAuthoritiesProperty.class);
if (p!=null)
return new UsernamePasswordAuthenticationToken(id, "", p.getAuthorities());
else
return new UsernamePasswordAuthenticationToken(id, "",
new GrantedAuthority[]{SecurityRealm.AUTHENTICATED_AUTHORITY});
// seems like a legitimate user we have no idea about. proceed with minimum access
return new UsernamePasswordAuthenticationToken(id, "",
new GrantedAuthority[]{SecurityRealm.AUTHENTICATED_AUTHORITY});
}
/**
......
......@@ -8,6 +8,7 @@ import hudson.util.spring.BeanBuilder;
import java.io.Console;
import java.io.IOException;
import jenkins.model.Jenkins;
import jenkins.security.ImpersonatingUserDetailsService;
import jenkins.security.SecurityListener;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
......@@ -45,7 +46,8 @@ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm i
builder.parse(Jenkins.getInstance().servletContext.getResourceAsStream("/WEB-INF/security/AbstractPasswordBasedSecurityRealm.groovy"),binding);
WebApplicationContext context = builder.createApplicationContext();
return new SecurityComponents(
findBean(AuthenticationManager.class, context),this);
findBean(AuthenticationManager.class, context),
new ImpersonatingUserDetailsService(this));
}
@Override
......
......@@ -23,20 +23,19 @@
*/
package hudson.security;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import hudson.Functions;
import jenkins.model.Jenkins;
import jenkins.security.HMACConfidentialKey;
import org.acegisecurity.Authentication;
import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.Authentication;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
/**
* {@link TokenBasedRememberMeServices} with modification so as not to rely
* on the user password being available.
......
package jenkins.security;
import hudson.model.User;
import hudson.security.SecurityRealm;
import hudson.security.UserMayOrMayNotExistException;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
import static java.util.Collections.*;
/**
* {@link UserDetailsService} for those {@link SecurityRealm}
* that doesn't allow query of other users.
*
* When the backend responds with {@link UserMayOrMayNotExistException}, we try to replace that with
* information stored in {@link LastGrantedAuthoritiesProperty}.
*
* @author Kohsuke Kawaguchi
*/
public class ImpersonatingUserDetailsService implements UserDetailsService {
private final UserDetailsService base;
public ImpersonatingUserDetailsService(UserDetailsService base) {
this.base = base;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
try {
return base.loadUserByUsername(username);
} catch (UserMayOrMayNotExistException e) {
return attemptToImpersonate(username, e);
} catch (DataAccessException e) {
return attemptToImpersonate(username, e);
}
}
protected UserDetails attemptToImpersonate(String username, RuntimeException e) {
// this backend cannot tell if the user name exists or not. so substitute by what we know
User u = User.get(username, false, emptyMap());
if (u!=null) {
LastGrantedAuthoritiesProperty p = u.getProperty(LastGrantedAuthoritiesProperty.class);
if (p!=null)
return new org.acegisecurity.userdetails.User(username,null,true,true,true,true,
p.getAuthorities());
}
throw e;
}
}
......@@ -17,7 +17,6 @@ import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
......@@ -29,6 +28,7 @@ import java.util.logging.Logger;
*
* @author Kohsuke Kawaguchi
* @since 1.556
* @see ImpersonatingUserDetailsService
*/
public class LastGrantedAuthoritiesProperty extends UserProperty {
private volatile String[] roles;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册