mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-04 08:58:22 +02:00
Merge branch 'develop' into feature/manage-tags
# Conflicts: # scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java
This commit is contained in:
@@ -36,7 +36,7 @@ import java.time.Instant;
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ApiKeyDto extends HalRepresentation {
|
||||
public class ApiKeyDto extends HalRepresentation implements CreateApiKeyDto {
|
||||
@NotEmpty
|
||||
private String displayName;
|
||||
@NotEmpty
|
||||
|
||||
@@ -28,7 +28,9 @@ import de.otto.edison.hal.HalRepresentation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.security.ApiKey;
|
||||
@@ -131,7 +133,22 @@ public class ApiKeyResource {
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.API_KEY)
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Operation(summary = "Create new api key for the current user", description = "Creates a new api key for the given user with the role specified in the given key.", tags = "User")
|
||||
@Operation(
|
||||
summary = "Create new api key for the current user",
|
||||
description = "Creates a new api key for the given user with the role specified in the given key.",
|
||||
tags = "User",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.API_KEY,
|
||||
schema = @Schema(implementation = CreateApiKeyDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Create a new api key named readKey with READ permission role.",
|
||||
value = "{\n \"displayName\":\"readKey\",\n \"permissionRole\":\"READ\"\n}",
|
||||
summary = "Create new api key"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "create success",
|
||||
@@ -170,4 +187,5 @@ public class ApiKeyResource {
|
||||
public void delete(@PathParam("id") String id) {
|
||||
apiKeyService.remove(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import de.otto.edison.hal.Embedded;
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import de.otto.edison.hal.Links;
|
||||
@@ -31,11 +32,14 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import sonia.scm.repository.Branch;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES;
|
||||
import java.time.Instant;
|
||||
|
||||
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -45,10 +49,13 @@ public class BranchDto extends HalRepresentation {
|
||||
|
||||
@NotEmpty
|
||||
@Length(min = 1, max = 100)
|
||||
@Pattern(regexp = VALID_BRANCH_NAMES)
|
||||
@Pattern(regexp = Branch.VALID_BRANCH_NAMES)
|
||||
private String name;
|
||||
private String revision;
|
||||
private boolean defaultBranch;
|
||||
@JsonInclude(NON_NULL)
|
||||
private Instant lastCommitDate;
|
||||
private boolean stale;
|
||||
|
||||
BranchDto(Links links, Embedded embedded) {
|
||||
super(links, embedded);
|
||||
|
||||
@@ -28,7 +28,9 @@ import com.google.common.base.Strings;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.PageResult;
|
||||
import sonia.scm.repository.Branch;
|
||||
@@ -209,7 +211,22 @@ public class BranchRootResource {
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.BRANCH_REQUEST)
|
||||
@Operation(summary = "Create branch", description = "Creates a new branch.", tags = "Repository")
|
||||
@Operation(
|
||||
summary = "Create branch",
|
||||
description = "Creates a new branch.",
|
||||
tags = "Repository",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.BRANCH_REQUEST,
|
||||
schema = @Schema(implementation = BranchRequestDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Branch a new develop branch from main.",
|
||||
value = "{\n \"parent\":\"main\",\n \"name\":\"develop\"\n}",
|
||||
summary = "Create a branch"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "create success",
|
||||
|
||||
@@ -38,11 +38,14 @@ import sonia.scm.web.EdisonHalAppender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
import static de.otto.edison.hal.Link.linkBuilder;
|
||||
import static de.otto.edison.hal.Links.linkingTo;
|
||||
|
||||
@Mapper
|
||||
public abstract class BranchToBranchDtoMapper extends HalAppenderMapper {
|
||||
public abstract class BranchToBranchDtoMapper extends HalAppenderMapper implements InstantAttributeMapper {
|
||||
|
||||
@Inject
|
||||
private ResourceLinks resourceLinks;
|
||||
@@ -68,4 +71,8 @@ public abstract class BranchToBranchDtoMapper extends HalAppenderMapper {
|
||||
|
||||
return new BranchDto(linksBuilder.build(), embeddedBuilder.build());
|
||||
}
|
||||
|
||||
Instant mapOptionalTime(Optional<Long> date) {
|
||||
return date.map(this::mapTime).orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.Set;
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class ConfigDto extends HalRepresentation {
|
||||
public class ConfigDto extends HalRepresentation implements UpdateConfigDto {
|
||||
|
||||
private String proxyPassword;
|
||||
private int proxyPort;
|
||||
|
||||
@@ -27,9 +27,10 @@ package sonia.scm.api.v2.resources;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import sonia.scm.config.ConfigurationPermissions;
|
||||
@@ -122,7 +123,22 @@ public class ConfigResource {
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.CONFIG)
|
||||
@Operation(summary = "Update instance configuration", description = "Modifies the instance configuration.", tags = "Instance configuration")
|
||||
@Operation(
|
||||
summary = "Update instance configuration",
|
||||
description = "Modifies the instance configuration.",
|
||||
tags = "Instance configuration",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.CONFIG,
|
||||
schema = @Schema(implementation = UpdateConfigDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Overwrites current configuration with this one.",
|
||||
value = "{\n \"realmDescription\":\"SONIA :: SCM-Manager\",\n \"dateFormat\":\"YYYY-MM-DD HH:mm:ss\",\n \"baseUrl\":\"http://localhost:8081/scm\",\n \"loginAttemptLimit\":-1,\n \"pluginUrl\":\"https://plugin-center-api.scm-manager.org/api/v1/plugins/{version}?os={os}&arch={arch}\",\n \"loginAttemptLimitTimeout\":500,\n \"namespaceStrategy\":\"CustomNamespaceStrategy\",\n \"loginInfoUrl\":\"https://login-info.scm-manager.org/api/v1/login-info\",\n \"releaseFeedUrl\":\"https://scm-manager.org/download/rss.xml\",\n \"mailDomainName\":\"scm-manager.local\"\n}",
|
||||
summary = "Simple update configuration"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized, the current user does not have the \"configuration:write\" privilege")
|
||||
@@ -151,4 +167,5 @@ public class ConfigResource {
|
||||
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
interface CreateApiKeyDto {
|
||||
@NotEmpty
|
||||
String getDisplayName();
|
||||
|
||||
@NotEmpty
|
||||
String getPermissionRole();
|
||||
}
|
||||
@@ -24,26 +24,19 @@
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is currently only used in the openapi scheme
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class CreateGroupDto {
|
||||
interface CreateGroupDto {
|
||||
|
||||
@Pattern(regexp = ValidationUtil.REGEX_NAME)
|
||||
private String name;
|
||||
private String description;
|
||||
private String type;
|
||||
private List<String> members;
|
||||
private boolean external;
|
||||
String getName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
List<String> getMembers();
|
||||
|
||||
boolean isExternal();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
interface CreateRepositoryDto {
|
||||
|
||||
String getNamespace();
|
||||
|
||||
@Pattern(regexp = ValidationUtil.REGEX_REPOSITORYNAME)
|
||||
String getName();
|
||||
|
||||
@NotEmpty
|
||||
String getType();
|
||||
|
||||
@Email
|
||||
String getContact();
|
||||
|
||||
String getDescription();
|
||||
|
||||
List<HealthCheckFailureDto> getHealthCheckFailures();
|
||||
|
||||
Instant getLastModified();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Collection;
|
||||
|
||||
interface CreateRepositoryRoleDto {
|
||||
|
||||
@NotEmpty
|
||||
String getName();
|
||||
|
||||
@NoBlankStrings
|
||||
@NotEmpty
|
||||
Collection<String> getVerbs();
|
||||
|
||||
String getType();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
interface CreateUserDto {
|
||||
@Pattern(regexp = ValidationUtil.REGEX_NAME)
|
||||
String getName();
|
||||
|
||||
@NotEmpty
|
||||
String getDisplayName();
|
||||
|
||||
@Email
|
||||
String getMail();
|
||||
|
||||
boolean isExternal();
|
||||
|
||||
String getPassword();
|
||||
|
||||
boolean isActive();
|
||||
|
||||
String getType();
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
@@ -40,7 +40,7 @@ import java.util.List;
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class GroupDto extends HalRepresentation {
|
||||
public class GroupDto extends HalRepresentation implements UpdateGroupDto, CreateGroupDto {
|
||||
|
||||
private Instant creationDate;
|
||||
private String description;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -181,4 +181,5 @@ public class GroupResource {
|
||||
public GroupPermissionResource permissions() {
|
||||
return groupPermissionResource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ package sonia.scm.api.v2.resources;
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
@@ -105,7 +107,22 @@ public class MeResource {
|
||||
@PUT
|
||||
@Path("password")
|
||||
@Consumes(VndMediaType.PASSWORD_CHANGE)
|
||||
@Operation(summary = "Change password", description = "Change password of the current user.", tags = "Current user")
|
||||
@Operation(
|
||||
summary = "Change password",
|
||||
description = "Change password of the current user.",
|
||||
tags = "Current user",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.PASSWORD_CHANGE,
|
||||
schema = @Schema(implementation = PasswordChangeDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Change password to a more difficult one.",
|
||||
value = "{ \"oldPassword\":\"scmadmin\",\n \"newPassword\":\"5cm4dm1n\"\n}",
|
||||
summary = "Simple change password"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(
|
||||
|
||||
@@ -28,7 +28,9 @@ import de.otto.edison.hal.HalRepresentation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import sonia.scm.NotFoundException;
|
||||
@@ -89,7 +91,22 @@ public class NamespacePermissionResource {
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Create namespace-specific permission", description = "Adds a new permission to the namespace for the user or group.", tags = {"Namespace", "Permissions"})
|
||||
@Operation(
|
||||
summary = "Create namespace-specific permission",
|
||||
description = "Adds a new permission to the namespace for the user or group.",
|
||||
tags = {"Namespace", "Permissions"},
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_PERMISSION,
|
||||
schema = @Schema(implementation = UpdateRepositoryPermissionDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Add read permissions for repositories and pull requests to manager group.",
|
||||
value = "{\n \"name\":\"manager\",\n \"verbs\":[\"read\",\"readPullRequest\"],\n \"groupPermission\":true\n}",
|
||||
summary = "Add a permission"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "creates",
|
||||
@@ -135,7 +152,7 @@ public class NamespacePermissionResource {
|
||||
@GET
|
||||
@Path("{permission-name}")
|
||||
@Produces(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Get single repository-specific permission", description = "Get the searched permission with permission name related to a repository.", tags = {"Repository", "Permissions"})
|
||||
@Operation(summary = "Get single namespace-specific permission", description = "Get the searched permission with permission name related to a repository.", tags = {"Namespace", "Permissions"})
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "success",
|
||||
@@ -180,7 +197,7 @@ public class NamespacePermissionResource {
|
||||
@GET
|
||||
@Path("")
|
||||
@Produces(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "List of namespace-specific permissions", description = "Get all permissions related to a namespace.", tags = {"Repository", "Permissions"})
|
||||
@Operation(summary = "List of namespace-specific permissions", description = "Get all permissions related to a namespace.", tags = {"Namespace", "Permissions"})
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "success",
|
||||
@@ -220,7 +237,22 @@ public class NamespacePermissionResource {
|
||||
@PUT
|
||||
@Path("{permission-name}")
|
||||
@Consumes(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Update repository-specific permission", description = "Update a permission to the user or group managed by the repository.", tags = {"Repository", "Permissions"})
|
||||
@Operation(
|
||||
summary = "Update namespace-specific permission",
|
||||
description = "Update a permission to the user or group managed by the repository.",
|
||||
tags = {"Namespace", "Permissions"},
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_PERMISSION,
|
||||
schema = @Schema(implementation = UpdateRepositoryPermissionDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Update permissions of manager group.",
|
||||
value = "{\n \"name\":\"manager\",\n \"verbs\":[\"read\",\"permissionRead\",\"readPullRequest\"],\n \"groupPermission\":true\n}",
|
||||
summary = "Update a permission"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(
|
||||
@@ -266,7 +298,7 @@ public class NamespacePermissionResource {
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{permission-name}")
|
||||
@Operation(summary = "Delete repository-specific permission", description = "Delete a permission with the given name.", tags = {"Repository", "Permissions"})
|
||||
@Operation(summary = "Delete namespace-specific permission", description = "Delete a permission with the given name.", tags = {"Namespace", "Permissions"})
|
||||
@ApiResponse(responseCode = "204", description = "delete success or nothing to delete")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized")
|
||||
@@ -325,6 +357,5 @@ public class NamespacePermissionResource {
|
||||
.stream()
|
||||
.anyMatch(p -> p.getName().equals(permission.getName()) && p.isGroupPermission() == permission.isGroupPermission());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
@@ -37,7 +37,7 @@ import javax.validation.constraints.NotNull;
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PermissionListDto extends HalRepresentation {
|
||||
public class PermissionListDto extends HalRepresentation implements UpdatePermissionListDto {
|
||||
|
||||
@NotNull
|
||||
private String[] permissions;
|
||||
|
||||
@@ -27,7 +27,9 @@ package sonia.scm.api.v2.resources;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import sonia.scm.repository.Repository;
|
||||
@@ -160,7 +162,22 @@ public class RepositoryCollectionResource {
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY)
|
||||
@Operation(summary = "Create repository", description = "Creates a new repository.", tags = "Repository")
|
||||
@Operation(
|
||||
summary = "Create repository",
|
||||
description = "Creates a new repository.",
|
||||
tags = "Repository",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY,
|
||||
schema = @Schema(implementation = CreateRepositoryDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Create a new git repository named scm-manager in scmadmin namespace.",
|
||||
value = "{\n \"namespace\":\"scmadmin\",\n \"name\":\"scm-manager\",\n \"type\":\"git\"\n}",
|
||||
summary = "Create a git repository"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "create success",
|
||||
@@ -220,4 +237,5 @@ public class RepositoryCollectionResource {
|
||||
SearchRequest searchRequest = new SearchRequest(search, true);
|
||||
return repository -> SearchUtil.matchesOne(searchRequest, repository.getName(), repository.getNamespace(), repository.getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
@@ -42,7 +42,7 @@ import java.util.List;
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class RepositoryDto extends HalRepresentation {
|
||||
public class RepositoryDto extends HalRepresentation implements CreateRepositoryDto, UpdateRepositoryDto {
|
||||
|
||||
@Email
|
||||
private String contact;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
@@ -39,7 +39,7 @@ import java.util.Collection;
|
||||
|
||||
@Getter @Setter @ToString @NoArgsConstructor
|
||||
@EitherRoleOrVerbs
|
||||
public class RepositoryPermissionDto extends HalRepresentation {
|
||||
public class RepositoryPermissionDto extends HalRepresentation implements UpdateRepositoryPermissionDto {
|
||||
|
||||
public static final String GROUP_PREFIX = "@";
|
||||
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
@@ -91,7 +93,22 @@ public class RepositoryPermissionRootResource {
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Create repository-specific permission", description = "Adds a new permission to the user or group managed by the repository.", tags = {"Repository", "Permissions"})
|
||||
@Operation(
|
||||
summary = "Create repository-specific permission",
|
||||
description = "Adds a new permission to the user or group managed by the repository.",
|
||||
tags = {"Repository", "Permissions"},
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_PERMISSION,
|
||||
schema = @Schema(implementation = UpdateRepositoryPermissionDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Add read permissions for repository and pull requests to manager group.",
|
||||
value = "{\n \"name\":\"manager\",\n \"verbs\":[\"read\",\"readPullRequest\"],\n \"groupPermission\":true\n}",
|
||||
summary = "Add permissions"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "creates",
|
||||
@@ -228,7 +245,21 @@ public class RepositoryPermissionRootResource {
|
||||
@PUT
|
||||
@Path("{permission-name}")
|
||||
@Consumes(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Update repository-specific permission", description = "Update a permission to the user or group managed by the repository.", tags = {"Repository", "Permissions"})
|
||||
@Operation(
|
||||
summary = "Update repository-specific permission",
|
||||
description = "Update a permission to the user or group managed by the repository.",
|
||||
tags = {"Repository", "Permissions"},
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_PERMISSION,
|
||||
schema = @Schema(implementation = UpdateRepositoryPermissionDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Update permissions of manager group.",
|
||||
value = "{\n \"name\":\"manager\",\n \"verbs\":[\"read\",\"permissionRead\",\"readPullRequest\"],\n \"groupPermission\":true\n}",
|
||||
summary = "Update a permission"
|
||||
)
|
||||
)
|
||||
))
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(
|
||||
|
||||
@@ -33,7 +33,7 @@ import javax.validation.constraints.Pattern;
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class RepositoryRenameDto {
|
||||
private String namespace;
|
||||
@Pattern(regexp = ValidationUtil.REGEX_REPOSITORYNAME)
|
||||
private String name;
|
||||
private String namespace;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Repository;
|
||||
@@ -151,7 +153,22 @@ public class RepositoryResource {
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY)
|
||||
@Operation(summary = "Update repository", description = "Modifies the repository for the given namespace and name.", tags = "Repository")
|
||||
@Operation(
|
||||
summary = "Update repository",
|
||||
description = "Modifies the repository for the given namespace and name.",
|
||||
tags = "Repository",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY,
|
||||
schema = @Schema(implementation = UpdateRepositoryDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Update repository description.",
|
||||
value = "{\n \"namespace\":\"scmadmin\",\n \"name\":\"scm-manager\",\n \"description\":\"The easiest way to share and manage your Git, Mercurial and Subversion repositories.\",\n \"type\":\"git\",\n \"lastModified\":\"2020-06-05T14:42:49.000Z\"\n}",
|
||||
summary = "Update a repository"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "400", description = "invalid body, e.g. illegal change of namespace or name")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@@ -273,4 +290,5 @@ public class RepositoryResource {
|
||||
private Predicate<Repository> nameAndNamespaceStaysTheSame(String namespace, String name) {
|
||||
return changed -> name.equals(changed.getName()) && namespace.equals(changed.getNamespace());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.repository.RepositoryRole;
|
||||
import sonia.scm.repository.RepositoryRoleManager;
|
||||
@@ -114,7 +116,22 @@ public class RepositoryRoleCollectionResource {
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY_ROLE)
|
||||
@Operation(summary = "Create repository role", description = "Creates a new repository role.", tags = "Repository role")
|
||||
@Operation(
|
||||
summary = "Create repository role",
|
||||
description = "Creates a new repository role.",
|
||||
tags = "Repository role",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_ROLE,
|
||||
schema = @Schema(implementation = CreateRepositoryRoleDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Create repository role named hero with read and delete repository permission.",
|
||||
value = "{\n \"name\":\"hero\",\n \"system\":false,\n \"verbs\":[\"read\",\"delete\"]\n}",
|
||||
summary = "Add a repository role"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "create success",
|
||||
@@ -137,4 +154,5 @@ public class RepositoryRoleCollectionResource {
|
||||
public Response create(@Valid RepositoryRoleDto repositoryRole) {
|
||||
return adapter.create(repositoryRole, () -> dtoToRepositoryRoleMapper.map(repositoryRole), u -> resourceLinks.repositoryRole().self(u.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Embedded;
|
||||
@@ -38,7 +38,7 @@ import java.util.Collection;
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class RepositoryRoleDto extends HalRepresentation {
|
||||
public class RepositoryRoleDto extends HalRepresentation implements CreateRepositoryRoleDto, UpdateRepositoryRoleDto {
|
||||
@NotEmpty
|
||||
private String name;
|
||||
@NoBlankStrings @NotEmpty
|
||||
|
||||
@@ -21,12 +21,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.repository.RepositoryRole;
|
||||
import sonia.scm.repository.RepositoryRoleManager;
|
||||
@@ -128,7 +130,22 @@ public class RepositoryRoleResource {
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY_ROLE)
|
||||
@Operation(summary = "Update repository role", description = "Modifies the repository role for the given name.", tags = "Repository role")
|
||||
@Operation(
|
||||
summary = "Update repository role",
|
||||
description = "Modifies the repository role for the given name.",
|
||||
tags = "Repository role",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_ROLE,
|
||||
schema = @Schema(implementation = UpdateRepositoryRoleDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Update repository role named hero with this verbs.",
|
||||
value = "{\n \"name\":\"hero\",\n \"system\":false,\n \"verbs\":[\"read\",\"pull\",\"write\",\"push\",\"delete\"],\n \"lastModified\":\"2020-06-05T14:42:49.000Z\"\n}",
|
||||
summary = "Update a repository role"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "400", description = "invalid body, e.g. illegal change of repository role name")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@@ -144,4 +161,5 @@ public class RepositoryRoleResource {
|
||||
public Response update(@PathParam("name") String name, @Valid RepositoryRoleDto repositoryRole) {
|
||||
return adapter.update(name, existing -> dtoToRepositoryRoleMapper.map(repositoryRole));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import sonia.scm.security.AnonymousMode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
interface UpdateConfigDto {
|
||||
String getProxyPassword();
|
||||
|
||||
int getProxyPort();
|
||||
|
||||
String getProxyServer();
|
||||
|
||||
String getProxyUser();
|
||||
|
||||
boolean isEnableProxy();
|
||||
|
||||
String getRealmDescription();
|
||||
|
||||
boolean isDisableGroupingGrid();
|
||||
|
||||
String getDateFormat();
|
||||
|
||||
boolean isAnonymousAccessEnabled();
|
||||
|
||||
AnonymousMode getAnonymousMode();
|
||||
|
||||
String getBaseUrl();
|
||||
|
||||
boolean isForceBaseUrl();
|
||||
|
||||
int getLoginAttemptLimit();
|
||||
|
||||
Set<String> getProxyExcludes();
|
||||
|
||||
boolean isSkipFailedAuthenticators();
|
||||
|
||||
String getPluginUrl();
|
||||
|
||||
long getLoginAttemptLimitTimeout();
|
||||
|
||||
boolean isEnabledXsrfProtection();
|
||||
|
||||
boolean isEnabledUserConverter();
|
||||
|
||||
String getNamespaceStrategy();
|
||||
|
||||
String getLoginInfoUrl();
|
||||
|
||||
String getReleaseFeedUrl();
|
||||
|
||||
String getMailDomainName();
|
||||
}
|
||||
@@ -25,29 +25,26 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is currently only used in the openapi scheme
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class UpdateGroupDto {
|
||||
interface UpdateGroupDto {
|
||||
|
||||
@Pattern(regexp = ValidationUtil.REGEX_NAME)
|
||||
private String name;
|
||||
private String description;
|
||||
String getName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Instant lastModified;
|
||||
private String type;
|
||||
private List<String> members;
|
||||
private boolean external;
|
||||
Instant getLastModified();
|
||||
|
||||
String getType();
|
||||
|
||||
List<String> getMembers();
|
||||
|
||||
boolean isExternal();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
interface UpdatePermissionListDto {
|
||||
|
||||
@NotNull
|
||||
String[] getPermissions();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
interface UpdateRepositoryDto {
|
||||
|
||||
String getNamespace();
|
||||
|
||||
@Pattern(regexp = ValidationUtil.REGEX_REPOSITORYNAME)
|
||||
String getName();
|
||||
|
||||
@NotEmpty
|
||||
String getType();
|
||||
|
||||
@Email
|
||||
String getContact();
|
||||
|
||||
String getDescription();
|
||||
|
||||
List<HealthCheckFailureDto> getHealthCheckFailures();
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
Instant getLastModified();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.util.Collection;
|
||||
|
||||
interface UpdateRepositoryPermissionDto {
|
||||
|
||||
@Pattern(regexp = ValidationUtil.REGEX_NAME)
|
||||
String getName();
|
||||
|
||||
@NoBlankStrings
|
||||
Collection<String> getVerbs();
|
||||
|
||||
String getRole();
|
||||
|
||||
boolean isGroupPermission();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
|
||||
interface UpdateRepositoryRoleDto {
|
||||
|
||||
@NotEmpty
|
||||
String getName();
|
||||
|
||||
@NoBlankStrings
|
||||
@NotEmpty
|
||||
Collection<String> getVerbs();
|
||||
|
||||
String getType();
|
||||
|
||||
Instant getLastModified();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.time.Instant;
|
||||
|
||||
interface UpdateUserDto {
|
||||
|
||||
@Pattern(regexp = ValidationUtil.REGEX_NAME)
|
||||
String getName();
|
||||
|
||||
@NotEmpty
|
||||
String getDisplayName();
|
||||
|
||||
@Email
|
||||
String getMail();
|
||||
|
||||
boolean isExternal();
|
||||
|
||||
String getPassword();
|
||||
|
||||
boolean isActive();
|
||||
|
||||
String getType();
|
||||
|
||||
Instant getLastModified();
|
||||
}
|
||||
@@ -27,7 +27,9 @@ package sonia.scm.api.v2.resources;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
import sonia.scm.search.SearchRequest;
|
||||
@@ -125,7 +127,22 @@ public class UserCollectionResource {
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.USER)
|
||||
@Operation(summary = "Create user", description = "Creates a new user.", tags = "User")
|
||||
@Operation(
|
||||
summary = "Create user",
|
||||
description = "Creates a new user.",
|
||||
tags = "User",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.USER,
|
||||
schema = @Schema(implementation = CreateUserDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Create an internal user.",
|
||||
value = "{\n \"name\":\"mustermann\",\n \"displayName\":\"Max Mustermann\",\n \"mail\":\"m.mustermann@scm-manager.org\",\n \"external\":false,\n \"password\":\"muster42*\",\n \"active\":true\n}",
|
||||
summary = "Create a simple user"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "create success",
|
||||
@@ -156,4 +173,5 @@ public class UserCollectionResource {
|
||||
SearchRequest searchRequest = new SearchRequest(search, true);
|
||||
return user -> SearchUtil.matchesOne(searchRequest, user.getName(), user.getDisplayName(), user.getMail());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import javax.validation.constraints.Pattern;
|
||||
import java.time.Instant;
|
||||
|
||||
@NoArgsConstructor @Getter @Setter
|
||||
public class UserDto extends HalRepresentation {
|
||||
public class UserDto extends HalRepresentation implements CreateUserDto, UpdateUserDto {
|
||||
private boolean active;
|
||||
private boolean external;
|
||||
private Instant creationDate;
|
||||
|
||||
@@ -26,7 +26,9 @@ package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.security.PermissionAssigner;
|
||||
import sonia.scm.security.PermissionDescriptor;
|
||||
@@ -106,7 +108,22 @@ public class UserPermissionResource {
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.PERMISSION_COLLECTION)
|
||||
@Operation(summary = "Update user permissions", description = "Sets permissions for a user. Overwrites all existing permissions.", tags = {"User", "Permissions"})
|
||||
@Operation(
|
||||
summary = "Update user permissions",
|
||||
description = "Sets permissions for a user. Overwrites all existing permissions.",
|
||||
tags = {"User", "Permissions"},
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.PERMISSION_COLLECTION,
|
||||
schema = @Schema(implementation = UpdatePermissionListDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Add read permissions for all repositories and pull requests.",
|
||||
value = "{\n \"permissions\":[\"repository:read,pull:*\",\"repository:readPullRequest:*\"]\n}",
|
||||
summary = "Simple update user permissions"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "400", description = "invalid body")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
|
||||
@@ -26,7 +26,9 @@ package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
import sonia.scm.user.User;
|
||||
@@ -137,7 +139,22 @@ public class UserResource {
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.USER)
|
||||
@Operation(summary = "Update user", description = "Modifies the user for the given id.", tags = "User")
|
||||
@Operation(
|
||||
summary = "Update user",
|
||||
description = "Modifies the user for the given id.",
|
||||
tags = "User",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.USER,
|
||||
schema = @Schema(implementation = UpdateUserDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Update the email address of user mustermann.",
|
||||
value = "{\n \"name\":\"mustermann\",\n \"displayName\":\"Max Mustermann\",\n \"mail\":\"maxmustermann@scm-manager.org\",\n \"external\":false,\n \"active\":true,\n \"lastModified\":\"2020-06-05T14:42:49.000Z\"\n}",
|
||||
summary = "Update a user"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "400", description = "invalid body, e.g. illegal change of id/user name")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@@ -168,7 +185,22 @@ public class UserResource {
|
||||
@PUT
|
||||
@Path("password")
|
||||
@Consumes(VndMediaType.PASSWORD_OVERWRITE)
|
||||
@Operation(summary = "Modifies a user password", description = "Lets admins modifies the user password for the given id.", tags = "User")
|
||||
@Operation(
|
||||
summary = "Modifies a user password",
|
||||
description = "Lets admins modifies the user password for the given id.",
|
||||
tags = "User",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.PASSWORD_OVERWRITE,
|
||||
schema = @Schema(implementation = PasswordOverwriteDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Overwrites current password with a more difficult one.",
|
||||
value = "{ \"newPassword\":\"5cm4dm1n\"\n}",
|
||||
summary = "Set new password"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "400", description = "invalid body, e.g. the user type is not xml or the given oldPassword do not match the stored one")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@@ -199,7 +231,22 @@ public class UserResource {
|
||||
@PUT
|
||||
@Path("convert-to-internal")
|
||||
@Consumes(VndMediaType.USER)
|
||||
@Operation(summary = "Converts an external user to internal", description = "Converts an external user to an internal one and set the new password.", tags = "User")
|
||||
@Operation(
|
||||
summary = "Converts an external user to internal",
|
||||
description = "Converts an external user to an internal one and set the new password.",
|
||||
tags = "User",
|
||||
requestBody = @RequestBody(
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.USER,
|
||||
schema = @Schema(implementation = PasswordOverwriteDto.class),
|
||||
examples = @ExampleObject(
|
||||
name = "Converts an external user to an internal one and set the new password.",
|
||||
value = "{ \"newPassword\":\"5cm4dm1n\"\n}",
|
||||
summary = "Simple converts an user"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "400", description = "invalid body, e.g. the new password is missing")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@@ -255,4 +302,5 @@ public class UserResource {
|
||||
public UserPermissionResource permissions() {
|
||||
return userPermissionResource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.filter;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
@@ -34,6 +34,7 @@ import org.apache.shiro.subject.Subject;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.TransactionId;
|
||||
import sonia.scm.security.DefaultKeyGenerator;
|
||||
import sonia.scm.web.filter.HttpFilter;
|
||||
|
||||
@@ -72,9 +73,6 @@ public class MDCFilter extends HttpFilter
|
||||
@VisibleForTesting
|
||||
static final String MDC_USERNAME = "username";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String MDC_TRANSACTION_ID = "transaction_id";
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -98,7 +96,7 @@ public class MDCFilter extends HttpFilter
|
||||
MDC.put(MDC_CLIENT_HOST, request.getRemoteHost());
|
||||
MDC.put(MDC_REQUEST_METHOD, request.getMethod());
|
||||
MDC.put(MDC_REQUEST_URI, request.getRequestURI());
|
||||
MDC.put(MDC_TRANSACTION_ID, TRANSACTION_KEY_GENERATOR.createKey());
|
||||
TransactionId.set(TRANSACTION_KEY_GENERATOR.createKey());
|
||||
|
||||
try
|
||||
{
|
||||
@@ -111,7 +109,7 @@ public class MDCFilter extends HttpFilter
|
||||
MDC.remove(MDC_CLIENT_HOST);
|
||||
MDC.remove(MDC_REQUEST_METHOD);
|
||||
MDC.remove(MDC_REQUEST_URI);
|
||||
MDC.remove(MDC_TRANSACTION_ID);
|
||||
TransactionId.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
|
||||
import org.apache.shiro.authz.permission.PermissionResolver;
|
||||
import org.apache.shiro.crypto.hash.DefaultHashService;
|
||||
import org.apache.shiro.guice.web.ShiroWebModule;
|
||||
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
||||
import org.apache.shiro.mgt.DefaultSubjectDAO;
|
||||
import org.apache.shiro.mgt.SubjectDAO;
|
||||
import org.apache.shiro.realm.Realm;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@@ -114,14 +117,24 @@ public class ScmSecurityModule extends ShiroWebModule
|
||||
}
|
||||
|
||||
// bind constant
|
||||
bindConstant().annotatedWith(Names.named("shiro.loginUrl")).to(
|
||||
"/index.html");
|
||||
bindConstant().annotatedWith(Names.named("shiro.loginUrl")).to("/index.html");
|
||||
|
||||
// disable access to mustache resources
|
||||
addFilterChain("/**.mustache", filterConfig(ROLES, "nobody"));
|
||||
|
||||
// disable session
|
||||
disableSession();
|
||||
}
|
||||
|
||||
private void disableSession() {
|
||||
addFilterChain("/**", NO_SESSION_CREATION);
|
||||
bindConstant().annotatedWith(Names.named("shiro.sessionStorageEnabled")).to(false);
|
||||
|
||||
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
|
||||
DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
|
||||
sessionStorageEvaluator.setSessionStorageEnabled(false);
|
||||
subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator);
|
||||
bind(SubjectDAO.class).toInstance(subjectDAO);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -192,10 +192,16 @@ public class DefaultPluginManager implements PluginManager {
|
||||
dependencyTracker.addInstalled(plugin.getDescriptor());
|
||||
pendingInstallations.add(pending);
|
||||
eventBus.post(new PluginEvent(PluginEvent.PluginEventType.INSTALLED, plugin));
|
||||
} catch (PluginInstallException ex) {
|
||||
cancelPending(pendingInstallations);
|
||||
eventBus.post(new PluginEvent(PluginEvent.PluginEventType.INSTALLATION_FAILED, plugin));
|
||||
throw ex;
|
||||
} catch (PluginInstallException installException) {
|
||||
try {
|
||||
cancelPending(pendingInstallations);
|
||||
} catch (PluginFailedToCancelInstallationException cancelInstallationException) {
|
||||
LOG.error("could not install plugin {}; uninstallation failed (see next exception)", plugin.getDescriptor().getInformation().getName(), installException);
|
||||
throw cancelInstallationException;
|
||||
} finally {
|
||||
eventBus.post(new PluginEvent(PluginEvent.PluginEventType.INSTALLATION_FAILED, plugin));
|
||||
}
|
||||
throw installException;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@@ -50,10 +50,14 @@ class PendingPluginInstallation {
|
||||
void cancel() {
|
||||
String name = plugin.getDescriptor().getInformation().getName();
|
||||
LOG.info("cancel installation of plugin {}", name);
|
||||
try {
|
||||
Files.delete(file);
|
||||
} catch (IOException ex) {
|
||||
throw new PluginFailedToCancelInstallationException("failed to cancel plugin installation ", name, ex);
|
||||
if (Files.exists(file)) {
|
||||
try {
|
||||
Files.delete(file);
|
||||
} catch (IOException ex) {
|
||||
throw new PluginFailedToCancelInstallationException("failed to cancel plugin installation ", name, ex);
|
||||
}
|
||||
} else {
|
||||
LOG.info("plugin file {} did not exists for plugin {}; nothing deleted", file, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +108,8 @@ public final class PluginTree
|
||||
throw new PluginConditionFailedException(
|
||||
condition,
|
||||
String.format(
|
||||
"could not load plugin %s, the plugin condition does not match",
|
||||
plugin.getInformation().getId()
|
||||
"could not load plugin %s, the plugin condition does not match: %s",
|
||||
plugin.getInformation().getId(), condition
|
||||
)
|
||||
);
|
||||
//J+
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
|
||||
package sonia.scm.security;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Maps;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
@@ -56,6 +58,12 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JwtAccessTokenBuilder.class);
|
||||
|
||||
@VisibleForTesting
|
||||
static final long DEFAULT_REFRESHABLE = 12L;
|
||||
|
||||
@VisibleForTesting
|
||||
static final TimeUnit DEFAULT_REFRESHABLE_UNIT = TimeUnit.HOURS;
|
||||
|
||||
private final KeyGenerator keyGenerator;
|
||||
private final SecureKeyResolver keyResolver;
|
||||
private final Clock clock;
|
||||
@@ -64,8 +72,8 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
private String issuer;
|
||||
private long expiresIn = 1;
|
||||
private TimeUnit expiresInUnit = TimeUnit.HOURS;
|
||||
private long refreshableFor = 12;
|
||||
private TimeUnit refreshableForUnit = TimeUnit.HOURS;
|
||||
private long refreshableFor = DEFAULT_REFRESHABLE;
|
||||
private TimeUnit refreshableForUnit = DEFAULT_REFRESHABLE_UNIT;
|
||||
private Instant refreshExpiration;
|
||||
private String parentKeyId;
|
||||
private Scope scope = Scope.empty();
|
||||
@@ -87,8 +95,6 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
|
||||
@Override
|
||||
public JwtAccessTokenBuilder custom(String key, Object value) {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(key), "null or empty value not allowed");
|
||||
Preconditions.checkArgument(value != null, "null or empty value not allowed");
|
||||
this.custom.put(key, value);
|
||||
return this;
|
||||
}
|
||||
@@ -183,8 +189,8 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
|
||||
|
||||
if (refreshableFor > 0) {
|
||||
long refreshExpiration = refreshableForUnit.toMillis(refreshableFor);
|
||||
claims.put(JwtAccessToken.REFRESHABLE_UNTIL_CLAIM_KEY, new Date(now.toEpochMilli() + refreshExpiration).getTime());
|
||||
long re = refreshableForUnit.toMillis(refreshableFor);
|
||||
claims.put(JwtAccessToken.REFRESHABLE_UNTIL_CLAIM_KEY, Date.from(now.plusMillis(re)));
|
||||
} else if (refreshExpiration != null) {
|
||||
claims.put(JwtAccessToken.REFRESHABLE_UNTIL_CLAIM_KEY, Date.from(refreshExpiration));
|
||||
}
|
||||
@@ -198,10 +204,11 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
claims.setIssuer(issuer);
|
||||
}
|
||||
|
||||
|
||||
// sign token and create compact version
|
||||
String compact = Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.signWith(SignatureAlgorithm.HS256, key.getBytes())
|
||||
.signWith(Keys.hmacShaKeyFor(key.getBytes()), SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
|
||||
return new JwtAccessToken(claims, compact);
|
||||
|
||||
Reference in New Issue
Block a user