getUserTypeChecker() {
+ return user -> {
+ if (!isTypeDefault(user)) {
+ throw new ChangePasswordNotAllowedException(MessageFormat.format(WRONG_USER_TYPE, user.getType()));
+ }
+ };
+ }
+
+ default boolean isTypeDefault(User user) {
+ return getDefaultType().equals(user.getType());
+ }
+
+
}
diff --git a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java
index d9a6846795..14350902a2 100644
--- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java
+++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java
@@ -21,7 +21,7 @@ public class VndMediaType {
public static final String PERMISSION = PREFIX + "permission" + SUFFIX;
public static final String CHANGESET = PREFIX + "changeset" + SUFFIX;
public static final String CHANGESET_COLLECTION = PREFIX + "changesetCollection" + SUFFIX;
- public static final String MODIFICATIONS = PREFIX + "modifications" + SUFFIX;;
+ public static final String MODIFICATIONS = PREFIX + "modifications" + SUFFIX;
public static final String TAG = PREFIX + "tag" + SUFFIX;
public static final String TAG_COLLECTION = PREFIX + "tagCollection" + SUFFIX;
public static final String BRANCH = PREFIX + "branch" + SUFFIX;
@@ -35,6 +35,8 @@ public class VndMediaType {
public static final String REPOSITORY_TYPE = PREFIX + "repositoryType" + SUFFIX;
public static final String UI_PLUGIN = PREFIX + "uiPlugin" + SUFFIX;
public static final String UI_PLUGIN_COLLECTION = PREFIX + "uiPluginCollection" + SUFFIX;
+ @SuppressWarnings("squid:S2068")
+ public static final String PASSWORD_CHANGE = PREFIX + "passwordChange" + SUFFIX;
public static final String ME = PREFIX + "me" + SUFFIX;
public static final String SOURCE = PREFIX + "source" + SUFFIX;
diff --git a/scm-it/src/test/java/sonia/scm/it/MeITCase.java b/scm-it/src/test/java/sonia/scm/it/MeITCase.java
new file mode 100644
index 0000000000..1c7b5c9e03
--- /dev/null
+++ b/scm-it/src/test/java/sonia/scm/it/MeITCase.java
@@ -0,0 +1,79 @@
+package sonia.scm.it;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import sonia.scm.it.utils.ScmRequests;
+import sonia.scm.it.utils.TestData;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MeITCase {
+
+ @Before
+ public void init() {
+ TestData.cleanup();
+ }
+
+ @Test
+ public void adminShouldChangeOwnPassword() {
+ String newPassword = TestData.USER_SCM_ADMIN + "1";
+ // admin change the own password
+ ScmRequests.start()
+ .given()
+ .url(TestData.getMeUrl())
+ .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN)
+ .getMeResource()
+ .assertStatusCode(200)
+ .usingMeResponse()
+ .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))
+ .assertPassword(Assert::assertNull)
+ .assertType(s -> assertThat(s).isEqualTo("xml"))
+ .requestChangePassword(TestData.USER_SCM_ADMIN, newPassword)
+ .assertStatusCode(204);
+ // assert password is changed -> login with the new Password than undo changes
+ ScmRequests.start()
+ .given()
+ .url(TestData.getUserUrl(TestData.USER_SCM_ADMIN))
+ .usernameAndPassword(TestData.USER_SCM_ADMIN, newPassword)
+ .getMeResource()
+ .assertStatusCode(200)
+ .usingMeResponse()
+ .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))// still admin
+ .requestChangePassword(newPassword, TestData.USER_SCM_ADMIN)
+ .assertStatusCode(204);
+ }
+
+ @Test
+ public void shouldHidePasswordLinkIfUserTypeIsNotXML() {
+ String newUser = "user";
+ String password = "pass";
+ String type = "not XML Type";
+ TestData.createUser(newUser, password, true, type);
+ ScmRequests.start()
+ .given()
+ .url(TestData.getMeUrl())
+ .usernameAndPassword(newUser, password)
+ .getMeResource()
+ .assertStatusCode(200)
+ .usingMeResponse()
+ .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))
+ .assertPassword(Assert::assertNull)
+ .assertType(s -> assertThat(s).isEqualTo(type))
+ .assertPasswordLinkDoesNotExists();
+ }
+
+ @Test
+ public void shouldGet403IfUserIsNotAdmin() {
+ String newUser = "user";
+ String password = "pass";
+ String type = "xml";
+ TestData.createUser(newUser, password, false, type);
+ ScmRequests.start()
+ .given()
+ .url(TestData.getMeUrl())
+ .usernameAndPassword(newUser, password)
+ .getMeResource()
+ .assertStatusCode(403);
+ }
+}
diff --git a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java
index 63d8b46d47..f288d4891c 100644
--- a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java
+++ b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java
@@ -39,6 +39,8 @@ import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+import sonia.scm.it.utils.RepositoryUtil;
+import sonia.scm.it.utils.TestData;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.client.api.RepositoryClient;
import sonia.scm.repository.client.api.RepositoryClientException;
@@ -51,11 +53,11 @@ import java.util.Objects;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import static sonia.scm.it.RepositoryUtil.addAndCommitRandomFile;
-import static sonia.scm.it.RestUtil.given;
-import static sonia.scm.it.ScmTypes.availableScmTypes;
-import static sonia.scm.it.TestData.USER_SCM_ADMIN;
-import static sonia.scm.it.TestData.callRepository;
+import static sonia.scm.it.utils.RepositoryUtil.addAndCommitRandomFile;
+import static sonia.scm.it.utils.RestUtil.given;
+import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
+import static sonia.scm.it.utils.TestData.USER_SCM_ADMIN;
+import static sonia.scm.it.utils.TestData.callRepository;
@RunWith(Parameterized.class)
public class PermissionsITCase {
diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoriesITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoriesITCase.java
index 21d4d97b1b..c49a65bea2 100644
--- a/scm-it/src/test/java/sonia/scm/it/RepositoriesITCase.java
+++ b/scm-it/src/test/java/sonia/scm/it/RepositoriesITCase.java
@@ -42,6 +42,8 @@ import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+import sonia.scm.it.utils.RepositoryUtil;
+import sonia.scm.it.utils.TestData;
import sonia.scm.repository.client.api.RepositoryClient;
import sonia.scm.web.VndMediaType;
@@ -53,11 +55,11 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
-import static sonia.scm.it.RegExMatcher.matchesPattern;
-import static sonia.scm.it.RestUtil.createResourceUrl;
-import static sonia.scm.it.RestUtil.given;
-import static sonia.scm.it.ScmTypes.availableScmTypes;
-import static sonia.scm.it.TestData.repositoryJson;
+import static sonia.scm.it.utils.RegExMatcher.matchesPattern;
+import static sonia.scm.it.utils.RestUtil.createResourceUrl;
+import static sonia.scm.it.utils.RestUtil.given;
+import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
+import static sonia.scm.it.utils.TestData.repositoryJson;
@RunWith(Parameterized.class)
public class RepositoriesITCase {
diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java
index 398921a692..3f8832a3f5 100644
--- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java
+++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java
@@ -4,7 +4,6 @@ import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import org.apache.http.HttpStatus;
import org.assertj.core.util.Lists;
-import org.assertj.core.util.Maps;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
@@ -12,6 +11,9 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import sonia.scm.it.utils.RepositoryUtil;
+import sonia.scm.it.utils.ScmRequests;
+import sonia.scm.it.utils.TestData;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.client.api.ClientCommand;
import sonia.scm.repository.client.api.RepositoryClient;
@@ -29,10 +31,10 @@ import static java.lang.Thread.sleep;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNotNull;
-import static sonia.scm.it.RestUtil.ADMIN_PASSWORD;
-import static sonia.scm.it.RestUtil.ADMIN_USERNAME;
-import static sonia.scm.it.RestUtil.given;
-import static sonia.scm.it.ScmTypes.availableScmTypes;
+import static sonia.scm.it.utils.RestUtil.ADMIN_PASSWORD;
+import static sonia.scm.it.utils.RestUtil.ADMIN_USERNAME;
+import static sonia.scm.it.utils.RestUtil.given;
+import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
@RunWith(Parameterized.class)
public class RepositoryAccessITCase {
@@ -42,7 +44,7 @@ public class RepositoryAccessITCase {
private final String repositoryType;
private File folder;
- private RepositoryRequests.AppliedRepositoryGetRequest repositoryGetRequest;
+ private ScmRequests.AppliedRepositoryRequest repositoryGetRequest;
public RepositoryAccessITCase(String repositoryType) {
this.repositoryType = repositoryType;
@@ -57,12 +59,17 @@ public class RepositoryAccessITCase {
public void init() {
TestData.createDefault();
folder = tempFolder.getRoot();
- repositoryGetRequest = RepositoryRequests.start()
+ repositoryGetRequest = ScmRequests.start()
.given()
.url(TestData.getDefaultRepositoryUrl(repositoryType))
.usernameAndPassword(ADMIN_USERNAME, ADMIN_PASSWORD)
- .get()
+ .getRepositoryResource()
.assertStatusCode(HttpStatus.SC_OK);
+ ScmRequests.AppliedMeRequest meGetRequest = ScmRequests.start()
+ .given()
+ .url(TestData.getMeUrl())
+ .usernameAndPassword(ADMIN_USERNAME, ADMIN_PASSWORD)
+ .getMeResource();
}
@Test
@@ -165,7 +172,7 @@ public class RepositoryAccessITCase {
.isNotNull()
.contains(String.format("%s/sources/%s", repositoryUrl, changeset.getId()));
- assertThat(response.body().jsonPath().getString("_embedded.tags.find{it.name=='" + tagName + "'}._links.changesets.href"))
+ assertThat(response.body().jsonPath().getString("_embedded.tags.find{it.name=='" + tagName + "'}._links.changeset.href"))
.as("assert single tag changesets link")
.isNotNull()
.contains(String.format("%s/changesets/%s", repositoryUrl, changeset.getId()));
diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java b/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java
deleted file mode 100644
index 79300d7b45..0000000000
--- a/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java
+++ /dev/null
@@ -1,293 +0,0 @@
-package sonia.scm.it;
-
-import io.restassured.RestAssured;
-import io.restassured.response.Response;
-
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-
-
-/**
- * Encapsulate rest requests of a repository in builder pattern
- *
- * A Get Request can be applied with the methods request*()
- * These methods return a AppliedGet*Request object
- * This object can be used to apply general assertions over the rest Assured response
- * In the AppliedGet*Request classes there is a using*Response() method
- * that return the *Response class containing specific operations related to the specific response
- * the *Response class contains also the request*() method to apply the next GET request from a link in the response.
- */
-public class RepositoryRequests {
-
- private String url;
- private String username;
- private String password;
-
- static RepositoryRequests start() {
- return new RepositoryRequests();
- }
-
- Given given() {
- return new Given();
- }
-
-
- /**
- * Apply a GET Request to the extracted url from the given link
- *
- * @param linkPropertyName the property name of link
- * @param response the response containing the link
- * @return the response of the GET request using the given link
- */
- private Response getResponseFromLink(Response response, String linkPropertyName) {
- return getResponse(response
- .then()
- .extract()
- .path(linkPropertyName));
- }
-
-
- /**
- * Apply a GET Request to the given url and return the response.
- *
- * @param url the url of the GET request
- * @return the response of the GET request using the given url
- */
- private Response getResponse(String url) {
- return RestAssured.given()
- .auth().preemptive().basic(username, password)
- .when()
- .get(url);
- }
-
- private void setUrl(String url) {
- this.url = url;
- }
-
- private void setUsername(String username) {
- this.username = username;
- }
-
- private void setPassword(String password) {
- this.password = password;
- }
-
- private String getUrl() {
- return url;
- }
-
- private String getUsername() {
- return username;
- }
-
- private String getPassword() {
- return password;
- }
-
- class Given {
-
- GivenUrl url(String url) {
- setUrl(url);
- return new GivenUrl();
- }
-
- }
-
- class GivenWithUrlAndAuth {
- AppliedRepositoryGetRequest get() {
- return new AppliedRepositoryGetRequest(
- getResponse(url)
- );
- }
- }
-
- class AppliedGetRequest {
- private Response response;
-
- public AppliedGetRequest(Response response) {
- this.response = response;
- }
-
- /**
- * apply custom assertions to the actual response
- *
- * @param consumer consume the response in order to assert the content. the header, the payload etc..
- * @return the self object
- */
- SELF assertResponse(Consumer consumer) {
- consumer.accept(response);
- return (SELF) this;
- }
-
- /**
- * special assertion of the status code
- *
- * @param expectedStatusCode the expected status code
- * @return the self object
- */
- SELF assertStatusCode(int expectedStatusCode) {
- this.response.then().assertThat().statusCode(expectedStatusCode);
- return (SELF) this;
- }
-
- }
-
- class AppliedRepositoryGetRequest extends AppliedGetRequest {
-
- AppliedRepositoryGetRequest(Response response) {
- super(response);
- }
-
- RepositoryResponse usingRepositoryResponse() {
- return new RepositoryResponse(super.response);
- }
- }
-
- class RepositoryResponse {
-
- private Response repositoryResponse;
-
- public RepositoryResponse(Response repositoryResponse) {
- this.repositoryResponse = repositoryResponse;
- }
-
- AppliedGetSourcesRequest requestSources() {
- return new AppliedGetSourcesRequest(getResponseFromLink(repositoryResponse, "_links.sources.href"));
- }
-
- AppliedGetChangesetsRequest requestChangesets() {
- return new AppliedGetChangesetsRequest(getResponseFromLink(repositoryResponse, "_links.changesets.href"));
- }
- }
-
- class AppliedGetChangesetsRequest extends AppliedGetRequest {
-
- AppliedGetChangesetsRequest(Response response) {
- super(response);
- }
-
- ChangesetsResponse usingChangesetsResponse() {
- return new ChangesetsResponse(super.response);
- }
- }
-
- class ChangesetsResponse {
- private Response changesetsResponse;
-
- public ChangesetsResponse(Response changesetsResponse) {
- this.changesetsResponse = changesetsResponse;
- }
-
- ChangesetsResponse assertChangesets(Consumer> changesetsConsumer) {
- List