mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-06 03:17:51 +02:00
Merged in feature/global_config_v2_endpoint (pull request #51)
Feature/global config v2 endpoint
This commit is contained in:
17
pom.xml
17
pom.xml
@@ -92,7 +92,6 @@
|
||||
</snapshots>
|
||||
</repository>
|
||||
|
||||
<!-- TODO remove jitpack after edison hal bugfix -->
|
||||
<repository>
|
||||
<id>jitpack</id>
|
||||
<url>https://jitpack.io</url>
|
||||
@@ -168,6 +167,20 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO replace by proper version from maven central (group: com.github.sdorra) once its there. -->
|
||||
<dependency>
|
||||
<groupId>com.github.sdorra.shiro-static-permissions</groupId>
|
||||
<artifactId>ssp-lib</artifactId>
|
||||
<version>${ssp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.sdorra.shiro-static-permissions</groupId>
|
||||
<artifactId>ssp-processor</artifactId>
|
||||
<version>${ssp.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -552,7 +565,7 @@
|
||||
<jetty.maven.version>9.2.10.v20150310</jetty.maven.version>
|
||||
|
||||
<!-- security libraries -->
|
||||
<ssp.version>1.0.0-SNAPSHOT</ssp.version>
|
||||
<ssp.version>967c8fd521</ssp.version>
|
||||
<shiro.version>1.4.0</shiro.version>
|
||||
|
||||
<!-- repostitory libraries -->
|
||||
|
||||
@@ -128,17 +128,16 @@
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- TODO replace by proper version from maven central (group: com.github.sdorra) once its there. -->
|
||||
<dependency>
|
||||
<groupId>com.github.sdorra</groupId>
|
||||
<groupId>com.github.sdorra.shiro-static-permissions</groupId>
|
||||
<artifactId>ssp-lib</artifactId>
|
||||
<version>${ssp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.sdorra</groupId>
|
||||
<groupId>com.github.sdorra.shiro-static-permissions</groupId>
|
||||
<artifactId>ssp-processor</artifactId>
|
||||
<version>${ssp.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
28
scm-core/src/main/java/sonia/scm/config/Configuration.java
Normal file
28
scm-core/src/main/java/sonia/scm/config/Configuration.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package sonia.scm.config;
|
||||
|
||||
import com.github.sdorra.ssp.PermissionObject;
|
||||
import com.github.sdorra.ssp.StaticPermissions;
|
||||
|
||||
/**
|
||||
* Base for all kinds of configurations.
|
||||
*
|
||||
* Allows for permission like
|
||||
*
|
||||
* <ul>
|
||||
* <li>"configuration:read:global",</li>
|
||||
* <li>"configuration:write:svn",</li>
|
||||
* <li>"configuration:*:git",</li>
|
||||
* <li>"configuration:*"</li>
|
||||
* </ul>
|
||||
*
|
||||
* <br/>
|
||||
*
|
||||
* And for permission checks like {@code ConfigurationPermissions.read(configurationObject).check();}
|
||||
*/
|
||||
@StaticPermissions(
|
||||
value = "configuration",
|
||||
permissions = {"read", "write"},
|
||||
globalPermissions = {}
|
||||
)
|
||||
public interface Configuration extends PermissionObject {
|
||||
}
|
||||
@@ -44,6 +44,7 @@ import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
@@ -57,10 +58,11 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
|
||||
@Singleton
|
||||
@XmlRootElement(name = "scm-config")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class ScmConfiguration {
|
||||
public class ScmConfiguration implements Configuration {
|
||||
|
||||
/**
|
||||
* Default JavaScript date format
|
||||
@@ -501,4 +503,12 @@ public class ScmConfiguration {
|
||||
public void setDefaultNamespaceStrategy(String defaultNamespaceStrategy) {
|
||||
this.defaultNamespaceStrategy = defaultNamespaceStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
// Only for permission checks, don't serialize to XML
|
||||
@XmlTransient
|
||||
public String getId() {
|
||||
// Don't change this without migrating SCM permission configuration!
|
||||
return "global";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ import sonia.scm.store.ConfigurationStoreFactory;
|
||||
*
|
||||
* @param <C>
|
||||
*/
|
||||
public abstract class AbstractRepositoryHandler<C extends SimpleRepositoryConfig>
|
||||
public abstract class AbstractRepositoryHandler<C extends RepositoryConfig>
|
||||
implements RepositoryHandler
|
||||
{
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ import java.net.URL;
|
||||
* @param <C>
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepositoryConfig>
|
||||
public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig>
|
||||
extends AbstractRepositoryHandler<C> implements RepositoryDirectoryHandler {
|
||||
|
||||
public static final String DEFAULT_VERSION_INFORMATION = "unknown";
|
||||
|
||||
@@ -33,15 +33,12 @@
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.Validateable;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import sonia.scm.config.Configuration;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Basic {@link Repository} configuration class.
|
||||
@@ -49,7 +46,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class SimpleRepositoryConfig implements Validateable
|
||||
public abstract class RepositoryConfig implements Validateable, Configuration
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -119,4 +116,19 @@ public class SimpleRepositoryConfig implements Validateable
|
||||
|
||||
/** directory for repositories */
|
||||
private File repositoryDirectory;
|
||||
|
||||
/**
|
||||
* Specifies the identifier of the concrete {@link RepositoryConfig} when checking permissions of an object.
|
||||
* The permission Strings will have the following format: "configuration:*:ID", where the ID part is defined by this
|
||||
* method.
|
||||
*
|
||||
* For example: "configuration:read:git".
|
||||
*
|
||||
* No need to serialize this.
|
||||
*
|
||||
* @return identifier of this RepositoryConfig in permission strings
|
||||
*/
|
||||
@Override
|
||||
@XmlTransient // Only for permission checks, don't serialize to XML
|
||||
public abstract String getId();
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import sonia.scm.event.Event;
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Event
|
||||
public class RepositoryHandlerConfigChangedEvent<C extends SimpleRepositoryConfig>
|
||||
public class RepositoryHandlerConfigChangedEvent<C extends RepositoryConfig>
|
||||
{
|
||||
|
||||
private final C configuration;
|
||||
|
||||
@@ -74,7 +74,7 @@ public final class RepositoryUtil {
|
||||
return getRepositoryId(handler.getConfig(), directory);
|
||||
}
|
||||
|
||||
public static String getRepositoryId(SimpleRepositoryConfig config, File directory) throws IOException {
|
||||
public static String getRepositoryId(RepositoryConfig config, File directory) throws IOException {
|
||||
return getRepositoryId(config.getRepositoryDirectory(), directory);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ public class VndMediaType {
|
||||
public static final String REPOSITORY_COLLECTION = PREFIX + "repositoryCollection" + SUFFIX;
|
||||
public static final String ME = PREFIX + "me" + SUFFIX;
|
||||
|
||||
public static final String CONFIG = PREFIX + "config" + SUFFIX;
|
||||
|
||||
private VndMediaType() {
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,14 @@ public class RepositoryUtilTest {
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Mock
|
||||
private AbstractRepositoryHandler<SimpleRepositoryConfig> repositoryHandler;
|
||||
private AbstractRepositoryHandler<RepositoryConfig> repositoryHandler;
|
||||
|
||||
private SimpleRepositoryConfig repositoryConfig = new SimpleRepositoryConfig();
|
||||
private RepositoryConfig repositoryConfig = new RepositoryConfig() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "repository";
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUpMocks() {
|
||||
|
||||
@@ -39,6 +39,7 @@ import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -46,7 +47,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
*/
|
||||
@XmlRootElement(name = "config")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class GitConfig extends SimpleRepositoryConfig {
|
||||
public class GitConfig extends RepositoryConfig {
|
||||
|
||||
@XmlElement(name = "gc-expression")
|
||||
private String gcExpression;
|
||||
@@ -55,5 +56,11 @@ public class GitConfig extends SimpleRepositoryConfig {
|
||||
{
|
||||
return gcExpression;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@XmlTransient // Only for permission checks, don't serialize to XML
|
||||
public String getId() {
|
||||
// Don't change this without migrating SCM permission configuration!
|
||||
return "git";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,20 +33,19 @@
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "config")
|
||||
public class HgConfig extends SimpleRepositoryConfig
|
||||
public class HgConfig extends RepositoryConfig
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -223,4 +222,11 @@ public class HgConfig extends SimpleRepositoryConfig
|
||||
|
||||
/** Field description */
|
||||
private boolean showRevisionInId = false;
|
||||
|
||||
@Override
|
||||
@XmlTransient // Only for permission checks, don't serialize to XML
|
||||
public String getId() {
|
||||
// Don't change this without migrating SCM permission configuration!
|
||||
return "hg";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,11 @@
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -46,7 +45,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
*/
|
||||
@XmlRootElement(name = "config")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class SvnConfig extends SimpleRepositoryConfig
|
||||
public class SvnConfig extends RepositoryConfig
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -108,4 +107,11 @@ public class SvnConfig extends SimpleRepositoryConfig
|
||||
|
||||
/** Field description */
|
||||
private Compatibility compatibility = Compatibility.NONE;
|
||||
|
||||
@Override
|
||||
@XmlTransient // Only for permission checks, don't serialize to XML
|
||||
public String getId() {
|
||||
// Don't change this without migrating SCM permission configuration!
|
||||
return "svn";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import sonia.scm.Type;
|
||||
import sonia.scm.io.DefaultFileSystem;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -48,7 +49,7 @@ import java.util.Set;
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class DummyRepositoryHandler
|
||||
extends AbstractSimpleRepositoryHandler<SimpleRepositoryConfig> {
|
||||
extends AbstractSimpleRepositoryHandler<DummyRepositoryHandler.DummyRepositoryConfig> {
|
||||
|
||||
public static final String TYPE_DISPLAYNAME = "Dummy";
|
||||
|
||||
@@ -79,12 +80,20 @@ public class DummyRepositoryHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleRepositoryConfig createInitialConfig() {
|
||||
return new SimpleRepositoryConfig();
|
||||
protected DummyRepositoryConfig createInitialConfig() {
|
||||
return new DummyRepositoryConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<SimpleRepositoryConfig> getConfigClass() {
|
||||
return SimpleRepositoryConfig.class;
|
||||
protected Class<DummyRepositoryConfig> getConfigClass() {
|
||||
return DummyRepositoryConfig.class;
|
||||
}
|
||||
|
||||
@XmlRootElement(name = "config")
|
||||
public static class DummyRepositoryConfig extends RepositoryConfig {
|
||||
@Override
|
||||
public String getId() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +48,8 @@ import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import javax.ws.rs.core.CacheControl;
|
||||
import javax.ws.rs.core.EntityTag;
|
||||
import javax.ws.rs.core.GenericEntity;
|
||||
import javax.ws.rs.core.Request;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.*;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
|
||||
@@ -47,22 +47,8 @@ import sonia.scm.group.GroupException;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.security.Role;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.GenericEntity;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Request;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
import java.util.Collection;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
@@ -50,15 +50,7 @@ import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.NotSupportedFeatuerException;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.api.rest.RestActionUploadResult;
|
||||
import sonia.scm.repository.AdvancedImportHandler;
|
||||
import sonia.scm.repository.ImportHandler;
|
||||
import sonia.scm.repository.ImportResult;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryAlreadyExistsException;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
import sonia.scm.repository.RepositoryHandler;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryType;
|
||||
import sonia.scm.repository.*;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
@@ -66,21 +58,8 @@ import sonia.scm.repository.api.UnbundleCommandBuilder;
|
||||
import sonia.scm.security.Role;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.FormParam;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.GenericEntity;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@@ -46,51 +46,16 @@ import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.BlameResult;
|
||||
import sonia.scm.repository.Branches;
|
||||
import sonia.scm.repository.BrowserResult;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.HealthChecker;
|
||||
import sonia.scm.repository.Permission;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
import sonia.scm.repository.RepositoryIsNotArchivedException;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryNotFoundException;
|
||||
import sonia.scm.repository.Tags;
|
||||
import sonia.scm.repository.api.BlameCommandBuilder;
|
||||
import sonia.scm.repository.api.BrowseCommandBuilder;
|
||||
import sonia.scm.repository.api.CatCommandBuilder;
|
||||
import sonia.scm.repository.api.CommandNotSupportedException;
|
||||
import sonia.scm.repository.api.DiffCommandBuilder;
|
||||
import sonia.scm.repository.api.DiffFormat;
|
||||
import sonia.scm.repository.api.LogCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.repository.*;
|
||||
import sonia.scm.repository.api.*;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.GenericEntity;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Request;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -50,21 +50,8 @@ import sonia.scm.user.UserManager;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.GenericEntity;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Request;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
import java.util.Collection;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import de.otto.edison.hal.Links;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class ConfigDto extends HalRepresentation {
|
||||
|
||||
private String proxyPassword;
|
||||
private int proxyPort;
|
||||
private String proxyServer;
|
||||
private String proxyUser;
|
||||
private boolean enableProxy;
|
||||
private String realmDescription;
|
||||
private boolean enableRepositoryArchive;
|
||||
private boolean disableGroupingGrid;
|
||||
private String dateFormat;
|
||||
private boolean anonymousAccessEnabled;
|
||||
private Set<String> adminGroups;
|
||||
private Set<String> adminUsers;
|
||||
private String baseUrl;
|
||||
private boolean forceBaseUrl;
|
||||
private int loginAttemptLimit;
|
||||
private Set<String> proxyExcludes;
|
||||
private boolean skipFailedAuthenticators;
|
||||
private String pluginUrl;
|
||||
private long loginAttemptLimitTimeout;
|
||||
private boolean enabledXsrfProtection;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
|
||||
protected HalRepresentation add(Links links) {
|
||||
return super.add(links);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
|
||||
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
|
||||
@SuppressWarnings("squid:S3306")
|
||||
@Mapper
|
||||
public abstract class ConfigDtoToScmConfigurationMapper {
|
||||
|
||||
public abstract ScmConfiguration map(ConfigDto dto);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import sonia.scm.config.ConfigurationPermissions;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.util.ScmConfigurationUtil;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
@Path(ConfigResource.CONFIG_PATH_V2)
|
||||
public class ConfigResource {
|
||||
|
||||
static final String CONFIG_PATH_V2 = "v2/config";
|
||||
private final ConfigDtoToScmConfigurationMapper dtoToConfigMapper;
|
||||
private final ScmConfigurationToConfigDtoMapper configToDtoMapper;
|
||||
private final ScmConfiguration configuration;
|
||||
|
||||
@Inject
|
||||
public ConfigResource(ConfigDtoToScmConfigurationMapper dtoToConfigMapper, ScmConfigurationToConfigDtoMapper configToDtoMapper, ScmConfiguration configuration) {
|
||||
this.dtoToConfigMapper = dtoToConfigMapper;
|
||||
this.configToDtoMapper = configToDtoMapper;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global scm config.
|
||||
*/
|
||||
@GET
|
||||
@Path("")
|
||||
@Produces(VndMediaType.CONFIG)
|
||||
@TypeHint(UserDto.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the global config"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response get() {
|
||||
|
||||
// We do this permission check in Resource and not in ScmConfiguration, because it must be available for reading
|
||||
// from within the code (plugins, etc.), but not for the whole anonymous world outside.
|
||||
ConfigurationPermissions.read(configuration).check();
|
||||
|
||||
return Response.ok(configToDtoMapper.map(configuration)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the global scm config.
|
||||
*
|
||||
* @param configDto new global scm configuration as DTO
|
||||
*/
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.CONFIG)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "update success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to update the global config"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
public Response update(ConfigDto configDto, @Context UriInfo uriInfo) {
|
||||
|
||||
// This *could* be moved to ScmConfiguration or ScmConfigurationUtil classes.
|
||||
// But to where to check? load() or store()? Leave it for now, SCMv1 legacy that can be cleaned up later.
|
||||
ConfigurationPermissions.write(configuration).check();
|
||||
|
||||
ScmConfiguration config = dtoToConfigMapper.map(configDto);
|
||||
synchronized (ScmConfiguration.class) {
|
||||
configuration.load(config);
|
||||
ScmConfigurationUtil.getInstance().store(configuration);
|
||||
}
|
||||
|
||||
return Response.noContent().build();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,13 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeaders;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import com.webcohesion.enunciate.metadata.rs.*;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupException;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@@ -9,13 +9,7 @@ import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
public class GroupResource {
|
||||
|
||||
@@ -15,6 +15,9 @@ public class MapperModule extends AbstractModule {
|
||||
bind(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass());
|
||||
bind(GroupCollectionToDtoMapper.class);
|
||||
|
||||
bind(ScmConfigurationToConfigDtoMapper.class).to(Mappers.getMapper(ScmConfigurationToConfigDtoMapper.class).getClass());
|
||||
bind(ConfigDtoToScmConfigurationMapper.class).to(Mappers.getMapper(ConfigDtoToScmConfigurationMapper.class).getClass());
|
||||
|
||||
bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapper(RepositoryToRepositoryDtoMapper.class).getClass());
|
||||
bind(RepositoryDtoToRepositoryMapper.class).to(Mappers.getMapper(RepositoryDtoToRepositoryMapper.class).getClass());
|
||||
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeaders;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import com.webcohesion.enunciate.metadata.rs.*;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
public class RepositoryCollectionResource {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Context;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.*;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
@Mapper
|
||||
|
||||
@@ -10,13 +10,7 @@ import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -76,7 +76,7 @@ class ResourceLinks {
|
||||
return userLinkBuilder.method("getUserResource").parameters(name).method("delete").parameters().href();
|
||||
}
|
||||
|
||||
String update(String name) {
|
||||
String update(String name) {
|
||||
return userLinkBuilder.method("getUserResource").parameters(name).method("update").parameters().href();
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,26 @@ class ResourceLinks {
|
||||
}
|
||||
}
|
||||
|
||||
ConfigLinks config() {
|
||||
return new ConfigLinks(uriInfoStore.get());
|
||||
}
|
||||
|
||||
static class ConfigLinks {
|
||||
private final LinkBuilder configLinkBuilder;
|
||||
|
||||
ConfigLinks(UriInfo uriInfo) {
|
||||
configLinkBuilder = new LinkBuilder(uriInfo, ConfigResource.class);
|
||||
}
|
||||
|
||||
String self() {
|
||||
return configLinkBuilder.method("get").parameters().href();
|
||||
}
|
||||
|
||||
String update() {
|
||||
return configLinkBuilder.method("update").parameters().href();
|
||||
}
|
||||
}
|
||||
|
||||
public RepositoryLinks repository() {
|
||||
return new RepositoryLinks(uriInfoStore.get());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Links;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import sonia.scm.config.ConfigurationPermissions;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static de.otto.edison.hal.Link.link;
|
||||
import static de.otto.edison.hal.Links.linkingTo;
|
||||
|
||||
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
|
||||
@SuppressWarnings("squid:S3306")
|
||||
@Mapper
|
||||
public abstract class ScmConfigurationToConfigDtoMapper {
|
||||
|
||||
@Inject
|
||||
private ResourceLinks resourceLinks;
|
||||
|
||||
public abstract ConfigDto map(ScmConfiguration config);
|
||||
|
||||
@AfterMapping
|
||||
void appendLinks(ScmConfiguration config, @MappingTarget ConfigDto target) {
|
||||
Links.Builder linksBuilder = linkingTo().self(resourceLinks.config().self());
|
||||
if (ConfigurationPermissions.write(config).isPermitted()) {
|
||||
linksBuilder.single(link("update", resourceLinks.config().update()));
|
||||
}
|
||||
target.add(linksBuilder.build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,13 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeaders;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import com.webcohesion.enunciate.metadata.rs.*;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserException;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@@ -9,13 +9,7 @@ import sonia.scm.user.UserManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
public class UserResource {
|
||||
|
||||
@@ -49,6 +49,7 @@ import sonia.scm.security.Role;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
// TODO before releasing v2, delete this filter (we use Permission objects now)
|
||||
@WebElement(
|
||||
value = Filters.PATTERN_CONFIG,
|
||||
morePatterns = {
|
||||
|
||||
@@ -52,12 +52,7 @@ import sonia.scm.util.CollectionAppender;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -42,30 +42,14 @@ import com.google.inject.Singleton;
|
||||
import org.apache.shiro.concurrent.SubjectAwareExecutorService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ArgumentIsInvalidException;
|
||||
import sonia.scm.ConfigurationException;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.ManagerDaoAdapter;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.*;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.security.KeyGenerator;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.CollectionAppender;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.util.Util;
|
||||
import sonia.scm.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
@@ -55,11 +55,7 @@ import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.internal.util.collections.Sets;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
public class ConfigDtoToScmConfigurationMapperTest {
|
||||
|
||||
@InjectMocks
|
||||
private ConfigDtoToScmConfigurationMapperImpl mapper;
|
||||
|
||||
private String[] expectedUsers = { "trillian", "arthur" };
|
||||
private String[] expectedGroups = { "admin", "plebs" };
|
||||
private String[] expectedExcludes = { "ex", "clude" };
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMapFields() {
|
||||
ConfigDto dto = createDefaultDto();
|
||||
ScmConfiguration config = mapper.map(dto);
|
||||
|
||||
assertEquals("prPw" , config.getProxyPassword());
|
||||
assertEquals(42 , config.getProxyPort());
|
||||
assertEquals("srvr" , config.getProxyServer());
|
||||
assertEquals("user" , config.getProxyUser());
|
||||
assertTrue(config.isEnableProxy());
|
||||
assertEquals("realm" , config.getRealmDescription());
|
||||
assertTrue(config.isEnableRepositoryArchive());
|
||||
assertTrue(config.isDisableGroupingGrid());
|
||||
assertEquals("yyyy" , config.getDateFormat());
|
||||
assertTrue(config.isAnonymousAccessEnabled());
|
||||
assertTrue("adminGroups", config.getAdminGroups().containsAll(Arrays.asList(expectedGroups)));
|
||||
assertTrue("adminUsers", config.getAdminUsers().containsAll(Arrays.asList(expectedUsers)));
|
||||
assertEquals("baseurl" , config.getBaseUrl());
|
||||
assertTrue(config.isForceBaseUrl());
|
||||
assertEquals(41 , config.getLoginAttemptLimit());
|
||||
assertTrue("proxyExcludes", config.getProxyExcludes().containsAll(Arrays.asList(expectedExcludes)));
|
||||
assertTrue(config.isSkipFailedAuthenticators());
|
||||
assertEquals("https://plug.ins" , config.getPluginUrl());
|
||||
assertEquals(40 , config.getLoginAttemptLimitTimeout());
|
||||
assertTrue(config.isEnabledXsrfProtection());
|
||||
}
|
||||
|
||||
private ConfigDto createDefaultDto() {
|
||||
ConfigDto configDto = new ConfigDto();
|
||||
configDto.setProxyPassword("prPw");
|
||||
configDto.setProxyPort(42);
|
||||
configDto.setProxyServer("srvr");
|
||||
configDto.setProxyUser("user");
|
||||
configDto.setEnableProxy(true);
|
||||
configDto.setRealmDescription("realm");
|
||||
configDto.setEnableRepositoryArchive(true);
|
||||
configDto.setDisableGroupingGrid(true);
|
||||
configDto.setDateFormat("yyyy");
|
||||
configDto.setAnonymousAccessEnabled(true);
|
||||
configDto.setAdminGroups(Sets.newSet(expectedGroups));
|
||||
configDto.setAdminUsers(Sets.newSet(expectedUsers));
|
||||
configDto.setBaseUrl("baseurl");
|
||||
configDto.setForceBaseUrl(true);
|
||||
configDto.setLoginAttemptLimit(41);
|
||||
configDto.setProxyExcludes(Sets.newSet(expectedExcludes));
|
||||
configDto.setSkipFailedAuthenticators(true);
|
||||
configDto.setPluginUrl("https://plug.ins");
|
||||
configDto.setLoginAttemptLimitTimeout(40);
|
||||
configDto.setEnabledXsrfProtection(true);
|
||||
|
||||
return configDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.github.sdorra.shiro.ShiroRule;
|
||||
import com.github.sdorra.shiro.SubjectAware;
|
||||
import com.google.common.io.Resources;
|
||||
import org.jboss.resteasy.core.Dispatcher;
|
||||
import org.jboss.resteasy.mock.MockDispatcherFactory;
|
||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.InjectMocks;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
@SubjectAware(
|
||||
configuration = "classpath:sonia/scm/configuration/shiro.ini",
|
||||
password = "secret"
|
||||
)
|
||||
public class ConfigResourceTest {
|
||||
|
||||
@Rule
|
||||
public ShiroRule shiro = new ShiroRule();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
||||
|
||||
private final URI baseUri = URI.create("/");
|
||||
@SuppressWarnings("unused") // Is injected
|
||||
private ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||
|
||||
@InjectMocks
|
||||
private ConfigDtoToScmConfigurationMapperImpl dtoToConfigMapper;
|
||||
@InjectMocks
|
||||
private ScmConfigurationToConfigDtoMapperImpl configToDtoMapper;
|
||||
|
||||
@Before
|
||||
public void prepareEnvironment() {
|
||||
initMocks(this);
|
||||
|
||||
ConfigResource configResource = new ConfigResource(dtoToConfigMapper, configToDtoMapper, createConfiguration());
|
||||
|
||||
dispatcher.getRegistry().addSingletonResource(configResource);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readOnly")
|
||||
public void shouldGetGlobalConfig() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + ConfigResource.CONFIG_PATH_V2);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
assertTrue(response.getContentAsString().contains("\"proxyPassword\":\"heartOfGold\""));
|
||||
assertTrue(response.getContentAsString().contains("\"self\":{\"href\":\"/v2/config"));
|
||||
assertFalse("Update link present", response.getContentAsString().contains("\"update\":{\"href\":\"/v2/config"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "writeOnly")
|
||||
public void shouldGetConfigOnlyWhenAuthorized() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + ConfigResource.CONFIG_PATH_V2);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
thrown.expectMessage("Subject does not have permission [configuration:read:global]");
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readWrite")
|
||||
public void shouldUpdateConfig() throws URISyntaxException, IOException {
|
||||
URL url = Resources.getResource("sonia/scm/api/v2/config-test-update.json");
|
||||
byte[] configJson = Resources.toByteArray(url);
|
||||
MockHttpRequest request = MockHttpRequest.put("/" + ConfigResource.CONFIG_PATH_V2)
|
||||
.contentType(VndMediaType.CONFIG)
|
||||
.content(configJson);
|
||||
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus());
|
||||
|
||||
request = MockHttpRequest.get("/" + ConfigResource.CONFIG_PATH_V2);
|
||||
response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
assertTrue(response.getContentAsString().contains("\"proxyPassword\":\"newPassword\""));
|
||||
assertTrue(response.getContentAsString().contains("\"self\":{\"href\":\"/v2/config"));
|
||||
assertTrue("link not found", response.getContentAsString().contains("\"update\":{\"href\":\"/v2/config"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readOnly")
|
||||
public void shouldUpdateConfigOnlyWhenAuthorized() throws URISyntaxException, IOException {
|
||||
URL url = Resources.getResource("sonia/scm/api/v2/config-test-update.json");
|
||||
byte[] configJson = Resources.toByteArray(url);
|
||||
MockHttpRequest request = MockHttpRequest.put("/" + ConfigResource.CONFIG_PATH_V2)
|
||||
.contentType(VndMediaType.CONFIG)
|
||||
.content(configJson);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
thrown.expectMessage("Subject does not have permission [configuration:write:global]");
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
}
|
||||
|
||||
private static ScmConfiguration createConfiguration() {
|
||||
ScmConfiguration scmConfiguration = new ScmConfiguration();
|
||||
scmConfiguration.setProxyPassword("heartOfGold");
|
||||
|
||||
return scmConfiguration;
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,7 @@ import java.net.URL;
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
@@ -111,8 +109,6 @@ public class GroupRootResourceTest {
|
||||
|
||||
Group group = createDummyGroup();
|
||||
when(groupManager.get("admin")).thenReturn(group);
|
||||
Group updatedGroup = createDummyGroup();
|
||||
updatedGroup.setDescription("Updated description");
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.put("/" + GroupRootResource.GROUPS_PATH_V2 + "admin")
|
||||
@@ -134,9 +130,6 @@ public class GroupRootResourceTest {
|
||||
URL url = Resources.getResource("sonia/scm/api/v2/group-test-update.json");
|
||||
byte[] groupJson = Resources.toByteArray(url);
|
||||
|
||||
Group updatedGroup = createDummyGroup();
|
||||
updatedGroup.setDescription("Updated description");
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.put("/" + GroupRootResource.GROUPS_PATH_V2 + "idontexist")
|
||||
.contentType(VndMediaType.GROUP)
|
||||
|
||||
@@ -27,19 +27,14 @@ import java.net.URL;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static javax.servlet.http.HttpServletResponse.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
@SubjectAware(
|
||||
|
||||
@@ -24,6 +24,7 @@ public class ResourceLinksMock {
|
||||
when(resourceLinks.changesetCollection()).thenReturn(new ResourceLinks.ChangesetCollectionLinks(uriInfo));
|
||||
when(resourceLinks.sourceCollection()).thenReturn(new ResourceLinks.SourceCollectionLinks(uriInfo));
|
||||
when(resourceLinks.permissionCollection()).thenReturn(new ResourceLinks.PermissionCollectionLinks(uriInfo));
|
||||
when(resourceLinks.config()).thenReturn(new ResourceLinks.ConfigLinks(uriInfo));
|
||||
return resourceLinks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +132,18 @@ public class ResourceLinksTest {
|
||||
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateCorrectConfigSelfUrl() {
|
||||
String url = resourceLinks.config().self();
|
||||
assertEquals(BASE_URL + ConfigResource.CONFIG_PATH_V2, url);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateCorrectConfigUpdateUrl() {
|
||||
String url = resourceLinks.config().update();
|
||||
assertEquals(BASE_URL + ConfigResource.CONFIG_PATH_V2, url);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initUriInfo() {
|
||||
initMocks(this);
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.subject.support.SubjectThreadState;
|
||||
import org.apache.shiro.util.ThreadContext;
|
||||
import org.apache.shiro.util.ThreadState;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.internal.util.collections.Sets;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
public class ScmConfigurationToConfigDtoMapperTest {
|
||||
|
||||
private URI baseUri = URI.create("http://example.com/base/");
|
||||
|
||||
private String[] expectedUsers = { "trillian", "arthur" };
|
||||
private String[] expectedGroups = { "admin", "plebs" };
|
||||
private String[] expectedExcludes = { "ex", "clude" };
|
||||
|
||||
@SuppressWarnings("unused") // Is injected
|
||||
private ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||
|
||||
@InjectMocks
|
||||
private ScmConfigurationToConfigDtoMapperImpl mapper;
|
||||
|
||||
private final Subject subject = mock(Subject.class);
|
||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||
|
||||
private URI expectedBaseUri;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
initMocks(this);
|
||||
expectedBaseUri = baseUri.resolve(ConfigResource.CONFIG_PATH_V2);
|
||||
subjectThreadState.bind();
|
||||
ThreadContext.bind(subject);
|
||||
}
|
||||
|
||||
@After
|
||||
public void unbindSubject() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMapFields() {
|
||||
ScmConfiguration config = createConfiguration();
|
||||
|
||||
|
||||
when(subject.isPermitted("configuration:write:global")).thenReturn(true);
|
||||
ConfigDto dto = mapper.map(config);
|
||||
|
||||
assertEquals("heartOfGold" , dto.getProxyPassword());
|
||||
assertEquals(1234 , dto.getProxyPort());
|
||||
assertEquals("proxyserver" , dto.getProxyServer());
|
||||
assertEquals("trillian" , dto.getProxyUser());
|
||||
assertTrue(dto.isEnableProxy());
|
||||
assertEquals("description" , dto.getRealmDescription());
|
||||
assertTrue(dto.isEnableRepositoryArchive());
|
||||
assertTrue(dto.isDisableGroupingGrid());
|
||||
assertEquals("dd" , dto.getDateFormat());
|
||||
assertTrue(dto.isAnonymousAccessEnabled());
|
||||
assertTrue("adminGroups", dto.getAdminGroups().containsAll(Arrays.asList(expectedGroups)));
|
||||
assertTrue("adminUsers", dto.getAdminUsers().containsAll(Arrays.asList(expectedUsers)));
|
||||
assertEquals("baseurl" , dto.getBaseUrl());
|
||||
assertTrue(dto.isForceBaseUrl());
|
||||
assertEquals(1 , dto.getLoginAttemptLimit());
|
||||
assertTrue("proxyExcludes", dto.getProxyExcludes().containsAll(Arrays.asList(expectedExcludes)));
|
||||
assertTrue(dto.isSkipFailedAuthenticators());
|
||||
assertEquals("pluginurl" , dto.getPluginUrl());
|
||||
assertEquals(2 , dto.getLoginAttemptLimitTimeout());
|
||||
assertTrue(dto.isEnabledXsrfProtection());
|
||||
|
||||
assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("self").get().getHref());
|
||||
assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("update").get().getHref());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMapFieldsWithoutUpdate() {
|
||||
ScmConfiguration config = createConfiguration();
|
||||
|
||||
when(subject.hasRole("configuration:write:global")).thenReturn(false);
|
||||
ConfigDto dto = mapper.map(config);
|
||||
|
||||
assertEquals("baseurl", dto.getBaseUrl());
|
||||
assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("self").get().getHref());
|
||||
assertFalse(dto.getLinks().hasLink("update"));
|
||||
}
|
||||
|
||||
private ScmConfiguration createConfiguration() {
|
||||
ScmConfiguration config = new ScmConfiguration();
|
||||
config.setProxyPassword("heartOfGold");
|
||||
config.setProxyPort(1234);
|
||||
config.setProxyServer("proxyserver");
|
||||
config.setProxyUser("trillian");
|
||||
config.setEnableProxy(true);
|
||||
config.setRealmDescription("description");
|
||||
config.setEnableRepositoryArchive(true);
|
||||
config.setDisableGroupingGrid(true);
|
||||
config.setDateFormat("dd");
|
||||
config.setAnonymousAccessEnabled(true);
|
||||
config.setAdminGroups(Sets.newSet(expectedGroups));
|
||||
config.setAdminUsers(Sets.newSet(expectedUsers));
|
||||
config.setBaseUrl("baseurl");
|
||||
config.setForceBaseUrl(true);
|
||||
config.setLoginAttemptLimit(1);
|
||||
config.setProxyExcludes(Sets.newSet(expectedExcludes));
|
||||
config.setSkipFailedAuthenticators(true);
|
||||
config.setPluginUrl("pluginurl");
|
||||
config.setLoginAttemptLimitTimeout(2);
|
||||
config.setEnabledXsrfProtection(true);
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,9 +18,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
import static sonia.scm.PageResult.createPage;
|
||||
|
||||
@@ -27,15 +27,10 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
@SubjectAware(
|
||||
|
||||
@@ -41,12 +41,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.Manager;
|
||||
import sonia.scm.ManagerTestBase;
|
||||
import sonia.scm.ModelObject;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.TypedObject;
|
||||
import sonia.scm.*;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.api.HookContext;
|
||||
@@ -59,23 +54,10 @@ import sonia.scm.security.KeyGenerator;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import sonia.scm.store.JAXBConfigurationStoreFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"proxyPassword": "newPassword"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[users]
|
||||
readOnly = secret, reader
|
||||
writeOnly = secret, writer
|
||||
readWrite = secret, readerWriter
|
||||
|
||||
[roles]
|
||||
reader = configuration:read
|
||||
writer = configuration:write
|
||||
readerWriter = configuration:*
|
||||
Reference in New Issue
Block a user