| author | Henrik Lynggaard Hansen | 2012-07-12 15:07:46 (EDT) |
|---|---|---|
| committer | Henrik Lynggaard Hansen | 2012-07-12 15:07:46 (EDT) |
| commit | 0228c8c57afb5b5d0f1f9762e162b747e67cb696 (patch) (side-by-side diff) | |
| tree | c0eb868946cf04a176d1bb1564f58ba4cae8611f | |
| parent | 2e3f55d880a7c54c95afb2f243678f960c79c6bf (diff) | |
| download | org.eclipse.hudson.core-0228c8c57afb5b5d0f1f9762e162b747e67cb696.zip org.eclipse.hudson.core-0228c8c57afb5b5d0f1f9762e162b747e67cb696.tar.gz org.eclipse.hudson.core-0228c8c57afb5b5d0f1f9762e162b747e67cb696.tar.bz2 | |
Reformat hudson.securityrefs/changes/44/6744/1
Change-Id: I827712ac8a7758919b7c7a1e035bdb2c05b97007
Signed-off-by: Henrik Lynggaard Hansen <henrik@hlyh.dk>
47 files changed, 1610 insertions, 1517 deletions
diff --git a/hudson-core/src/main/java/hudson/security/ACL.java b/hudson-core/src/main/java/hudson/security/ACL.java index ce00ccb..d94c328 100644 --- a/hudson-core/src/main/java/hudson/security/ACL.java +++ b/hudson-core/src/main/java/hudson/security/ACL.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi - * + * *******************************************************************************/ package hudson.security; @@ -26,54 +26,54 @@ import org.eclipse.hudson.security.HudsonSecurityManager; * Gate-keeper that controls access to Hudson's model objects. * * @author Kohsuke Kawaguchi - * @see http://wiki.hudson-ci.org/display/HUDSON/Making+your+plugin+behave+in+secured+Hudson + * @see + * http://wiki.hudson-ci.org/display/HUDSON/Making+your+plugin+behave+in+secured+Hudson */ public abstract class ACL { + /** * Checks if the current security principal has this permission. * - * <p> - * This is just a convenience function. + * <p> This is just a convenience function. * - * @throws org.acegisecurity.AccessDeniedException - * if the user doesn't have the permission. + * @throws org.acegisecurity.AccessDeniedException if the user doesn't have + * the permission. */ public final void checkPermission(Permission p) { Authentication a = HudsonSecurityManager.getAuthentication(); - if(!hasPermission(a,p)) - throw new AccessDeniedException2(a,p); + if (!hasPermission(a, p)) { + throw new AccessDeniedException2(a, p); + } } /** * Checks if the current security principal has this permission. * - * @return false - * if the user doesn't have the permission. + * @return false if the user doesn't have the permission. */ public final boolean hasPermission(Permission p) { - return hasPermission(HudsonSecurityManager.getAuthentication(),p); + return hasPermission(HudsonSecurityManager.getAuthentication(), p); } /** * Checks if the given principle has the given permission. * - * <p> - * Note that {@link #SYSTEM} can be passed in as the authentication parameter, - * in which case you should probably just assume it has every permission. + * <p> Note that {@link #SYSTEM} can be passed in as the authentication + * parameter, in which case you should probably just assume it has every + * permission. */ public abstract boolean hasPermission(Authentication a, Permission permission); - // // Sid constants // - /** - * Special {@link Sid} that represents "everyone", even including anonymous users. + * Special {@link Sid} that represents "everyone", even including anonymous + * users. * - * <p> - * This doesn't need to be included in {@link Authentication#getAuthorities()}, - * but {@link ACL} is responsible for checking it nontheless, as if it was the - * last entry in the granted authority. + * <p> This doesn't need to be included in + * {@link Authentication#getAuthorities()}, but {@link ACL} is responsible + * for checking it nontheless, as if it was the last entry in the granted + * authority. */ public static final Sid EVERYONE = new Sid() { @Override @@ -81,27 +81,21 @@ public abstract class ACL { return "EVERYONE"; } }; - /** - * {@link Sid} that represents the anonymous unauthenticated users. - * <p> + * {@link Sid} that represents the anonymous unauthenticated users. <p> * {@link HudsonFilter} sets this up, so this sid remains the same * regardless of the current {@link SecurityRealm} in use. */ public static final Sid ANONYMOUS = new PrincipalSid("anonymous"); - - protected static final Sid[] AUTOMATIC_SIDS = new Sid[]{EVERYONE,ANONYMOUS}; - + protected static final Sid[] AUTOMATIC_SIDS = new Sid[]{EVERYONE, ANONYMOUS}; /** - * {@link Sid} that represents the Hudson itself. - * <p> - * This is used when Hudson is performing computation for itself, instead - * of acting on behalf of an user, such as doing builds. + * {@link Sid} that represents the Hudson itself. <p> This is used when + * Hudson is performing computation for itself, instead of acting on behalf + * of an user, such as doing builds. * - * <p> - * (Note that one of the features being considered is to keep track of who triggered - * a build — so in a future, perhaps {@link Executor} will run on behalf of - * the user who triggered a build.) + * <p> (Note that one of the features being considered is to keep track of + * who triggered a build — so in a future, perhaps {@link Executor} + * will run on behalf of the user who triggered a build.) */ - public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken("SYSTEM","SYSTEM"); + public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken("SYSTEM", "SYSTEM"); } diff --git a/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java b/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java index 48c081d..03c09ca 100644 --- a/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java +++ b/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Nikita Levyankov, Winston Prakash - * + * *******************************************************************************/ package hudson.security; @@ -41,21 +41,23 @@ import org.springframework.security.providers.anonymous.AnonymousAuthenticationP import org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider; /** - * Partial implementation of {@link SecurityRealm} for username/password based authentication. - * This is a convenience base class if all you are trying to do is to check the given username - * and password with the information stored in somewhere else, and you don't want to do anything - * with Spring Security. - * <p/> + * Partial implementation of {@link SecurityRealm} for username/password based + * authentication. This is a convenience base class if all you are trying to do + * is to check the given username and password with the information stored in + * somewhere else, and you don't want to do anything with Spring Security. * <p/> - * This {@link SecurityRealm} uses the standard login form (and a few other optional mechanisms like BASIC auth) - * to gather the username/password information. Subtypes are responsible for authenticating this information. + * < + * p/> + * This {@link SecurityRealm} uses the standard login form (and a few other + * optional mechanisms like BASIC auth) to gather the username/password + * information. Subtypes are responsible for authenticating this information. * * @author Kohsuke Kawaguchi * @author Nikita Levyankov * @since 1.317 */ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm implements UserDetailsService { - + @Override public SecurityComponents createSecurityComponents() { @@ -89,11 +91,9 @@ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm i return new CliAuthenticator() { @Option(name = "--username", usage = "User name to authenticate yourself to Hudson") public String userName; - @Option(name = "--password", - usage = "Password for authentication. Note that passing a password in arguments is insecure.") + usage = "Password for authentication. Note that passing a password in arguments is insecure.") public String password; - @Option(name = "--password-file", usage = "File that contains the password") public String passwordFile; @@ -124,29 +124,38 @@ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm i } /** - * Authenticate a login attempt. - * This method is the heart of a {@link AbstractPasswordBasedSecurityRealm}. - * <p/> + * Authenticate a login attempt. This method is the heart of a + * {@link AbstractPasswordBasedSecurityRealm}. * <p/> - * If the user name and the password pair matches, retrieve the information about this user and - * return it as a {@link UserDetails} object. {@link org.springframework.security.userdetails.User} is a convenient - * implementation to use, but if your backend offers additional data, you may want to use your own subtype - * so that the rest of Hudson can use those additional information (such as e-mail address --- see + * < + * p/> + * If the user name and the password pair matches, retrieve the information + * about this user and return it as a {@link UserDetails} object. + * {@link org.springframework.security.userdetails.User} is a convenient + * implementation to use, but if your backend offers additional data, you + * may want to use your own subtype so that the rest of Hudson can use those + * additional information (such as e-mail address --- see * {@link MailAddressResolver}.) * <p/> + * < + * p/> + * Properties like {@link UserDetails#getPassword()} make no sense, so just + * return an empty value from it. The only information that you need to pay + * real attention is {@link UserDetails#getAuthorities()}, which is a list + * of roles/groups that the user is in. At minimum, this must contain + * {@link #AUTHENTICATED_AUTHORITY} (which indicates that this user is + * authenticated and not anonymous), but if your backend supports a notion + * of groups, you should make sure that the authorities contain one entry + * per one group. This enables users to control authorization based on + * groups. * <p/> - * Properties like {@link UserDetails#getPassword()} make no sense, so just return an empty value from it. - * The only information that you need to pay real attention is {@link UserDetails#getAuthorities()}, which - * is a list of roles/groups that the user is in. At minimum, this must contain {@link #AUTHENTICATED_AUTHORITY} - * (which indicates that this user is authenticated and not anonymous), but if your backend supports a notion - * of groups, you should make sure that the authorities contain one entry per one group. This enables - * users to control authorization based on groups. - * <p/> - * <p/> - * If the user name and the password pair doesn't match, throw {@link AuthenticationException} to reject the login - * attempt. - * If authentication was successful - HUDSON_USER environment variable will be set - * <a href='http://issues.hudson-ci.org/browse/HUDSON-4463'>HUDSON-4463</a> + * < + * p/> + * If the user name and the password pair doesn't match, throw + * {@link AuthenticationException} to reject the login attempt. If + * authentication was successful - HUDSON_USER environment variable will be + * set <a + * href='http://issues.hudson-ci.org/browse/HUDSON-4463'>HUDSON-4463</a> */ protected UserDetails doAuthenticate(String username, String password) throws AuthenticationException { UserDetails userDetails = authenticate(username, password); @@ -155,42 +164,47 @@ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm i } /** - * Implements same logic as {@link #doAuthenticate(String, String)} method, but doesn't set hudson_user env variable. + * Implements same logic as {@link #doAuthenticate(String, String)} method, + * but doesn't set hudson_user env variable. */ protected abstract UserDetails authenticate(String username, String password) throws AuthenticationException; /** * Retrieves information about an user by its name. * <p/> - * <p/> - * This method is used, for example, to validate if the given token is a valid user name when the user is configuring an ACL. - * This is an optional method that improves the user experience. If your backend doesn't support + * < + * p/> + * This method is used, for example, to validate if the given token is a + * valid user name when the user is configuring an ACL. This is an optional + * method that improves the user experience. If your backend doesn't support * a query like this, just always throw {@link UsernameNotFoundException}. */ @Override public abstract UserDetails loadUserByUsername(String username) - throws UsernameNotFoundException, DataAccessException; + throws UsernameNotFoundException, DataAccessException; /** * Retrieves information about a group by its name. * <p/> - * This method is the group version of the {@link #loadUserByUsername(String)}. + * This method is the group version of the + * {@link #loadUserByUsername(String)}. */ @Override public abstract GroupDetails loadGroupByGroupname(String groupname) - throws UsernameNotFoundException, DataAccessException; + throws UsernameNotFoundException, DataAccessException; class Authenticator extends AbstractUserDetailsAuthenticationProvider { + protected void additionalAuthenticationChecks(UserDetails userDetails, - UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { + UsernamePasswordAuthenticationToken authentication) + throws AuthenticationException { // authentication is assumed to be done already in the retrieveUser method } protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { + throws AuthenticationException { return AbstractPasswordBasedSecurityRealm.this.doAuthenticate(username, - authentication.getCredentials().toString()); + authentication.getCredentials().toString()); } } @@ -198,6 +212,7 @@ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm i * Asks for the password. */ private static class InteractivelyAskForPassword implements Callable<String, IOException> { + public String call() throws IOException { Console console = System.console(); if (console == null) { @@ -210,7 +225,6 @@ public abstract class AbstractPasswordBasedSecurityRealm extends SecurityRealm i } return new String(w); } - private static final long serialVersionUID = 1L; } } diff --git a/hudson-core/src/main/java/hudson/security/AccessControlled.java b/hudson-core/src/main/java/hudson/security/AccessControlled.java index d5bf9f2..9ef8a1f 100644 --- a/hudson-core/src/main/java/hudson/security/AccessControlled.java +++ b/hudson-core/src/main/java/hudson/security/AccessControlled.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* + * Contributors: + * * Kohsuke Kawaguchi, Tom Huybrechts - * + * * *******************************************************************************/ @@ -22,9 +22,11 @@ import org.springframework.security.AccessDeniedException; * Object that has an {@link ACL} * * @since 1.220 - * @see http://wiki.hudson-ci.org/display/HUDSON/Making+your+plugin+behave+in+secured+Hudson + * @see + * http://wiki.hudson-ci.org/display/HUDSON/Making+your+plugin+behave+in+secured+Hudson */ public interface AccessControlled { + /** * Obtains the ACL associated with this object. * @@ -41,5 +43,4 @@ public interface AccessControlled { * Convenient short-cut for {@code getACL().hasPermission(permission)} */ boolean hasPermission(Permission permission); - } diff --git a/hudson-core/src/main/java/hudson/security/AccessDeniedException2.java b/hudson-core/src/main/java/hudson/security/AccessDeniedException2.java index 6a70b50..5fb5e5a 100644 --- a/hudson-core/src/main/java/hudson/security/AccessDeniedException2.java +++ b/hudson-core/src/main/java/hudson/security/AccessDeniedException2.java @@ -8,7 +8,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * + * * *******************************************************************************/ @@ -19,25 +19,26 @@ import org.springframework.security.Authentication; /** * {@link AccessDeniedException} with more information. + * * @author Kohsuke Kawaguchi */ public class AccessDeniedException2 extends AccessDeniedException { + /** * This object represents the user being authenticated. */ public final Authentication authentication; - /** * This object represents the permission that the user needed. */ public final Permission permission; public AccessDeniedException2(Authentication authentication, Permission permission) { - this(null,authentication,permission); + this(null, authentication, permission); } public AccessDeniedException2(Throwable t, Authentication authentication, Permission permission) { - super(Messages.AccessDeniedException2_MissingPermission(authentication.getName(),permission.name), t); + super(Messages.AccessDeniedException2_MissingPermission(authentication.getName(), permission.name), t); this.authentication = authentication; this.permission = permission; } diff --git a/hudson-core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java b/hudson-core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java index 2bb1991..38d40ae 100644 --- a/hudson-core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java +++ b/hudson-core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -39,12 +39,13 @@ import java.util.Vector; * @author Kohsuke Kawaguchi */ public class AccessDeniedHandlerImpl implements AccessDeniedHandler { + public void handle(ServletRequest request, ServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse rsp = (HttpServletResponse) response; rsp.setStatus(HttpServletResponse.SC_FORBIDDEN); - req.setAttribute("exception",accessDeniedException); + req.setAttribute("exception", accessDeniedException); Stapler stapler = new Stapler(); stapler.init(new ServletConfig() { public String getServletName() { @@ -64,6 +65,6 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler { } }); - stapler.invoke(req,rsp, Hudson.getInstance(),"/accessDenied"); + stapler.invoke(req, rsp, Hudson.getInstance(), "/accessDenied"); } } diff --git a/hudson-core/src/main/java/hudson/security/AuthenticationManagerProxy.java b/hudson-core/src/main/java/hudson/security/AuthenticationManagerProxy.java index 9134151..f2142a0 100644 --- a/hudson-core/src/main/java/hudson/security/AuthenticationManagerProxy.java +++ b/hudson-core/src/main/java/hudson/security/AuthenticationManagerProxy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -24,23 +24,24 @@ import org.springframework.security.DisabledException; /** * {@link AuthenticationManager} proxy that delegates to another instance. * - * <p> - * This is used so that we can set up servlet filters first (which requires a reference - * to {@link AuthenticationManager}), then later change the actual authentication manager - * (and its set up) at runtime. + * <p> This is used so that we can set up servlet filters first (which requires + * a reference to {@link AuthenticationManager}), then later change the actual + * authentication manager (and its set up) at runtime. * * @author Kohsuke Kawaguchi */ public class AuthenticationManagerProxy implements AuthenticationManager { + private volatile AuthenticationManager delegate; public Authentication authenticate(Authentication authentication) throws AuthenticationException { AuthenticationManager m = delegate; // fix the reference we are working with - if(m ==null) + if (m == null) { throw new DisabledException("Authentication service is still not ready yet"); - else + } else { return m.authenticate(authentication); + } } public void setDelegate(AuthenticationManager manager) { diff --git a/hudson-core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java b/hudson-core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java index be14412..d37bbfe 100644 --- a/hudson-core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java +++ b/hudson-core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi, Matthew R. Harrah - * + * Contributors: + * + * Kohsuke Kawaguchi, Matthew R. Harrah + * * *******************************************************************************/ @@ -28,25 +28,28 @@ import org.springframework.security.AuthenticationException; import org.springframework.security.ui.webapp.AuthenticationProcessingFilter; /** - * {@link AuthenticationProcessingFilter} with a change for Hudson so that - * we can pick up the hidden "from" form field defined in <tt>login.jelly</tt> - * to send the user back to where he came from, after a successful authentication. - * + * {@link AuthenticationProcessingFilter} with a change for Hudson so that we + * can pick up the hidden "from" form field defined in <tt>login.jelly</tt> to + * send the user back to where he came from, after a successful authentication. + * * @author Kohsuke Kawaguchi */ public class AuthenticationProcessingFilter2 extends AuthenticationProcessingFilter { + @Override protected String determineTargetUrl(HttpServletRequest request) { String targetUrl = request.getParameter("from"); request.getSession().setAttribute("from", targetUrl); - if (targetUrl == null) + if (targetUrl == null) { return getDefaultTargetUrl(); + } // URL returned from determineTargetUrl() is resolved against the context path, // whereas the "from" URL is resolved against the top of the website, so adjust this. - if(targetUrl.startsWith(request.getContextPath())) + if (targetUrl.startsWith(request.getContextPath())) { return targetUrl.substring(request.getContextPath().length()); + } // not sure when this happens, but apparently this happens in some case. // see #1274 @@ -54,28 +57,29 @@ public class AuthenticationProcessingFilter2 extends AuthenticationProcessingFil } /** - * @see org.springframework.security.ui.AbstractProcessingFilter#determineFailureUrl(javax.servlet.http.HttpServletRequest, org.springframework.security.AuthenticationException) + * @see + * org.springframework.security.ui.AbstractProcessingFilter#determineFailureUrl(javax.servlet.http.HttpServletRequest, + * org.springframework.security.AuthenticationException) */ @Override protected String determineFailureUrl(HttpServletRequest request, AuthenticationException failed) { Properties excMap = getExceptionMappings(); - String failedClassName = failed.getClass().getName(); - String whereFrom = request.getParameter("from"); - request.getSession().setAttribute("from", whereFrom); - return excMap.getProperty(failedClassName, getAuthenticationFailureUrl()); + String failedClassName = failed.getClass().getName(); + String whereFrom = request.getParameter("from"); + request.getSession().setAttribute("from", whereFrom); + return excMap.getProperty(failedClassName, getAuthenticationFailureUrl()); } /** * Leave the information about login failure. * - * <p> - * Otherwise it seems like Spring Security doesn't really leave the detail of the failure anywhere. + * <p> Otherwise it seems like Spring Security doesn't really leave the + * detail of the failure anywhere. */ @Override protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { super.onUnsuccessfulAuthentication(request, response, failed); LOGGER.log(Level.INFO, "Login attempt failed", failed); } - private static final Logger LOGGER = Logger.getLogger(AuthenticationProcessingFilter2.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java b/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java index 2f757de..a9de3fb 100644 --- a/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java +++ b/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Winston Prakash, Peter Hayes, Tom Huybrechts - * + * *******************************************************************************/ package hudson.security; @@ -57,82 +57,84 @@ import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder; /** * {@link JobProperty} to associate ACL for each project. * - * <p> - * Once created (and initialized), this object becomes immutable. + * <p> Once created (and initialized), this object becomes immutable. */ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> { - private transient SidACL acl = new AclImpl(); - - /** - * List up all permissions that are granted. - * - * Strings are either the granted authority or the principal, which is not - * distinguished. - */ - private final Map<Permission, Set<String>> grantedPermissions = new HashMap<Permission, Set<String>>(); - - private Set<String> sids = new HashSet<String>(); + private transient SidACL acl = new AclImpl(); + /** + * List up all permissions that are granted. + * + * Strings are either the granted authority or the principal, which is not + * distinguished. + */ + private final Map<Permission, Set<String>> grantedPermissions = new HashMap<Permission, Set<String>>(); + private Set<String> sids = new HashSet<String>(); private AuthorizationMatrixProperty() { } public AuthorizationMatrixProperty(Map<Permission, Set<String>> grantedPermissions) { // do a deep copy to be safe - for (Entry<Permission,Set<String>> e : grantedPermissions.entrySet()) - this.grantedPermissions.put(e.getKey(),new HashSet<String>(e.getValue())); + for (Entry<Permission, Set<String>> e : grantedPermissions.entrySet()) { + this.grantedPermissions.put(e.getKey(), new HashSet<String>(e.getValue())); + } } - public Set<String> getGroups() { - return sids; - } - - /** - * Returns all SIDs configured in this matrix, minus "anonymous" - * - * @return Always non-null. - */ - public List<String> getAllSIDs() { - Set<String> r = new HashSet<String>(); - for (Set<String> set : grantedPermissions.values()) - r.addAll(set); - r.remove("anonymous"); - - String[] data = r.toArray(new String[r.size()]); - Arrays.sort(data); - return Arrays.asList(data); - } + public Set<String> getGroups() { + return sids; + } /** - * Returns all the (Permission,sid) pairs that are granted, in the multi-map form. + * Returns all SIDs configured in this matrix, minus "anonymous" * - * @return - * read-only. never null. + * @return Always non-null. */ - public Map<Permission,Set<String>> getGrantedPermissions() { + public List<String> getAllSIDs() { + Set<String> r = new HashSet<String>(); + for (Set<String> set : grantedPermissions.values()) { + r.addAll(set); + } + r.remove("anonymous"); + + String[] data = r.toArray(new String[r.size()]); + Arrays.sort(data); + return Arrays.asList(data); + } + + /** + * Returns all the (Permission,sid) pairs that are granted, in the multi-map + * form. + * + * @return read-only. never null. + */ + public Map<Permission, Set<String>> getGrantedPermissions() { return Collections.unmodifiableMap(grantedPermissions); } /** - * Adds to {@link #grantedPermissions}. Use of this method should be limited - * during construction, as this object itself is considered immutable once - * populated. - */ - protected void add(Permission p, String sid) { - Set<String> set = grantedPermissions.get(p); - if (set == null) - grantedPermissions.put(p, set = new HashSet<String>()); - set.add(sid); - sids.add(sid); - } + * Adds to {@link #grantedPermissions}. Use of this method should be limited + * during construction, as this object itself is considered immutable once + * populated. + */ + protected void add(Permission p, String sid) { + Set<String> set = grantedPermissions.get(p); + if (set == null) { + grantedPermissions.put(p, set = new HashSet<String>()); + } + set.add(sid); + sids.add(sid); + } @Extension public static class DescriptorImpl extends JobPropertyDescriptor { - @Override - public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException { + + @Override + public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException { formData = formData.getJSONObject("useProjectSecurity"); - if (formData.isNullObject()) + if (formData.isNullObject()) { return null; + } AuthorizationMatrixProperty amp = new AuthorizationMatrixProperty(); for (Map.Entry<String, Object> r : (Set<Map.Entry<String, Object>>) formData.getJSONObject("data").entrySet()) { @@ -147,26 +149,26 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> { } } } - return amp; - } + return amp; + } - @Override - public boolean isApplicable(Class<? extends Job> jobType) { + @Override + public boolean isApplicable(Class<? extends Job> jobType) { // only applicable when ProjectMatrixAuthorizationStrategy is in charge return HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getAuthorizationStrategy() instanceof ProjectMatrixAuthorizationStrategy; - } + } - @Override - public String getDisplayName() { - return "Authorization Matrix"; - } + @Override + public String getDisplayName() { + return "Authorization Matrix"; + } - public List<PermissionGroup> getAllGroups() { - return Arrays.asList(PermissionGroup.get(Item.class),PermissionGroup.get(Run.class)); - } + public List<PermissionGroup> getAllGroups() { + return Arrays.asList(PermissionGroup.get(Item.class), PermissionGroup.get(Run.class)); + } public boolean showPermission(Permission p) { - return p.getEnabled() && p!=Item.CREATE; + return p.getEnabled() && p != Item.CREATE; } public FormValidation doCheckName(@AncestorInPath Job project, @QueryParameter String value) throws IOException, ServletException { @@ -174,38 +176,42 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> { } } - private final class AclImpl extends SidACL { - protected Boolean hasPermission(Sid sid, Permission p) { - if (AuthorizationMatrixProperty.this.hasPermission(toString(sid),p)) - return true; - return null; - } - } - - public SidACL getACL() { - return acl; - } - - /** - * Checks if the given SID has the given permission. - */ - public boolean hasPermission(String sid, Permission p) { - for (; p != null; p = p.impliedBy) { - Set<String> set = grantedPermissions.get(p); - if (set != null && set.contains(sid)) - return true; - } - return false; - } + private final class AclImpl extends SidACL { + + protected Boolean hasPermission(Sid sid, Permission p) { + if (AuthorizationMatrixProperty.this.hasPermission(toString(sid), p)) { + return true; + } + return null; + } + } + + public SidACL getACL() { + return acl; + } /** - * Checks if the permission is explicitly given, instead of implied through {@link Permission#impliedBy}. + * Checks if the given SID has the given permission. + */ + public boolean hasPermission(String sid, Permission p) { + for (; p != null; p = p.impliedBy) { + Set<String> set = grantedPermissions.get(p); + if (set != null && set.contains(sid)) { + return true; + } + } + return false; + } + + /** + * Checks if the permission is explicitly given, instead of implied through + * {@link Permission#impliedBy}. */ public boolean hasExplicitPermission(String sid, Permission p) { Set<String> set = grantedPermissions.get(p); return set != null && set.contains(sid); } - + /** * Works like {@link #add(Permission, String)} but takes both parameters * from a single string of the form <tt>PERMISSIONID:sid</tt> @@ -213,59 +219,62 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> { private void add(String shortForm) { int idx = shortForm.indexOf(':'); Permission p = Permission.fromId(shortForm.substring(0, idx)); - if (p==null) - throw new IllegalArgumentException("Failed to parse '"+shortForm+"' --- no such permission"); + if (p == null) { + throw new IllegalArgumentException("Failed to parse '" + shortForm + "' --- no such permission"); + } add(p, shortForm.substring(idx + 1)); } - /** - * Persist {@link ProjectMatrixAuthorizationStrategy} as a list of IDs that - * represent {@link ProjectMatrixAuthorizationStrategy#grantedPermissions}. - */ - public static final class ConverterImpl implements Converter { - public boolean canConvert(Class type) { - return type == AuthorizationMatrixProperty.class; - } - - public void marshal(Object source, HierarchicalStreamWriter writer, - MarshallingContext context) { - AuthorizationMatrixProperty amp = (AuthorizationMatrixProperty) source; - - for (Entry<Permission, Set<String>> e : amp.grantedPermissions - .entrySet()) { - String p = e.getKey().getId(); - for (String sid : e.getValue()) { - writer.startNode("permission"); - writer.setValue(p + ':' + sid); - writer.endNode(); - } - } - } - - public Object unmarshal(HierarchicalStreamReader reader, - final UnmarshallingContext context) { - AuthorizationMatrixProperty as = new AuthorizationMatrixProperty(); - - String prop = reader.peekNextChild(); - if (prop!=null && prop.equals("useProjectSecurity")) { - reader.moveDown(); - reader.getValue(); // we used to use this but not any more. - reader.moveUp(); - } + /** + * Persist {@link ProjectMatrixAuthorizationStrategy} as a list of IDs that + * represent {@link ProjectMatrixAuthorizationStrategy#grantedPermissions}. + */ + public static final class ConverterImpl implements Converter { + + public boolean canConvert(Class type) { + return type == AuthorizationMatrixProperty.class; + } + + public void marshal(Object source, HierarchicalStreamWriter writer, + MarshallingContext context) { + AuthorizationMatrixProperty amp = (AuthorizationMatrixProperty) source; + + for (Entry<Permission, Set<String>> e : amp.grantedPermissions + .entrySet()) { + String p = e.getKey().getId(); + for (String sid : e.getValue()) { + writer.startNode("permission"); + writer.setValue(p + ':' + sid); + writer.endNode(); + } + } + } + + public Object unmarshal(HierarchicalStreamReader reader, + final UnmarshallingContext context) { + AuthorizationMatrixProperty as = new AuthorizationMatrixProperty(); + + String prop = reader.peekNextChild(); + if (prop != null && prop.equals("useProjectSecurity")) { + reader.moveDown(); + reader.getValue(); // we used to use this but not any more. + reader.moveUp(); + } while (reader.hasMoreChildren()) { reader.moveDown(); try { as.add(reader.getValue()); } catch (IllegalArgumentException ex) { - Logger.getLogger(AuthorizationMatrixProperty.class.getName()) - .log(Level.WARNING,"Skipping a non-existent permission",ex); - RobustReflectionConverter.addErrorInContext(context, ex); + Logger.getLogger(AuthorizationMatrixProperty.class.getName()) + .log(Level.WARNING, "Skipping a non-existent permission", ex); + RobustReflectionConverter.addErrorInContext(context, ex); } reader.moveUp(); } - if (GlobalMatrixAuthorizationStrategy.migrateHudson2324(as.grantedPermissions)) + if (GlobalMatrixAuthorizationStrategy.migrateHudson2324(as.grantedPermissions)) { OldDataMonitor.report(context, "1.301"); + } return as; } diff --git a/hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java index 83559dd..751b243 100644 --- a/hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java +++ b/hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi, Seiji Sogabe, Tom Huybrechts - * + * Contributors: + * + * Kohsuke Kawaguchi, Seiji Sogabe, Tom Huybrechts + * * *******************************************************************************/ @@ -35,64 +35,61 @@ import org.kohsuke.stapler.StaplerRequest; /** * Controls authorization throughout Hudson. * - * <h2>Persistence</h2> - * <p> - * This object will be persisted along with {@link Hudson} object. - * Hudson by itself won't put the ACL returned from {@link #getRootACL()} into the serialized object graph, - * so if that object contains state and needs to be persisted, it's the responsibility of - * {@link AuthorizationStrategy} to do so (by keeping them in an instance field.) + * <h2>Persistence</h2> <p> This object will be persisted along with + * {@link Hudson} object. Hudson by itself won't put the ACL returned from + * {@link #getRootACL()} into the serialized object graph, so if that object + * contains state and needs to be persisted, it's the responsibility of + * {@link AuthorizationStrategy} to do so (by keeping them in an instance + * field.) * - * <h2>Re-configuration</h2> - * <p> - * The corresponding {@link Describable} instance will be asked to create a new {@link AuthorizationStrategy} - * every time the system configuration is updated. Implementations that keep more state in ACL beyond - * the system configuration should use {@link Hudson#getAuthorizationStrategy()} to talk to the current - * instance to carry over the state. + * <h2>Re-configuration</h2> <p> The corresponding {@link Describable} instance + * will be asked to create a new {@link AuthorizationStrategy} every time the + * system configuration is updated. Implementations that keep more state in ACL + * beyond the system configuration should use + * {@link Hudson#getAuthorizationStrategy()} to talk to the current instance to + * carry over the state. * * @author Kohsuke Kawaguchi * @see SecurityRealm */ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<AuthorizationStrategy> implements ExtensionPoint { + /** - * Returns the instance of {@link ACL} where all the other {@link ACL} instances - * for all the other model objects eventually delegate. - * <p> - * IOW, this ACL will have the ultimate say on the access control. + * Returns the instance of {@link ACL} where all the other {@link ACL} + * instances for all the other model objects eventually delegate. <p> IOW, + * this ACL will have the ultimate say on the access control. */ public abstract ACL getRootACL(); /** - * @deprecated since 1.277 - * Override {@link #getACL(Job)} instead. + * @deprecated since 1.277 Override {@link #getACL(Job)} instead. */ @Deprecated - public ACL getACL(AbstractProject<?,?> project) { - return getACL((Job)project); + public ACL getACL(AbstractProject<?, ?> project) { + return getACL((Job) project); } - public ACL getACL(Job<?,?> project) { - return getRootACL(); + public ACL getACL(Job<?, ?> project) { + return getRootACL(); } /** * Implementation can choose to provide different ACL for different views. * This can be used as a basis for more fine-grained access control. * - * <p> - * The default implementation returns the ACL of the ViewGroup. + * <p> The default implementation returns the ACL of the ViewGroup. * * @since 1.220 */ public ACL getACL(View item) { - return item.getOwner().getACL(); + return item.getOwner().getACL(); } - + /** * Implementation can choose to provide different ACL for different items. * This can be used as a basis for more fine-grained access control. * - * <p> - * The default implementation returns {@link #getRootACL()}. + * <p> The default implementation returns {@link #getRootACL()}. * * @since 1.220 */ @@ -101,11 +98,10 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth } /** - * Implementation can choose to provide different ACL per user. - * This can be used as a basis for more fine-grained access control. + * Implementation can choose to provide different ACL per user. This can be + * used as a basis for more fine-grained access control. * - * <p> - * The default implementation returns {@link #getRootACL()}. + * <p> The default implementation returns {@link #getRootACL()}. * * @since 1.221 */ @@ -114,11 +110,11 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth } /** - * Implementation can choose to provide different ACL for different computers. - * This can be used as a basis for more fine-grained access control. + * Implementation can choose to provide different ACL for different + * computers. This can be used as a basis for more fine-grained access + * control. * - * <p> - * The default implementation delegates to {@link #getACL(Node)} + * <p> The default implementation delegates to {@link #getACL(Node)} * * @since 1.220 */ @@ -127,11 +123,11 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth } /** - * Implementation can choose to provide different ACL for different {@link Cloud}s. - * This can be used as a basis for more fine-grained access control. + * Implementation can choose to provide different ACL for different + * {@link Cloud}s. This can be used as a basis for more fine-grained access + * control. * - * <p> - * The default implementation returns {@link #getRootACL()}. + * <p> The default implementation returns {@link #getRootACL()}. * * @since 1.252 */ @@ -144,46 +140,42 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth } /** - * Returns the list of all group/role names used in this authorization strategy, - * and the ACL returned from the {@link #getRootACL()} method. - * <p> - * This method is used by {@link ContainerAuthentication} to work around the servlet API issue - * that prevents us from enumerating roles that the user has. - * <p> - * If such enumeration is impossible, do the best to list as many as possible, then - * return it. In the worst case, just return an empty list. Doing so would prevent - * users from using role names as group names (see HUDSON-2716 for such one such report.) + * Returns the list of all group/role names used in this authorization + * strategy, and the ACL returned from the {@link #getRootACL()} method. <p> + * This method is used by {@link ContainerAuthentication} to work around the + * servlet API issue that prevents us from enumerating roles that the user + * has. <p> If such enumeration is impossible, do the best to list as many + * as possible, then return it. In the worst case, just return an empty + * list. Doing so would prevent users from using role names as group names + * (see HUDSON-2716 for such one such report.) * - * @return - * never null. + * @return never null. */ public abstract Collection<String> getGroups(); /** * Returns all the registered {@link AuthorizationStrategy} descriptors. */ - public static DescriptorExtensionList<AuthorizationStrategy,Descriptor<AuthorizationStrategy>> all() { - return Hudson.getInstance().<AuthorizationStrategy,Descriptor<AuthorizationStrategy>>getDescriptorList(AuthorizationStrategy.class); + public static DescriptorExtensionList<AuthorizationStrategy, Descriptor<AuthorizationStrategy>> all() { + return Hudson.getInstance().<AuthorizationStrategy, Descriptor<AuthorizationStrategy>>getDescriptorList(AuthorizationStrategy.class); } - /** * All registered {@link SecurityRealm} implementations. * - * @deprecated since 1.286 - * Use {@link #all()} for read access, and {@link Extension} for registration. + * @deprecated since 1.286 Use {@link #all()} for read access, and + * {@link Extension} for registration. */ public static final DescriptorList<AuthorizationStrategy> LIST = new DescriptorList<AuthorizationStrategy>(AuthorizationStrategy.class); - /** - * {@link AuthorizationStrategy} that implements the semantics - * of unsecured Hudson where everyone has full control. + * {@link AuthorizationStrategy} that implements the semantics of unsecured + * Hudson where everyone has full control. * - * <p> - * This singleton is safe because {@link Unsecured} is stateless. + * <p> This singleton is safe because {@link Unsecured} is stateless. */ public static final AuthorizationStrategy UNSECURED = new Unsecured(); public static final class Unsecured extends AuthorizationStrategy implements Serializable { + /** * Maintains the singleton semantics. */ @@ -199,7 +191,6 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth public Collection<String> getGroups() { return Collections.emptySet(); } - private static final ACL UNSECURED_ACL = new ACL() { public boolean hasPermission(Authentication a, Permission permission) { return true; @@ -208,6 +199,7 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth @Extension public static final class DescriptorImpl extends Descriptor<AuthorizationStrategy> { + public String getDisplayName() { return Messages.AuthorizationStrategy_DisplayName(); } diff --git a/hudson-core/src/main/java/hudson/security/BasicAuthenticationFilter.java b/hudson-core/src/main/java/hudson/security/BasicAuthenticationFilter.java index 5a96eda..4e5103a 100644 --- a/hudson-core/src/main/java/hudson/security/BasicAuthenticationFilter.java +++ b/hudson-core/src/main/java/hudson/security/BasicAuthenticationFilter.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Winston Prakash - * + * * *******************************************************************************/ @@ -35,46 +35,39 @@ import org.springframework.security.context.SecurityContextHolder; /** * Implements the dual authentcation mechanism. * - * <p> - * Hudson supports both the HTTP basic authentication and the form-based authentication. - * The former is for scripted clients, and the latter is for humans. Unfortunately, - * becase the servlet spec does not allow us to programatically authenticate users, - * we need to rely on some work around to make it work, and this is the class that implements - * that work around. + * <p> Hudson supports both the HTTP basic authentication and the form-based + * authentication. The former is for scripted clients, and the latter is for + * humans. Unfortunately, becase the servlet spec does not allow us to + * programatically authenticate users, we need to rely on some work around to + * make it work, and this is the class that implements that work around. * - * <p> - * When an HTTP request arrives with an HTTP basic auth header, this filter detects - * that and emulate an invocation of <tt>/j_security_check</tt> - * (see <a href="http://mail-archives.apache.org/mod_mbox/tomcat-users/200105.mbox/%3C9005C0C9C85BD31181B20060085DAC8B10C8EF@tuvi.andmevara.ee%3E">this page</a> for the original technique.) + * <p> When an HTTP request arrives with an HTTP basic auth header, this filter + * detects that and emulate an invocation of <tt>/j_security_check</tt> (see <a + * href="http://mail-archives.apache.org/mod_mbox/tomcat-users/200105.mbox/%3C9005C0C9C85BD31181B20060085DAC8B10C8EF@tuvi.andmevara.ee%3E">this + * page</a> for the original technique.) * - * <p> - * This causes the container to perform authentication, but there's no way - * to find out whether the user has been successfully authenticated or not. - * So to find this out, we then redirect the user to + * <p> This causes the container to perform authentication, but there's no way + * to find out whether the user has been successfully authenticated or not. So + * to find this out, we then redirect the user to * {@link Hudson#doSecured(org.kohsuke.stapler.StaplerRequest, org.kohsuke.stapler.StaplerResponse) <tt>/secured/...</tt> page}. * - * <p> - * The handler of the above URL checks if the user is authenticated, - * and if not report an HTTP error code. Otherwise the user is - * redirected back to the original URL, where the request is served. + * <p> The handler of the above URL checks if the user is authenticated, and if + * not report an HTTP error code. Otherwise the user is redirected back to the + * original URL, where the request is served. * - * <p> - * So all in all, the redirection works like <tt>/abc/def</tt> -> <tt>/secured/abc/def</tt> - * -> <tt>/abc/def</tt>. + * <p> So all in all, the redirection works like <tt>/abc/def</tt> -> + * <tt>/secured/abc/def</tt> -> <tt>/abc/def</tt>. * - * <h2>Notes</h2> - * <ul> - * <li> - * The technique of getting a request dispatcher for <tt>/j_security_check</tt> may not - * work for all containers, but so far that seems like the only way to make this work. - * <li> - * This A->B->A redirect is a cyclic redirection, so we need to watch out for clients - * that detect this as an error. - * </ul> + * <h2>Notes</h2> <ul> <li> The technique of getting a request dispatcher for + * <tt>/j_security_check</tt> may not work for all containers, but so far that + * seems like the only way to make this work. <li> This A->B->A redirect is a + * cyclic redirection, so we need to watch out for clients that detect this as + * an error. </ul> * * @author Kohsuke Kawaguchi */ public class BasicAuthenticationFilter implements Filter { + private ServletContext servletContext; public void init(FilterConfig filterConfig) throws ServletException { @@ -87,10 +80,10 @@ public class BasicAuthenticationFilter implements Filter { String authorization = req.getHeader("Authorization"); String path = req.getServletPath(); - if(authorization==null || req.getUserPrincipal() !=null || path.startsWith("/secured/") - || !HudsonSecurityEntitiesHolder.getHudsonSecurityManager().isUseSecurity()) { + if (authorization == null || req.getUserPrincipal() != null || path.startsWith("/secured/") + || !HudsonSecurityEntitiesHolder.getHudsonSecurityManager().isUseSecurity()) { // normal requests, or security not enabled - if(req.getUserPrincipal()!=null) { + if (req.getUserPrincipal() != null) { // before we route this request, integrate the container authentication // to Spring Security. For anonymous users that doesn't have user principal, // AnonymousProcessingFilter that follows this should create @@ -98,7 +91,7 @@ public class BasicAuthenticationFilter implements Filter { SecurityContextHolder.getContext().setAuthentication(new ContainerAuthentication(req)); } try { - chain.doFilter(request,response); + chain.doFilter(request, response); } finally { SecurityContextHolder.clearContext(); } @@ -112,28 +105,29 @@ public class BasicAuthenticationFilter implements Filter { int idx = uidpassword.indexOf(':'); if (idx >= 0) { username = uidpassword.substring(0, idx); - password = uidpassword.substring(idx+1); + password = uidpassword.substring(idx + 1); } - if(username==null) { + if (username == null) { rsp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - rsp.setHeader("WWW-Authenticate","Basic realm=\"Hudson administrator\""); + rsp.setHeader("WWW-Authenticate", "Basic realm=\"Hudson administrator\""); return; } - path = req.getContextPath()+"/secured"+path; + path = req.getContextPath() + "/secured" + path; String q = req.getQueryString(); - if(q!=null) - path += '?'+q; + if (q != null) { + path += '?' + q; + } // prepare a redirect rsp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - rsp.setHeader("Location",path); + rsp.setHeader("Location", path); // ... but first let the container authenticate this request - RequestDispatcher d = servletContext.getRequestDispatcher("/j_security_check?j_username="+ - URLEncoder.encode(username,"UTF-8")+"&j_password="+URLEncoder.encode(password,"UTF-8")); - d.include(req,rsp); + RequestDispatcher d = servletContext.getRequestDispatcher("/j_security_check?j_username=" + + URLEncoder.encode(username, "UTF-8") + "&j_password=" + URLEncoder.encode(password, "UTF-8")); + d.include(req, rsp); } //public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -149,8 +143,6 @@ public class BasicAuthenticationFilter implements Filter { // ((HttpServletResponse)response).sendRedirect(req.getContextPath()+"/secured"+path); // } //} - public void destroy() { } - } diff --git a/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java b/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java index 1a11b58..eb4fbec 100644 --- a/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java +++ b/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Winston Prakash - * + * * *******************************************************************************/ package hudson.security; @@ -25,32 +25,31 @@ import org.springframework.security.providers.ldap.authenticator.BindAuthenticat /** * {@link BindAuthenticator} with improved diagnostics. - * + * */ public class BindAuthenticator2 extends BindAuthenticator { + /** - * If we ever had a successful authentication, + * If we ever had a successful authentication, */ private boolean hadSuccessfulAuthentication; public BindAuthenticator2(SpringSecurityContextSource springSecurityContextSource) { super(springSecurityContextSource); } - + @Override public DirContextOperations authenticate(Authentication authentication) { - DirContextOperations dirContextOperations = super.authenticate(authentication); - hadSuccessfulAuthentication = true; - return dirContextOperations; + DirContextOperations dirContextOperations = super.authenticate(authentication); + hadSuccessfulAuthentication = true; + return dirContextOperations; } - @Override protected void handleBindException(String userDn, String username, Throwable cause) { - LOGGER.log(hadSuccessfulAuthentication? Level.FINE : Level.WARNING, - "Failed to bind to LDAP: userDn"+userDn+" username="+username,cause); + LOGGER.log(hadSuccessfulAuthentication ? Level.FINE : Level.WARNING, + "Failed to bind to LDAP: userDn" + userDn + " username=" + username, cause); super.handleBindException(userDn, username, cause); } - private static final Logger LOGGER = Logger.getLogger(BindAuthenticator2.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/ChainedServletFilter.java b/hudson-core/src/main/java/hudson/security/ChainedServletFilter.java index 5649954..b7506bb 100644 --- a/hudson-core/src/main/java/hudson/security/ChainedServletFilter.java +++ b/hudson-core/src/main/java/hudson/security/ChainedServletFilter.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -36,6 +36,7 @@ import javax.servlet.ServletResponse; */ public class ChainedServletFilter implements Filter { // array is assumed to be immutable once set + protected volatile Filter[] filters; public ChainedServletFilter() { @@ -55,38 +56,41 @@ public class ChainedServletFilter implements Filter { } public void init(FilterConfig filterConfig) throws ServletException { - if (LOGGER.isLoggable(Level.FINEST)) - for (Filter f : filters) + if (LOGGER.isLoggable(Level.FINEST)) { + for (Filter f : filters) { LOGGER.finest("ChainedServletFilter contains: " + f); + } + } - for (Filter f : filters) + for (Filter f : filters) { f.init(filterConfig); + } } public void doFilter(ServletRequest request, ServletResponse response, final FilterChain chain) throws IOException, ServletException { LOGGER.entering(ChainedServletFilter.class.getName(), "doFilter"); new FilterChain() { - private int position=0; + private int position = 0; // capture the array for thread-safety private final Filter[] filters = ChainedServletFilter.this.filters; public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - if(position==filters.length) { + if (position == filters.length) { // reached to the end - chain.doFilter(request,response); + chain.doFilter(request, response); } else { // call next - filters[position++].doFilter(request,response,this); + filters[position++].doFilter(request, response, this); } } - }.doFilter(request,response); + }.doFilter(request, response); } public void destroy() { - for (Filter f : filters) + for (Filter f : filters) { f.destroy(); + } } - private static final Logger LOGGER = Logger.getLogger(ChainedServletFilter.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/CliAuthenticator.java b/hudson-core/src/main/java/hudson/security/CliAuthenticator.java index 6144cf8..aa6af1e 100644 --- a/hudson-core/src/main/java/hudson/security/CliAuthenticator.java +++ b/hudson-core/src/main/java/hudson/security/CliAuthenticator.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: + * + * * - * - * * *******************************************************************************/ @@ -23,59 +23,61 @@ import org.springframework.security.AuthenticationException; /** * Handles authentication for CLI commands. * - * <p> - * {@link CliAuthenticator} is used to authenticate an invocation of the CLI command, so that - * the thread carries the correct {@link Authentication} that represents the user who's invoking the command. + * <p> {@link CliAuthenticator} is used to authenticate an invocation of the CLI + * command, so that the thread carries the correct {@link Authentication} that + * represents the user who's invoking the command. * - * <h2>Lifecycle</h2> - * <p> - * Each time a CLI command is invoked, {@link SecurityRealm#createCliAuthenticator(CLICommand)} is called - * to allocate a fresh {@link CliAuthenticator} object. + * <h2>Lifecycle</h2> <p> Each time a CLI command is invoked, + * {@link SecurityRealm#createCliAuthenticator(CLICommand)} is called to + * allocate a fresh {@link CliAuthenticator} object. * - * <p> - * The {@link Option} and {@link Argument} annotations on the returned {@link CliAuthenticator} instance are - * scanned and added into the {@link CmdLineParser}, then that parser is used to parse command line arguments. - * This means subtypes can define fields/setters with those annotations to define authentication-specific options - * to CLI commands. + * <p> The {@link Option} and {@link Argument} annotations on the returned + * {@link CliAuthenticator} instance are scanned and added into the + * {@link CmdLineParser}, then that parser is used to parse command line + * arguments. This means subtypes can define fields/setters with those + * annotations to define authentication-specific options to CLI commands. * - * <p> - * Once the arguments and options are parsed and populated, {@link #authenticate()} method is called to - * perform the authentications. If the authentication succeeds, this method returns an {@link Authentication} - * instance that represents the user. If the authentication fails, this method throws {@link AuthenticationException}. - * To authenticate, the method can use parsed argument/option values, as well as interacting with the client - * via {@link CLICommand} by using its stdin/stdout and its channel (for example, if you want to interactively prompt - * a password, you can do so by using {@link CLICommand#channel}.) + * <p> Once the arguments and options are parsed and populated, + * {@link #authenticate()} method is called to perform the authentications. If + * the authentication succeeds, this method returns an {@link Authentication} + * instance that represents the user. If the authentication fails, this method + * throws {@link AuthenticationException}. To authenticate, the method can use + * parsed argument/option values, as well as interacting with the client via + * {@link CLICommand} by using its stdin/stdout and its channel (for example, if + * you want to interactively prompt a password, you can do so by using + * {@link CLICommand#channel}.) * - * <p> - * If no explicit credential is provided, or if the {@link SecurityRealm} depends on a mode of authentication - * that doesn't involve in explicit password (such as Kerberos), it's also often useful to fall back to - * {@link CLICommand#getTransportAuthentication()}, in case the user is authenticated at the transport level. + * <p> If no explicit credential is provided, or if the {@link SecurityRealm} + * depends on a mode of authentication that doesn't involve in explicit password + * (such as Kerberos), it's also often useful to fall back to + * {@link CLICommand#getTransportAuthentication()}, in case the user is + * authenticated at the transport level. * - * <p> - * Many commands do not require any authentication (for example, the "help" command), and still more commands - * can be run successfully with the anonymous permission. So the authenticator should normally allow unauthenticated - * CLI command invocations. For those, return {@link Hudson#ANONYMOUS} from the {@link #authenticate()} method. + * <p> Many commands do not require any authentication (for example, the "help" + * command), and still more commands can be run successfully with the anonymous + * permission. So the authenticator should normally allow unauthenticated CLI + * command invocations. For those, return {@link Hudson#ANONYMOUS} from the + * {@link #authenticate()} method. * - * <h2>Example</h2> - * <p> - * For a complete example, see the implementation of + * <h2>Example</h2> <p> For a complete example, see the implementation of * {@link AbstractPasswordBasedSecurityRealm#createCliAuthenticator(CLICommand)} * * @author Kohsuke Kawaguchi * @since 1.350 */ public abstract class CliAuthenticator { + /** * Authenticates the CLI invocation. See class javadoc for the semantics. * - * @throws AuthenticationException - * If the authentication failed and hence the processing shouldn't proceed. - * @throws IOException - * Can be thrown if the {@link CliAuthenticator} fails to interact with the client. - * This exception is treated as a failure of authentication. It's just that allowing this - * would often simplify the callee. - * @throws InterruptedException - * Same motivation as {@link IOException}. Treated as an authentication failure. + * @throws AuthenticationException If the authentication failed and hence + * the processing shouldn't proceed. + * @throws IOException Can be thrown if the {@link CliAuthenticator} fails + * to interact with the client. This exception is treated as a failure of + * authentication. It's just that allowing this would often simplify the + * callee. + * @throws InterruptedException Same motivation as {@link IOException}. + * Treated as an authentication failure. */ public abstract Authentication authenticate() throws AuthenticationException, IOException, InterruptedException; } diff --git a/hudson-core/src/main/java/hudson/security/ContainerAuthentication.java b/hudson-core/src/main/java/hudson/security/ContainerAuthentication.java index cb544ab..9c2b41f 100644 --- a/hudson-core/src/main/java/hudson/security/ContainerAuthentication.java +++ b/hudson-core/src/main/java/hudson/security/ContainerAuthentication.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Winston Prakash - * + * *******************************************************************************/ package hudson.security; @@ -27,35 +27,37 @@ import java.util.ArrayList; import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder; /** - * {@link Authentication} implementation for {@link Principal} - * given through {@link HttpServletRequest}. + * {@link Authentication} implementation for {@link Principal} given through + * {@link HttpServletRequest}. * - * <p> - * This is used to plug the container authentication to Spring Security, - * for backward compatibility with Hudson < 1.160. + * <p> This is used to plug the container authentication to Spring Security, for + * backward compatibility with Hudson < 1.160. * * @author Kohsuke Kawaguchi */ public final class ContainerAuthentication implements Authentication { + private final Principal principal; private GrantedAuthority[] authorities; /** - * Servlet container can tie a {@link ServletRequest} to the request handling thread, - * so we need to capture all the information upfront to allow {@link Authentication} - * to be passed to other threads, like update center does. See HUDSON-5382. + * Servlet container can tie a {@link ServletRequest} to the request + * handling thread, so we need to capture all the information upfront to + * allow {@link Authentication} to be passed to other threads, like update + * center does. See HUDSON-5382. */ public ContainerAuthentication(HttpServletRequest request) { this.principal = request.getUserPrincipal(); - if (principal==null) + if (principal == null) { throw new IllegalStateException(); // for anonymous users, we just don't call SecurityContextHolder.getContext().setAuthentication. - + } // Servlet API doesn't provide a way to list up all roles the current user // has, so we need to ask AuthorizationStrategy what roles it is going to check against. List<GrantedAuthority> l = new ArrayList<GrantedAuthority>(); - for( String g : HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getAuthorizationStrategy().getGroups()) { - if(request.isUserInRole(g)) + for (String g : HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getAuthorizationStrategy().getGroups()) { + if (request.isUserInRole(g)) { l.add(new GrantedAuthorityImpl(g)); + } } l.add(SecurityRealm.AUTHENTICATED_AUTHORITY); authorities = l.toArray(new GrantedAuthority[l.size()]); diff --git a/hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java b/hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java index 55a114f..a7d4d71 100644 --- a/hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java +++ b/hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java @@ -7,17 +7,17 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ package hudson.security; import org.springframework.security.GrantedAuthority; -import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.ContextSource; import org.springframework.security.ldap.LdapAuthoritiesPopulator; import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; import hudson.security.SecurityRealm.SecurityComponents; @@ -27,11 +27,11 @@ import org.springframework.ldap.core.DirContextOperations; * Implementation of {@link LdapAuthoritiesPopulator} that defers creation of a * {@link DefaultLdapAuthoritiesPopulator} until one is needed. This is done to * ensure that the groupSearchBase property can be set. - * + * * @author justinedelson - * @deprecated as of 1.280 - * {@link SecurityComponents} are now created after {@link SecurityRealm} is created, so - * the initialization order issue that this code was trying to address no longer exists. + * @deprecated as of 1.280 {@link SecurityComponents} are now created after + * {@link SecurityRealm} is created, so the initialization order issue that this + * code was trying to address no longer exists. */ public class DeferredCreationLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator { @@ -39,56 +39,47 @@ public class DeferredCreationLdapAuthoritiesPopulator implements LdapAuthorities * A default role which will be assigned to all authenticated users if set. */ private String defaultRole = null; - /** * An initial context source is only required if searching for groups is * required. */ - private ContextSource contextSource; - /** * Controls used to determine whether group searches should be performed * over the full sub-tree from the base DN. */ private boolean searchSubtree = false; - /** * The ID of the attribute which contains the role name for a group */ private String groupRoleAttribute = "cn"; - /** * The base DN from which the search for group membership should be * performed */ private String groupSearchBase = null; - /** * The pattern to be used for the user search. {0} is the user's DN */ private String groupSearchFilter = "(| (member={0}) (uniqueMember={0}) (memberUid={0}))"; - private String rolePrefix = "ROLE_"; - private boolean convertToUpperCase = true; /** * Constructor. - * - * @param initialDirContextFactory - * supplies the contexts used to search for user roles. - * @param groupSearchBase - * if this is an empty string the search will be performed from - * the root DN of the context factory. + * + * @param initialDirContextFactory supplies the contexts used to search for + * user roles. + * @param groupSearchBase if this is an empty string the search will be + * performed from the root DN of the context factory. */ public DeferredCreationLdapAuthoritiesPopulator( ContextSource contextSource, String groupSearchBase) { this.contextSource = contextSource; this.setGroupSearchBase(groupSearchBase); } - - public GrantedAuthority[] getGrantedAuthorities(DirContextOperations user, String username) { + + public GrantedAuthority[] getGrantedAuthorities(DirContextOperations user, String username) { return create().getGrantedAuthorities(user, username); } @@ -122,7 +113,7 @@ public class DeferredCreationLdapAuthoritiesPopulator implements LdapAuthorities /** * Create a new DefaultLdapAuthoritiesPopulator object. - * + * * @return a DefaultLdapAuthoritiesPopulator. */ private DefaultLdapAuthoritiesPopulator create() { diff --git a/hudson-core/src/main/java/hudson/security/FederatedLoginService.java b/hudson-core/src/main/java/hudson/security/FederatedLoginService.java index bf4f87e..6abccd3 100644 --- a/hudson-core/src/main/java/hudson/security/FederatedLoginService.java +++ b/hudson-core/src/main/java/hudson/security/FederatedLoginService.java @@ -7,8 +7,8 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: - * + * Contributors: + * * Kohsuke Kawaguchi, Winston Prakash * *******************************************************************************/ @@ -36,7 +36,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package hudson.security; import hudson.ExtensionList; @@ -56,70 +55,65 @@ import java.io.IOException; import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder; /** - * Abstraction for a login mechanism through external authenticator/identity provider - * (instead of username/password.) + * Abstraction for a login mechanism through external authenticator/identity + * provider (instead of username/password.) * - * <p> - * This extension point adds additional login mechanism for {@link SecurityRealm}s that - * authenticate the user via username/password (which typically extends from {@link AbstractPasswordBasedSecurityRealm}.) - * The intended use case is protocols like OpenID, OAuth, and other SSO-like services. + * <p> This extension point adds additional login mechanism for + * {@link SecurityRealm}s that authenticate the user via username/password + * (which typically extends from {@link AbstractPasswordBasedSecurityRealm}.) + * The intended use case is protocols like OpenID, OAuth, and other SSO-like + * services. * - * <p> - * The basic abstraction is that: + * <p> The basic abstraction is that: * - * <ul> - * <li> - * The user can have (possibly multiple, possibly zero) opaque strings to their {@linkplain User} object. - * Such opaque strings are called "identifiers." - * Think of them as OpenID URLs, twitter account names, etc. - * Identifiers are only comparable within the same {@link FederatedLoginService} implementation. + * <ul> <li> The user can have (possibly multiple, possibly zero) opaque strings + * to their {@linkplain User} object. Such opaque strings are called + * "identifiers." Think of them as OpenID URLs, twitter account names, etc. + * Identifiers are only comparable within the same {@link FederatedLoginService} + * implementation. * - * <li> - * After getting authenticated by some means, the user can add additional identifiers to their account. - * Your implementation would do protocol specific thing to verify that the user indeed owns the claimed identifier, - * create a {@link FederatedIdentity} instance, - * then call {@link FederatedIdentity#addToCurrentUser()} to record such association. + * <li> After getting authenticated by some means, the user can add additional + * identifiers to their account. Your implementation would do protocol specific + * thing to verify that the user indeed owns the claimed identifier, create a + * {@link FederatedIdentity} instance, then call + * {@link FederatedIdentity#addToCurrentUser()} to record such association. * - * <li> - * In the login page, instead of entering the username and password, the user opts for authenticating - * via other services. Think of OpenID, OAuth, your corporate SSO service, etc. - * The user proves (by your protocol specific way) that they own some identifier, then - * create a {@link FederatedIdentity} instance, and invoke {@link FederatedIdentity#signin()} to sign in that user. + * <li> In the login page, instead of entering the username and password, the + * user opts for authenticating via other services. Think of OpenID, OAuth, your + * corporate SSO service, etc. The user proves (by your protocol specific way) + * that they own some identifier, then create a {@link FederatedIdentity} + * instance, and invoke {@link FederatedIdentity#signin()} to sign in that user. * * </ul> * * - * <h2>Views</h2> - * <dl> - * <dt>loginFragment.jelly - * <dd> - * Injected into the login form page, after the default "login" button but before - * the "create account" link. Use this to generate a button or a link so that the user - * can initiate login via your federated login service. - * </dl> + * <h2>Views</h2> <dl> <dt>loginFragment.jelly <dd> Injected into the login form + * page, after the default "login" button but before the "create account" link. + * Use this to generate a button or a link so that the user can initiate login + * via your federated login service. </dl> * - * <h2>URL Binding</h2> - * <p> - * Each {@link FederatedLoginService} is exposed to the URL space via {@link Hudson#getFederatedLoginService(String)}. - * So for example if your {@linkplain #getUrlName() url name} is "openid", this object gets + * <h2>URL Binding</h2> <p> Each {@link FederatedLoginService} is exposed to the + * URL space via {@link Hudson#getFederatedLoginService(String)}. So for example + * if your {@linkplain #getUrlName() url name} is "openid", this object gets * "/federatedLoginService/openid" as the URL. * * @author Kohsuke Kawaguchi * @since 1.394 */ public abstract class FederatedLoginService implements ExtensionPoint { + /** - * Returns the url name that determines where this {@link FederatedLoginService} is mapped to in the URL space. + * Returns the url name that determines where this + * {@link FederatedLoginService} is mapped to in the URL space. * - * <p> - * The object is bound to /federatedLoginService/URLNAME/. The url name needs to be unique among all - * {@link FederatedLoginService}s. + * <p> The object is bound to /federatedLoginService/URLNAME/. The url name + * needs to be unique among all {@link FederatedLoginService}s. */ public abstract String getUrlName(); /** - * Returns your implementation of {@link FederatedLoginServiceUserProperty} that stores - * opaque identifiers. + * Returns your implementation of {@link FederatedLoginServiceUserProperty} + * that stores opaque identifiers. */ public abstract Class<? extends FederatedLoginServiceUserProperty> getUserPropertyClass(); @@ -127,24 +121,27 @@ public abstract class FederatedLoginService implements ExtensionPoint { * Identity information as obtained from {@link FederatedLoginService}. */ public abstract class FederatedIdentity { + /** - * Gets the string representation of the identity in the form that makes sense to the enclosing - * {@link FederatedLoginService}, such as full OpenID URL. + * Gets the string representation of the identity in the form that makes + * sense to the enclosing {@link FederatedLoginService}, such as full + * OpenID URL. * * @return must not be null. */ public abstract String getIdentifier(); /** - * Gets a short ID of this user, as a suitable candidate for {@link User#getId()}. - * This should be Unix username like token. + * Gets a short ID of this user, as a suitable candidate for + * {@link User#getId()}. This should be Unix username like token. * * @return null if this information is not available. */ public abstract String getNickname(); /** - * Gets a human readable full name of this user. Maps to {@link User#getDisplayName()} + * Gets a human readable full name of this user. Maps to + * {@link User#getDisplayName()} * * @return null if this information is not available. */ @@ -158,8 +155,9 @@ public abstract class FederatedLoginService implements ExtensionPoint { public abstract String getEmailAddress(); /** - * Returns a human-readable pronoun that describes this kind of identifier. - * This is used for rendering UI. For example, "OpenID", "Twitter ID", etc. + * Returns a human-readable pronoun that describes this kind of + * identifier. This is used for rendering UI. For example, "OpenID", + * "Twitter ID", etc. */ public abstract String getPronoun(); @@ -171,32 +169,35 @@ public abstract class FederatedLoginService implements ExtensionPoint { String id = getIdentifier(); for (User u : User.getAll()) { - if (u.getProperty(pt).has(id)) + if (u.getProperty(pt).has(id)) { return u; + } } return null; } /** - * Call this method to authenticate the user when you confirmed (via your protocol specific work) that - * the current HTTP request indeed owns this identifier. + * Call this method to authenticate the user when you confirmed (via + * your protocol specific work) that the current HTTP request indeed + * owns this identifier. * - * <p> - * This method will locate the user who owns this identifier, associate the credential with - * the current session. IOW, it signs in the user. + * <p> This method will locate the user who owns this identifier, + * associate the credential with the current session. IOW, it signs in + * the user. * - * @throws UnclaimedIdentityException - * If this identifier is not claimed by anyone. If you just let this exception propagate - * to the caller of your "doXyz" method, it will either render an error page or initiate - * a user registration session (provided that {@link SecurityRealm} supports that.) + * @throws UnclaimedIdentityException If this identifier is not claimed + * by anyone. If you just let this exception propagate to the caller of + * your "doXyz" method, it will either render an error page or initiate + * a user registration session (provided that {@link SecurityRealm} + * supports that.) */ public User signin() throws UnclaimedIdentityException { User u = locateUser(); - if (u!=null) { + if (u != null) { // login as this user UserDetails d = HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm().loadUserByUsername(u.getId()); - UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(d,"",d.getAuthorities()); + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(d, "", d.getAuthorities()); token.setDetails(d); SecurityContextHolder.getContext().setAuthentication(token); return u; @@ -207,16 +208,18 @@ public abstract class FederatedLoginService implements ExtensionPoint { } /** - * Your implementation will call this method to add this identifier to the current user - * of an already authenticated session. + * Your implementation will call this method to add this identifier to + * the current user of an already authenticated session. * - * <p> - * This method will record the identifier in {@link FederatedLoginServiceUserProperty} so that - * in the future the user can login to Hudson with the identifier. + * <p> This method will record the identifier in + * {@link FederatedLoginServiceUserProperty} so that in the future the + * user can login to Hudson with the identifier. */ public void addToCurrentUser() throws IOException { User u = User.current(); - if (u==null) throw new IllegalStateException("Current request is unauthenticated"); + if (u == null) { + throw new IllegalStateException("Current request is unauthenticated"); + } addTo(u); } @@ -226,7 +229,7 @@ public abstract class FederatedLoginService implements ExtensionPoint { */ public void addTo(User u) throws IOException { FederatedLoginServiceUserProperty p = u.getProperty(getUserPropertyClass()); - if (p==null) { + if (p == null) { p = (FederatedLoginServiceUserProperty) UserProperty.all().find(getUserPropertyClass()).newInstance(u); u.addProperty(p); } @@ -240,11 +243,12 @@ public abstract class FederatedLoginService implements ExtensionPoint { } /** - * Used in {@link FederatedIdentity#signin()} to indicate that the identifier is not currently - * associated with anyone. + * Used in {@link FederatedIdentity#signin()} to indicate that the + * identifier is not currently associated with anyone. */ public static class UnclaimedIdentityException extends RuntimeException implements HttpResponse { //TODO: review and check whether we can do it private + public final FederatedIdentity identity; public UnclaimedIdentityException(FederatedIdentity identity) { @@ -259,7 +263,7 @@ public abstract class FederatedLoginService implements ExtensionPoint { SecurityRealm sr = HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm(); if (sr.allowsSignup()) { try { - sr.commenceSignup(identity).generateResponse(req,rsp,node); + sr.commenceSignup(identity).generateResponse(req, rsp, node); return; } catch (UnsupportedOperationException e) { // fall through @@ -268,7 +272,7 @@ public abstract class FederatedLoginService implements ExtensionPoint { // this security realm doesn't support user registration. // just report an error - req.getView(this,"error").forward(req,rsp); + req.getView(this, "error").forward(req, rsp); } } diff --git a/hudson-core/src/main/java/hudson/security/FederatedLoginServiceUserProperty.java b/hudson-core/src/main/java/hudson/security/FederatedLoginServiceUserProperty.java index 3a01b47..786ece6 100644 --- a/hudson-core/src/main/java/hudson/security/FederatedLoginServiceUserProperty.java +++ b/hudson-core/src/main/java/hudson/security/FederatedLoginServiceUserProperty.java @@ -7,8 +7,8 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: - * + * Contributors: + * * *******************************************************************************/ @@ -35,7 +35,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package hudson.security; import hudson.model.UserProperty; @@ -53,6 +52,7 @@ import java.util.Set; * @see FederatedLoginService */ public class FederatedLoginServiceUserProperty extends UserProperty { + protected final Set<String> identifiers; protected FederatedLoginServiceUserProperty(Collection<String> identifiers) { diff --git a/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java index 501ea41..55f48d0 100644 --- a/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java +++ b/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* + * Contributors: + * * Kohsuke Kawaguchi, Seiji Sogabe - * + * * *******************************************************************************/ @@ -34,6 +34,7 @@ import org.kohsuke.stapler.StaplerRequest; * @author Kohsuke Kawaguchi */ public class FullControlOnceLoggedInAuthorizationStrategy extends AuthorizationStrategy { + @Override public ACL getRootACL() { return THE_ACL; @@ -42,15 +43,13 @@ public class FullControlOnceLoggedInAuthorizationStrategy extends AuthorizationS public List<String> getGroups() { return Collections.emptyList(); } - private static final SparseACL THE_ACL = new SparseACL(null); static { - THE_ACL.add(ACL.EVERYONE,Hudson.ADMINISTER,true); - THE_ACL.add(ACL.ANONYMOUS,Hudson.ADMINISTER,false); - THE_ACL.add(ACL.ANONYMOUS,Permission.READ,true); + THE_ACL.add(ACL.EVERYONE, Hudson.ADMINISTER, true); + THE_ACL.add(ACL.ANONYMOUS, Hudson.ADMINISTER, false); + THE_ACL.add(ACL.ANONYMOUS, Permission.READ, true); } - @Extension public static final Descriptor<AuthorizationStrategy> DESCRIPTOR = new Descriptor<AuthorizationStrategy>() { public String getDisplayName() { diff --git a/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java index d7075e1..08f18dd 100644 --- a/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java +++ b/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Winston Prakash - * + * *******************************************************************************/ package hudson.security; @@ -62,29 +62,30 @@ import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder; */ // TODO: think about the concurrency commitment of this class public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { - private transient SidACL acl = new AclImpl(); + private transient SidACL acl = new AclImpl(); /** * List up all permissions that are granted. * - * Strings are either the granted authority or the principal, - * which is not distinguished. + * Strings are either the granted authority or the principal, which is not + * distinguished. */ - private final Map<Permission,Set<String>> grantedPermissions = new HashMap<Permission, Set<String>>(); - + private final Map<Permission, Set<String>> grantedPermissions = new HashMap<Permission, Set<String>>(); private final Set<String> sids = new HashSet<String>(); /** - * Adds to {@link #grantedPermissions}. - * Use of this method should be limited during construction, - * as this object itself is considered immutable once populated. + * Adds to {@link #grantedPermissions}. Use of this method should be limited + * during construction, as this object itself is considered immutable once + * populated. */ public void add(Permission p, String sid) { - if (p==null) + if (p == null) { throw new IllegalArgumentException(); + } Set<String> set = grantedPermissions.get(p); - if(set==null) - grantedPermissions.put(p,set = new HashSet<String>()); + if (set == null) { + grantedPermissions.put(p, set = new HashSet<String>()); + } set.add(sid); sids.add(sid); } @@ -98,7 +99,7 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { Permission p = Permission.fromId(shortForm.substring(0, idx)); if (p != null) { add(p, shortForm.substring(idx + 1)); - }else{ + } else { // This should not happen if Hudson is fully initialized. // But Initial Setup also loads Security setup before Hudson Initialization if (Hudson.getInstance() != null) { @@ -117,27 +118,28 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { } /** - * Due to HUDSON-2324, we want to inject Item.READ permission to everyone who has Hudson.READ, - * to remain backward compatible. + * Due to HUDSON-2324, we want to inject Item.READ permission to everyone + * who has Hudson.READ, to remain backward compatible. + * * @param grantedPermissions */ - /*package*/ static boolean migrateHudson2324(Map<Permission,Set<String>> grantedPermissions) { + /*package*/ static boolean migrateHudson2324(Map<Permission, Set<String>> grantedPermissions) { boolean result = false; // Hudson may not be initialized yet in case of Initial Setup - if (Hudson.getInstance() == null){ + if (Hudson.getInstance() == null) { return false; } - if(Hudson.getInstance().isUpgradedFromBefore(new VersionNumber("1.300.*"))) { + if (Hudson.getInstance().isUpgradedFromBefore(new VersionNumber("1.300.*"))) { Set<String> f = grantedPermissions.get(Hudson.READ); - if (f!=null) { + if (f != null) { Set<String> t = grantedPermissions.get(Item.READ); - if (t!=null) + if (t != null) { result = t.addAll(f); - else { + } else { t = new HashSet<String>(f); result = true; } - grantedPermissions.put(Item.READ,t); + grantedPermissions.put(Item.READ, t); } } return result; @@ -147,16 +149,18 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { * Checks if the given SID has the given permission. */ public boolean hasPermission(String sid, Permission p) { - for(; p!=null; p=p.impliedBy) { + for (; p != null; p = p.impliedBy) { Set<String> set = grantedPermissions.get(p); - if(set!=null && set.contains(sid) && p.getEnabled()) + if (set != null && set.contains(sid) && p.getEnabled()) { return true; + } } return false; } /** - * Checks if the permission is explicitly given, instead of implied through {@link Permission#impliedBy}. + * Checks if the permission is explicitly given, instead of implied through + * {@link Permission#impliedBy}. */ public boolean hasExplicitPermission(String sid, Permission p) { Set<String> set = grantedPermissions.get(p); @@ -166,13 +170,13 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { /** * Returns all SIDs configured in this matrix, minus "anonymous" * - * @return - * Always non-null. + * @return Always non-null. */ public List<String> getAllSIDs() { Set<String> r = new HashSet<String>(); - for (Set<String> set : grantedPermissions.values()) + for (Set<String> set : grantedPermissions.values()) { r.addAll(set); + } r.remove("anonymous"); String[] data = r.toArray(new String[r.size()]); @@ -181,13 +185,14 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { } private final class AclImpl extends SidACL { + protected Boolean hasPermission(Sid p, Permission permission) { - if(GlobalMatrixAuthorizationStrategy.this.hasPermission(toString(p),permission)) + if (GlobalMatrixAuthorizationStrategy.this.hasPermission(toString(p), permission)) { return true; + } return null; } } - @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); @@ -196,12 +201,13 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { * represent {@link GlobalMatrixAuthorizationStrategy#grantedPermissions}. */ public static class ConverterImpl implements Converter { + public boolean canConvert(Class type) { - return type==GlobalMatrixAuthorizationStrategy.class; + return type == GlobalMatrixAuthorizationStrategy.class; } public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - GlobalMatrixAuthorizationStrategy strategy = (GlobalMatrixAuthorizationStrategy)source; + GlobalMatrixAuthorizationStrategy strategy = (GlobalMatrixAuthorizationStrategy) source; // Output in alphabetical order for readability. SortedMap<Permission, Set<String>> sortedPermissions = new TreeMap<Permission, Set<String>>(Permission.ID_COMPARATOR); @@ -212,7 +218,7 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { Collections.sort(sids); for (String sid : sids) { writer.startNode("permission"); - writer.setValue(p+':'+sid); + writer.setValue(p + ':' + sid); writer.endNode(); } } @@ -228,14 +234,15 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { as.add(reader.getValue()); } catch (IllegalArgumentException ex) { Logger.getLogger(GlobalMatrixAuthorizationStrategy.class.getName()) - .log(Level.WARNING,"Skipping a non-existent permission",ex); + .log(Level.WARNING, "Skipping a non-existent permission", ex); RobustReflectionConverter.addErrorInContext(context, ex); } reader.moveUp(); } - if (migrateHudson2324(as.grantedPermissions)) + if (migrateHudson2324(as.grantedPermissions)) { OldDataMonitor.report(context, "1.301"); + } return as; } @@ -244,8 +251,9 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { return new GlobalMatrixAuthorizationStrategy(); } } - + public static class DescriptorImpl extends Descriptor<AuthorizationStrategy> { + protected DescriptorImpl(Class<? extends GlobalMatrixAuthorizationStrategy> clazz) { super(clazz); } @@ -260,12 +268,12 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { @Override public AuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException { GlobalMatrixAuthorizationStrategy gmas = create(); - for(Map.Entry<String,JSONObject> r : (Set<Map.Entry<String,JSONObject>>)formData.getJSONObject("data").entrySet()) { + for (Map.Entry<String, JSONObject> r : (Set<Map.Entry<String, JSONObject>>) formData.getJSONObject("data").entrySet()) { String sid = r.getKey(); - for(Map.Entry<String,Boolean> e : (Set<Map.Entry<String,Boolean>>)r.getValue().entrySet()) { - if(e.getValue()) { + for (Map.Entry<String, Boolean> e : (Set<Map.Entry<String, Boolean>>) r.getValue().entrySet()) { + if (e.getValue()) { Permission p = Permission.fromId(e.getKey()); - gmas.add(p,sid); + gmas.add(p, sid); } } } @@ -286,24 +294,26 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { return p.getEnabled(); } - public FormValidation doCheckName(@QueryParameter String value ) throws IOException, ServletException { + public FormValidation doCheckName(@QueryParameter String value) throws IOException, ServletException { return doCheckName(value, Hudson.getInstance(), Hudson.ADMINISTER); } FormValidation doCheckName(String value, AccessControlled subject, Permission permission) throws IOException, ServletException { - if(!subject.hasPermission(permission)) return FormValidation.ok(); // can't check - - final String v = value.substring(1,value.length()-1); + if (!subject.hasPermission(permission)) { + return FormValidation.ok(); // can't check + } + final String v = value.substring(1, value.length() - 1); SecurityRealm sr = HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm(); String ev = Functions.escape(v); - if(v.equals("authenticated")) - // system reserved group - return FormValidation.respond(Kind.OK, makeImg("user.png") +ev); + if (v.equals("authenticated")) // system reserved group + { + return FormValidation.respond(Kind.OK, makeImg("user.png") + ev); + } try { sr.loadUserByUsername(v); - return FormValidation.respond(Kind.OK, makeImg("person.png")+ev); + return FormValidation.respond(Kind.OK, makeImg("person.png") + ev); } catch (UserMayOrMayNotExistException e) { // undecidable, meaning the user may exist return FormValidation.respond(Kind.OK, ev); @@ -315,7 +325,7 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { try { sr.loadGroupByGroupname(v); - return FormValidation.respond(Kind.OK, makeImg("user.png") +ev); + return FormValidation.respond(Kind.OK, makeImg("user.png") + ev); } catch (UserMayOrMayNotExistException e) { // undecidable, meaning the group may exist return FormValidation.respond(Kind.OK, ev); @@ -326,7 +336,7 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { } // couldn't find it. it doesn't exist - return FormValidation.respond(Kind.ERROR, makeImg("error.png") +ev); + return FormValidation.respond(Kind.ERROR, makeImg("error.png") + ev); } private String makeImg(String png) { @@ -334,4 +344,3 @@ public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy { } } } - diff --git a/hudson-core/src/main/java/hudson/security/GroupDetails.java b/hudson-core/src/main/java/hudson/security/GroupDetails.java index d2a8284..fe8e3d3 100644 --- a/hudson-core/src/main/java/hudson/security/GroupDetails.java +++ b/hudson-core/src/main/java/hudson/security/GroupDetails.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* + * Contributors: + * * Kohsuke Kawaguchi - * + * * *******************************************************************************/ @@ -26,6 +26,7 @@ import org.springframework.security.userdetails.UserDetails; * @see UserDetails */ public abstract class GroupDetails { + /** * Returns the name of the group. * @@ -36,8 +37,7 @@ public abstract class GroupDetails { /** * Returns the human-readable name used for rendering in HTML. * - * <p> - * This may contain arbitrary character, and it can change. + * <p> This may contain arbitrary character, and it can change. * * @return never null. */ diff --git a/hudson-core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java b/hudson-core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java index 00840f7..6c5b547 100644 --- a/hudson-core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java +++ b/hudson-core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* + * Contributors: + * * Kohsuke Kawaguchi - * + * * *******************************************************************************/ @@ -29,28 +29,30 @@ import javax.servlet.http.HttpSession; import java.io.IOException; /** - * Erases the {@link SecurityContext} persisted in {@link HttpSession} - * if {@link InvalidatableUserDetails#isInvalid()} returns true. + * Erases the {@link SecurityContext} persisted in {@link HttpSession} if + * {@link InvalidatableUserDetails#isInvalid()} returns true. * * @see InvalidatableUserDetails */ public class HttpSessionContextIntegrationFilter2 extends HttpSessionContextIntegrationFilter { + public HttpSessionContextIntegrationFilter2() throws ServletException { setContextClass(NotSerilizableSecurityContext.class); } public void doFilterHttp(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpSession session = ((HttpServletRequest) req).getSession(false); - if(session!=null) { - SecurityContext o = (SecurityContext)session.getAttribute(SPRING_SECURITY_CONTEXT_KEY); - if(o!=null) { + if (session != null) { + SecurityContext o = (SecurityContext) session.getAttribute(SPRING_SECURITY_CONTEXT_KEY); + if (o != null) { Authentication a = o.getAuthentication(); - if(a!=null) { + if (a != null) { if (a.getPrincipal() instanceof InvalidatableUserDetails) { InvalidatableUserDetails ud = (InvalidatableUserDetails) a.getPrincipal(); - if(ud.isInvalid()) - // don't let Spring Security see invalid security context - session.setAttribute(SPRING_SECURITY_CONTEXT_KEY,null); + if (ud.isInvalid()) // don't let Spring Security see invalid security context + { + session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null); + } } } } diff --git a/hudson-core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java b/hudson-core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java index 914e078..c498223 100644 --- a/hudson-core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java +++ b/hudson-core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -33,28 +33,27 @@ import java.net.URLEncoder; import java.text.MessageFormat; /** - * For anonymous requests to pages that require authentication, - * first respond with {@link HttpServletResponse#SC_FORBIDDEN}, - * then redirect browsers automatically to the login page. + * For anonymous requests to pages that require authentication, first respond + * with {@link HttpServletResponse#SC_FORBIDDEN}, then redirect browsers + * automatically to the login page. * - * <p> - * This is a compromise to handle programmatic access and - * real browsers equally well. + * <p> This is a compromise to handle programmatic access and real browsers + * equally well. * - * <p> - * The page that programs see is entirely white, and it auto-redirects, - * so humans wouldn't notice it. + * <p> The page that programs see is entirely white, and it auto-redirects, so + * humans wouldn't notice it. * * @author Kohsuke Kawaguchi */ public class HudsonAuthenticationEntryPoint extends AuthenticationProcessingFilterEntryPoint { + @Override public void commence(ServletRequest request, ServletResponse response, AuthenticationException authException) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse rsp = (HttpServletResponse) response; String requestedWith = req.getHeader("X-Requested-With"); - if("XMLHttpRequest".equals(requestedWith)) { + if ("XMLHttpRequest".equals(requestedWith)) { // container authentication normally relies on session attribute to // remember where the user came from, so concurrent AJAX requests // often ends up sending users back to AJAX pages after successful login. @@ -63,8 +62,8 @@ public class HudsonAuthenticationEntryPoint extends AuthenticationProcessingFilt rsp.sendError(SC_FORBIDDEN); } else { // give the opportunity to include the target URL - String loginForm = req.getContextPath()+getLoginFormUrl(); - loginForm = MessageFormat.format(loginForm, URLEncoder.encode(req.getRequestURI(),"UTF-8")); + String loginForm = req.getContextPath() + getLoginFormUrl(); + loginForm = MessageFormat.format(loginForm, URLEncoder.encode(req.getRequestURI(), "UTF-8")); req.setAttribute("loginForm", loginForm); rsp.setStatus(SC_FORBIDDEN); @@ -77,17 +76,17 @@ public class HudsonAuthenticationEntryPoint extends AuthenticationProcessingFilt out = rsp.getWriter(); } out.printf( - "<html><head>" + - "<meta http-equiv='refresh' content='1;url=%1$s'/>" + - "<script>window.location.replace('%1$s');</script>" + - "</head>" + - "<body style='background-color:white; color:white;'>" + - "Authentication required</body></html>", loginForm - ); + "<html><head>" + + "<meta http-equiv='refresh' content='1;url=%1$s'/>" + + "<script>window.location.replace('%1$s');</script>" + + "</head>" + + "<body style='background-color:white; color:white;'>" + + "Authentication required</body></html>", loginForm); // Turn Off "Show Friendly HTTP Error Messages" Feature on the Server Side. // See http://support.microsoft.com/kb/294807 - for (int i=0; i < 10; i++) + for (int i = 0; i < 10; i++) { out.print(" "); + } out.flush(); } } diff --git a/hudson-core/src/main/java/hudson/security/HudsonFilter.java b/hudson-core/src/main/java/hudson/security/HudsonFilter.java index 5e16e2f..e82a2b1 100644 --- a/hudson-core/src/main/java/hudson/security/HudsonFilter.java +++ b/hudson-core/src/main/java/hudson/security/HudsonFilter.java @@ -9,7 +9,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * + * * Kohsuke Kawaguchi, Winston Prakash * ****************************************************************************** @@ -39,7 +39,8 @@ import org.springframework.security.userdetails.UserDetailsService; * {@link Filter} that Hudson uses to implement security support. * * <p> This is the instance the servlet container creates, but internally this - * just acts as a proxy to the real {@link Filter}, created by {@link SecurityRealm#createFilter(FilterConfig)}. + * just acts as a proxy to the real {@link Filter}, created by + * {@link SecurityRealm#createFilter(FilterConfig)}. * * @author Kohsuke Kawaguchi * @since 1.160 @@ -61,7 +62,8 @@ public class HudsonFilter implements Filter { * {@link AuthenticationManager} proxy so that the Spring Security filter * chain can stay the same even when security setting is reconfigured. * - * @deprecated in 1.271. This proxy always delegate to {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().manager}, + * @deprecated in 1.271. This proxy always delegate to + * {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().manager}, * so use that instead. */ public static final AuthenticationManagerProxy AUTHENTICATION_MANAGER = new AuthenticationManagerProxy(); @@ -69,7 +71,8 @@ public class HudsonFilter implements Filter { * {@link UserDetailsService} proxy so that the Spring Security filter chain * can stay the same even when security setting is reconfigured. * - * @deprecated in 1.271. This proxy always delegate to {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().userDetails}, + * @deprecated in 1.271. This proxy always delegate to + * {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().userDetails}, * so use that instead. */ public static final UserDetailsServiceProxy USER_DETAILS_SERVICE_PROXY = new UserDetailsServiceProxy(); @@ -77,7 +80,8 @@ public class HudsonFilter implements Filter { * {@link RememberMeServices} proxy so that the Spring Security filter chain * can stay the same even when security setting is reconfigured. * - * @deprecated in 1.271. This proxy always delegate to {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().rememberMe}, + * @deprecated in 1.271. This proxy always delegate to + * {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().rememberMe}, * so use that instead. */ public static final RememberMeServicesProxy REMEMBER_ME_SERVICES_PROXY = new RememberMeServicesProxy(); @@ -106,7 +110,8 @@ public class HudsonFilter implements Filter { } /** - * Gets the {@link HudsonFilter} created for the given {@link ServletContext}. + * Gets the {@link HudsonFilter} created for the given + * {@link ServletContext}. */ public static HudsonFilter get(ServletContext context) { // As of 3.0.0 we no longer set it to the context diff --git a/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java index a2ab17c..316e3c1 100644 --- a/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java +++ b/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, David Calavera, Seiji Sogabe, Anton Kozak - * + * * *******************************************************************************/ @@ -57,27 +57,25 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder; /** - * {@link SecurityRealm} that performs authentication by looking up {@link User}. + * {@link SecurityRealm} that performs authentication by looking up + * {@link User}. * - * <p> - * Implements {@link AccessControlled} to satisfy view rendering, but in reality the access control - * is done against the {@link Hudson} object. + * <p> Implements {@link AccessControlled} to satisfy view rendering, but in + * reality the access control is done against the {@link Hudson} object. * * @author Kohsuke Kawaguchi */ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRealm implements ModelObject, AccessControlled { + /** - * If true, sign up is not allowed. - * <p> - * This is a negative switch so that the default value 'false' remains compatible with older installations. + * If true, sign up is not allowed. <p> This is a negative switch so that + * the default value 'false' remains compatible with older installations. */ private final boolean disableSignup; - /** * If true, captcha will be enabled. */ private final boolean enableCaptcha; - /** * If true, user will be notified of Hudson account creation. */ @@ -100,13 +98,13 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } @DataBoundConstructor - public HudsonPrivateSecurityRealm(boolean allowsSignup, boolean enableCaptcha, CaptchaSupport captchaSupport, boolean notifyUser) { + public HudsonPrivateSecurityRealm(boolean allowsSignup, boolean enableCaptcha, CaptchaSupport captchaSupport, boolean notifyUser) { this.disableSignup = !allowsSignup; this.enableCaptcha = enableCaptcha; setCaptchaSupport(captchaSupport); this.notifyUser = notifyUser; - if(!allowsSignup && !hasSomeUser()) { + if (!allowsSignup && !hasSomeUser()) { // if Hudson is newly set up with the security realm and there's no user account created yet, // insert a filter that asks the user to create one try { @@ -143,13 +141,14 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea /** * Computes if this Hudson has some user accounts configured. * - * <p> - * This is used to check for the initial + * <p> This is used to check for the initial */ private static boolean hasSomeUser() { - for (User u : User.getAll()) - if(u.getProperty(Details.class)!=null) + for (User u : User.getAll()) { + if (u.getProperty(Details.class) != null) { return true; + } + } return false; } @@ -164,19 +163,22 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea @Override public Details loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { User u = User.get(username, false); - Details p = u!=null ? u.getProperty(Details.class) : null; - if(p==null) - throw new UsernameNotFoundException("Password is not set: "+username); - if(p.getUser()==null) + Details p = u != null ? u.getProperty(Details.class) : null; + if (p == null) { + throw new UsernameNotFoundException("Password is not set: " + username); + } + if (p.getUser() == null) { throw new AssertionError(); + } return p; } @Override protected Details authenticate(String username, String password) throws AuthenticationException { Details u = loadUserByUsername(username); - if (!PASSWORD_ENCODER.isPasswordValid(u.getPassword(),password,null)) - throw new BadCredentialsException("Failed to login as "+username); + if (!PASSWORD_ENCODER.isPasswordValid(u.getPassword(), password, null)) { + throw new BadCredentialsException("Failed to login as " + username); + } return u; } @@ -186,12 +188,12 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea @Override public HttpResponse commenceSignup(final FederatedIdentity identity) { // store the identity in the session so that we can use this later - Stapler.getCurrentRequest().getSession().setAttribute(FEDERATED_IDENTITY_SESSION_KEY,identity); - return new ForwardToView(this,"signupWithFederatedIdentity.jelly") { + Stapler.getCurrentRequest().getSession().setAttribute(FEDERATED_IDENTITY_SESSION_KEY, identity); + return new ForwardToView(this, "signupWithFederatedIdentity.jelly") { @Override public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { SignupInfo si = new SignupInfo(identity); - si.errorMessage = Messages.HudsonPrivateSecurityRealm_WouldYouLikeToSignUp(identity.getPronoun(),identity.getIdentifier()); + si.errorMessage = Messages.HudsonPrivateSecurityRealm_WouldYouLikeToSignUp(identity.getPronoun(), identity.getIdentifier()); req.setAttribute("data", si); super.generateResponse(req, rsp, node); } @@ -199,17 +201,17 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } /** - * Creates an account and associates that with the given identity. Used in conjunction - * with {@link #commenceSignup(FederatedIdentity)}. + * Creates an account and associates that with the given identity. Used in + * conjunction with {@link #commenceSignup(FederatedIdentity)}. */ public User doCreateAccountWithFederatedIdentity(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - User u = _doCreateAccount(req,rsp,"signupWithFederatedIdentity.jelly"); - if (u!=null) - ((FederatedIdentity)req.getSession().getAttribute(FEDERATED_IDENTITY_SESSION_KEY)).addTo(u); + User u = _doCreateAccount(req, rsp, "signupWithFederatedIdentity.jelly"); + if (u != null) { + ((FederatedIdentity) req.getSession().getAttribute(FEDERATED_IDENTITY_SESSION_KEY)).addTo(u); + } return u; } - - private static final String FEDERATED_IDENTITY_SESSION_KEY = HudsonPrivateSecurityRealm.class.getName()+".federatedIdentity"; + private static final String FEDERATED_IDENTITY_SESSION_KEY = HudsonPrivateSecurityRealm.class.getName() + ".federatedIdentity"; /** * Creates an user account. Used for self-registration. @@ -219,41 +221,45 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } private User _doCreateAccount(StaplerRequest req, StaplerResponse rsp, String formView) throws ServletException, IOException { - if(!allowsSignup()) - throw HttpResponses.error(SC_UNAUTHORIZED,new Exception("User sign up is prohibited")); + if (!allowsSignup()) { + throw HttpResponses.error(SC_UNAUTHORIZED, new Exception("User sign up is prohibited")); + } boolean firstUser = !hasSomeUser(); User u = createAccount(req, rsp, enableCaptcha, formView); - if(u!=null) { - if(firstUser) + if (u != null) { + if (firstUser) { tryToMakeAdmin(u); // the first user should be admin, or else there's a risk of lock out + } loginAndTakeBack(req, rsp, u); } return u; } /** - * Lets the current user silently login as the given user and report back accordingly. + * Lets the current user silently login as the given user and report back + * accordingly. */ private void loginAndTakeBack(StaplerRequest req, StaplerResponse rsp, User u) throws ServletException, IOException { // ... and let him login - Authentication a = new UsernamePasswordAuthenticationToken(u.getId(),req.getParameter("password1")); + Authentication a = new UsernamePasswordAuthenticationToken(u.getId(), req.getParameter("password1")); a = this.getSecurityComponents().manager.authenticate(a); SecurityContextHolder.getContext().setAuthentication(a); // then back to top - req.getView(this,"success.jelly").forward(req,rsp); + req.getView(this, "success.jelly").forward(req, rsp); } /** * Creates an user account. Used by admins. * - * This version behaves differently from {@link #doCreateAccount(StaplerRequest, StaplerResponse)} in that - * this is someone creating another user. + * This version behaves differently from + * {@link #doCreateAccount(StaplerRequest, StaplerResponse)} in that this is + * someone creating another user. */ public void doCreateAccountByAdmin(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { checkPermission(Hudson.ADMINISTER); - if(createAccount(req, rsp, false, "addUser.jelly")!=null) { + if (createAccount(req, rsp, false, "addUser.jelly") != null) { rsp.sendRedirect("."); // send the user back to the listing page } } @@ -261,16 +267,16 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea /** * Creates a first admin user account. * - * <p> - * This can be run by anyone, but only to create the very first user account. + * <p> This can be run by anyone, but only to create the very first user + * account. */ public void doCreateFirstAccount(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - if(hasSomeUser()) { - rsp.sendError(SC_UNAUTHORIZED,"First user was already created"); + if (hasSomeUser()) { + rsp.sendError(SC_UNAUTHORIZED, "First user was already created"); return; } User u = createAccount(req, rsp, false, "firstUser.jelly"); - if (u!=null) { + if (u != null) { tryToMakeAdmin(u); loginAndTakeBack(req, rsp, u); } @@ -288,49 +294,54 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } /** - * @return - * null if failed. The browser is already redirected to retry by the time this method returns. - * a valid {@link User} object if the user creation was successful. + * @return null if failed. The browser is already redirected to retry by the + * time this method returns. a valid {@link User} object if the user + * creation was successful. */ private User createAccount(StaplerRequest req, StaplerResponse rsp, boolean selfRegistration, String formView) throws ServletException, IOException { // form field validation // this pattern needs to be generalized and moved to stapler SignupInfo si = new SignupInfo(req); - if(selfRegistration && !validateCaptcha(si.captcha)) + if (selfRegistration && !validateCaptcha(si.captcha)) { si.errorMessage = "Text didn't match the word shown in the image"; + } - if(si.password1 != null && !si.password1.equals(si.password2)) + if (si.password1 != null && !si.password1.equals(si.password2)) { si.errorMessage = "Password didn't match"; + } - if(!(si.password1 != null && si.password1.length() != 0)) + if (!(si.password1 != null && si.password1.length() != 0)) { si.errorMessage = "Password is required"; + } try { Hudson.checkGoodName(si.username); User user = User.get(si.username); - if (user.getProperty(Details.class)!=null) { + if (user.getProperty(Details.class) != null) { si.errorMessage = "User name is already taken. Did you forget the password?"; } } catch (Failure e) { si.errorMessage = "User name is not valid: " + e.getMessage(); } - if(si.fullname==null || si.fullname.length()==0) + if (si.fullname == null || si.fullname.length() == 0) { si.fullname = si.username; + } - if(si.email==null || !si.email.contains("@")) + if (si.email == null || !si.email.contains("@")) { si.errorMessage = "Invalid e-mail address"; + } - if(si.errorMessage!=null) { + if (si.errorMessage != null) { // failed. ask the user to try again. - req.setAttribute("data",si); - req.getView(this, formView).forward(req,rsp); + req.setAttribute("data", si); + req.getView(this, formView).forward(req, rsp); return null; } // register the user - final User user = createAccount(si.username,si.password1); + final User user = createAccount(si.username, si.password1); user.addProperty(new Mailer.UserProperty(si.email)); user.setFullName(si.fullname); user.save(); @@ -346,7 +357,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea protected String getText() { String baseUrl = Mailer.descriptor().getUrl(); return hudson.mail.Messages - .account_creation_email_text(fullname != null ? fullname : "", baseUrl, email, username, + .account_creation_email_text(fullname != null ? fullname : "", baseUrl, email, username, passwd); } @@ -367,7 +378,8 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } /** - * This is used primarily when the object is listed in the breadcrumb, in the user management screen. + * This is used primarily when the object is listed in the breadcrumb, in + * the user management screen. */ public String getDisplayName() { return "User Database"; @@ -385,36 +397,34 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea return HudsonSecurityEntitiesHolder.getHudsonSecurityManager().hasPermission(permission); } - /** * All users who can login to the system. */ public List<User> getAllUsers() { List<User> r = new ArrayList<User>(); for (User u : User.getAll()) { - if(u.getProperty(Details.class)!=null) + if (u.getProperty(Details.class) != null) { r.add(u); + } } Collections.sort(r); return r; } /** - * This is to map users under the security realm URL. - * This in turn helps us set up the right navigation breadcrumb. + * This is to map users under the security realm URL. This in turn helps us + * set up the right navigation breadcrumb. */ public User getUser(String id) { return User.get(id); } - // TODO private static final GrantedAuthority[] TEST_AUTHORITY = {AUTHENTICATED_AUTHORITY}; public static final class SignupInfo { //TODO: review and check whether we can do it private - public String username,password1,password2,fullname,email,captcha; - + public String username, password1, password2, fullname, email, captcha; /** * To display an error message, set it here. */ @@ -432,6 +442,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea this.fullname = i.getFullName(); this.email = i.getEmailAddress(); } + public String getUsername() { return username; } @@ -462,27 +473,27 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } /** - * {@link UserProperty} that provides the {@link UserDetails} view of the User object. + * {@link UserProperty} that provides the {@link UserDetails} view of the + * User object. * - * <p> - * When a {@link User} object has this property on it, it means the user is configured - * for log-in. + * <p> When a {@link User} object has this property on it, it means the user + * is configured for log-in. * - * <p> - * When a {@link User} object is re-configured via the UI, the password - * is sent to the hidden input field by using {@link Protector}, so that - * the same password can be retained but without leaking information to the browser. + * <p> When a {@link User} object is re-configured via the UI, the password + * is sent to the hidden input field by using {@link Protector}, so that the + * same password can be retained but without leaking information to the + * browser. */ public static final class Details extends UserProperty implements InvalidatableUserDetails { + /** * Hashed password. */ private /*almost final*/ String passwordHash; - /** - * @deprecated Scrambled password. - * Field kept here to load old (pre 1.283) user records, - * but now marked transient so field is no longer saved. + * @deprecated Scrambled password. Field kept here to load old (pre + * 1.283) user records, but now marked transient so field is no longer + * saved. */ private transient String password; @@ -495,7 +506,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } static Details fromPlainPassword(String rawPassword) { - return new Details(PASSWORD_ENCODER.encodePassword(rawPassword,null)); + return new Details(PASSWORD_ENCODER.encodePassword(rawPassword, null)); } public GrantedAuthority[] getAuthorities() { @@ -509,7 +520,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea public String getProtectedPassword() { // put session Id in it to prevent a replay attack. - return Protector.protect(Stapler.getCurrentRequest().getSession().getId()+':'+getPassword()); + return Protector.protect(Stapler.getCurrentRequest().getSession().getId() + ':' + getPassword()); } public String getUsername() { @@ -537,15 +548,20 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } public boolean isInvalid() { - return user==null; + return user == null; } public static class ConverterImpl extends XStream2.PassthruConverter<Details> { - public ConverterImpl(XStream2 xstream) { super(xstream); } - @Override protected void callback(Details d, UnmarshallingContext context) { + + public ConverterImpl(XStream2 xstream) { + super(xstream); + } + + @Override + protected void callback(Details d, UnmarshallingContext context) { // Convert to hashed password and report to monitor if we load old data - if (d.password!=null && d.passwordHash==null) { - d.passwordHash = PASSWORD_ENCODER.encodePassword(Scrambler.descramble(d.password),null); + if (d.password != null && d.passwordHash == null) { + d.passwordHash = PASSWORD_ENCODER.encodePassword(Scrambler.descramble(d.password), null); OldDataMonitor.report(context, "1.283"); } } @@ -553,27 +569,31 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea @Extension public static final class DescriptorImpl extends UserPropertyDescriptor { + public String getDisplayName() { // this feature is only when HudsonPrivateSecurityRealm is enabled - if(isEnabled()) + if (isEnabled()) { return Messages.HudsonPrivateSecurityRealm_Details_DisplayName(); - else + } else { return null; + } } @Override public Details newInstance(StaplerRequest req, JSONObject formData) throws FormException { String pwd = Util.fixEmpty(req.getParameter("user.password")); - String pwd2= Util.fixEmpty(req.getParameter("user.password2")); + String pwd2 = Util.fixEmpty(req.getParameter("user.password2")); - if(!Util.fixNull(pwd).equals(Util.fixNull(pwd2))) - throw new FormException("Please confirm the password by typing it twice","user.password2"); + if (!Util.fixNull(pwd).equals(Util.fixNull(pwd2))) { + throw new FormException("Please confirm the password by typing it twice", "user.password2"); + } String data = Protector.unprotect(pwd); - if(data!=null) { + if (data != null) { String prefix = Stapler.getCurrentRequest().getSession().getId() + ':'; - if(data.startsWith(prefix)) + if (data.startsWith(prefix)) { return Details.fromHashedPassword(data.substring(prefix.length())); + } } return Details.fromPlainPassword(Util.fixNull(pwd)); } @@ -590,16 +610,18 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea } /** - * Displays "manage users" link in the system config if {@link HudsonPrivateSecurityRealm} - * is in effect. + * Displays "manage users" link in the system config if + * {@link HudsonPrivateSecurityRealm} is in effect. */ @Extension public static final class ManageUserLinks extends ManagementLink { + public String getIconFileName() { - if(HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm() instanceof HudsonPrivateSecurityRealm) + if (HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm() instanceof HudsonPrivateSecurityRealm) { return "user.png"; - else + } else { return null; // not applicable now + } } public String getUrlName() { @@ -615,17 +637,15 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea return Messages.HudsonPrivateSecurityRealm_ManageUserLinks_Description(); } } - /** * {@link PasswordEncoder} based on SHA-256 and random salt generation. * - * <p> - * The salt is prepended to the hashed password and returned. So the encoded password is of the form - * <tt>SALT ':' hash(PASSWORD,SALT)</tt>. + * <p> The salt is prepended to the hashed password and returned. So the + * encoded password is of the form <tt>SALT ':' hash(PASSWORD,SALT)</tt>. * - * <p> - * This abbreviates the need to store the salt separately, which in turn allows us to hide the salt handling - * in this little class. The rest of the Acegi thinks that we are not using salt. + * <p> This abbreviates the need to store the salt separately, which in turn + * allows us to hide the salt handling in this little class. The rest of the + * Acegi thinks that we are not using salt. */ public static final PasswordEncoder PASSWORD_ENCODER = new PasswordEncoder() { private final PasswordEncoder passwordEncoder = new ShaPasswordEncoder(256); @@ -637,9 +657,11 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea public boolean isPasswordValid(String encPass, String rawPass, Object _) throws DataAccessException { // pull out the sale from the encoded password int i = encPass.indexOf(':'); - if(i<0) return false; - String salt = encPass.substring(0,i); - return encPass.substring(i+1).equals(passwordEncoder.encodePassword(rawPass,salt)); + if (i < 0) { + return false; + } + String salt = encPass.substring(0, i); + return encPass.substring(i + 1).equals(passwordEncoder.encodePassword(rawPass, salt)); } /** @@ -647,7 +669,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea */ private String hash(String password) { String salt = generateSalt(); - return salt+':'+passwordEncoder.encodePassword(password,salt); + return salt + ':' + passwordEncoder.encodePassword(password, salt); } /** @@ -656,10 +678,12 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea private String generateSalt() { StringBuilder buf = new StringBuilder(); SecureRandom sr = new SecureRandom(); - for( int i=0; i<6; i++ ) {// log2(52^6)=34.20... so, this is about 32bit strong. + for (int i = 0; i < 6; i++) {// log2(52^6)=34.20... so, this is about 32bit strong. boolean upper = sr.nextBoolean(); - char ch = (char)(sr.nextInt(26) + 'a'); - if(upper) ch=Character.toUpperCase(ch); + char ch = (char) (sr.nextInt(26) + 'a'); + if (upper) { + ch = Character.toUpperCase(ch); + } buf.append(ch); } return buf.toString(); @@ -668,16 +692,16 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea @Extension public static final class DescriptorImpl extends Descriptor<SecurityRealm> { + public String getDisplayName() { return Messages.HudsonPrivateSecurityRealm_DisplayName(); } @Override public String getHelpFile() { - return "/help/security/private-realm.html"; + return "/help/security/private-realm.html"; } } - private static final Filter CREATE_FIRST_USER_FILTER = new Filter() { public void init(FilterConfig config) throws ServletException { } @@ -685,20 +709,21 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; - if(req.getRequestURI().equals(req.getContextPath()+"/")) { + if (req.getRequestURI().equals(req.getContextPath() + "/")) { if (needsToCreateFirstUser()) { - ((HttpServletResponse)response).sendRedirect("securityRealm/firstUser"); + ((HttpServletResponse) response).sendRedirect("securityRealm/firstUser"); } else {// the first user already created. the role of this filter is over. PluginServletFilter.removeFilter(this); - chain.doFilter(request,response); + chain.doFilter(request, response); } - } else - chain.doFilter(request,response); + } else { + chain.doFilter(request, response); + } } private boolean needsToCreateFirstUser() { return !hasSomeUser() - && HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm() instanceof HudsonPrivateSecurityRealm; + && HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm() instanceof HudsonPrivateSecurityRealm; } public void destroy() { diff --git a/hudson-core/src/main/java/hudson/security/InvalidatableUserDetails.java b/hudson-core/src/main/java/hudson/security/InvalidatableUserDetails.java index 6d1f9a4..bd86893 100644 --- a/hudson-core/src/main/java/hudson/security/InvalidatableUserDetails.java +++ b/hudson-core/src/main/java/hudson/security/InvalidatableUserDetails.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -25,27 +25,26 @@ import javax.servlet.http.HttpSession; /** * {@link UserDetails} that can mark {@link Authentication} invalid. * - * <p> - * Tomcat persists sessions by using Java serialization (and - * that includes the security token created by Spring Security, which includes this object) - * and when that happens, the next time the server comes back - * it will try to deserialize {@link SecurityContext} that Spring Security - * puts into {@link HttpSession} (which transitively includes {@link UserDetails} - * that can be implemented by Hudson. - * - * <p> - * Such {@link UserDetails} implementation can override the {@link #isInvalid()} - * method and return false, so that such {@link SecurityContext} will be - * dropped before the rest of Spring Security sees it. - * - * <p> - * See http://issues.hudson-ci.org/browse/HUDSON-1482 - * + * <p> Tomcat persists sessions by using Java serialization (and that includes + * the security token created by Spring Security, which includes this object) + * and when that happens, the next time the server comes back it will try to + * deserialize {@link SecurityContext} that Spring Security puts into + * {@link HttpSession} (which transitively includes {@link UserDetails} that can + * be implemented by Hudson. + * + * <p> Such {@link UserDetails} implementation can override the + * {@link #isInvalid()} method and return false, so that such + * {@link SecurityContext} will be dropped before the rest of Spring Security + * sees it. + * + * <p> See http://issues.hudson-ci.org/browse/HUDSON-1482 + * * @author Kohsuke Kawaguchi - * @deprecated - * Starting 1.285, Hudson stops persisting {@link Authentication} altogether - * (see {@link NotSerilizableSecurityContext}), so there's no need to use this mechanism. + * @deprecated Starting 1.285, Hudson stops persisting {@link Authentication} + * altogether (see {@link NotSerilizableSecurityContext}), so there's no need to + * use this mechanism. */ public interface InvalidatableUserDetails extends UserDetails { + boolean isInvalid(); } diff --git a/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java b/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java index c2e3e72..23912a8 100644 --- a/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java +++ b/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Seiji Sogabe, Winston Prakash - * + * *******************************************************************************/ package hudson.security; @@ -68,7 +68,6 @@ import org.springframework.security.providers.ldap.LdapAuthenticationProvider; import org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider; import org.springframework.security.userdetails.ldap.LdapUserDetailsService; - /** * {@link SecurityRealm} implementation that uses LDAP for authentication. * @@ -77,209 +76,205 @@ import org.springframework.security.userdetails.ldap.LdapUserDetailsService; * * <h4>Group Membership</h4> * - * <p> - * Two object classes seem to be relevant. These are in RFC 2256 and core.schema. These use DN for membership, - * so it can create a group of anything. I don't know what the difference between these two are. + * <p> Two object classes seem to be relevant. These are in RFC 2256 and + * core.schema. These use DN for membership, so it can create a group of + * anything. I don't know what the difference between these two are. * <pre> - attributetype ( 2.5.4.31 NAME 'member' - DESC 'RFC2256: member of a group' - SUP distinguishedName ) - - attributetype ( 2.5.4.50 NAME 'uniqueMember' - DESC 'RFC2256: unique member of a group' - EQUALITY uniqueMemberMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 ) - - objectclass ( 2.5.6.9 NAME 'groupOfNames' - DESC 'RFC2256: a group of names (DNs)' - SUP top STRUCTURAL - MUST ( member $ cn ) - MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) ) - - objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames' - DESC 'RFC2256: a group of unique names (DN and Unique Identifier)' - SUP top STRUCTURAL - MUST ( uniqueMember $ cn ) - MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) ) + * attributetype ( 2.5.4.31 NAME 'member' + * DESC 'RFC2256: member of a group' + * SUP distinguishedName ) + * + * attributetype ( 2.5.4.50 NAME 'uniqueMember' + * DESC 'RFC2256: unique member of a group' + * EQUALITY uniqueMemberMatch + * SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 ) + * + * objectclass ( 2.5.6.9 NAME 'groupOfNames' + * DESC 'RFC2256: a group of names (DNs)' + * SUP top STRUCTURAL + * MUST ( member $ cn ) + * MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) ) + * + * objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames' + * DESC 'RFC2256: a group of unique names (DN and Unique Identifier)' + * SUP top STRUCTURAL + * MUST ( uniqueMember $ cn ) + * MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) ) * </pre> * - * <p> - * This one is from nis.schema, and appears to model POSIX group/user thing more closely. + * <p> This one is from nis.schema, and appears to model POSIX group/user thing + * more closely. * <pre> - objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' - DESC 'Abstraction of a group of accounts' - SUP top STRUCTURAL - MUST ( cn $ gidNumber ) - MAY ( userPassword $ memberUid $ description ) ) - - attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' - DESC 'Abstraction of an account with POSIX attributes' - SUP top AUXILIARY - MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) - MAY ( userPassword $ loginShell $ gecos $ description ) ) - - attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber' - DESC 'An integer uniquely identifying a user in an administrative domain' - EQUALITY integerMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) - - attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' - DESC 'An integer uniquely identifying a group in an administrative domain' - EQUALITY integerMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + * objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' + * DESC 'Abstraction of a group of accounts' + * SUP top STRUCTURAL + * MUST ( cn $ gidNumber ) + * MAY ( userPassword $ memberUid $ description ) ) + * + * attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid' + * EQUALITY caseExactIA5Match + * SUBSTR caseExactIA5SubstringsMatch + * SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + * + * objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' + * DESC 'Abstraction of an account with POSIX attributes' + * SUP top AUXILIARY + * MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) + * MAY ( userPassword $ loginShell $ gecos $ description ) ) + * + * attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber' + * DESC 'An integer uniquely identifying a user in an administrative domain' + * EQUALITY integerMatch + * SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + * + * attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' + * DESC 'An integer uniquely identifying a group in an administrative domain' + * EQUALITY integerMatch + * SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) * </pre> * - * <p> - * Active Directory specific schemas (from <a href="http://www.grotan.com/ldap/microsoft.schema">here</a>). + * <p> Active Directory specific schemas (from <a + * href="http://www.grotan.com/ldap/microsoft.schema">here</a>). * <pre> - objectclass ( 1.2.840.113556.1.5.8 - NAME 'group' - SUP top - STRUCTURAL - MUST (groupType ) - MAY (member $ nTGroupMembers $ operatorCount $ adminCount $ - groupAttributes $ groupMembershipSAM $ controlAccessRights $ - desktopProfile $ nonSecurityMember $ managedBy $ - primaryGroupToken $ mail ) ) - - objectclass ( 1.2.840.113556.1.5.9 - NAME 'user' - SUP organizationalPerson - STRUCTURAL - MAY (userCertificate $ networkAddress $ userAccountControl $ - badPwdCount $ codePage $ homeDirectory $ homeDrive $ - badPasswordTime $ lastLogoff $ lastLogon $ dBCSPwd $ - localeID $ scriptPath $ logonHours $ logonWorkstation $ - maxStorage $ userWorkstations $ unicodePwd $ - otherLoginWorkstations $ ntPwdHistory $ pwdLastSet $ - preferredOU $ primaryGroupID $ userParameters $ - profilePath $ operatorCount $ adminCount $ accountExpires $ - lmPwdHistory $ groupMembershipSAM $ logonCount $ - controlAccessRights $ defaultClassStore $ groupsToIgnore $ - groupPriority $ desktopProfile $ dynamicLDAPServer $ - userPrincipalName $ lockoutTime $ userSharedFolder $ - userSharedFolderOther $ servicePrincipalName $ - aCSPolicyName $ terminalServer $ mSMQSignCertificates $ - mSMQDigests $ mSMQDigestsMig $ mSMQSignCertificatesMig $ - msNPAllowDialin $ msNPCallingStationID $ - msNPSavedCallingStationID $ msRADIUSCallbackNumber $ - msRADIUSFramedIPAddress $ msRADIUSFramedRoute $ - msRADIUSServiceType $ msRASSavedCallbackNumber $ - msRASSavedFramedIPAddress $ msRASSavedFramedRoute $ - mS-DS-CreatorSID ) ) + * objectclass ( 1.2.840.113556.1.5.8 + * NAME 'group' + * SUP top + * STRUCTURAL + * MUST (groupType ) + * MAY (member $ nTGroupMembers $ operatorCount $ adminCount $ + * groupAttributes $ groupMembershipSAM $ controlAccessRights $ + * desktopProfile $ nonSecurityMember $ managedBy $ + * primaryGroupToken $ mail ) ) + * + * objectclass ( 1.2.840.113556.1.5.9 + * NAME 'user' + * SUP organizationalPerson + * STRUCTURAL + * MAY (userCertificate $ networkAddress $ userAccountControl $ + * badPwdCount $ codePage $ homeDirectory $ homeDrive $ + * badPasswordTime $ lastLogoff $ lastLogon $ dBCSPwd $ + * localeID $ scriptPath $ logonHours $ logonWorkstation $ + * maxStorage $ userWorkstations $ unicodePwd $ + * otherLoginWorkstations $ ntPwdHistory $ pwdLastSet $ + * preferredOU $ primaryGroupID $ userParameters $ + * profilePath $ operatorCount $ adminCount $ accountExpires $ + * lmPwdHistory $ groupMembershipSAM $ logonCount $ + * controlAccessRights $ defaultClassStore $ groupsToIgnore $ + * groupPriority $ desktopProfile $ dynamicLDAPServer $ + * userPrincipalName $ lockoutTime $ userSharedFolder $ + * userSharedFolderOther $ servicePrincipalName $ + * aCSPolicyName $ terminalServer $ mSMQSignCertificates $ + * mSMQDigests $ mSMQDigestsMig $ mSMQSignCertificatesMig $ + * msNPAllowDialin $ msNPCallingStationID $ + * msNPSavedCallingStationID $ msRADIUSCallbackNumber $ + * msRADIUSFramedIPAddress $ msRADIUSFramedRoute $ + * msRADIUSServiceType $ msRASSavedCallbackNumber $ + * msRASSavedFramedIPAddress $ msRASSavedFramedRoute $ + * mS-DS-CreatorSID ) ) * </pre> * * - * <h2>References</h2> - * <dl> - * <dt><a href="http://www.openldap.org/doc/admin22/schema.html">Standard Schemas</a> - * <dd> - * The downloadable distribution contains schemas that define the structure of LDAP entries. - * Because this is a standard, we expect most LDAP servers out there to use it, although - * there are different objectClasses that can be used for similar purposes, and apparently - * many deployments choose to use different objectClasses. + * <h2>References</h2> <dl> <dt><a + * href="http://www.openldap.org/doc/admin22/schema.html">Standard Schemas</a> + * <dd> The downloadable distribution contains schemas that define the structure + * of LDAP entries. Because this is a standard, we expect most LDAP servers out + * there to use it, although there are different objectClasses that can be used + * for similar purposes, and apparently many deployments choose to use different + * objectClasses. + * + * <dt><a href="http://www.ietf.org/rfc/rfc2256.txt">RFC 2256</a> <dd> Defines + * the meaning of several key datatypes used in the schemas with some + * explanations. * - * <dt><a href="http://www.ietf.org/rfc/rfc2256.txt">RFC 2256</a> - * <dd> - * Defines the meaning of several key datatypes used in the schemas with some explanations. + * <dt><a + * href="http://msdn.microsoft.com/en-us/library/ms675085(VS.85).aspx">Active + * Directory schema</a> <dd> More navigable schema list, including core and MS + * extensions specific to Active Directory. </dl> * - * <dt><a href="http://msdn.microsoft.com/en-us/library/ms675085(VS.85).aspx">Active Directory schema</a> - * <dd> - * More navigable schema list, including core and MS extensions specific to Active Directory. - * </dl> - * * @author Kohsuke Kawaguchi * @since 1.166 */ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { + /** * LDAP server name, optionally with TCP port number, like "ldap.acme.org" * or "ldap.acme.org:389". */ public final String server; - /** * The root DN to connect to. Normally something like "dc=sun,dc=com" * * How do I infer this? */ public final String rootDN; - /** - * Specifies the relative DN from {@link #rootDN the root DN}. - * This is used to narrow down the search space when doing user search. + * Specifies the relative DN from {@link #rootDN the root DN}. This is used + * to narrow down the search space when doing user search. * * Something like "ou=people" but can be empty. */ public final String userSearchBase; - /** - * Query to locate an entry that identifies the user, given the user name string. + * Query to locate an entry that identifies the user, given the user name + * string. * * Normally "uid={0}" * * @see FilterBasedLdapUserSearch */ public final String userSearch; - /** * This defines the organizational unit that contains groups. * - * Normally "" to indicate the full LDAP search, but can be often narrowed down to - * something like "ou=groups" + * Normally "" to indicate the full LDAP search, but can be often narrowed + * down to something like "ou=groups" * * @see FilterBasedLdapUserSearch */ public final String groupSearchBase; /* - Other configurations that are needed: + Other configurations that are needed: - group search base DN (relative to root DN) - group search filter (uniquemember={1} seems like a reasonable default) - group target (CN is a reasonable default) + group search base DN (relative to root DN) + group search filter (uniquemember={1} seems like a reasonable default) + group target (CN is a reasonable default) - manager dn/password if anonyomus search is not allowed. + manager dn/password if anonyomus search is not allowed. - See GF configuration at http://weblogs.java.net/blog/tchangu/archive/2007/01/ldap_security_r.html - Geronimo configuration at http://cwiki.apache.org/GMOxDOC11/ldap-realm.html + See GF configuration at http://weblogs.java.net/blog/tchangu/archive/2007/01/ldap_security_r.html + Geronimo configuration at http://cwiki.apache.org/GMOxDOC11/ldap-realm.html */ - /** - * If non-null, we use this and {@link #managerPassword} - * when binding to LDAP. + * If non-null, we use this and {@link #managerPassword} when binding to + * LDAP. * * This is necessary when LDAP doesn't support anonymous access. */ public final String managerDN; - /** * Scrambled password, used to first bind to LDAP. */ private final String managerPassword; - /** - * Created in {@link #createSecurityComponents()}. Can be used to connect to LDAP. + * Created in {@link #createSecurityComponents()}. Can be used to connect to + * LDAP. */ private transient SpringSecurityLdapTemplate ldapTemplate; - - private static String GROUP_SEARCH_FILTER = "(| (member={0}) (uniqueMember={0}) (memberUid={1}))"; + private static String GROUP_SEARCH_FILTER = "(| (member={0}) (uniqueMember={0}) (memberUid={1}))"; @DataBoundConstructor public LDAPSecurityRealm(String server, String rootDN, String userSearchBase, String userSearch, String groupSearchBase, String managerDN, String managerPassword) { this.server = server.trim(); this.managerDN = fixEmpty(managerDN); this.managerPassword = Scrambler.scramble(fixEmpty(managerPassword)); - if(fixEmptyAndTrim(rootDN)==null) rootDN= fixNull(inferRootDN(server)); + if (fixEmptyAndTrim(rootDN) == null) { + rootDN = fixNull(inferRootDN(server)); + } this.rootDN = rootDN.trim(); this.userSearchBase = fixNull(userSearchBase).trim(); userSearch = fixEmptyAndTrim(userSearch); - this.userSearch = userSearch!=null ? userSearch : "uid={0}"; + this.userSearch = userSearch != null ? userSearch : "uid={0}"; this.groupSearchBase = fixEmptyAndTrim(groupSearchBase); } @@ -294,28 +289,30 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { */ private String inferRootDN(String server) { try { - Hashtable<String,String> props = new Hashtable<String,String>(); - if(managerDN!=null) { - props.put(Context.SECURITY_PRINCIPAL,managerDN); - props.put(Context.SECURITY_CREDENTIALS,getManagerPassword()); + Hashtable<String, String> props = new Hashtable<String, String>(); + if (managerDN != null) { + props.put(Context.SECURITY_PRINCIPAL, managerDN); + props.put(Context.SECURITY_CREDENTIALS, getManagerPassword()); } props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); - props.put(Context.PROVIDER_URL, getServerUrl()+'/'); + props.put(Context.PROVIDER_URL, getServerUrl() + '/'); DirContext ctx = new InitialDirContext(props); Attributes atts = ctx.getAttributes(""); Attribute a = atts.get("defaultNamingContext"); - if(a!=null) // this entry is available on Active Directory. See http://msdn2.microsoft.com/en-us/library/ms684291(VS.85).aspx + if (a != null) // this entry is available on Active Directory. See http://msdn2.microsoft.com/en-us/library/ms684291(VS.85).aspx + { return a.toString(); - + } + a = atts.get("namingcontexts"); - if(a==null) { - LOGGER.warning("namingcontexts attribute not found in root DSE of "+server); + if (a == null) { + LOGGER.warning("namingcontexts attribute not found in root DSE of " + server); return null; } return a.get().toString(); } catch (NamingException e) { - LOGGER.log(Level.WARNING,"Failed to connect to LDAP to infer Root DN for "+server,e); + LOGGER.log(Level.WARNING, "Failed to connect to LDAP to infer Root DN for " + server, e); return null; } } @@ -325,43 +322,43 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { } public String getLDAPURL() { - return getServerUrl()+'/'+ fixNull(rootDN); + return getServerUrl() + '/' + fixNull(rootDN); } public synchronized SecurityComponents createSecurityComponents() { DefaultDirObjectFactory factory = new DefaultDirObjectFactory(); DefaultSpringSecurityContextSource securityContextSource = new DefaultSpringSecurityContextSource(getLDAPURL()); - if (managerDN != null){ + if (managerDN != null) { securityContextSource.setUserDn(managerDN); securityContextSource.setPassword(getManagerPassword()); } Map envProps = new HashMap(); envProps.put(Context.REFERRAL, "follow"); - securityContextSource.setDirObjectFactory(factory.getClass ()); + securityContextSource.setDirObjectFactory(factory.getClass()); securityContextSource.setBaseEnvironmentProperties(envProps); try { securityContextSource.afterPropertiesSet(); } catch (Exception ex) { - LOGGER.log(Level.WARNING,"Failed to set security Context for LDAP Server " + server, ex); + LOGGER.log(Level.WARNING, "Failed to set security Context for LDAP Server " + server, ex); } - + ldapTemplate = new SpringSecurityLdapTemplate(securityContextSource); - - FilterBasedLdapUserSearch ldapUserSearch =new FilterBasedLdapUserSearch(userSearchBase, userSearch, securityContextSource); + + FilterBasedLdapUserSearch ldapUserSearch = new FilterBasedLdapUserSearch(userSearchBase, userSearch, securityContextSource); ldapUserSearch.setSearchSubtree(true); - + BindAuthenticator2 bindAuthenticator = new BindAuthenticator2(securityContextSource); - bindAuthenticator.setUserSearch(ldapUserSearch); - + bindAuthenticator.setUserSearch(ldapUserSearch); + AuthoritiesPopulatorImpl authoritiesPopulator = new AuthoritiesPopulatorImpl(securityContextSource, groupSearchBase); authoritiesPopulator.setSearchSubtree(true); - authoritiesPopulator.setGroupSearchFilter(GROUP_SEARCH_FILTER); - - + authoritiesPopulator.setGroupSearchFilter(GROUP_SEARCH_FILTER); + + // talk to LDAP - LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(bindAuthenticator, authoritiesPopulator); - + LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(bindAuthenticator, authoritiesPopulator); + // these providers apply everywhere RememberMeAuthenticationProvider rememberMeAuthenticationProvider = new RememberMeAuthenticationProvider(); rememberMeAuthenticationProvider.setKey(HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecretKey()); @@ -381,7 +378,7 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { ProviderManager providerManager = new ProviderManager(); providerManager.setProviders(Arrays.asList(authenticationProvider)); return new SecurityComponents(providerManager, new LDAPUserDetailsService(ldapUserSearch, authoritiesPopulator)); - + } /** @@ -390,7 +387,7 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { @Override protected UserDetails authenticate(String username, String password) throws AuthenticationException { return (UserDetails) getSecurityComponents().manager.authenticate( - new UsernamePasswordAuthenticationToken(username, password)).getPrincipal(); + new UsernamePasswordAuthenticationToken(username, password)).getPrincipal(); } /** @@ -402,10 +399,10 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { } /** - * Lookup a group; given input must match the configured syntax for group names - * in GROUP_SEARCH_FILTER of authoritiesPopulator entry. - * The defaults are a prefix of "ROLE_" and using all uppercase. This method will - * not return any data if the given name lacks the proper prefix and/or case. + * Lookup a group; given input must match the configured syntax for group + * names in GROUP_SEARCH_FILTER of authoritiesPopulator entry. The defaults + * are a prefix of "ROLE_" and using all uppercase. This method will not + * return any data if the given name lacks the proper prefix and/or case. */ @Override public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException { @@ -413,24 +410,27 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { String prefix = ""; boolean onlyUpperCase = false; try { - AuthoritiesPopulatorImpl api = (AuthoritiesPopulatorImpl) - ((LDAPUserDetailsService)getSecurityComponents().userDetails).authoritiesPopulator; + AuthoritiesPopulatorImpl api = (AuthoritiesPopulatorImpl) ((LDAPUserDetailsService) getSecurityComponents().userDetails).authoritiesPopulator; prefix = api.rolePrefix; onlyUpperCase = api.convertToUpperCase; - } catch (Exception ignore) { } - if (onlyUpperCase && !groupname.equals(groupname.toUpperCase())) + } catch (Exception ignore) { + } + if (onlyUpperCase && !groupname.equals(groupname.toUpperCase())) { throw new UsernameNotFoundException(groupname + " should be all uppercase"); - if (!groupname.startsWith(prefix)) + } + if (!groupname.startsWith(prefix)) { throw new UsernameNotFoundException(groupname + " is missing prefix: " + prefix); + } groupname = groupname.substring(prefix.length()); // TODO: obtain a DN instead so that we can obtain multiple attributes later String searchBase = groupSearchBase != null ? groupSearchBase : ""; - final Set<String> groups = (Set<String>)ldapTemplate.searchForSingleAttributeValues(searchBase, GROUP_SEARCH, + final Set<String> groups = (Set<String>) ldapTemplate.searchForSingleAttributeValues(searchBase, GROUP_SEARCH, new String[]{groupname}, "cn"); - if(groups.isEmpty()) + if (groups.isEmpty()) { throw new UsernameNotFoundException(groupname); + } return new GroupDetails() { public String getName() { @@ -440,6 +440,7 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { } public static class LDAPUserDetailsService implements UserDetailsService { + private final LdapUserSearch ldapSearch; private final LdapAuthoritiesPopulator authoritiesPopulator; @@ -467,39 +468,46 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { */ @Extension public static final class MailAdressResolverImpl extends MailAddressResolver { + public String findMailAddressFor(User u) { // LDAP not active SecurityRealm realm = HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSecurityRealm(); - if(!(realm instanceof LDAPSecurityRealm)) + if (!(realm instanceof LDAPSecurityRealm)) { return null; + } try { - LdapUserDetails details = (LdapUserDetails)realm.getSecurityComponents().userDetails.loadUserByUsername(u.getId()); + LdapUserDetails details = (LdapUserDetails) realm.getSecurityComponents().userDetails.loadUserByUsername(u.getId()); Attribute mail = details.getAttributes().get("mail"); - if(mail==null) return null; // not found - return (String)mail.get(); + if (mail == null) { + return null; // not found + } + return (String) mail.get(); } catch (UsernameNotFoundException e) { - LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address",e); + LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address", e); return null; } catch (DataAccessException e) { - LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address",e); + LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address", e); return null; } catch (NamingException e) { - LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address",e); + LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address", e); return null; } catch (SpringSecurityException e) { - LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address",e); + LOGGER.log(Level.FINE, "Failed to look up LDAP for e-mail address", e); return null; } } } /** - * {@link LdapAuthoritiesPopulator} that adds the automatic 'authenticated' role. + * {@link LdapAuthoritiesPopulator} that adds the automatic 'authenticated' + * role. */ public static final class AuthoritiesPopulatorImpl extends DefaultLdapAuthoritiesPopulator { // Make these available (private in parent class and no get methods!) + String rolePrefix; boolean convertToUpperCase; + public AuthoritiesPopulatorImpl(ContextSource initialDirContextFactory, String groupSearchBase) { super(initialDirContextFactory, fixNull(groupSearchBase)); // These match the defaults in Spring Security 1.0.5; set again to store in non-private fields: @@ -527,29 +535,30 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { @Extension public static final class DescriptorImpl extends Descriptor<SecurityRealm> { + public String getDisplayName() { return Messages.LDAPSecurityRealm_DisplayName(); } public FormValidation doServerCheck( @QueryParameter final String server, - @QueryParameter final String managerDN, - @QueryParameter final String managerPassword) { + @QueryParameter final String managerDN, + @QueryParameter final String managerPassword) { - if(!HudsonSecurityEntitiesHolder.getHudsonSecurityManager().hasPermission(Hudson.ADMINISTER) || StringUtils.isEmpty(server)){ + if (!HudsonSecurityEntitiesHolder.getHudsonSecurityManager().hasPermission(Hudson.ADMINISTER) || StringUtils.isEmpty(server)) { return FormValidation.ok(); } try { - Hashtable<String,String> props = new Hashtable<String,String>(); - if(managerDN!=null && managerDN.trim().length() > 0 && !"undefined".equals(managerDN)) { - props.put(Context.SECURITY_PRINCIPAL,managerDN); + Hashtable<String, String> props = new Hashtable<String, String>(); + if (managerDN != null && managerDN.trim().length() > 0 && !"undefined".equals(managerDN)) { + props.put(Context.SECURITY_PRINCIPAL, managerDN); } - if(managerPassword!=null && managerPassword.trim().length() > 0 && !"undefined".equals(managerPassword)) { - props.put(Context.SECURITY_CREDENTIALS,managerPassword); + if (managerPassword != null && managerPassword.trim().length() > 0 && !"undefined".equals(managerPassword)) { + props.put(Context.SECURITY_CREDENTIALS, managerPassword); } props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); - props.put(Context.PROVIDER_URL, addPrefix(server)+'/'); + props.put(Context.PROVIDER_URL, addPrefix(server) + '/'); DirContext ctx = new InitialDirContext(props); ctx.getAttributes(""); @@ -557,25 +566,27 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { } catch (NamingException e) { // trouble-shoot Matcher m = Pattern.compile("(ldaps://)?([^:]+)(?:\\:(\\d+))?").matcher(server.trim()); - if(!m.matches()) + if (!m.matches()) { return FormValidation.error(Messages.LDAPSecurityRealm_SyntaxOfServerField()); + } try { InetAddress adrs = InetAddress.getByName(m.group(2)); - int port = m.group(1)!=null ? 636 : 389; - if(m.group(3)!=null) + int port = m.group(1) != null ? 636 : 389; + if (m.group(3) != null) { port = Integer.parseInt(m.group(3)); - Socket s = new Socket(adrs,port); + } + Socket s = new Socket(adrs, port); s.close(); } catch (UnknownHostException x) { return FormValidation.error(Messages.LDAPSecurityRealm_UnknownHost(x.getMessage())); } catch (IOException x) { - return FormValidation.error(x,Messages.LDAPSecurityRealm_UnableToConnect(server, x.getMessage())); + return FormValidation.error(x, Messages.LDAPSecurityRealm_UnableToConnect(server, x.getMessage())); } // otherwise we don't know what caused it, so fall back to the general error report // getMessage() alone doesn't offer enough - return FormValidation.error(e,Messages.LDAPSecurityRealm_UnableToConnect(server, e)); + return FormValidation.error(e, Messages.LDAPSecurityRealm_UnableToConnect(server, e)); } catch (NumberFormatException x) { // The getLdapCtxInstance method throws this if it fails to parse the port number return FormValidation.error(Messages.LDAPSecurityRealm_InvalidPortNumber()); @@ -584,23 +595,25 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm { } /** - * If the given "server name" is just a host name (plus optional host name), add ldap:// prefix. - * Otherwise assume it already contains the scheme, and leave it intact. + * If the given "server name" is just a host name (plus optional host name), + * add ldap:// prefix. Otherwise assume it already contains the scheme, and + * leave it intact. */ private static String addPrefix(String server) { - if(server.contains("://")) return server; - else return "ldap://"+server; + if (server.contains("://")) { + return server; + } else { + return "ldap://" + server; + } } - private static final Logger LOGGER = Logger.getLogger(LDAPSecurityRealm.class.getName()); - /** * LDAP filter to look for groups by their names. * - * "{0}" is the group name as given by the user. - * See http://msdn.microsoft.com/en-us/library/aa746475(VS.85).aspx for the syntax by example. - * WANTED: The specification of the syntax. + * "{0}" is the group name as given by the user. See + * http://msdn.microsoft.com/en-us/library/aa746475(VS.85).aspx for the + * syntax by example. WANTED: The specification of the syntax. */ - public static String GROUP_SEARCH = System.getProperty(LDAPSecurityRealm.class.getName()+".groupSearch", + public static String GROUP_SEARCH = System.getProperty(LDAPSecurityRealm.class.getName() + ".groupSearch", "(& (cn={0}) (| (objectclass=groupOfNames) (objectclass=groupOfUniqueNames) (objectclass=posixGroup)))"); } diff --git a/hudson-core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java index f85e3fb..56394d1 100644 --- a/hudson-core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java +++ b/hudson-core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -19,14 +19,14 @@ package hudson.security; import hudson.RestrictedSince; /** - * {@link AuthorizationStrategy} implementation that emulates the legacy behavior. + * {@link AuthorizationStrategy} implementation that emulates the legacy + * behavior. * * @author Kohsuke Kawaguchi - * @deprecated as of 2.2.0 - * This strategy was removed due to <a href='http://issues.hudson-ci.org/browse/HUDSON-8944'>HUDSON-8944</a> + * @deprecated as of 2.2.0 This strategy was removed due to <a + * href='http://issues.hudson-ci.org/browse/HUDSON-8944'>HUDSON-8944</a> */ @Deprecated @RestrictedSince("2.2.0") public final class LegacyAuthorizationStrategy extends FullControlOnceLoggedInAuthorizationStrategy { } - diff --git a/hudson-core/src/main/java/hudson/security/LegacySecurityRealm.java b/hudson-core/src/main/java/hudson/security/LegacySecurityRealm.java index 44b8c49..4d424b6 100644 --- a/hudson-core/src/main/java/hudson/security/LegacySecurityRealm.java +++ b/hudson-core/src/main/java/hudson/security/LegacySecurityRealm.java @@ -7,7 +7,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Seiji Sogabe, Winston Prakash * @@ -31,26 +31,28 @@ import javax.servlet.FilterConfig; /** * {@link SecurityRealm} that accepts {@link ContainerAuthentication} object - * without any check (that is, by assuming that the such token is - * already authenticated by the container.) - * + * without any check (that is, by assuming that the such token is already + * authenticated by the container.) + * * @author Kohsuke Kawaguchi */ public final class LegacySecurityRealm extends SecurityRealm implements AuthenticationManager { + public SecurityComponents createSecurityComponents() { return new SecurityComponents(this); } public Authentication authenticate(Authentication authentication) throws AuthenticationException { - if(authentication instanceof ContainerAuthentication) + if (authentication instanceof ContainerAuthentication) { return authentication; - else + } else { return null; + } } /** - * To have the username/password authenticated by the container, - * submit the form to the URL defined by the servlet spec. + * To have the username/password authenticated by the container, submit the + * form to the URL defined by the servlet spec. */ @Override public String getAuthenticationGatewayUrl() { @@ -63,29 +65,27 @@ public final class LegacySecurityRealm extends SecurityRealm implements Authenti } /** - * Filter to run for the LegacySecurityRealm is the - * ChainServletFilter + * Filter to run for the LegacySecurityRealm is the ChainServletFilter */ @Override public Filter createFilter(FilterConfig filterConfig) { - + // this filter set up is used to emulate the legacy Hudson behavior // of container authentication before 1.160 // when using container-authentication we can't hit /login directly. // we first have to hit protected /loginEntry, then let the container // trap that into /login. - + List<Filter> filters = new ArrayList<Filter>(); BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(); filters.add(basicAuthenticationFilter); - + filters.addAll(Arrays.asList(getCommonFilters())); - - return new ChainedServletFilter(filters); - - } + return new ChainedServletFilter(filters); + + } @Extension public static final Descriptor<SecurityRealm> DESCRIPTOR = new Descriptor<SecurityRealm>() { public SecurityRealm newInstance(StaplerRequest req, JSONObject formData) throws FormException { diff --git a/hudson-core/src/main/java/hudson/security/NotSerilizableSecurityContext.java b/hudson-core/src/main/java/hudson/security/NotSerilizableSecurityContext.java index f0ccd7b..557231b 100644 --- a/hudson-core/src/main/java/hudson/security/NotSerilizableSecurityContext.java +++ b/hudson-core/src/main/java/hudson/security/NotSerilizableSecurityContext.java @@ -23,25 +23,26 @@ import org.springframework.security.userdetails.UserDetails; import javax.servlet.http.HttpSession; /** - * The same as {@link SecurityContextImpl} but doesn't serialize {@link Authentication}. + * The same as {@link SecurityContextImpl} but doesn't serialize + * {@link Authentication}. * - * <p> - * {@link Authentication} often contains {@link UserDetails} implemented by a plugin, - * but when it's persisted as a part of {@link HttpSession}, such instance will never - * de-serialize correctly because the container isn't aware of additional classloading - * in Hudson. + * <p> {@link Authentication} often contains {@link UserDetails} implemented by + * a plugin, but when it's persisted as a part of {@link HttpSession}, such + * instance will never de-serialize correctly because the container isn't aware + * of additional classloading in Hudson. * - * <p> - * Hudson doesn't work with a clustering anyway, and so it's better to just not persist - * Authentication at all. + * <p> Hudson doesn't work with a clustering anyway, and so it's better to just + * not persist Authentication at all. * - * See http://www.nabble.com/ActiveDirectory-Plugin%3A-ClassNotFoundException-while-loading--persisted-sessions%3A-td22085140.html + * See + * http://www.nabble.com/ActiveDirectory-Plugin%3A-ClassNotFoundException-while-loading--persisted-sessions%3A-td22085140.html * for the problem report. * * @author Kohsuke Kawaguchi * @see HttpSessionContextIntegrationFilter2 */ public class NotSerilizableSecurityContext implements SecurityContext { + private transient Authentication authentication; @Override @@ -54,7 +55,7 @@ public class NotSerilizableSecurityContext implements SecurityContext { } if ((this.getAuthentication() != null) && (test.getAuthentication() != null) - && this.getAuthentication().equals(test.getAuthentication())) { + && this.getAuthentication().equals(test.getAuthentication())) { return true; } } diff --git a/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java b/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java index f72e24a..cc56e04 100644 --- a/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java +++ b/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java @@ -7,8 +7,8 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: - * + * Contributors: + * * Kohsuke Kawaguchi, Winston Prakash * *******************************************************************************/ @@ -123,7 +123,6 @@ public class PAMSecurityRealm extends SecurityRealm { providerManager.setProviders(Arrays.asList(authenticationProvider)); UserDetailsService userDetailsService = new UserDetailsService() { - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { try { if (!NativeUtils.getInstance().checkUnixUser(username)) { @@ -156,7 +155,6 @@ public class PAMSecurityRealm extends SecurityRealm { } return new GroupDetails() { - @Override public String getName() { return groupname; diff --git a/hudson-core/src/main/java/hudson/security/Permission.java b/hudson-core/src/main/java/hudson/security/Permission.java index 3628149..2cd8646 100644 --- a/hudson-core/src/main/java/hudson/security/Permission.java +++ b/hudson-core/src/main/java/hudson/security/Permission.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi, Yahoo! Inc. - * + * Contributors: + * + * Kohsuke Kawaguchi, Yahoo! Inc. + * * *******************************************************************************/ @@ -29,11 +29,12 @@ import org.jvnet.localizer.Localizable; /** * Permission, which represents activity that requires a security privilege. * - * <p> - * Each permission is represented by a specific instance of {@link Permission}. + * <p> Each permission is represented by a specific instance of + * {@link Permission}. * * @author Kohsuke Kawaguchi - * @see http://wiki.hudson-ci.org/display/HUDSON/Making+your+plugin+behave+in+secured+Hudson + * @see + * http://wiki.hudson-ci.org/display/HUDSON/Making+your+plugin+behave+in+secured+Hudson */ public final class Permission { @@ -41,7 +42,6 @@ public final class Permission { * Comparator that orders {@link Permission} objects based on their ID. */ public static final Comparator<Permission> ID_COMPARATOR = new Comparator<Permission>() { - /** * {@inheritDoc} */ @@ -51,57 +51,45 @@ public final class Permission { return one.getId().compareTo(two.getId()); } }; - //TODO: review and check whether we can do it private public final Class owner; - //TODO: review and check whether we can do it private public final PermissionGroup group; - /** * Human readable ID of the permission. * - * <p> - * This name should uniquely determine a permission among - * its owner class. The name must be a valid Java identifier. - * <p> - * The expected naming convention is something like "BrowseWorkspace". + * <p> This name should uniquely determine a permission among its owner + * class. The name must be a valid Java identifier. <p> The expected naming + * convention is something like "BrowseWorkspace". */ //TODO: review and check whether we can do it private public final String name; - /** - * Human-readable description of this permission. - * Used as a tooltip to explain this permission, so this message - * should be a couple of sentences long. + * Human-readable description of this permission. Used as a tooltip to + * explain this permission, so this message should be a couple of sentences + * long. * - * <p> - * If null, there will be no description text. + * <p> If null, there will be no description text. */ //TODO: review and check whether we can do it private public final Localizable description; - /** * Bundled {@link Permission} that also implies this permission. * - * <p> - * This allows us to organize permissions in a hierarchy, so that - * for example we can say "view workspace" permission is implied by - * the (broader) "read" permission. + * <p> This allows us to organize permissions in a hierarchy, so that for + * example we can say "view workspace" permission is implied by the + * (broader) "read" permission. * - * <p> - * The idea here is that for most people, access control based on - * such broad permission bundle is good enough, and those few - * that need finer control can do so. + * <p> The idea here is that for most people, access control based on such + * broad permission bundle is good enough, and those few that need finer + * control can do so. */ //TODO: review and check whether we can do it private public final Permission impliedBy; - /** * Whether this permission is available for use. * - * <p> - * This allows us to dynamically enable or disable the visibility of + * <p> This allows us to dynamically enable or disable the visibility of * permissions, so administrators can control the complexity of their * permission matrix. * @@ -109,13 +97,12 @@ public final class Permission { */ //TODO: review and check whether we can do it private public boolean enabled; - + /** * Defines a new permission. * - * @param group - * Permissions are grouped per classes that own them. Specify the permission group - * created for that class. The idiom is: + * @param group Permissions are grouped per classes that own them. Specify + * the permission group created for that class. The idiom is: * * <pre> * class Foo { @@ -124,19 +111,18 @@ public final class Permission { * } * </pre> * - * Because of the classloading problems and the difficulty for Hudson to enumerate them, - * the permission constants really need to be static field of the owner class. + * Because of the classloading problems and the difficulty for Hudson to + * enumerate them, the permission constants really need to be static field + * of the owner class. * - * @param name - * See {@link #name}. - * @param description - * See {@link #description}. - * @param impliedBy - * See {@link #impliedBy}. + * @param name See {@link #name}. + * @param description See {@link #description}. + * @param impliedBy See {@link #impliedBy}. */ public Permission(PermissionGroup group, String name, Localizable description, Permission impliedBy, boolean enable) { - if(!JSONUtils.isJavaIdentifier(name)) - throw new IllegalArgumentException(name+" is not a Java identifier"); + if (!JSONUtils.isJavaIdentifier(name)) { + throw new IllegalArgumentException(name + " is not a Java identifier"); + } this.owner = group.owner; this.group = group; this.name = name; @@ -151,31 +137,30 @@ public final class Permission { public Permission(PermissionGroup group, String name, Localizable description, Permission impliedBy) { this(group, name, description, impliedBy, true); } - + /** - * @deprecated since 1.257. - * Use {@link #Permission(PermissionGroup, String, Localizable, Permission)} + * @deprecated since 1.257. Use + * {@link #Permission(PermissionGroup, String, Localizable, Permission)} */ public Permission(PermissionGroup group, String name, Permission impliedBy) { - this(group,name,null,impliedBy); + this(group, name, null, impliedBy); } private Permission(PermissionGroup group, String name) { - this(group,name,null,null); + this(group, name, null, null); } /** - * Returns the string representation of this {@link Permission}, - * which can be converted back to {@link Permission} via the - * {@link #fromId(String)} method. + * Returns the string representation of this {@link Permission}, which can + * be converted back to {@link Permission} via the {@link #fromId(String)} + * method. * - * <p> - * This string representation is suitable for persistence. + * <p> This string representation is suitable for persistence. * * @see #fromId(String) */ public String getId() { - return owner.getName()+'.'+name; + return owner.getName() + '.' + name; } public Class getOwner() { @@ -205,8 +190,7 @@ public final class Permission { /** * Convert the ID representation into {@link Permission} object. * - * @return - * null if the conversion failed. + * @return null if the conversion failed. * @see #getId() */ public static Permission fromId(String id) { @@ -218,9 +202,9 @@ public final class Permission { try { // force the initialization so that it will put all its permissions into the list. Class cl; - if (Hudson.getInstance() != null){ + if (Hudson.getInstance() != null) { cl = Class.forName(id.substring(0, idx), true, Hudson.getInstance().getPluginManager().uberClassLoader); - }else{ + } else { // Hudson may not be yet initialized - to support Initial Setup cl = Class.forName(id.substring(0, idx)); } @@ -236,7 +220,7 @@ public final class Permission { @Override public String toString() { - return "Permission["+owner+','+name+']'; + return "Permission[" + owner + ',' + name + ']'; } public void setEnabled(boolean enable) { @@ -246,47 +230,41 @@ public final class Permission { public boolean getEnabled() { return enabled; } - + /** * Returns all the {@link Permission}s available in the system. - * @return - * always non-null. Read-only. + * + * @return always non-null. Read-only. */ public static List<Permission> getAll() { return ALL_VIEW; } - /** * All permissions in the system but in a single list. */ private static final List<Permission> ALL = new CopyOnWriteArrayList<Permission>(); - private static final List<Permission> ALL_VIEW = Collections.unmodifiableList(ALL); - // // // Because of the initialization order issue, these two fields need to be defined here, // even though they logically belong to Hudson. // - /** * {@link PermissionGroup} for {@link Hudson}. * - * @deprecated since 2009-01-23. - * Access {@link Hudson#PERMISSIONS} instead. + * @deprecated since 2009-01-23. Access {@link Hudson#PERMISSIONS} instead. */ public static final PermissionGroup HUDSON_PERMISSIONS = new PermissionGroup(Hudson.class, hudson.model.Messages._Hudson_Permissions_Title()); /** - * {@link Permission} that represents the God-like access. Equivalent of Unix root. + * {@link Permission} that represents the God-like access. Equivalent of + * Unix root. * - * <p> - * All permissions are eventually {@linkplain Permission#impliedBy implied by} this permission. + * <p> All permissions are eventually + * {@linkplain Permission#impliedBy implied by} this permission. * - * @deprecated since 2009-01-23. - * Access {@link Hudson#ADMINISTER} instead. + * @deprecated since 2009-01-23. Access {@link Hudson#ADMINISTER} instead. */ - public static final Permission HUDSON_ADMINISTER = new Permission(HUDSON_PERMISSIONS,"Administer", hudson.model.Messages._Hudson_AdministerPermission_Description(),null); - + public static final Permission HUDSON_ADMINISTER = new Permission(HUDSON_PERMISSIONS, "Administer", hudson.model.Messages._Hudson_AdministerPermission_Description(), null); // // // Root Permissions. @@ -294,45 +272,36 @@ public final class Permission { // These permisisons are meant to be used as the 'impliedBy' permission for other more specific permissions. // The intention is to allow a simplified AuthorizationStrategy implementation agnostic to // specific permissions. - - public static final PermissionGroup GROUP = new PermissionGroup(Permission.class,Messages._Permission_Permissions_Title()); - + public static final PermissionGroup GROUP = new PermissionGroup(Permission.class, Messages._Permission_Permissions_Title()); /** - * Historically this was separate from {@link #HUDSON_ADMINISTER} but such a distinction doesn't make sense - * any more, so deprecated. + * Historically this was separate from {@link #HUDSON_ADMINISTER} but such a + * distinction doesn't make sense any more, so deprecated. * - * @deprecated since 2009-01-23. - * Use {@link Hudson#ADMINISTER}. + * @deprecated since 2009-01-23. Use {@link Hudson#ADMINISTER}. */ - public static final Permission FULL_CONTROL = new Permission(GROUP,"FullControl",HUDSON_ADMINISTER); - + public static final Permission FULL_CONTROL = new Permission(GROUP, "FullControl", HUDSON_ADMINISTER); /** * Generic read access. */ - public static final Permission READ = new Permission(GROUP,"GenericRead",null,HUDSON_ADMINISTER); - + public static final Permission READ = new Permission(GROUP, "GenericRead", null, HUDSON_ADMINISTER); /** * Generic write access. */ - public static final Permission WRITE = new Permission(GROUP,"GenericWrite",null,HUDSON_ADMINISTER); - + public static final Permission WRITE = new Permission(GROUP, "GenericWrite", null, HUDSON_ADMINISTER); /** * Generic create access. */ - public static final Permission CREATE = new Permission(GROUP,"GenericCreate",null,WRITE); - + public static final Permission CREATE = new Permission(GROUP, "GenericCreate", null, WRITE); /** * Generic update access. */ - public static final Permission UPDATE = new Permission(GROUP,"GenericUpdate",null,WRITE); - + public static final Permission UPDATE = new Permission(GROUP, "GenericUpdate", null, WRITE); /** * Generic delete access. */ - public static final Permission DELETE = new Permission(GROUP,"GenericDelete",null,WRITE); - + public static final Permission DELETE = new Permission(GROUP, "GenericDelete", null, WRITE); /** * Generic configuration access. */ - public static final Permission CONFIGURE = new Permission(GROUP,"GenericConfigure",null,UPDATE); + public static final Permission CONFIGURE = new Permission(GROUP, "GenericConfigure", null, UPDATE); } diff --git a/hudson-core/src/main/java/hudson/security/PermissionGroup.java b/hudson-core/src/main/java/hudson/security/PermissionGroup.java index 500a18a..4dce708 100644 --- a/hudson-core/src/main/java/hudson/security/PermissionGroup.java +++ b/hudson-core/src/main/java/hudson/security/PermissionGroup.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -30,19 +30,19 @@ import java.util.concurrent.ConcurrentHashMap; import org.jvnet.localizer.Localizable; /** - * Group of {@link Permission}s that share the same {@link Permission#owner owner}. + * Group of {@link Permission}s that share the same + * {@link Permission#owner owner}. * * Sortable by the owner class name. */ public final class PermissionGroup implements Iterable<Permission>, Comparable<PermissionGroup> { + private final List<Permission> permisisons = new CopyOnWriteArrayList<Permission>(); private final List<Permission> permisisonsView = Collections.unmodifiableList(permisisons); //TODO: review and check whether we can do it private public final Class owner; - /** - * Human readable title of this permission group. - * This should be short. + * Human readable title of this permission group. This should be short. */ //TODO: review and check whether we can do it private public final Localizable title; @@ -59,14 +59,14 @@ public final class PermissionGroup implements Iterable<Permission>, Comparable<P this.owner = owner; this.title = title; - synchronized(PermissionGroup.class) { + synchronized (PermissionGroup.class) { List<PermissionGroup> allGroups = new ArrayList<PermissionGroup>(ALL); allGroups.add(this); Collections.sort(allGroups); ALL = Collections.unmodifiableList(allGroups); } - PERMISSIONS.put(owner,this); + PERMISSIONS.put(owner, this); } public Iterator<Permission> iterator() { @@ -89,8 +89,9 @@ public final class PermissionGroup implements Iterable<Permission>, Comparable<P */ public Permission find(String name) { for (Permission p : permisisons) { - if(p.name.equals(name)) + if (p.name.equals(name)) { return p; + } } return null; } @@ -98,8 +99,10 @@ public final class PermissionGroup implements Iterable<Permission>, Comparable<P public int compareTo(PermissionGroup that) { // first, sort by the 'compare order' number. This is so that // we can put Hudson.PERMISSIONS first. - int r= this.compareOrder()-that.compareOrder(); - if(r!=0) return r; + int r = this.compareOrder() - that.compareOrder(); + if (r != 0) { + return r; + } // among the permissions of the same group, just sort by their names // so that the sort order is consistent regardless of classloading order. @@ -107,14 +110,15 @@ public final class PermissionGroup implements Iterable<Permission>, Comparable<P } private int compareOrder() { - if(owner== Hudson.class) return 0; + if (owner == Hudson.class) { + return 0; + } return 1; } public int size() { return permisisons.size(); } - /** * All groups. Sorted. */ @@ -123,22 +127,22 @@ public final class PermissionGroup implements Iterable<Permission>, Comparable<P /** * Returns all the {@link PermissionGroup}s available in the system. - * @return - * always non-null. Read-only. + * + * @return always non-null. Read-only. */ public static List<PermissionGroup> getAll() { return ALL; } /** - * Gets the {@link PermissionGroup} whose {@link PermissionGroup#owner} is the given class. + * Gets the {@link PermissionGroup} whose {@link PermissionGroup#owner} is + * the given class. * - * @return null if not found. + * @return null if not found. */ public static PermissionGroup get(Class owner) { return PERMISSIONS.get(owner); } - /** * All the permissions in the system, keyed by their owners. */ diff --git a/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java index ddcac5d..5ca1b84 100644 --- a/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java +++ b/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi, Yahoo! Inc., Seiji Sogabe, Tom Huybrechts - * + * Contributors: + * + * Kohsuke Kawaguchi, Yahoo! Inc., Seiji Sogabe, Tom Huybrechts + * * *******************************************************************************/ @@ -32,14 +32,14 @@ import java.util.Set; /** * {@link GlobalMatrixAuthorizationStrategy} plus per-project ACL. * - * <p> - * Per-project ACL is stored in {@link AuthorizationMatrixProperty}. + * <p> Per-project ACL is stored in {@link AuthorizationMatrixProperty}. * * @author Kohsuke Kawaguchi */ public class ProjectMatrixAuthorizationStrategy extends GlobalMatrixAuthorizationStrategy { + @Override - public ACL getACL(Job<?,?> project) { + public ACL getACL(Job<?, ?> project) { AuthorizationMatrixProperty amp = project.getProperty(AuthorizationMatrixProperty.class); if (amp != null) { return amp.getACL().newInheritingACL(getRootACL()); @@ -52,14 +52,14 @@ public class ProjectMatrixAuthorizationStrategy extends GlobalMatrixAuthorizatio public Set<String> getGroups() { Set<String> r = new HashSet<String>(); r.addAll(super.getGroups()); - for (Job<?,?> j : Hudson.getInstance().getItems(Job.class)) { + for (Job<?, ?> j : Hudson.getInstance().getItems(Job.class)) { AuthorizationMatrixProperty amp = j.getProperty(AuthorizationMatrixProperty.class); - if (amp != null) + if (amp != null) { r.addAll(amp.getGroups()); + } } return r; } - @Extension public static final Descriptor<AuthorizationStrategy> DESCRIPTOR = new DescriptorImpl() { @Override @@ -74,10 +74,11 @@ public class ProjectMatrixAuthorizationStrategy extends GlobalMatrixAuthorizatio }; public static class ConverterImpl extends GlobalMatrixAuthorizationStrategy.ConverterImpl { + private RobustReflectionConverter ref; public ConverterImpl(Mapper m) { - ref = new RobustReflectionConverter(m,new JVM().bestReflectionProvider()); + ref = new RobustReflectionConverter(m, new JVM().bestReflectionProvider()); } @Override @@ -88,18 +89,18 @@ public class ProjectMatrixAuthorizationStrategy extends GlobalMatrixAuthorizatio @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String name = reader.peekNextChild(); - if(name!=null && (name.equals("permission") || name.equals("useProjectSecurity"))) - // the proper serialization form + if (name != null && (name.equals("permission") || name.equals("useProjectSecurity"))) // the proper serialization form + { return super.unmarshal(reader, context); - else - // remain compatible with earlier problem where we used reflection converter - return ref.unmarshal(reader,context); + } else // remain compatible with earlier problem where we used reflection converter + { + return ref.unmarshal(reader, context); + } } @Override public boolean canConvert(Class type) { - return type==ProjectMatrixAuthorizationStrategy.class; + return type == ProjectMatrixAuthorizationStrategy.class; } } } - diff --git a/hudson-core/src/main/java/hudson/security/RememberMeServicesProxy.java b/hudson-core/src/main/java/hudson/security/RememberMeServicesProxy.java index 1ecac62..f02e54e 100644 --- a/hudson-core/src/main/java/hudson/security/RememberMeServicesProxy.java +++ b/hudson-core/src/main/java/hudson/security/RememberMeServicesProxy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -27,34 +27,39 @@ import hudson.model.Hudson; /** * {@link RememberMeServices} proxy. * - * <p> - * In Hudson, we need {@link Hudson} instance to perform remember-me service, - * because it relies on {@link Hudson#getSecretKey()}. However, security - * filters can be initialized before Hudson is initialized. - * (See #1210 for example.) + * <p> In Hudson, we need {@link Hudson} instance to perform remember-me + * service, because it relies on {@link Hudson#getSecretKey()}. However, + * security filters can be initialized before Hudson is initialized. (See #1210 + * for example.) * - * <p> - * So to work around the problem, we use a proxy. + * <p> So to work around the problem, we use a proxy. * * @author Kohsuke Kawaguchi */ public class RememberMeServicesProxy implements RememberMeServices { + private volatile RememberMeServices delegate; public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) { RememberMeServices d = delegate; - if(d!=null) return d.autoLogin(request,response); + if (d != null) { + return d.autoLogin(request, response); + } return null; } public void loginFail(HttpServletRequest request, HttpServletResponse response) { RememberMeServices d = delegate; - if(d!=null) d.loginFail(request,response); + if (d != null) { + d.loginFail(request, response); + } } public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { RememberMeServices d = delegate; - if(d!=null) d.loginSuccess(request,response,successfulAuthentication); + if (d != null) { + d.loginSuccess(request, response, successfulAuthentication); + } } public void setDelegate(RememberMeServices delegate) { diff --git a/hudson-core/src/main/java/hudson/security/SecurityMode.java b/hudson-core/src/main/java/hudson/security/SecurityMode.java index 3618db3..5b0f477 100644 --- a/hudson-core/src/main/java/hudson/security/SecurityMode.java +++ b/hudson-core/src/main/java/hudson/security/SecurityMode.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -22,19 +22,17 @@ package hudson.security; * @author Kohsuke Kawaguchi */ public enum SecurityMode { + /** - * None. Anyone can make any changes. + * None. Anyone can make any changes. */ UNSECURED, /** - * Legacy "secure mode." - * <p> - * In this model, an user is either admin or not. An admin user - * can do anything, and non-admin user can only browse. - * Authentication is performed by the container. - * <p> - * This is the only secured mode of Hudson up to 1.160. - * This is maintained only for backward compatibility. + * Legacy "secure mode." <p> In this model, an user is either admin or not. + * An admin user can do anything, and non-admin user can only browse. + * Authentication is performed by the container. <p> This is the only + * secured mode of Hudson up to 1.160. This is maintained only for backward + * compatibility. */ LEGACY, /** diff --git a/hudson-core/src/main/java/hudson/security/SecurityRealm.java b/hudson-core/src/main/java/hudson/security/SecurityRealm.java index 0c62de2..d9de777 100644 --- a/hudson-core/src/main/java/hudson/security/SecurityRealm.java +++ b/hudson-core/src/main/java/hudson/security/SecurityRealm.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * * Kohsuke Kawaguchi, Nikita Levyankov, Winston Prakash - * + * *******************************************************************************/ package hudson.security; @@ -69,56 +69,64 @@ import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices; /** * Pluggable security realm that connects external user database to Hudson. * <p/> - * <p/> - * If additional views/URLs need to be exposed, - * an active {@link SecurityRealm} is bound to <tt>CONTEXT_ROOT/securityRealm/</tt> - * through {@link Hudson#getSecurityRealm()}, so you can define additional pages and + * < + * p/> + * If additional views/URLs need to be exposed, an active {@link SecurityRealm} + * is bound to <tt>CONTEXT_ROOT/securityRealm/</tt> through + * {@link Hudson#getSecurityRealm()}, so you can define additional pages and * operations on your {@link SecurityRealm}. * <p/> * <h2>How do I implement this class?</h2> * <p/> - * For compatibility reasons, there are two somewhat different ways to implement a custom SecurityRealm. - * <p/> + * For compatibility reasons, there are two somewhat different ways to implement + * a custom SecurityRealm. * <p/> - * One is to override the {@link #createSecurityComponents()} and create key Spring Security components - * that control the authentication process. - * The default {@link SecurityRealm#createFilter(FilterConfig)} implementation then assembles them - * into a chain of {@link Filter}s. All the incoming requests to Hudson go through this filter chain, - * and when the filter chain is done, {@link SecurityContext#getAuthentication()} would tell us - * who the current user is. - * <p/> - * <p/> - * If your {@link SecurityRealm} needs to touch the default {@link Filter} chain configuration - * (e.g., adding new ones), then you can also override {@link #createFilter(FilterConfig)} to do so. + * < + * p/> + * One is to override the {@link #createSecurityComponents()} and create key + * Spring Security components that control the authentication process. The + * default {@link SecurityRealm#createFilter(FilterConfig)} implementation then + * assembles them into a chain of {@link Filter}s. All the incoming requests to + * Hudson go through this filter chain, and when the filter chain is done, + * {@link SecurityContext#getAuthentication()} would tell us who the current + * user is. * <p/> + * < + * p/> + * If your {@link SecurityRealm} needs to touch the default {@link Filter} chain + * configuration (e.g., adding new ones), then you can also override + * {@link #createFilter(FilterConfig)} to do so. * <p/> + * < + * p/> * This model is expected to fit most {@link SecurityRealm} implementations. * <p/> - * <p/> - * <p/> - * The other way of doing this is to ignore {@link #createSecurityComponents()} completely (by returning - * {@link SecurityComponents} created by the default constructor) and just concentrate on {@link #createFilter(FilterConfig)}. - * As long as the resulting filter chain properly sets up {@link Authentication} object at the end of the processing, - * Hudson doesn't really need you to fit the standard Spring Security models like {@link AuthenticationManager} and + * < + * p/> + * < + * p/> + * The other way of doing this is to ignore {@link #createSecurityComponents()} + * completely (by returning {@link SecurityComponents} created by the default + * constructor) and just concentrate on {@link #createFilter(FilterConfig)}. As + * long as the resulting filter chain properly sets up {@link Authentication} + * object at the end of the processing, Hudson doesn't really need you to fit + * the standard Spring Security models like {@link AuthenticationManager} and * {@link UserDetailsService}. * <p/> - * <p/> + * < + * p/> * This model is for those "weird" implementations. * <p/> - * <p/> - * <h2>Views</h2> - * <dl> - * <dt>loginLink.jelly</dt> - * <dd> - * This view renders the login link on the top right corner of every page, when the user - * is anonymous. For {@link SecurityRealm}s that support user sign-up, this is a good place - * to show a "sign up" link. See {@link HudsonPrivateSecurityRealm} implementation + * < + * p/> + * <h2>Views</h2> <dl> <dt>loginLink.jelly</dt> <dd> This view renders the login + * link on the top right corner of every page, when the user is anonymous. For + * {@link SecurityRealm}s that support user sign-up, this is a good place to + * show a "sign up" link. See {@link HudsonPrivateSecurityRealm} implementation * for an example of this. * <p/> - * <dt>config.jelly</dt> - * <dd> - * This view is used to render the configuration page in the system config screen. - * </dl> + * <dt>config.jelly</dt> <dd> This view is used to render the configuration page + * in the system config screen. </dl> * * @author Kohsuke Kawaguchi * @author Nikita Levyankov @@ -128,20 +136,23 @@ import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices; public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityRealm> implements ExtensionPoint { /** - * Creates fully-configured {@link AuthenticationManager} that performs authentication - * against the user realm. The implementation hides how such authentication manager - * is configured. - * <p/> - * <p/> - * {@link AuthenticationManager} instantiation often depends on the user-specified parameters - * (for example, if the authentication is based on LDAP, the user needs to specify - * the host name of the LDAP server.) Such configuration is expected to be - * presented to the user via <tt>config.jelly</tt> and then - * captured as instance variables inside the {@link SecurityRealm} implementation. + * Creates fully-configured {@link AuthenticationManager} that performs + * authentication against the user realm. The implementation hides how such + * authentication manager is configured. * <p/> + * < + * p/> + * {@link AuthenticationManager} instantiation often depends on the + * user-specified parameters (for example, if the authentication is based on + * LDAP, the user needs to specify the host name of the LDAP server.) Such + * configuration is expected to be presented to the user via + * <tt>config.jelly</tt> and then captured as instance variables inside the + * {@link SecurityRealm} implementation. * <p/> - * Your {@link SecurityRealm} may also wants to alter {@link Filter} set up by - * overriding {@link #createFilter(FilterConfig)}. + * < + * p/> + * Your {@link SecurityRealm} may also wants to alter {@link Filter} set up + * by overriding {@link #createFilter(FilterConfig)}. */ public abstract SecurityComponents createSecurityComponents(); /** @@ -150,16 +161,17 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal private CaptchaSupport captchaSupport; /** - * Creates a {@link CliAuthenticator} object that authenticates an invocation of a CLI command. - * See {@link CliAuthenticator} for more details. + * Creates a {@link CliAuthenticator} object that authenticates an + * invocation of a CLI command. See {@link CliAuthenticator} for more + * details. * * @param command The command about to be executed. - * @return never null. By default, this method returns a no-op authenticator that always authenticates - * the session as authenticated by the transport (which is often just {@link Hudson#ANONYMOUS}.) + * @return never null. By default, this method returns a no-op authenticator + * that always authenticates the session as authenticated by the transport + * (which is often just {@link Hudson#ANONYMOUS}.) */ public CliAuthenticator createCliAuthenticator(final CLICommand command) { return new CliAuthenticator() { - public Authentication authenticate() { return command.getTransportAuthentication(); } @@ -169,7 +181,8 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal /** * {@inheritDoc} * <p/> - * <p/> + * < + * p/> * {@link SecurityRealm} is a singleton resource in Hudson, and therefore * it's always configured through <tt>config.jelly</tt> and never with * <tt>global.jelly</tt>. @@ -179,23 +192,24 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * Returns the URL to submit a form for the authentication. - * There's no need to override this, except for {@link LegacySecurityRealm}. + * Returns the URL to submit a form for the authentication. There's no need + * to override this, except for {@link LegacySecurityRealm}. */ public String getAuthenticationGatewayUrl() { return "j_spring_security_check"; } /** - * Gets the target URL of the "login" link. - * There's no need to override this, except for {@link LegacySecurityRealm}. - * On legacy implementation this should point to {@code loginEntry}, which - * is protected by <tt>web.xml</tt>, so that the user can be eventually authenticated - * by the container. - * <p/> + * Gets the target URL of the "login" link. There's no need to override + * this, except for {@link LegacySecurityRealm}. On legacy implementation + * this should point to {@code loginEntry}, which is protected by + * <tt>web.xml</tt>, so that the user can be eventually authenticated by the + * container. * <p/> - * Path is relative from the context root of the Hudson application. - * The URL returned by this method will get the "from" query parameter indicating + * < + * p/> + * Path is relative from the context root of the Hudson application. The URL + * returned by this method will get the "from" query parameter indicating * the page that the user was at. */ public String getLoginUrl() { @@ -203,14 +217,18 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * Returns true if this {@link SecurityRealm} supports explicit logout operation. - * <p/> - * <p/> - * If the method returns false, "logout" link will not be displayed. This is useful - * when authentication doesn't require an explicit login activity (such as NTLM authentication - * or Kerberos authentication, where Hudson has no ability to log off the current user.) + * Returns true if this {@link SecurityRealm} supports explicit logout + * operation. * <p/> + * < + * p/> + * If the method returns false, "logout" link will not be displayed. This is + * useful when authentication doesn't require an explicit login activity + * (such as NTLM authentication or Kerberos authentication, where Hudson has + * no ability to log off the current user.) * <p/> + * < + * p/> * By default, this method returns true. * * @since 1.307 @@ -220,14 +238,15 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * Controls where the user is sent to after a logout. By default, it's the top page - * of Hudson, but you can return arbitrary URL. + * Controls where the user is sent to after a logout. By default, it's the + * top page of Hudson, but you can return arbitrary URL. * - * @param req {@link StaplerRequest} that represents the current request. Primarily so that - * you can get the context path. By the time this method is called, the session - * is already invalidated. Never null. - * @param auth The {@link Authentication} object that represents the user that was logging in. - * This parameter allows you to redirect people to different pages depending on who they are. + * @param req {@link StaplerRequest} that represents the current request. + * Primarily so that you can get the context path. By the time this method + * is called, the session is already invalidated. Never null. + * @param auth The {@link Authentication} object that represents the user + * that was logging in. This parameter allows you to redirect people to + * different pages depending on who they are. * @return never null. * @see #doLogout(StaplerRequest, StaplerResponse) * @since 1.314 @@ -251,9 +270,11 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal /** * Handles the logout processing. * <p/> - * <p/> - * The default implementation erases the session and do a few other clean up, then - * redirect the user to the URL specified by {@link #getPostLogOutUrl(StaplerRequest, Authentication)}. + * < + * p/> + * The default implementation erases the session and do a few other clean + * up, then redirect the user to the URL specified by + * {@link #getPostLogOutUrl(StaplerRequest, Authentication)}. * * @since 1.314 */ @@ -277,15 +298,17 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * Returns true if this {@link SecurityRealm} allows online sign-up. - * This creates a hyperlink that redirects users to <tt>CONTEXT_ROOT/signUp</tt>, + * Returns true if this {@link SecurityRealm} allows online sign-up. This + * creates a hyperlink that redirects users to <tt>CONTEXT_ROOT/signUp</tt>, * which will be served by the <tt>signup.jelly</tt> view of this class. * <p/> + * < + * p/> + * If the implementation needs to redirect the user to a different URL for + * signing up, use the following jelly script as <tt>signup.jelly</tt> * <p/> - * If the implementation needs to redirect the user to a different URL - * for signing up, use the following jelly script as <tt>signup.jelly</tt> - * <p/> - * <pre><xmp> + * < + * pre><xmp> * <st:redirect url="http://www.sun.com/" xmlns:st="jelly:stapler"/> * </xmp></pre> */ @@ -298,38 +321,47 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal * Shortcut for {@link UserDetailsService#loadUserByUsername(String)}. * * @return never null. - * @throws UserMayOrMayNotExistException If the security realm cannot even tell if the user exists or not. + * @throws UserMayOrMayNotExistException If the security realm cannot even + * tell if the user exists or not. */ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { return getSecurityComponents().userDetails.loadUserByUsername(username); } /** - * If this {@link SecurityRealm} supports a look up of {@link GroupDetails} by their names, override this method - * to provide the look up. - * <p/> + * If this {@link SecurityRealm} supports a look up of {@link GroupDetails} + * by their names, override this method to provide the look up. * <p/> - * This information, when available, can be used by {@link AuthorizationStrategy}s to improve the UI and - * error diagnostics for the user. + * < + * p/> + * This information, when available, can be used by + * {@link AuthorizationStrategy}s to improve the UI and error diagnostics + * for the user. */ public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException { throw new UserMayOrMayNotExistException(groupname); } /** - * Starts the user registration process for a new user that has the given verified identity. - * <p/> + * Starts the user registration process for a new user that has the given + * verified identity. * <p/> - * If the user logs in through a {@link FederatedLoginService}, verified that the current user - * owns an {@linkplain FederatedIdentity identity}, but no existing user account has claimed that identity, - * then this method is invoked. + * < + * p/> + * If the user logs in through a {@link FederatedLoginService}, verified + * that the current user owns an {@linkplain FederatedIdentity identity}, + * but no existing user account has claimed that identity, then this method + * is invoked. * <p/> - * <p/> - * The expected behaviour is to confirm that the user would like to create a new account, and - * associate this federated identity to the newly created account (via {@link FederatedIdentity#addToCurrentUser()}. + * < + * p/> + * The expected behaviour is to confirm that the user would like to create a + * new account, and associate this federated identity to the newly created + * account (via {@link FederatedIdentity#addToCurrentUser()}. * - * @throws UnsupportedOperationException If this implementation doesn't support the signup through this mechanism. - * This is the default implementation. + * @throws UnsupportedOperationException If this implementation doesn't + * support the signup through this mechanism. This is the default + * implementation. * @since 1.394 */ public HttpResponse commenceSignup(FederatedIdentity identity) { @@ -340,7 +372,7 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal * Generates a captcha image. */ public final void doCaptcha(StaplerRequest req, StaplerResponse rsp) throws IOException { - if (captchaSupport != null) { + if (captchaSupport != null) { String id = req.getSession().getId(); rsp.setContentType("image/png"); rsp.addHeader("Cache-Control", "no-cache"); @@ -364,12 +396,12 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * 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}. + * 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}. * <p/> - * This method is intended to be used to pick up a Spring Security object from - * spring once the bean definition file is parsed. + * This method is intended to be used to pick up a Spring Security 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); @@ -399,15 +431,17 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * Creates {@link Filter} that all the incoming HTTP requests will go through - * for authentication. - * <p/> - * <p/> - * The default implementation uses {@link #getSecurityComponents()} and builds - * a standard filter - * But subclasses can override this to completely change the filter sequence. + * Creates {@link Filter} that all the incoming HTTP requests will go + * through for authentication. * <p/> + * < + * p/> + * The default implementation uses {@link #getSecurityComponents()} and + * builds a standard filter But subclasses can override this to completely + * change the filter sequence. * <p/> + * < + * p/> * For other plugins that want to contribute {@link Filter}, see * {@link PluginServletFilter}. * @@ -415,14 +449,14 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal */ public Filter createFilter(FilterConfig filterConfig) throws ServletException { LOGGER.entering(SecurityRealm.class.getName(), "createFilter"); - + List<Filter> filters = new ArrayList<Filter>(); - + SecurityComponents sc = getSecurityComponents(); - + HttpSessionContextIntegrationFilter2 httpSessionContextIntegrationFilter = new HttpSessionContextIntegrationFilter2(); filters.add(httpSessionContextIntegrationFilter); - + // 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 @@ -433,7 +467,7 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal basicProcessingFilterEntryPoint.setRealmName("Hudson"); basicProcessingFilter.setAuthenticationEntryPoint(basicProcessingFilterEntryPoint); filters.add(basicProcessingFilter); - + AuthenticationProcessingFilter2 authenticationProcessingFilter = new AuthenticationProcessingFilter2(); authenticationProcessingFilter.setAuthenticationManager(sc.getManager()); authenticationProcessingFilter.setRememberMeServices(sc.getRememberMe()); @@ -441,18 +475,18 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal authenticationProcessingFilter.setDefaultTargetUrl("/"); authenticationProcessingFilter.setFilterProcessesUrl("/j_spring_security_check"); filters.add(authenticationProcessingFilter); - + RememberMeProcessingFilter rememberMeProcessingFilter = new RememberMeProcessingFilter(); rememberMeProcessingFilter.setRememberMeServices(sc.getRememberMe()); rememberMeProcessingFilter.setAuthenticationManager(sc.getManager()); filters.add(rememberMeProcessingFilter); - + filters.addAll(Arrays.asList(getCommonFilters())); - - return new ChainedServletFilter(filters); + + return new ChainedServletFilter(filters); } - - public Filter[] getCommonFilters(){ + + public Filter[] getCommonFilters() { AnonymousProcessingFilter anonymousProcessingFilter = new AnonymousProcessingFilter(); anonymousProcessingFilter.setKey("anonymous"); // must match with the AnonymousProvider UserAttribute userAttribute = new UserAttribute(); @@ -460,27 +494,25 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal String authorities = "anonymous, ROLE_ANONYMOUS"; userAttribute.setAuthoritiesAsString(Arrays.asList(authorities)); anonymousProcessingFilter.setUserAttribute(userAttribute); - + ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(); AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl(); exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler); HudsonAuthenticationEntryPoint hudsonAuthenticationEntryPoint = new HudsonAuthenticationEntryPoint(); hudsonAuthenticationEntryPoint.setLoginFormUrl('/' + getLoginUrl() + "?from={0}"); exceptionTranslationFilter.setAuthenticationEntryPoint(hudsonAuthenticationEntryPoint); - - + + UnwrapSecurityExceptionFilter unwrapSecurityExceptionFilter = new UnwrapSecurityExceptionFilter(); - - Filter[] filters = { + + Filter[] filters = { anonymousProcessingFilter, exceptionTranslationFilter, unwrapSecurityExceptionFilter }; - + return filters; } - - /** * Singleton constant that represents "no authentication." */ @@ -490,13 +522,10 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal public SecurityComponents createSecurityComponents() { return new SecurityComponents(new AuthenticationManager() { - public Authentication authenticate(Authentication authentication) { return authentication; } }, new UserDetailsService() { - - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { throw new UsernameNotFoundException(username); @@ -505,8 +534,8 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * This special instance is not configurable explicitly, - * so it doesn't have a descriptor. + * This special instance is not configurable explicitly, so it doesn't + * have a descriptor. */ @Override public Descriptor<SecurityRealm> getDescriptor() { @@ -518,7 +547,7 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal */ @Override public GroupDetails loadGroupByGroupname(String groupname) - throws UsernameNotFoundException, DataAccessException { + throws UsernameNotFoundException, DataAccessException { throw new UsernameNotFoundException(groupname); } @@ -539,16 +568,18 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } /** - * Just a tuple so that we can create various inter-related security related objects and - * return them all at once. - * <p/> + * Just a tuple so that we can create various inter-related security related + * objects and return them all at once. * <p/> + * < + * p/> * None of the fields are ever null. * * @see SecurityRealm#createSecurityComponents() */ public static final class SecurityComponents { //TODO: review and check whether we can do it private + public final AuthenticationManager manager; public final UserDetailsService userDetails; public final RememberMeServices rememberMe; @@ -569,7 +600,6 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal this(manager, userDetails, createRememberMeService(userDetails)); } - public SecurityComponents(AuthenticationManager manager, UserDetailsService userDetails, RememberMeServices rememberMe) { assert manager != null && userDetails != null && rememberMe != null; @@ -602,8 +632,8 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal /** * All registered {@link SecurityRealm} implementations. * - * @deprecated as of 1.286 - * Use {@link #all()} for read access, and use {@link Extension} for registration. + * @deprecated as of 1.286 Use {@link #all()} for read access, and use + * {@link Extension} for registration. */ public static final DescriptorList<SecurityRealm> LIST = new DescriptorList<SecurityRealm>(SecurityRealm.class); @@ -615,8 +645,8 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal } private static final Logger LOGGER = Logger.getLogger(SecurityRealm.class.getName()); /** - * {@link GrantedAuthority} that represents the built-in "authenticated" role, which is granted to - * anyone non-anonymous. + * {@link GrantedAuthority} that represents the built-in "authenticated" + * role, which is granted to anyone non-anonymous. */ public static final GrantedAuthority AUTHENTICATED_AUTHORITY = new GrantedAuthorityImpl("authenticated"); } diff --git a/hudson-core/src/main/java/hudson/security/SidACL.java b/hudson-core/src/main/java/hudson/security/SidACL.java index 6934983..9f353da 100644 --- a/hudson-core/src/main/java/hudson/security/SidACL.java +++ b/hudson-core/src/main/java/hudson/security/SidACL.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -27,8 +27,8 @@ import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINER; /** - * {@link ACL} that checks permissions based on {@link GrantedAuthority} - * of the {@link Authentication}. + * {@link ACL} that checks permissions based on {@link GrantedAuthority} of the + * {@link Authentication}. * * @author Kohsuke Kawaguchi */ @@ -36,54 +36,62 @@ public abstract class SidACL extends ACL { @Override public boolean hasPermission(Authentication a, Permission permission) { - if(a==SYSTEM) { - if(LOGGER.isLoggable(FINE)) - LOGGER.fine("hasPermission("+a+","+permission+")=>SYSTEM user has full access"); + if (a == SYSTEM) { + if (LOGGER.isLoggable(FINE)) { + LOGGER.fine("hasPermission(" + a + "," + permission + ")=>SYSTEM user has full access"); + } return true; } - Boolean b = _hasPermission(a,permission); + Boolean b = _hasPermission(a, permission); - if(LOGGER.isLoggable(FINE)) - LOGGER.fine("hasPermission("+a+","+permission+")=>"+(b==null?"null, thus false":b)); + if (LOGGER.isLoggable(FINE)) { + LOGGER.fine("hasPermission(" + a + "," + permission + ")=>" + (b == null ? "null, thus false" : b)); + } - if(b==null) b=false; // default to rejection + if (b == null) { + b = false; // default to rejection + } return b; } /** - * Implementation that backs up {@link #hasPermission(Authentication, Permission)}. + * Implementation that backs up + * {@link #hasPermission(Authentication, Permission)}. * - * @return - * true or false if {@link #hasPermission(Sid, Permission)} returns it. - * Otherwise null, indicating that this ACL doesn't have any entry for it. + * @return true or false if {@link #hasPermission(Sid, Permission)} returns + * it. Otherwise null, indicating that this ACL doesn't have any entry for + * it. */ protected Boolean _hasPermission(Authentication a, Permission permission) { // ACL entries for this principal takes precedence - Boolean b = hasPermission(new PrincipalSid(a),permission); - if(b!=null) { - if(LOGGER.isLoggable(FINER)) - LOGGER.finer("hasPermission(PrincipalSID:"+a.getPrincipal()+","+permission+")=>"+b); + Boolean b = hasPermission(new PrincipalSid(a), permission); + if (b != null) { + if (LOGGER.isLoggable(FINER)) { + LOGGER.finer("hasPermission(PrincipalSID:" + a.getPrincipal() + "," + permission + ")=>" + b); + } return b; } // after that, we check if the groups this principal belongs to // has any ACL entries. // here we are using GrantedAuthority as a group - for(GrantedAuthority ga : a.getAuthorities()) { - b = hasPermission(new GrantedAuthoritySid(ga),permission); - if(b!=null) { - if(LOGGER.isLoggable(FINER)) - LOGGER.finer("hasPermission(GroupSID:"+ga.getAuthority()+","+permission+")=>"+b); + for (GrantedAuthority ga : a.getAuthorities()) { + b = hasPermission(new GrantedAuthoritySid(ga), permission); + if (b != null) { + if (LOGGER.isLoggable(FINER)) { + LOGGER.finer("hasPermission(GroupSID:" + ga.getAuthority() + "," + permission + ")=>" + b); + } return b; } } // permissions granted to 'everyone' and 'anonymous' users are granted to everyone for (Sid sid : AUTOMATIC_SIDS) { - b = hasPermission(sid,permission); - if(b!=null) { - if(LOGGER.isLoggable(FINER)) - LOGGER.finer("hasPermission("+sid+","+permission+")=>"+b); + b = hasPermission(sid, permission); + if (b != null) { + if (LOGGER.isLoggable(FINER)) { + LOGGER.finer("hasPermission(" + sid + "," + permission + ")=>" + b); + } return b; } } @@ -94,52 +102,54 @@ public abstract class SidACL extends ACL { /** * Checks if the given {@link Sid} has the given {@link Permission}. * - * <p> - * {@link #hasPermission(Authentication, Permission)} is implemented - * by checking authentication's {@link GrantedAuthority} by using - * this method. + * <p> {@link #hasPermission(Authentication, Permission)} is implemented by + * checking authentication's {@link GrantedAuthority} by using this method. * - * <p> - * It is the implementor's responsibility to recognize {@link Permission#impliedBy} - * and take that into account. + * <p> It is the implementor's responsibility to recognize + * {@link Permission#impliedBy} and take that into account. * - * @return - * true if the access should be granted, false if it should be denied. - * The null value indicates that the ACL does no rule for this Sid/Permission - * combination. The caller can decide what to do &mash; such as consulting the higher level ACL, - * or denying the access (if the model is no-access-by-default.) + * @return true if the access should be granted, false if it should be + * denied. The null value indicates that the ACL does no rule for this + * Sid/Permission combination. The caller can decide what to do &mash; such + * as consulting the higher level ACL, or denying the access (if the model + * is no-access-by-default.) */ protected abstract Boolean hasPermission(Sid p, Permission permission); protected String toString(Sid p) { - if (p instanceof GrantedAuthoritySid) + if (p instanceof GrantedAuthoritySid) { return ((GrantedAuthoritySid) p).getGrantedAuthority(); - if (p instanceof PrincipalSid) + } + if (p instanceof PrincipalSid) { return ((PrincipalSid) p).getPrincipal(); - if (p == EVERYONE) + } + if (p == EVERYONE) { return "role_everyone"; + } // hmm... return p.toString(); } /** - * Creates a new {@link SidACL} that first consults 'this' {@link SidACL} and then delegate to - * the given parent {@link SidACL}. By doing this at the {@link SidACL} level and not at the - * {@link ACL} level, this allows the child ACLs to have an explicit deny entry. - * Note that the combined ACL calls hasPermission(Sid,Permission) in the child and parent - * SidACLs directly, so if these override _hasPermission then this custom behavior will - * not be applied. + * Creates a new {@link SidACL} that first consults 'this' {@link SidACL} + * and then delegate to the given parent {@link SidACL}. By doing this at + * the {@link SidACL} level and not at the {@link ACL} level, this allows + * the child ACLs to have an explicit deny entry. Note that the combined ACL + * calls hasPermission(Sid,Permission) in the child and parent SidACLs + * directly, so if these override _hasPermission then this custom behavior + * will not be applied. */ public final SidACL newInheritingACL(final SidACL parent) { final SidACL child = this; return new SidACL() { protected Boolean hasPermission(Sid p, Permission permission) { Boolean b = child.hasPermission(p, permission); - if(b!=null) return b; - return parent.hasPermission(p,permission); + if (b != null) { + return b; + } + return parent.hasPermission(p, permission); } }; } - private static final Logger LOGGER = Logger.getLogger(SidACL.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/SparseACL.java b/hudson-core/src/main/java/hudson/security/SparseACL.java index c6ebb1e..597896e 100644 --- a/hudson-core/src/main/java/hudson/security/SparseACL.java +++ b/hudson-core/src/main/java/hudson/security/SparseACL.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -30,9 +30,11 @@ import static java.util.logging.Level.FINE; * @author Kohsuke Kawaguchi */ public class SparseACL extends SidACL { + public static final class Entry { // Sid has value-equality semantics //TODO: review and check whether we can do it private + public final Sid sid; public final Permission permission; public final boolean allowed; @@ -55,7 +57,6 @@ public class SparseACL extends SidACL { return allowed; } } - private final List<Entry> entries = new ArrayList<Entry>(); private ACL parent; @@ -68,19 +69,24 @@ public class SparseACL extends SidACL { } public void add(Sid sid, Permission permission, boolean allowed) { - add(new Entry(sid,permission,allowed)); + add(new Entry(sid, permission, allowed)); } @Override public boolean hasPermission(Authentication a, Permission permission) { - if(a==SYSTEM) return true; - Boolean b = _hasPermission(a,permission); - if(b!=null) return b; - - if(parent!=null) { - if(LOGGER.isLoggable(FINE)) - LOGGER.fine("hasPermission("+a+","+permission+") is delegating to parent ACL: "+parent); - return parent.hasPermission(a,permission); + if (a == SYSTEM) { + return true; + } + Boolean b = _hasPermission(a, permission); + if (b != null) { + return b; + } + + if (parent != null) { + if (LOGGER.isLoggable(FINE)) { + LOGGER.fine("hasPermission(" + a + "," + permission + ") is delegating to parent ACL: " + parent); + } + return parent.hasPermission(a, permission); } // the ultimate default is to reject everything @@ -89,14 +95,14 @@ public class SparseACL extends SidACL { @Override protected Boolean hasPermission(Sid p, Permission permission) { - for( ; permission!=null; permission=permission.impliedBy ) { + for (; permission != null; permission = permission.impliedBy) { for (Entry e : entries) { - if(e.permission==permission && e.sid.equals(p)) + if (e.permission == permission && e.sid.equals(p)) { return e.allowed; + } } } return null; } - private static final Logger LOGGER = Logger.getLogger(SparseACL.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java b/hudson-core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java index 5b70d87..7c4d14c 100644 --- a/hudson-core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java +++ b/hudson-core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -21,17 +21,16 @@ import org.springframework.security.Authentication; import org.apache.commons.codec.digest.DigestUtils; /** - * {@link TokenBasedRememberMeServices} with modification so as not to rely - * on the user password being available. + * {@link TokenBasedRememberMeServices} with modification so as not to rely on + * the user password being available. * - * <p> - * This allows remember-me to work with security realms where the password + * <p> This allows remember-me to work with security realms where the password * is never available in clear text. * * @author Kohsuke Kawaguchi */ public class TokenBasedRememberMeServices2 extends TokenBasedRememberMeServices { - + @Override protected String makeTokenSignature(long tokenExpiryTime, String username, String password) { String expectedTokenSignature = DigestUtils.md5Hex(username + ":" + tokenExpiryTime + ":" diff --git a/hudson-core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java b/hudson-core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java index d8d2834..bbfc154 100644 --- a/hudson-core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java +++ b/hudson-core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -29,19 +29,20 @@ import javax.servlet.FilterChain; import java.io.IOException; /** - * If {@link SpringSecurityException} caused {@link JellyTagException}, - * rethrow it accordingly so that {@link ExceptionTranslationFilter} - * can pick it up and initiate the redirection. - * + * If {@link SpringSecurityException} caused {@link JellyTagException}, rethrow + * it accordingly so that {@link ExceptionTranslationFilter} can pick it up and + * initiate the redirection. + * * @author Kohsuke Kawaguchi */ public class UnwrapSecurityExceptionFilter implements Filter { + public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { - chain.doFilter(request,response); + chain.doFilter(request, response); } catch (ServletException e) { Throwable t = e.getRootCause(); if (t instanceof JellyTagException) { diff --git a/hudson-core/src/main/java/hudson/security/UserDetailsServiceProxy.java b/hudson-core/src/main/java/hudson/security/UserDetailsServiceProxy.java index 966ef6c..f987ffe 100644 --- a/hudson-core/src/main/java/hudson/security/UserDetailsServiceProxy.java +++ b/hudson-core/src/main/java/hudson/security/UserDetailsServiceProxy.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* + * Contributors: + * * Kohsuke Kawaguchi - * + * * *******************************************************************************/ @@ -23,22 +23,23 @@ 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) + if (uds == null) { throw new UserMayOrMayNotExistException(Messages.UserDetailsServiceProxy_UnableToQuery(username)); + } return uds.loadUserByUsername(username); } public void setDelegate(UserDetailsService core) { this.delegate = core; } - } diff --git a/hudson-core/src/main/java/hudson/security/UserMayOrMayNotExistException.java b/hudson-core/src/main/java/hudson/security/UserMayOrMayNotExistException.java index c84c013..9d4a47b 100644 --- a/hudson-core/src/main/java/hudson/security/UserMayOrMayNotExistException.java +++ b/hudson-core/src/main/java/hudson/security/UserMayOrMayNotExistException.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi - * + * Contributors: + * + * Kohsuke Kawaguchi + * * *******************************************************************************/ @@ -20,19 +20,20 @@ import org.springframework.security.userdetails.UsernameNotFoundException; import org.springframework.security.userdetails.UserDetailsService; /** - * Thrown from {@link UserDetailsService#loadUserByUsername(String)} - * to indicate that the underlying {@link SecurityRealm} is incapable - * of retrieving the information, and furthermore, the system cannot - * tell if such an user exists or not. + * Thrown from {@link UserDetailsService#loadUserByUsername(String)} to indicate + * that the underlying {@link SecurityRealm} is incapable of retrieving the + * information, and furthermore, the system cannot tell if such an user exists + * or not. * - * <p> - * This happens, for example, when the security realm is on top of the servlet implementation, - * there's no way of even knowing if an user of a given name exists or not. + * <p> This happens, for example, when the security realm is on top of the + * servlet implementation, there's no way of even knowing if an user of a given + * name exists or not. * * @author Kohsuke Kawaguchi * @since 1.280 */ public class UserMayOrMayNotExistException extends UsernameNotFoundException { + public UserMayOrMayNotExistException(String msg) { super(msg); } diff --git a/hudson-core/src/main/java/hudson/security/csrf/CrumbFilter.java b/hudson-core/src/main/java/hudson/security/csrf/CrumbFilter.java index 2f9aceb..dfa37dd 100644 --- a/hudson-core/src/main/java/hudson/security/csrf/CrumbFilter.java +++ b/hudson-core/src/main/java/hudson/security/csrf/CrumbFilter.java @@ -8,7 +8,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * + * * *******************************************************************************/ @@ -32,18 +32,22 @@ import javax.servlet.http.HttpServletResponse; /** * Checks for and validates crumbs on requests that cause state changes, to * protect against cross site request forgeries. - * + * * @author dty */ public class CrumbFilter implements Filter { + /** - * Because servlet containers generally don't specify the ordering of the initialization - * (and different implementations indeed do this differently --- See HUDSON-3878), - * we cannot use Hudson to the CrumbIssuer into CrumbFilter eagerly. + * Because servlet containers generally don't specify the ordering of the + * initialization (and different implementations indeed do this differently + * --- See HUDSON-3878), we cannot use Hudson to the CrumbIssuer into + * CrumbFilter eagerly. */ public CrumbIssuer getCrumbIssuer() { Hudson h = Hudson.getInstance(); - if(h==null) return null; // before Hudson is initialized? + if (h == null) { + return null; // before Hudson is initialized? + } return h.getCrumbIssuer(); } @@ -78,8 +82,8 @@ public class CrumbFilter implements Filter { if (crumbIssuer.validateCrumb(httpRequest, crumbSalt, crumb)) { valid = true; } else { - LOGGER.warning("Found invalid crumb " + crumb + - ". Will check remaining parameters for a valid one..."); + LOGGER.warning("Found invalid crumb " + crumb + + ". Will check remaining parameters for a valid one..."); } } // Multipart requests need to be handled by each handler. @@ -88,7 +92,7 @@ public class CrumbFilter implements Filter { } else { LOGGER.warning("No valid crumb was included in request for " + httpRequest.getRequestURI() + ". Returning " + HttpServletResponse.SC_FORBIDDEN + "."); HttpServletResponse httpResponse = (HttpServletResponse) response; - httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN,"No valid crumb was included in the request"); + httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "No valid crumb was included in the request"); } } else { chain.doFilter(request, response); @@ -124,6 +128,5 @@ public class CrumbFilter implements Filter { */ public void destroy() { } - private static final Logger LOGGER = Logger.getLogger(CrumbFilter.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuer.java b/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuer.java index 93dc3cc..8abdf55 100644 --- a/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuer.java +++ b/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuer.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: + * + * * - * - * * *******************************************************************************/ @@ -46,8 +46,8 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension private static final String CRUMB_ATTRIBUTE = CrumbIssuer.class.getName() + "_crumb"; /** - * Get the name of the request parameter the crumb will be stored in. Exposed - * here for the remote API. + * Get the name of the request parameter the crumb will be stored in. + * Exposed here for the remote API. */ @Exported public String getCrumbRequestField() { @@ -55,8 +55,9 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension } /** - * Get a crumb value based on user specific information in the current request. - * Intended for use only by the remote API. + * Get a crumb value based on user specific information in the current + * request. Intended for use only by the remote API. + * * @return */ @Exported @@ -66,6 +67,7 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension /** * Get a crumb value based on user specific information in the request. + * * @param request * @return */ @@ -77,7 +79,7 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension if (crumb == null) { crumb = issueCrumb(request, getDescriptor().getCrumbSalt()); if (request != null) { - if ((crumb != null) && crumb.length()>0) { + if ((crumb != null) && crumb.length() > 0) { request.setAttribute(CRUMB_ATTRIBUTE, crumb); } else { request.removeAttribute(CRUMB_ATTRIBUTE); @@ -90,11 +92,9 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension /** * Create a crumb value based on user specific information in the request. - * The crumb should be generated by building a cryptographic hash of: - * <ul> - * <li>relevant information in the request that can uniquely identify the client - * <li>the salt value - * <li>an implementation specific guarded secret. + * The crumb should be generated by building a cryptographic hash of: <ul> + * <li>relevant information in the request that can uniquely identify the + * client <li>the salt value <li>an implementation specific guarded secret. * </ul> * * @param request @@ -137,11 +137,13 @@ public abstract class CrumbIssuer implements Describable<CrumbIssuer>, Extension } /** - * Validate a previously created crumb against information in the current request. + * Validate a previously created crumb against information in the current + * request. * * @param request * @param salt - * @param crumb The previously generated crumb to validate against information in the current request + * @param crumb The previously generated crumb to validate against + * information in the current request * @return */ public abstract boolean validateCrumb(ServletRequest request, String salt, String crumb); diff --git a/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuerDescriptor.java b/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuerDescriptor.java index 3d7115c..76bcbaf 100644 --- a/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuerDescriptor.java +++ b/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuerDescriptor.java @@ -8,7 +8,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * + * * *******************************************************************************/ @@ -18,9 +18,9 @@ import hudson.Util; import hudson.model.Descriptor; /** - * Describes global configuration for crumb issuers. Create subclasses to specify - * additional global configuration for custom crumb issuers. - * + * Describes global configuration for crumb issuers. Create subclasses to + * specify additional global configuration for custom crumb issuers. + * * @author dty */ public abstract class CrumbIssuerDescriptor<T extends CrumbIssuer> extends Descriptor<CrumbIssuer> { @@ -32,7 +32,8 @@ public abstract class CrumbIssuerDescriptor<T extends CrumbIssuer> extends Descr * Crumb issuers always take a salt and a request field name. * * @param salt Salt value - * @param crumbRequestField Request parameter name containing crumb from previous response + * @param crumbRequestField Request parameter name containing crumb from + * previous response */ protected CrumbIssuerDescriptor(String salt, String crumbRequestField) { setCrumbSalt(salt); @@ -41,6 +42,7 @@ public abstract class CrumbIssuerDescriptor<T extends CrumbIssuer> extends Descr /** * Get the salt value. + * * @return */ public String getCrumbSalt() { @@ -49,6 +51,7 @@ public abstract class CrumbIssuerDescriptor<T extends CrumbIssuer> extends Descr /** * Set the salt value. Must not be null. + * * @param salt */ public void setCrumbSalt(String salt) { diff --git a/hudson-core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java b/hudson-core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java index f1040c3..b6c0dd8 100644 --- a/hudson-core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java +++ b/hudson-core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: + * + * * - * - * * *******************************************************************************/ @@ -36,12 +36,13 @@ import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; /** - * A crumb issuing algorithm based on the request principal and the remote address. - * + * A crumb issuing algorithm based on the request principal and the remote + * address. + * * @author dty */ public class DefaultCrumbIssuer extends CrumbIssuer { - + private transient MessageDigest md; private boolean excludeClientIPFromCrumb; @@ -60,7 +61,7 @@ public class DefaultCrumbIssuer extends CrumbIssuer { public boolean isExcludeClientIPFromCrumb() { return this.excludeClientIPFromCrumb; } - + private Object readResolve() { try { this.md = MessageDigest.getInstance("MD5"); @@ -68,10 +69,10 @@ public class DefaultCrumbIssuer extends CrumbIssuer { this.md = null; LOGGER.log(Level.SEVERE, "Can't find MD5", e); } - + return this; } - + /** * {@inheritDoc} */ @@ -120,21 +121,20 @@ public class DefaultCrumbIssuer extends CrumbIssuer { } return false; } - private final String PROXY_HEADER = "X-Forwarded-For"; private String getClientIP(HttpServletRequest req) { String defaultAddress = req.getRemoteAddr(); String forwarded = req.getHeader(PROXY_HEADER); if (forwarded != null) { - String[] hopList = forwarded.split(","); + String[] hopList = forwarded.split(","); if (hopList.length >= 1) { return hopList[0]; } } return defaultAddress; } - + @Extension public static final class DescriptorImpl extends CrumbIssuerDescriptor<DefaultCrumbIssuer> implements ModelObject { @@ -153,6 +153,5 @@ public class DefaultCrumbIssuer extends CrumbIssuer { return req.bindJSON(DefaultCrumbIssuer.class, formData); } } - private static final Logger LOGGER = Logger.getLogger(DefaultCrumbIssuer.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/security/package.html b/hudson-core/src/main/java/hudson/security/package.html index 914bdd2..1c70f87 100644 --- a/hudson-core/src/main/java/hudson/security/package.html +++ b/hudson-core/src/main/java/hudson/security/package.html @@ -16,5 +16,5 @@ --> <html><head/><body> -Security-related code -</body></html>
\ No newline at end of file + Security-related code + </body></html>
\ No newline at end of file |

