Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hudson-core/src/main/java/hudson/model/Hudson.java29
-rw-r--r--hudson-core/src/main/java/hudson/model/Job.java6
-rw-r--r--hudson-core/src/main/java/hudson/model/JobPropertyDescriptor.java4
-rw-r--r--hudson-core/src/main/java/hudson/model/ParametersDefinitionProperty.java81
-rw-r--r--hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java200
-rw-r--r--hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java296
-rw-r--r--hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java12
-rw-r--r--hudson-core/src/main/java/hudson/security/BindAuthenticator2.java56
-rw-r--r--hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java141
-rw-r--r--hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java70
-rw-r--r--hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java327
-rw-r--r--hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java706
-rw-r--r--hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java568
-rw-r--r--hudson-core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java32
-rw-r--r--hudson-core/src/main/java/hudson/security/LegacySecurityRealm.java98
-rw-r--r--hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java176
-rw-r--r--hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java105
-rw-r--r--hudson-core/src/main/java/hudson/security/SecurityRealm.java14
-rw-r--r--hudson-core/src/main/java/hudson/util/CascadingUtil.java4
19 files changed, 249 insertions, 2676 deletions
diff --git a/hudson-core/src/main/java/hudson/model/Hudson.java b/hudson-core/src/main/java/hudson/model/Hudson.java
index 3ca32324..d17c9510 100644
--- a/hudson-core/src/main/java/hudson/model/Hudson.java
+++ b/hudson-core/src/main/java/hudson/model/Hudson.java
@@ -73,9 +73,7 @@ import hudson.security.AccessControlled;
import hudson.security.AuthorizationStrategy;
import hudson.security.BasicAuthenticationFilter;
import hudson.security.FederatedLoginService;
-import hudson.security.FullControlOnceLoggedInAuthorizationStrategy;
import hudson.security.HudsonFilter;
-import hudson.security.LegacySecurityRealm;
import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.security.SecurityMode;
@@ -1951,14 +1949,8 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
public SecurityMode getSecurity() {
// fix the variable so that this code works under concurrent modification to securityRealm.
SecurityRealm realm = securityRealm;
-
- if (realm == SecurityRealm.NO_AUTHENTICATION) {
- return SecurityMode.UNSECURED;
- }
- if (realm instanceof LegacySecurityRealm) {
- return SecurityMode.LEGACY;
- }
- return SecurityMode.SECURED;
+
+ return realm.getSecurityMode();
}
/**
@@ -2393,16 +2385,21 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
if (authorizationStrategy == null) {
if (useSecurity == null || !useSecurity) {
authorizationStrategy = AuthorizationStrategy.UNSECURED;
- } else {
- authorizationStrategy = new FullControlOnceLoggedInAuthorizationStrategy();
- }
+ }
+// else {
+// authorizationStrategy = new FullControlOnceLoggedInAuthorizationStrategy();
+// }
}
+
+
+
if (securityRealm == null) {
if (useSecurity == null || !useSecurity) {
setSecurityRealm(SecurityRealm.NO_AUTHENTICATION);
- } else {
- setSecurityRealm(new LegacySecurityRealm());
- }
+ }
+// else {
+// setSecurityRealm(new LegacySecurityRealm());
+// }
} else {
// force the set to proxy
setSecurityRealm(securityRealm);
diff --git a/hudson-core/src/main/java/hudson/model/Job.java b/hudson-core/src/main/java/hudson/model/Job.java
index 397ae044..b765e171 100644
--- a/hudson-core/src/main/java/hudson/model/Job.java
+++ b/hudson-core/src/main/java/hudson/model/Job.java
@@ -42,9 +42,9 @@ import hudson.search.SearchIndexBuilder;
import hudson.search.SearchItem;
import hudson.search.SearchItems;
import hudson.security.ACL;
-import hudson.security.AuthorizationMatrixProperty;
+import hudson.security.AuthorizationStrategy;
import hudson.security.Permission;
-import hudson.security.ProjectMatrixAuthorizationStrategy;
+//import hudson.security.ProjectMatrixAuthorizationStrategy;
import hudson.tasks.LogRotator;
import hudson.util.ColorPalette;
import hudson.util.CopyOnWriteList;
@@ -489,7 +489,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
* @param user user
*/
protected void grantProjectMatrixPermissions(User user) {
- if (Hudson.getInstance().getAuthorizationStrategy() instanceof ProjectMatrixAuthorizationStrategy) {
+ if (Hudson.getInstance().getAuthorizationStrategy().getMode() == AuthorizationStrategy.MODE_PROJECT_MATRIX) {
Map<Permission, Set<String>> grantedPermissions = new HashMap<Permission, Set<String>>();
Set<String> users = Sets.newHashSet(user.getId());
grantedPermissions.put(Item.BUILD, users);
diff --git a/hudson-core/src/main/java/hudson/model/JobPropertyDescriptor.java b/hudson-core/src/main/java/hudson/model/JobPropertyDescriptor.java
index e6246f1f..8b8a4761 100644
--- a/hudson-core/src/main/java/hudson/model/JobPropertyDescriptor.java
+++ b/hudson-core/src/main/java/hudson/model/JobPropertyDescriptor.java
@@ -85,6 +85,10 @@ public abstract class JobPropertyDescriptor extends Descriptor<JobProperty<?>> {
throw new AssertionError(clazz+" doesn't properly parameterize JobProperty. The isApplicable() method must be overriden.");
}
}
+
+ public boolean isCascadable(){
+ return true;
+ }
/**
* Gets the {@link JobPropertyDescriptor}s applicable for a given job type.
diff --git a/hudson-core/src/main/java/hudson/model/ParametersDefinitionProperty.java b/hudson-core/src/main/java/hudson/model/ParametersDefinitionProperty.java
index 1a5f43cc..c4b61c41 100644
--- a/hudson-core/src/main/java/hudson/model/ParametersDefinitionProperty.java
+++ b/hudson-core/src/main/java/hudson/model/ParametersDefinitionProperty.java
@@ -1,19 +1,20 @@
-/*******************************************************************************
+/**
+ * *****************************************************************************
*
* Copyright (c) 2004-2010 Oracle Corporation.
*
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
- * Kohsuke Kawaguchi, Jean-Baptiste Quenot, Seiji Sogabe, Tom Huybrechts
- *
+ * Kohsuke Kawaguchi, Jean-Baptiste Quenot, Seiji Sogabe, Tom Huybrechts
*
- *******************************************************************************/
-
+ *
+ ******************************************************************************
+ */
package hudson.model;
import java.io.IOException;
@@ -39,11 +40,10 @@ import hudson.Extension;
/**
* Keeps a list of the parameters defined for a project.
*
- * <p>
- * This class also implements {@link Action} so that <tt>index.jelly</tt> provides
- * a form to enter build parameters.
+ * <p> This class also implements {@link Action} so that <tt>index.jelly</tt>
+ * provides a form to enter build parameters.
*/
-@ExportedBean(defaultVisibility=2)
+@ExportedBean(defaultVisibility = 2)
public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?, ?>>
implements Action {
@@ -67,7 +67,7 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
super.setOwner(owner);
}
- public AbstractProject<?,?> getOwner() {
+ public AbstractProject<?, ?> getOwner() {
return owner;
}
@@ -81,6 +81,7 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
*/
public List<String> getParameterDefinitionNames() {
return new AbstractList<String>() {
+
public String get(int index) {
return parameterDefinitions.get(index).getName();
}
@@ -101,15 +102,15 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
}
/**
- * Interprets the form submission and schedules a build for a parameterized job.
+ * Interprets the form submission and schedules a build for a parameterized
+ * job.
*
- * <p>
- * This method is supposed to be invoked from {@link AbstractProject#doBuild(StaplerRequest, StaplerResponse)}.
+ * <p> This method is supposed to be invoked from {@link AbstractProject#doBuild(StaplerRequest, StaplerResponse)}.
*/
public void _doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- if(!req.getMethod().equals("POST")) {
+ if (!req.getMethod().equals("POST")) {
// show the parameter entry form.
- req.getView(this,"index.jelly").forward(req,rsp);
+ req.getView(this, "index.jelly").forward(req, rsp);
return;
}
@@ -123,13 +124,14 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
String name = jo.getString("name");
ParameterDefinition d = getParameterDefinition(name);
- if(d==null)
+ if (d == null) {
throw new IllegalArgumentException("No such parameter definition: " + name);
+ }
ParameterValue parameterValue = d.createValue(req, jo);
values.add(parameterValue);
}
- Hudson.getInstance().getQueue().schedule(
+ Hudson.getInstance().getQueue().schedule(
owner, owner.getDelay(req), new ParametersAction(values), new CauseAction(new Cause.UserCause()));
// send the user back to the job top page.
@@ -138,16 +140,16 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
public void buildWithParameters(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
List<ParameterValue> values = new ArrayList<ParameterValue>();
- for (ParameterDefinition d: parameterDefinitions) {
- ParameterValue value = d.createValue(req);
- if (value != null) {
- values.add(value);
- } else {
- throw new IllegalArgumentException("Parameter " + d.getName() + " was missing.");
- }
+ for (ParameterDefinition d : parameterDefinitions) {
+ ParameterValue value = d.createValue(req);
+ if (value != null) {
+ values.add(value);
+ } else {
+ throw new IllegalArgumentException("Parameter " + d.getName() + " was missing.");
+ }
}
- Hudson.getInstance().getQueue().schedule(
+ Hudson.getInstance().getQueue().schedule(
owner, owner.getDelay(req), new ParametersAction(values), owner.getBuildCause(req));
// send the user back to the job top page.
@@ -158,14 +160,17 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
* Gets the {@link ParameterDefinition} of the given name, if any.
*/
public ParameterDefinition getParameterDefinition(String name) {
- for (ParameterDefinition pd : parameterDefinitions)
- if (pd.getName().equals(name))
+ for (ParameterDefinition pd : parameterDefinitions) {
+ if (pd.getName().equals(name)) {
return pd;
+ }
+ }
return null;
}
@Extension
public static class DescriptorImpl extends JobPropertyDescriptor {
+
@Override
public boolean isApplicable(Class<? extends Job> jobType) {
return AbstractProject.class.isAssignableFrom(jobType);
@@ -173,7 +178,7 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
@Override
public JobProperty<?> newInstance(StaplerRequest req,
- JSONObject formData) throws FormException {
+ JSONObject formData) throws FormException {
if (formData.isNullObject()) {
return null;
}
@@ -181,16 +186,22 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
JSONObject parameterized = formData.getJSONObject("parameterized");
if (parameterized.isNullObject()) {
- return null;
+ return null;
}
List<ParameterDefinition> parameterDefinitions = Descriptor.newInstancesFromHeteroList(
req, parameterized, "parameter", ParameterDefinition.all());
- if(parameterDefinitions.isEmpty())
+ if (parameterDefinitions.isEmpty()) {
return null;
+ }
return new ParametersDefinitionProperty(parameterDefinitions);
}
+
+ @Override
+ public boolean isCascadable() {
+ return false;
+ }
@Override
public String getDisplayName() {
@@ -221,7 +232,7 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
ParametersDefinitionProperty that = (ParametersDefinitionProperty) o;
if (parameterDefinitions != null ? !this.parameterDefinitions.equals(that.parameterDefinitions)
- : that.parameterDefinitions != null) {
+ : that.parameterDefinitions != null) {
return false;
}
diff --git a/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java b/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java
deleted file mode 100644
index 7af879c3..00000000
--- a/hudson-core/src/main/java/hudson/security/AbstractPasswordBasedSecurityRealm.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2011, Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- * Nikita Levyankov
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import groovy.lang.Binding;
-import hudson.EnvVars;
-import hudson.FilePath;
-import hudson.cli.CLICommand;
-import hudson.model.Hudson;
-import hudson.remoting.Callable;
-import hudson.tasks.MailAddressResolver;
-import hudson.util.spring.BeanBuilder;
-import java.io.Console;
-import java.io.IOException;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.AuthenticationManager;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider;
-import org.springframework.security.userdetails.UserDetails;
-import org.springframework.security.userdetails.UserDetailsService;
-import org.springframework.security.userdetails.UsernameNotFoundException;
-import org.kohsuke.args4j.Option;
-import org.springframework.dao.DataAccessException;
-import org.springframework.web.context.WebApplicationContext;
-
-/**
- * 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/>
- * <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() {
- Binding binding = new Binding();
- binding.setVariable("authenticator", new Authenticator());
-
- BeanBuilder builder = new BeanBuilder();
- builder.parse(Hudson.getInstance()
- .servletContext
- .getResourceAsStream("/WEB-INF/security/AbstractPasswordBasedSecurityRealm.groovy"), binding);
- WebApplicationContext context = builder.createApplicationContext();
- return new SecurityComponents(
- findBean(AuthenticationManager.class, context), this);
- }
-
- @Override
- public CliAuthenticator createCliAuthenticator(final CLICommand command) {
- 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.")
- public String password;
-
- @Option(name = "--password-file", usage = "File that contains the password")
- public String passwordFile;
-
- public Authentication authenticate() throws AuthenticationException, IOException, InterruptedException {
- if (userName == null) {
- return Hudson.ANONYMOUS; // no authentication parameter. run as anonymous
- }
-
- if (passwordFile != null) {
- try {
- password = new FilePath(command.channel, passwordFile).readToString().trim();
- } catch (IOException e) {
- throw new BadCredentialsException("Failed to read " + passwordFile, e);
- }
- }
- if (password == null) {
- password = command.channel.call(new InteractivelyAskForPassword());
- }
-
- if (password == null) {
- throw new BadCredentialsException("No password specified");
- }
-
- UserDetails d = AbstractPasswordBasedSecurityRealm.this.doAuthenticate(userName, password);
- return new UsernamePasswordAuthenticationToken(d, password, d.getAuthorities());
- }
- };
- }
-
- /**
- * Authenticate a login attempt.
- * This method is the heart of a {@link AbstractPasswordBasedSecurityRealm}.
- * <p/>
- * <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/>
- * <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);
- EnvVars.setHudsonUserEnvVar(userDetails.getUsername());
- return userDetails;
- }
-
- /**
- * 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
- * a query like this, just always throw {@link UsernameNotFoundException}.
- */
- @Override
- public abstract UserDetails loadUserByUsername(String username)
- throws UsernameNotFoundException, DataAccessException;
-
- /**
- * Retrieves information about a group by its name.
- * <p/>
- * This method is the group version of the {@link #loadUserByUsername(String)}.
- */
- @Override
- public abstract GroupDetails loadGroupByGroupname(String groupname)
- throws UsernameNotFoundException, DataAccessException;
-
- class Authenticator extends AbstractUserDetailsAuthenticationProvider {
- protected void additionalAuthenticationChecks(UserDetails userDetails,
- UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- // authentication is assumed to be done already in the retrieveUser method
- }
-
- protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- return AbstractPasswordBasedSecurityRealm.this.doAuthenticate(username,
- authentication.getCredentials().toString());
- }
- }
-
- /**
- * Asks for the password.
- */
- private static class InteractivelyAskForPassword implements Callable<String, IOException> {
- public String call() throws IOException {
- Console console = System.console();
- if (console == null) {
- return null; // no terminal
- }
-
- char[] w = console.readPassword("Password:");
- if (w == null) {
- return null;
- }
- return new String(w);
- }
-
- private static final long serialVersionUID = 1L;
- }
-}
diff --git a/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java b/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java
index 8b2dea88..d16fdcb1 100644
--- a/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java
+++ b/hudson-core/src/main/java/hudson/security/AuthorizationMatrixProperty.java
@@ -1,19 +1,20 @@
-/*******************************************************************************
+/**
+ * *****************************************************************************
*
* Copyright (c) 2004-2010 Oracle Corporation.
*
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
- * Kohsuke Kawaguchi, Yahoo! Inc., Peter Hayes, Tom Huybrechts
- *
+ * Kohsuke Kawaguchi, Yahoo! Inc., Peter Hayes, Tom Huybrechts
*
- *******************************************************************************/
-
+ *
+ ******************************************************************************
+ */
package hudson.security;
import hudson.diagnosis.OldDataMonitor;
@@ -52,95 +53,101 @@ import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import hudson.security.Permission;
+import hudson.security.PermissionGroup;
+import hudson.security.SidACL;
import javax.servlet.ServletException;
+import org.eclipse.hudson.plugins.security.GlobalMatrixAuthorizationStrategy;
+import org.eclipse.hudson.plugins.security.ProjectMatrixAuthorizationStrategy;
/**
* {@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;
}
- 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);
- }
+ /**
+ * 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);
+ }
/**
- * Returns all the (Permission,sid) pairs that are granted, in the multi-map form.
+ * Returns all the (Permission,sid) pairs that are granted, in the multi-map
+ * form.
*
- * @return
- * read-only. never null.
+ * @return read-only. never null.
*/
- public Map<Permission,Set<String>> getGrantedPermissions() {
+ 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()) {
String sid = r.getKey();
if (r.getValue() instanceof JSONObject) {
- for (Map.Entry<String, Boolean> e : (Set<Map.Entry<String, Boolean>>) ((JSONObject) r
- .getValue()).entrySet()) {
+ for (Map.Entry<String, Boolean> e : (Set<Map.Entry<String, Boolean>>) ((JSONObject) r.getValue()).entrySet()) {
if (e.getValue()) {
Permission p = Permission.fromId(e.getKey());
amp.add(p, sid);
@@ -148,26 +155,31 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> {
}
}
}
- return amp;
- }
+ return amp;
+ }
+
+ @Override
+ public boolean isCascadable() {
+ return false;
+ }
- @Override
- public boolean isApplicable(Class<? extends Job> jobType) {
+ @Override
+ public boolean isApplicable(Class<? extends Job> jobType) {
// only applicable when ProjectMatrixAuthorizationStrategy is in charge
return Hudson.getInstance().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 {
@@ -175,29 +187,32 @@ 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 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}.
@@ -206,7 +221,7 @@ public class AuthorizationMatrixProperty extends JobProperty<Job<?, ?>> {
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>
@@ -214,59 +229,60 @@ 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 83559dd6..44da9302 100644
--- a/hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java
+++ b/hudson-core/src/main/java/hudson/security/AuthorizationStrategy.java
@@ -60,6 +60,10 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth
* IOW, this ACL will have the ultimate say on the access control.
*/
public abstract ACL getRootACL();
+
+ public static int MODE_GLOBAL_MATRIX = 1;
+ public static int MODE_PROJECT_MATRIX = 2;
+ public static int MODE_STANDARD = 3;
/**
* @deprecated since 1.277
@@ -142,6 +146,14 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl<Auth
public ACL getACL(Node node) {
return getRootACL();
}
+
+ /**
+ * Return the type of this strategy.
+ * @return int mode
+ */
+ public int getMode(){
+ return MODE_STANDARD;
+ }
/**
* Returns the list of all group/role names used in this authorization strategy,
diff --git a/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java b/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java
deleted file mode 100644
index 1a11b580..00000000
--- a/hudson-core/src/main/java/hudson/security/BindAuthenticator2.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- * Kohsuke Kawaguchi, Winston Prakash
- *
- *
- *******************************************************************************/
-package hudson.security;
-
-import org.springframework.security.ldap.SpringSecurityContextSource;
-
-import java.util.logging.Logger;
-import java.util.logging.Level;
-import org.springframework.ldap.core.DirContextOperations;
-import org.springframework.security.Authentication;
-import org.springframework.security.providers.ldap.authenticator.BindAuthenticator;
-
-/**
- * {@link BindAuthenticator} with improved diagnostics.
- *
- */
-public class BindAuthenticator2 extends BindAuthenticator {
- /**
- * 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;
- }
-
-
- @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);
- 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/DeferredCreationLdapAuthoritiesPopulator.java b/hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java
deleted file mode 100644
index 55a114f1..00000000
--- a/hudson-core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
-*
-* Kohsuke Kawaguchi
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import org.springframework.security.GrantedAuthority;
-import org.springframework.ldap.core.ContextSource;
-import org.springframework.security.ldap.LdapAuthoritiesPopulator;
-import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
-import hudson.security.SecurityRealm.SecurityComponents;
-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.
- */
-public class DeferredCreationLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
-
- /**
- * 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.
- */
- public DeferredCreationLdapAuthoritiesPopulator(
- ContextSource contextSource, String groupSearchBase) {
- this.contextSource = contextSource;
- this.setGroupSearchBase(groupSearchBase);
- }
-
- public GrantedAuthority[] getGrantedAuthorities(DirContextOperations user, String username) {
- return create().getGrantedAuthorities(user, username);
- }
-
- public void setConvertToUpperCase(boolean convertToUpperCase) {
- this.convertToUpperCase = convertToUpperCase;
- }
-
- public void setDefaultRole(String defaultRole) {
- this.defaultRole = defaultRole;
- }
-
- public void setGroupRoleAttribute(String groupRoleAttribute) {
- this.groupRoleAttribute = groupRoleAttribute;
- }
-
- public void setGroupSearchBase(String groupSearchBase) {
- this.groupSearchBase = groupSearchBase;
- }
-
- public void setGroupSearchFilter(String groupSearchFilter) {
- this.groupSearchFilter = groupSearchFilter;
- }
-
- public void setRolePrefix(String rolePrefix) {
- this.rolePrefix = rolePrefix;
- }
-
- public void setSearchSubtree(boolean searchSubtree) {
- this.searchSubtree = searchSubtree;
- }
-
- /**
- * Create a new DefaultLdapAuthoritiesPopulator object.
- *
- * @return a DefaultLdapAuthoritiesPopulator.
- */
- private DefaultLdapAuthoritiesPopulator create() {
- DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator(
- contextSource, groupSearchBase);
- populator.setConvertToUpperCase(convertToUpperCase);
- if (defaultRole != null) {
- populator.setDefaultRole(defaultRole);
- }
- populator.setGroupRoleAttribute(groupRoleAttribute);
- populator.setGroupSearchFilter(groupSearchFilter);
- populator.setRolePrefix(rolePrefix);
- populator.setSearchSubtree(searchSubtree);
- return populator;
- }
-}
diff --git a/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java
deleted file mode 100644
index 501ea410..00000000
--- a/hudson-core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
-*
-* Kohsuke Kawaguchi, Seiji Sogabe
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import hudson.model.Descriptor;
-import hudson.model.Hudson;
-import hudson.Extension;
-
-import java.util.Collections;
-import java.util.List;
-
-import net.sf.json.JSONObject;
-
-import org.kohsuke.stapler.StaplerRequest;
-
-/**
- * {@link AuthorizationStrategy} that grants full-control to authenticated user
- * (other than anonymous users.)
- *
- * @author Kohsuke Kawaguchi
- */
-public class FullControlOnceLoggedInAuthorizationStrategy extends AuthorizationStrategy {
- @Override
- public ACL getRootACL() {
- return THE_ACL;
- }
-
- 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);
- }
-
- @Extension
- public static final Descriptor<AuthorizationStrategy> DESCRIPTOR = new Descriptor<AuthorizationStrategy>() {
- public String getDisplayName() {
- return Messages.FullControlOnceLoggedInAuthorizationStrategy_DisplayName();
- }
-
- @Override
- public AuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException {
- return new FullControlOnceLoggedInAuthorizationStrategy();
- }
-
- @Override
- public String getHelpFile() {
- return "/help/security/full-control-once-logged-in.html";
- }
- };
-}
diff --git a/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java
deleted file mode 100644
index f4f9cf48..00000000
--- a/hudson-core/src/main/java/hudson/security/GlobalMatrixAuthorizationStrategy.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2010 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- * Kohsuke Kawaguchi, Yahoo! Inc.
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import com.thoughtworks.xstream.converters.Converter;
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import hudson.diagnosis.OldDataMonitor;
-import hudson.model.Descriptor;
-import hudson.model.Hudson;
-import hudson.model.Item;
-import hudson.util.FormValidation;
-import hudson.util.FormValidation.Kind;
-import hudson.util.VersionNumber;
-import hudson.util.RobustReflectionConverter;
-import hudson.Functions;
-import hudson.Extension;
-import net.sf.json.JSONObject;
-import org.springframework.security.userdetails.UsernameNotFoundException;
-import org.springframework.security.acls.sid.Sid;
-import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.QueryParameter;
-import org.springframework.dao.DataAccessException;
-
-import javax.servlet.ServletException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-/**
- * Role-based authorization via a matrix.
- *
- * @author Kohsuke Kawaguchi
- */
-// TODO: think about the concurrency commitment of this class
-public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy {
- 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 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.
- */
- public void add(Permission p, String sid) {
- if (p==null)
- throw new IllegalArgumentException();
- Set<String> set = grantedPermissions.get(p);
- if(set==null)
- grantedPermissions.put(p,set = new HashSet<String>());
- set.add(sid);
- sids.add(sid);
- }
-
- /**
- * Works like {@link #add(Permission, String)} but takes both parameters
- * from a single string of the form <tt>PERMISSIONID:sid</tt>
- */
- 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");
- add(p,shortForm.substring(idx+1));
- }
-
- @Override
- public SidACL getRootACL() {
- return acl;
- }
-
- public Set<String> getGroups() {
- return sids;
- }
-
- /**
- * 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) {
- boolean result = false;
- if(Hudson.getInstance().isUpgradedFromBefore(new VersionNumber("1.300.*"))) {
- Set<String> f = grantedPermissions.get(Hudson.READ);
- if (f!=null) {
- Set<String> t = grantedPermissions.get(Item.READ);
- if (t!=null)
- result = t.addAll(f);
- else {
- t = new HashSet<String>(f);
- result = true;
- }
- grantedPermissions.put(Item.READ,t);
- }
- }
- return result;
- }
-
- /**
- * 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) && p.getEnabled())
- 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) && p.getEnabled();
- }
-
- /**
- * 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);
- }
-
- private final class AclImpl extends SidACL {
- protected Boolean hasPermission(Sid p, Permission permission) {
- if(GlobalMatrixAuthorizationStrategy.this.hasPermission(toString(p),permission))
- return true;
- return null;
- }
- }
-
- @Extension
- public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
-
- /**
- * Persist {@link GlobalMatrixAuthorizationStrategy} as a list of IDs that
- * represent {@link GlobalMatrixAuthorizationStrategy#grantedPermissions}.
- */
- public static class ConverterImpl implements Converter {
- public boolean canConvert(Class type) {
- return type==GlobalMatrixAuthorizationStrategy.class;
- }
-
- public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
- GlobalMatrixAuthorizationStrategy strategy = (GlobalMatrixAuthorizationStrategy)source;
-
- // Output in alphabetical order for readability.
- SortedMap<Permission, Set<String>> sortedPermissions = new TreeMap<Permission, Set<String>>(Permission.ID_COMPARATOR);
- sortedPermissions.putAll(strategy.grantedPermissions);
- for (Entry<Permission, Set<String>> e : sortedPermissions.entrySet()) {
- String p = e.getKey().getId();
- List<String> sids = new ArrayList<String>(e.getValue());
- Collections.sort(sids);
- for (String sid : sids) {
- writer.startNode("permission");
- writer.setValue(p+':'+sid);
- writer.endNode();
- }
- }
-
- }
-
- public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingContext context) {
- GlobalMatrixAuthorizationStrategy as = create();
-
- while (reader.hasMoreChildren()) {
- reader.moveDown();
- try {
- as.add(reader.getValue());
- } catch (IllegalArgumentException ex) {
- Logger.getLogger(GlobalMatrixAuthorizationStrategy.class.getName())
- .log(Level.WARNING,"Skipping a non-existent permission",ex);
- RobustReflectionConverter.addErrorInContext(context, ex);
- }
- reader.moveUp();
- }
-
- if (migrateHudson2324(as.grantedPermissions))
- OldDataMonitor.report(context, "1.301");
-
- return as;
- }
-
- protected GlobalMatrixAuthorizationStrategy create() {
- return new GlobalMatrixAuthorizationStrategy();
- }
- }
-
- public static class DescriptorImpl extends Descriptor<AuthorizationStrategy> {
- protected DescriptorImpl(Class<? extends GlobalMatrixAuthorizationStrategy> clazz) {
- super(clazz);
- }
-
- public DescriptorImpl() {
- }
-
- public String getDisplayName() {
- return Messages.GlobalMatrixAuthorizationStrategy_DisplayName();
- }
-
- @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()) {
- String sid = r.getKey();
- 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);
- }
- }
- }
- return gmas;
- }
-
- protected GlobalMatrixAuthorizationStrategy create() {
- return new GlobalMatrixAuthorizationStrategy();
- }
-
- public List<PermissionGroup> getAllGroups() {
- List<PermissionGroup> groups = new ArrayList<PermissionGroup>(PermissionGroup.getAll());
- groups.remove(PermissionGroup.get(Permission.class));
- return groups;
- }
-
- public boolean showPermission(Permission p) {
- return p.getEnabled();
- }
-
- 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);
- SecurityRealm sr = Hudson.getInstance().getSecurityRealm();
- String ev = Functions.escape(v);
-
- 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);
- } catch (UserMayOrMayNotExistException e) {
- // undecidable, meaning the user may exist
- return FormValidation.respond(Kind.OK, ev);
- } catch (UsernameNotFoundException e) {
- // fall through next
- } catch (DataAccessException e) {
- // fall through next
- }
-
- try {
- sr.loadGroupByGroupname(v);
- return FormValidation.respond(Kind.OK, makeImg("user.png") +ev);
- } catch (UserMayOrMayNotExistException e) {
- // undecidable, meaning the group may exist
- return FormValidation.respond(Kind.OK, ev);
- } catch (UsernameNotFoundException e) {
- // fall through next
- } catch (DataAccessException e) {
- // fall through next
- }
-
- // couldn't find it. it doesn't exist
- return FormValidation.respond(Kind.ERROR, makeImg("error.png") +ev);
- }
-
- private String makeImg(String png) {
- return String.format("<img src='%s%s/images/16x16/%s' style='margin-right:0.2em'>", Stapler.getCurrentRequest().getContextPath(), Hudson.RESOURCE_PATH, png);
- }
- }
-}
-
diff --git a/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
deleted file mode 100644
index e100b6ae..00000000
--- a/hudson-core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
+++ /dev/null
@@ -1,706 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2011 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- * Kohsuke Kawaguchi, David Calavera, Seiji Sogabe, Anton Kozak
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import hudson.mail.BaseMailSender;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import hudson.Extension;
-import hudson.Util;
-import hudson.diagnosis.OldDataMonitor;
-import hudson.model.*;
-import hudson.security.FederatedLoginService.FederatedIdentity;
-import hudson.security.captcha.CaptchaSupport;
-import hudson.tasks.Mailer;
-import hudson.util.PluginServletFilter;
-import hudson.util.Protector;
-import hudson.util.Scrambler;
-import hudson.util.XStream2;
-import net.sf.json.JSONObject;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.providers.encoding.PasswordEncoder;
-import org.springframework.security.providers.encoding.ShaPasswordEncoder;
-import org.springframework.security.userdetails.UserDetails;
-import org.springframework.security.userdetails.UsernameNotFoundException;
-import org.kohsuke.stapler.*;
-import org.springframework.dao.DataAccessException;
-
-import javax.servlet.*;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
-
-/**
- * {@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.
- *
- * @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.
- */
- private final boolean disableSignup;
-
- /**
- * If true, captcha will be enabled.
- */
- private final boolean enableCaptcha;
-
- /**
- * If true, user will be notified of Hudson account creation.
- */
- private final boolean notifyUser;
-
- /**
- * @deprecated as of 2.0.1
- */
- @Deprecated
- public HudsonPrivateSecurityRealm(boolean allowsSignup) {
- this(allowsSignup, true);
- }
-
- /**
- * @deprecated as of 2.2.0
- */
- @Deprecated
- public HudsonPrivateSecurityRealm(boolean allowsSignup, boolean enableCaptcha) {
- this(allowsSignup, true, null, false);
- }
-
- @DataBoundConstructor
- 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 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 {
- PluginServletFilter.addFilter(CREATE_FIRST_USER_FILTER);
- } catch (ServletException e) {
- throw new AssertionError(e); // never happen because our Filter.init is no-op
- }
- }
- }
-
- @Override
- public boolean allowsSignup() {
- return !disableSignup;
- }
-
- /**
- * Checks if captcha is enabled on signup.
- *
- * @return true if captcha is enabled on signup.
- */
- public boolean isEnableCaptcha() {
- return enableCaptcha;
- }
-
- /**
- * Returns true if Hudson should notify user of account creation.
- *
- * @return true if Hudson should notify user of account creation.
- */
- public boolean isNotifyUser() {
- return notifyUser;
- }
-
- /**
- * Computes if this Hudson has some user accounts configured.
- *
- * <p>
- * This is used to check for the initial
- */
- private static boolean hasSomeUser() {
- for (User u : User.getAll())
- if(u.getProperty(Details.class)!=null)
- return true;
- return false;
- }
-
- /**
- * This implementation doesn't support groups.
- */
- @Override
- public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException {
- throw new UsernameNotFoundException(groupname);
- }
-
- @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)
- 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);
- return u;
- }
-
- /**
- * Show the sign up page with the data from the identity.
- */
- @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") {
- @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());
- req.setAttribute("data", si);
- super.generateResponse(req, rsp, node);
- }
- };
- }
-
- /**
- * 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);
- return u;
- }
-
- private static final String FEDERATED_IDENTITY_SESSION_KEY = HudsonPrivateSecurityRealm.class.getName()+".federatedIdentity";
-
- /**
- * Creates an user account. Used for self-registration.
- */
- public User doCreateAccount(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- return _doCreateAccount(req, rsp, "signup.jelly");
- }
-
- 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"));
-
- boolean firstUser = !hasSomeUser();
- User u = createAccount(req, rsp, enableCaptcha, formView);
- 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.
- */
- 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"));
- a = this.getSecurityComponents().manager.authenticate(a);
- SecurityContextHolder.getContext().setAuthentication(a);
-
- // then back to top
- 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.
- */
- public void doCreateAccountByAdmin(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- checkPermission(Hudson.ADMINISTER);
- if(createAccount(req, rsp, false, "addUser.jelly")!=null) {
- rsp.sendRedirect("."); // send the user back to the listing page
- }
- }
-
- /**
- * Creates a first admin 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");
- return;
- }
- User u = createAccount(req, rsp, false, "firstUser.jelly");
- if (u!=null) {
- tryToMakeAdmin(u);
- loginAndTakeBack(req, rsp, u);
- }
- }
-
- /**
- * Try to make this user a super-user
- */
- private void tryToMakeAdmin(User u) {
- AuthorizationStrategy as = Hudson.getInstance().getAuthorizationStrategy();
- if (as instanceof GlobalMatrixAuthorizationStrategy) {
- GlobalMatrixAuthorizationStrategy ma = (GlobalMatrixAuthorizationStrategy) as;
- ma.add(Hudson.ADMINISTER, u.getId());
- }
- }
-
- /**
- * @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))
- si.errorMessage = "Text didn't match the word shown in the image";
-
- if(si.password1 != null && !si.password1.equals(si.password2))
- si.errorMessage = "Password didn't match";
-
- 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) {
- 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)
- si.fullname = si.username;
-
- if(si.email==null || !si.email.contains("@"))
- si.errorMessage = "Invalid e-mail address";
-
- if(si.errorMessage!=null) {
- // failed. ask the user to try again.
- req.setAttribute("data",si);
- req.getView(this, formView).forward(req,rsp);
- return null;
- }
-
- // register the user
- final User user = createAccount(si.username,si.password1);
- user.addProperty(new Mailer.UserProperty(si.email));
- user.setFullName(si.fullname);
- user.save();
- if (notifyUser && StringUtils.isNotEmpty(si.email)) {
- notifyUser(si.username, si.email, si.fullname, si.password1);
- }
- return user;
- }
-
- private void notifyUser(final String username, final String email, final String fullname, final String passwd) {
- new BaseMailSender(email) {
- @Override
- protected String getText() {
- String baseUrl = Mailer.descriptor().getUrl();
- return hudson.mail.Messages
- .account_creation_email_text(fullname != null ? fullname : "", baseUrl, email, username,
- passwd);
- }
-
- @Override
- protected String getSubject() {
- return hudson.mail.Messages.account_creation_email_subject();
- }
- }.execute();
- }
-
- /**
- * Creates a new user account by registering a password to the user.
- */
- public User createAccount(String userName, String password) throws IOException {
- User user = User.get(userName);
- user.addProperty(Details.fromPlainPassword(password));
- return user;
- }
-
- /**
- * This is used primarily when the object is listed in the breadcrumb, in the user management screen.
- */
- public String getDisplayName() {
- return "User Database";
- }
-
- public ACL getACL() {
- return Hudson.getInstance().getACL();
- }
-
- public void checkPermission(Permission permission) {
- Hudson.getInstance().checkPermission(permission);
- }
-
- public boolean hasPermission(Permission permission) {
- return Hudson.getInstance().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)
- 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.
- */
- 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;
-
- /**
- * To display an error message, set it here.
- */
- public String errorMessage;
-
- public SignupInfo() {
- }
-
- public SignupInfo(StaplerRequest req) {
- req.bindParameters(this);
- }
-
- public SignupInfo(FederatedIdentity i) {
- this.username = i.getNickname();
- this.fullname = i.getFullName();
- this.email = i.getEmailAddress();
- }
- public String getUsername() {
- return username;
- }
-
- public String getPassword1() {
- return password1;
- }
-
- public String getPassword2() {
- return password2;
- }
-
- public String getFullname() {
- return fullname;
- }
-
- public String getEmail() {
- return email;
- }
-
- public String getCaptcha() {
- return captcha;
- }
-
- public String getErrorMessage() {
- return errorMessage;
- }
- }
-
- /**
- * {@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 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.
- */
- private transient String password;
-
- private Details(String passwordHash) {
- this.passwordHash = passwordHash;
- }
-
- static Details fromHashedPassword(String hashed) {
- return new Details(hashed);
- }
-
- static Details fromPlainPassword(String rawPassword) {
- return new Details(PASSWORD_ENCODER.encodePassword(rawPassword,null));
- }
-
- public GrantedAuthority[] getAuthorities() {
- // TODO
- return TEST_AUTHORITY;
- }
-
- public String getPassword() {
- return passwordHash;
- }
-
- public String getProtectedPassword() {
- // put session Id in it to prevent a replay attack.
- return Protector.protect(Stapler.getCurrentRequest().getSession().getId()+':'+getPassword());
- }
-
- public String getUsername() {
- return user.getId();
- }
-
- /*package*/ User getUser() {
- return user;
- }
-
- public boolean isAccountNonExpired() {
- return true;
- }
-
- public boolean isAccountNonLocked() {
- return true;
- }
-
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
- public boolean isEnabled() {
- return true;
- }
-
- public boolean isInvalid() {
- 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) {
- // 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);
- OldDataMonitor.report(context, "1.283");
- }
- }
- }
-
- @Extension
- public static final class DescriptorImpl extends UserPropertyDescriptor {
- public String getDisplayName() {
- // this feature is only when HudsonPrivateSecurityRealm is enabled
- if(isEnabled())
- return Messages.HudsonPrivateSecurityRealm_Details_DisplayName();
- 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"));
-
- 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) {
- String prefix = Stapler.getCurrentRequest().getSession().getId() + ':';
- if(data.startsWith(prefix))
- return Details.fromHashedPassword(data.substring(prefix.length()));
- }
- return Details.fromPlainPassword(Util.fixNull(pwd));
- }
-
- @Override
- public boolean isEnabled() {
- return Hudson.getInstance().getSecurityRealm() instanceof HudsonPrivateSecurityRealm;
- }
-
- public UserProperty newInstance(User user) {
- return null;
- }
- }
- }
-
- /**
- * 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(Hudson.getInstance().getSecurityRealm() instanceof HudsonPrivateSecurityRealm)
- return "user.png";
- else
- return null; // not applicable now
- }
-
- public String getUrlName() {
- return "securityRealm/";
- }
-
- public String getDisplayName() {
- return Messages.HudsonPrivateSecurityRealm_ManageUserLinks_DisplayName();
- }
-
- @Override
- public String getDescription() {
- 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>
- * 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);
-
- public String encodePassword(String rawPass, Object _) throws DataAccessException {
- return hash(rawPass);
- }
-
- 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));
- }
-
- /**
- * Creates a hashed password by generating a random salt.
- */
- private String hash(String password) {
- String salt = generateSalt();
- return salt+':'+passwordEncoder.encodePassword(password,salt);
- }
-
- /**
- * Generates random salt.
- */
- 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.
- boolean upper = sr.nextBoolean();
- char ch = (char)(sr.nextInt(26) + 'a');
- if(upper) ch=Character.toUpperCase(ch);
- buf.append(ch);
- }
- return buf.toString();
- }
- };
-
- @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";
- }
- }
-
- private static final Filter CREATE_FIRST_USER_FILTER = new Filter() {
- public void init(FilterConfig config) throws ServletException {
- }
-
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest req = (HttpServletRequest) request;
-
- if(req.getRequestURI().equals(req.getContextPath()+"/")) {
- if (needsToCreateFirstUser()) {
- ((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);
- }
- } else
- chain.doFilter(request,response);
- }
-
- private boolean needsToCreateFirstUser() {
- return !hasSomeUser()
- && Hudson.getInstance().getSecurityRealm() instanceof HudsonPrivateSecurityRealm;
- }
-
- public void destroy() {
- }
- };
-}
diff --git a/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java b/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java
deleted file mode 100644
index 2634f2ba..00000000
--- a/hudson-core/src/main/java/hudson/security/LDAPSecurityRealm.java
+++ /dev/null
@@ -1,568 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2010 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- * Kohsuke Kawaguchi, Seiji Sogabe
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import groovy.lang.Binding;
-import hudson.Extension;
-import static hudson.Util.fixNull;
-import static hudson.Util.fixEmptyAndTrim;
-import static hudson.Util.fixEmpty;
-import hudson.model.Descriptor;
-import hudson.model.Hudson;
-import hudson.model.User;
-import hudson.tasks.MailAddressResolver;
-import hudson.util.FormValidation;
-import hudson.util.Scrambler;
-import hudson.util.spring.BeanBuilder;
-import org.springframework.security.AuthenticationManager;
-import org.springframework.security.SpringSecurityException;
-import org.springframework.security.AuthenticationException;
-import org.springframework.ldap.core.ContextSource;
-import org.springframework.security.ldap.LdapUserSearch;
-import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.ldap.SpringSecurityLdapTemplate;
-import org.springframework.security.ldap.LdapAuthoritiesPopulator;
-import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
-import org.springframework.security.userdetails.UserDetails;
-import org.springframework.security.userdetails.UserDetailsService;
-import org.springframework.security.userdetails.UsernameNotFoundException;
-import org.springframework.security.userdetails.ldap.LdapUserDetails;
-import org.apache.commons.lang3.StringUtils;
-import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.QueryParameter;
-import org.springframework.dao.DataAccessException;
-import org.springframework.web.context.WebApplicationContext;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.springframework.ldap.core.DirContextOperations;
-import org.springframework.security.userdetails.ldap.LdapUserDetailsService;
-
-
-/**
- * {@link SecurityRealm} implementation that uses LDAP for authentication.
- *
- *
- * <h2>Key Object Classes</h2>
- *
- * <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.
- * <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 ) )
- * </pre>
- *
- * <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 )
- * </pre>
- *
- * <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 ) )
- * </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.
- *
- * <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>
- *
- * @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.
- *
- * 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.
- *
- * 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"
- *
- * @see FilterBasedLdapUserSearch
- */
- public final String groupSearchBase;
-
- /*
- 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)
-
- 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
- */
-
- /**
- * 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.
- */
- private transient SpringSecurityLdapTemplate ldapTemplate;
-
- @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));
- this.rootDN = rootDN.trim();
- this.userSearchBase = fixNull(userSearchBase).trim();
- userSearch = fixEmptyAndTrim(userSearch);
- this.userSearch = userSearch!=null ? userSearch : "uid={0}";
- this.groupSearchBase = fixEmptyAndTrim(groupSearchBase);
- }
-
- public String getServerUrl() {
- return addPrefix(server);
- }
-
- /**
- * Infer the root DN.
- *
- * @return null if not found.
- */
- 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());
- }
- props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
- 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
- return a.toString();
-
- a = atts.get("namingcontexts");
- 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);
- return null;
- }
- }
-
- public String getManagerPassword() {
- return Scrambler.descramble(managerPassword);
- }
-
- public String getLDAPURL() {
- return getServerUrl()+'/'+ fixNull(rootDN);
- }
-
- public SecurityComponents createSecurityComponents() {
- Binding binding = new Binding();
- binding.setVariable("instance", this);
-
- BeanBuilder builder = new BeanBuilder();
- builder.parse(Hudson.getInstance().servletContext.getResourceAsStream("/WEB-INF/security/LDAPBindSecurityRealm.groovy"),binding);
- WebApplicationContext appContext = builder.createApplicationContext();
-
- ldapTemplate = new SpringSecurityLdapTemplate(findBean(ContextSource.class, appContext));
-
- return new SecurityComponents(
- findBean(AuthenticationManager.class, appContext),
- new LDAPUserDetailsService(appContext));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected UserDetails authenticate(String username, String password) throws AuthenticationException {
- return (UserDetails) getSecurityComponents().manager.authenticate(
- new UsernamePasswordAuthenticationToken(username, password)).getPrincipal();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
- return getSecurityComponents().userDetails.loadUserByUsername(username);
- }
-
- /**
- * Lookup a group; given input must match the configured syntax for group names
- * in WEB-INF/security/LDAPBindSecurityRealm.groovy's 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 {
- // Check proper syntax based on Spring Security configuration
- String prefix = "";
- boolean onlyUpperCase = false;
- try {
- AuthoritiesPopulatorImpl api = (AuthoritiesPopulatorImpl)
- ((LDAPUserDetailsService)getSecurityComponents().userDetails).authoritiesPopulator;
- prefix = api.rolePrefix;
- onlyUpperCase = api.convertToUpperCase;
- } catch (Exception ignore) { }
- if (onlyUpperCase && !groupname.equals(groupname.toUpperCase()))
- throw new UsernameNotFoundException(groupname + " should be all uppercase");
- 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,
- new String[]{groupname}, "cn");
-
- if(groups.isEmpty())
- throw new UsernameNotFoundException(groupname);
-
- return new GroupDetails() {
- public String getName() {
- return groups.iterator().next();
- }
- };
- }
-
- public static class LDAPUserDetailsService implements UserDetailsService {
- private final LdapUserSearch ldapSearch;
- private final LdapAuthoritiesPopulator authoritiesPopulator;
-
- LDAPUserDetailsService(WebApplicationContext appContext) {
- ldapSearch = findBean(LdapUserSearch.class, appContext);
- authoritiesPopulator = findBean(LdapAuthoritiesPopulator.class, appContext);
- }
-
- LDAPUserDetailsService(LdapUserSearch ldapSearch, LdapAuthoritiesPopulator authoritiesPopulator) {
- this.ldapSearch = ldapSearch;
- this.authoritiesPopulator = authoritiesPopulator;
- }
-
- public LdapUserSearch getLdapSearch() {
- return ldapSearch;
- }
-
- public LdapAuthoritiesPopulator getAuthoritiesPopulator() {
- return authoritiesPopulator;
- }
-
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
- LdapUserDetailsService ldapUserDetailsService = new LdapUserDetailsService(ldapSearch, authoritiesPopulator);
- return ldapUserDetailsService.loadUserByUsername(username);
- }
- }
-
- /**
- * If the security realm is LDAP, try to pick up e-mail address from LDAP.
- */
- @Extension
- public static final class MailAdressResolverImpl extends MailAddressResolver {
- public String findMailAddressFor(User u) {
- // LDAP not active
- SecurityRealm realm = Hudson.getInstance().getSecurityRealm();
- if(!(realm instanceof LDAPSecurityRealm))
- return null;
- try {
- 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();
- } catch (UsernameNotFoundException 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);
- return null;
- } catch (NamingException 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);
- return null;
- }
- }
- }
-
- /**
- * {@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:
- setRolePrefix("ROLE_");
- setConvertToUpperCase(true);
- }
-
- @Override
- protected Set getAdditionalRoles(DirContextOperations ldapUser, String username) {
- return Collections.singleton(AUTHENTICATED_AUTHORITY);
- }
-
- @Override
- public void setRolePrefix(String rolePrefix) {
- super.setRolePrefix(rolePrefix);
- this.rolePrefix = rolePrefix;
- }
-
- @Override
- public void setConvertToUpperCase(boolean convertToUpperCase) {
- super.setConvertToUpperCase(convertToUpperCase);
- this.convertToUpperCase = convertToUpperCase;
- }
- }
-
- @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) {
-
- if(!Hudson.getInstance().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);
- }
- 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)+'/');
-
- DirContext ctx = new InitialDirContext(props);
- ctx.getAttributes("");
- return FormValidation.ok(); // connected
- } catch (NamingException e) {
- // trouble-shoot
- Matcher m = Pattern.compile("(ldaps://)?([^:]+)(?:\\:(\\d+))?").matcher(server.trim());
- 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)
- port = Integer.parseInt(m.group(3));
- 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()));
- }
-
- // 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));
- } catch (NumberFormatException x) {
- // The getLdapCtxInstance method throws this if it fails to parse the port number
- return FormValidation.error(Messages.LDAPSecurityRealm_InvalidPortNumber());
- }
- }
- }
-
- /**
- * 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;
- }
-
- 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.
- */
- 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
deleted file mode 100644
index f85e3fb7..00000000
--- a/hudson-core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
-*
-* Kohsuke Kawaguchi
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import hudson.RestrictedSince;
-
-/**
- * {@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
-@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
deleted file mode 100644
index 512873ec..00000000
--- a/hudson-core/src/main/java/hudson/security/LegacySecurityRealm.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
-*
-* Kohsuke Kawaguchi, Seiji Sogabe
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import org.springframework.security.AuthenticationManager;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.web.context.WebApplicationContext;
-import org.kohsuke.stapler.StaplerRequest;
-import groovy.lang.Binding;
-import hudson.model.Descriptor;
-import hudson.util.spring.BeanBuilder;
-import hudson.Extension;
-import net.sf.json.JSONObject;
-
-import javax.servlet.Filter;
-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.)
- *
- * @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)
- return authentication;
- else
- return null;
- }
-
- /**
- * To have the username/password authenticated by the container,
- * submit the form to the URL defined by the servlet spec.
- */
- @Override
- public String getAuthenticationGatewayUrl() {
- return "j_security_check";
- }
-
- @Override
- public String getLoginUrl() {
- return "loginEntry";
- }
-
- /**
- * Filter to run for the LegacySecurityRealm is the
- * ChainServletFilter legacy from /WEB-INF/security/SecurityFilters.groovy.
- */
- @Override
- public Filter createFilter(FilterConfig filterConfig) {
- Binding binding = new Binding();
- SecurityComponents sc = this.createSecurityComponents();
- binding.setVariable("securityComponents", sc);
- binding.setVariable("securityRealm",this);
- BeanBuilder builder = new BeanBuilder();
- builder.parse(filterConfig.getServletContext().getResourceAsStream("/WEB-INF/security/SecurityFilters.groovy"),binding);
-
- WebApplicationContext context = builder.createApplicationContext();
-
- return (Filter) context.getBean("legacy");
- }
-
- @Extension
- public static final Descriptor<SecurityRealm> DESCRIPTOR = new Descriptor<SecurityRealm>() {
- public SecurityRealm newInstance(StaplerRequest req, JSONObject formData) throws FormException {
- return new LegacySecurityRealm();
- }
-
- public String getDisplayName() {
- return Messages.LegacySecurityRealm_Displayname();
- }
-
- public String getHelpFile() {
- return "/help/security/container-realm.html";
- }
- };
-}
diff --git a/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java b/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java
deleted file mode 100644
index 60d77338..00000000
--- a/hudson-core/src/main/java/hudson/security/PAMSecurityRealm.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009, Oracle Corporation
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- *
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import groovy.lang.Binding;
-import hudson.EnvVars;
-import hudson.Functions;
-import hudson.model.Descriptor;
-import hudson.model.Hudson;
-import hudson.Util;
-import hudson.Extension;
-import hudson.util.FormValidation;
-import hudson.util.jna.NativeAccessException;
-import hudson.util.jna.NativeUtils;
-import hudson.util.spring.BeanBuilder;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationException;
-import org.springframework.security.AuthenticationManager;
-import org.springframework.security.BadCredentialsException;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.providers.AuthenticationProvider;
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.userdetails.UsernameNotFoundException;
-import org.springframework.security.userdetails.UserDetailsService;
-import org.springframework.security.userdetails.UserDetails;
-import org.springframework.security.userdetails.User;
-import org.springframework.dao.DataAccessException;
-import org.springframework.web.context.WebApplicationContext;
-import org.kohsuke.stapler.DataBoundConstructor;
-
-import java.util.Set;
-
-/**
- * {@link SecurityRealm} that uses Unix PAM authentication.
- *
- * @author Kohsuke Kawaguchi
- * @since 1.282
- */
-public class PAMSecurityRealm extends SecurityRealm {
-
- public final String serviceName;
-
- @DataBoundConstructor
- public PAMSecurityRealm(String serviceName) {
- serviceName = Util.fixEmptyAndTrim(serviceName);
- if (serviceName == null) {
- serviceName = "sshd"; // use sshd as the default
- }
- this.serviceName = serviceName;
- }
-
- public static class PAMAuthenticationProvider implements AuthenticationProvider {
-
- private String serviceName;
-
- public PAMAuthenticationProvider(String serviceName) {
- this.serviceName = serviceName;
- }
-
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- String username = authentication.getPrincipal().toString();
- String password = authentication.getCredentials().toString();
-
- try {
-
- Set<String> grps = NativeUtils.getInstance().pamAuthenticate(serviceName, username, password);
- GrantedAuthority[] groups = new GrantedAuthority[grps.size()];
- int i = 0;
- for (String g : grps) {
- groups[i++] = new GrantedAuthorityImpl(g);
- }
- EnvVars.setHudsonUserEnvVar(username);
- // I never understood why Spring Security insists on keeping the password...
- return new UsernamePasswordAuthenticationToken(username, password, groups);
- } catch (NativeAccessException exc) {
- throw new BadCredentialsException(exc.getMessage(), exc);
- }
-
- }
-
- public boolean supports(Class clazz) {
- return true;
- }
- }
-
- public SecurityComponents createSecurityComponents() {
- Binding binding = new Binding();
- binding.setVariable("instance", this);
-
- BeanBuilder builder = new BeanBuilder();
- builder.parse(Hudson.getInstance().servletContext.getResourceAsStream("/WEB-INF/security/PAMSecurityRealm.groovy"), binding);
- WebApplicationContext context = builder.createApplicationContext();
- return new SecurityComponents(
- findBean(AuthenticationManager.class, context),
- new UserDetailsService() {
-
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
- try {
- if (!NativeUtils.getInstance().checkUnixUser(username)) {
- throw new UsernameNotFoundException("No such Unix user: " + username);
- }
- } catch (NativeAccessException exc) {
- throw new DataAccessException("Failed to find Unix User", exc) {
- };
- }
-
- // return some dummy instance
- return new User(username, "", true, true, true, true,
- new GrantedAuthority[]{AUTHENTICATED_AUTHORITY});
- }
- });
- }
-
- @Override
- public GroupDetails loadGroupByGroupname(final String groupname) throws UsernameNotFoundException, DataAccessException {
- try {
- if (!NativeUtils.getInstance().checkUnixGroup(groupname)) {
- throw new UsernameNotFoundException("No such Unix group: " + groupname);
- }
- } catch (NativeAccessException exc) {
- throw new DataAccessException("Failed to find Unix Group", exc) {
- };
- }
-
- return new GroupDetails() {
-
- @Override
- public String getName() {
- return groupname;
- }
- };
- }
-
- public static final class DescriptorImpl extends Descriptor<SecurityRealm> {
-
- public String getDisplayName() {
- return Messages.PAMSecurityRealm_DisplayName();
- }
-
- public FormValidation doTest() {
- try {
- String message = NativeUtils.getInstance().checkPamAuthentication();
- if (message.startsWith("Error:")) {
- return FormValidation.error(message.replaceFirst("Error:", ""));
- } else {
- return FormValidation.ok(message);
- }
- } catch (NativeAccessException exc) {
- return FormValidation.error("Native Support for PAM Authentication not available.");
- }
- }
- }
-
- @Extension
- public static DescriptorImpl install() {
- if (!Functions.isWindows()) {
- return new DescriptorImpl();
- }
- return null;
- }
-}
diff --git a/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java b/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java
deleted file mode 100644
index ddcac5d2..00000000
--- a/hudson-core/src/main/java/hudson/security/ProjectMatrixAuthorizationStrategy.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * 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
- *
- *
- *******************************************************************************/
-
-package hudson.security;
-
-import hudson.model.Descriptor;
-import hudson.model.Hudson;
-import hudson.model.Job;
-import hudson.util.RobustReflectionConverter;
-import hudson.Extension;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.mapper.Mapper;
-import com.thoughtworks.xstream.core.JVM;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * {@link GlobalMatrixAuthorizationStrategy} plus per-project ACL.
- *
- * <p>
- * Per-project ACL is stored in {@link AuthorizationMatrixProperty}.
- *
- * @author Kohsuke Kawaguchi
- */
-public class ProjectMatrixAuthorizationStrategy extends GlobalMatrixAuthorizationStrategy {
- @Override
- public ACL getACL(Job<?,?> project) {
- AuthorizationMatrixProperty amp = project.getProperty(AuthorizationMatrixProperty.class);
- if (amp != null) {
- return amp.getACL().newInheritingACL(getRootACL());
- } else {
- return getRootACL();
- }
- }
-
- @Override
- public Set<String> getGroups() {
- Set<String> r = new HashSet<String>();
- r.addAll(super.getGroups());
- for (Job<?,?> j : Hudson.getInstance().getItems(Job.class)) {
- AuthorizationMatrixProperty amp = j.getProperty(AuthorizationMatrixProperty.class);
- if (amp != null)
- r.addAll(amp.getGroups());
- }
- return r;
- }
-
- @Extension
- public static final Descriptor<AuthorizationStrategy> DESCRIPTOR = new DescriptorImpl() {
- @Override
- protected GlobalMatrixAuthorizationStrategy create() {
- return new ProjectMatrixAuthorizationStrategy();
- }
-
- @Override
- public String getDisplayName() {
- return Messages.ProjectMatrixAuthorizationStrategy_DisplayName();
- }
- };
-
- public static class ConverterImpl extends GlobalMatrixAuthorizationStrategy.ConverterImpl {
- private RobustReflectionConverter ref;
-
- public ConverterImpl(Mapper m) {
- ref = new RobustReflectionConverter(m,new JVM().bestReflectionProvider());
- }
-
- @Override
- protected GlobalMatrixAuthorizationStrategy create() {
- return new ProjectMatrixAuthorizationStrategy();
- }
-
- @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
- return super.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;
- }
- }
-}
-
diff --git a/hudson-core/src/main/java/hudson/security/SecurityRealm.java b/hudson-core/src/main/java/hudson/security/SecurityRealm.java
index a564d761..6eddfa47 100644
--- a/hudson-core/src/main/java/hudson/security/SecurityRealm.java
+++ b/hudson-core/src/main/java/hudson/security/SecurityRealm.java
@@ -194,6 +194,15 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal
public String getLoginUrl() {
return "login";
}
+
+ /**
+ * Return security mode of this realm
+ * @return
+ * @since 3.0.0
+ */
+ public SecurityMode getSecurityMode(){
+ return SecurityMode.SECURED;
+ }
/**
* Returns true if this {@link SecurityRealm} supports explicit logout operation.
@@ -426,6 +435,11 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal
public static final SecurityRealm NO_AUTHENTICATION = new None();
private static class None extends SecurityRealm {
+
+ @Override
+ public SecurityMode getSecurityMode(){
+ return SecurityMode.UNSECURED;
+ }
public SecurityComponents createSecurityComponents() {
return new SecurityComponents(new AuthenticationManager() {
diff --git a/hudson-core/src/main/java/hudson/util/CascadingUtil.java b/hudson-core/src/main/java/hudson/util/CascadingUtil.java
index ad9f5958..20ae8009 100644
--- a/hudson-core/src/main/java/hudson/util/CascadingUtil.java
+++ b/hudson-core/src/main/java/hudson/util/CascadingUtil.java
@@ -24,7 +24,6 @@ import hudson.model.Job;
import hudson.model.JobPropertyDescriptor;
import hudson.model.ParameterDefinition;
import hudson.model.ParametersDefinitionProperty;
-import hudson.security.AuthorizationMatrixProperty;
import hudson.triggers.Trigger;
import hudson.triggers.TriggerDescriptor;
import java.io.IOException;
@@ -525,7 +524,6 @@ public class CascadingUtil {
* @see hudson.model.Job#getParameterDefinitionProperties()
*/
public static boolean isCascadableJobProperty(JobPropertyDescriptor d) {
- return !(d instanceof AuthorizationMatrixProperty.DescriptorImpl
- || d instanceof ParametersDefinitionProperty.DescriptorImpl);
+ return d.isCascadable();
}
}

Back to the top