Merged in feature/global_config_v2_endpoint (pull request #51)

Feature/global config v2 endpoint
This commit is contained in:
Johannes Schnatterer
2018-07-31 14:25:49 +00:00
49 changed files with 728 additions and 275 deletions

17
pom.xml
View File

@@ -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 -->

View File

@@ -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>

View 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 {
}

View File

@@ -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";
}
}

View File

@@ -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
{

View File

@@ -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";

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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() {
}

View File

@@ -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() {

View File

@@ -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";
}
}

View File

@@ -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";
}
}

View File

@@ -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";
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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 ------------------------------------------------------------

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 ------------------------------------------------------------

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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());

View File

@@ -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 {

View File

@@ -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

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -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());
}
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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 = {

View File

@@ -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 ------------------------------------------------------------

View File

@@ -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;

View File

@@ -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 ------------------------------------------------------------

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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(

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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(

View File

@@ -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;

View File

@@ -0,0 +1,3 @@
{
"proxyPassword": "newPassword"
}

View File

@@ -0,0 +1,9 @@
[users]
readOnly = secret, reader
writeOnly = secret, writer
readWrite = secret, readerWriter
[roles]
reader = configuration:read
writer = configuration:write
readerWriter = configuration:*