diff --git a/Jenkinsfile b/Jenkinsfile
index e817ac2ba1..0f586bf346 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -51,9 +51,9 @@ node('docker') {
if (isMainBranch()) {
- stage('Lifecycle') {
- nexusPolicyEvaluation iqApplication: selectedApplication('scm'), iqScanPatterns: [[scanPattern: 'scm-server/target/scm-server-app.zip']], iqStage: 'build'
- }
+// stage('Lifecycle') {
+// nexusPolicyEvaluation iqApplication: selectedApplication('scm'), iqScanPatterns: [[scanPattern: 'scm-server/target/scm-server-app.zip']], iqStage: 'build'
+// }
stage('Archive') {
archiveArtifacts 'scm-webapp/target/scm-webapp.war'
diff --git a/pom.xml b/pom.xml
index a7108df873..d8437f2934 100644
--- a/pom.xml
+++ b/pom.xml
@@ -826,7 +826,7 @@
9.4.14.v20181114
- 1.1.0
+ 1.2.01.4.0
diff --git a/scm-core/src/main/java/sonia/scm/config/Configuration.java b/scm-core/src/main/java/sonia/scm/config/Configuration.java
index 823c50b155..4019925c27 100644
--- a/scm-core/src/main/java/sonia/scm/config/Configuration.java
+++ b/scm-core/src/main/java/sonia/scm/config/Configuration.java
@@ -22,7 +22,8 @@ import com.github.sdorra.ssp.StaticPermissions;
@StaticPermissions(
value = "configuration",
permissions = {"read", "write"},
- globalPermissions = {"list"}
+ globalPermissions = {"list"},
+ custom = true, customGlobal = true
)
public interface Configuration extends PermissionObject {
}
diff --git a/scm-core/src/main/java/sonia/scm/group/Group.java b/scm-core/src/main/java/sonia/scm/group/Group.java
index c0b3c2ee8b..8860545c93 100644
--- a/scm-core/src/main/java/sonia/scm/group/Group.java
+++ b/scm-core/src/main/java/sonia/scm/group/Group.java
@@ -61,7 +61,11 @@ import java.util.List;
*
* @author Sebastian Sdorra
*/
-@StaticPermissions(value = "group", globalPermissions = {"create", "list", "autocomplete"})
+@StaticPermissions(
+ value = "group",
+ globalPermissions = {"create", "list", "autocomplete"},
+ custom = true, customGlobal = true
+)
@XmlRootElement(name = "groups")
@XmlAccessorType(XmlAccessType.FIELD)
public class Group extends BasicPropertiesAware
diff --git a/scm-core/src/main/java/sonia/scm/group/GroupNames.java b/scm-core/src/main/java/sonia/scm/group/GroupNames.java
index 24d32972b6..faeec7218b 100644
--- a/scm-core/src/main/java/sonia/scm/group/GroupNames.java
+++ b/scm-core/src/main/java/sonia/scm/group/GroupNames.java
@@ -70,21 +70,9 @@ public final class GroupNames implements Serializable, Iterable
* Constructs ...
*
*/
- @SuppressWarnings("unchecked")
public GroupNames()
{
- this.collection = Collections.EMPTY_LIST;
- }
-
- /**
- * Constructs ...
- *
- *
- * @param collection
- */
- public GroupNames(Collection collection)
- {
- this.collection = Collections.unmodifiableCollection(collection);
+ this(Collections.emptyList());
}
/**
@@ -96,7 +84,30 @@ public final class GroupNames implements Serializable, Iterable
*/
public GroupNames(String groupName, String... groupNames)
{
- this.collection = Lists.asList(groupName, groupNames);
+ this(Lists.asList(groupName, groupNames));
+ }
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param collection
+ */
+ public GroupNames(Collection collection)
+ {
+ this(collection, false);
+ }
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param collection
+ */
+ public GroupNames(Collection collection, boolean external)
+ {
+ this.collection = Collections.unmodifiableCollection(collection);
+ this.external = external;
}
//~--- methods --------------------------------------------------------------
@@ -165,7 +176,7 @@ public final class GroupNames implements Serializable, Iterable
@Override
public String toString()
{
- return Joiner.on(", ").join(collection);
+ return Joiner.on(", ").join(collection) + "(" + (external? "external": "internal") + ")";
}
//~--- get methods ----------------------------------------------------------
@@ -181,8 +192,13 @@ public final class GroupNames implements Serializable, Iterable
return collection;
}
- //~--- fields ---------------------------------------------------------------
+ public boolean isExternal() {
+ return external;
+ }
+ //~--- fields ---------------------------------------------------------------
/** Field description */
private final Collection collection;
+
+ private final boolean external;
}
diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java
index 3ae359ceb7..6de52c3cca 100644
--- a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java
+++ b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java
@@ -61,7 +61,8 @@ import java.util.List;
value = "plugin",
generatedClass = "PluginPermissions",
permissions = {},
- globalPermissions = { "read", "manage" }
+ globalPermissions = { "read", "manage" },
+ custom = true, customGlobal = true
)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "plugin-information")
diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java
index 568b75e525..18613c1a12 100644
--- a/scm-core/src/main/java/sonia/scm/repository/Repository.java
+++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java
@@ -62,7 +62,8 @@ import java.util.Set;
*/
@StaticPermissions(
value = "repository",
- permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"}
+ permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"},
+ custom = true, customGlobal = true
)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "repositories")
diff --git a/scm-core/src/main/java/sonia/scm/security/Permission.java b/scm-core/src/main/java/sonia/scm/security/Permission.java
index 1b7c34f740..a7aa2798e7 100644
--- a/scm-core/src/main/java/sonia/scm/security/Permission.java
+++ b/scm-core/src/main/java/sonia/scm/security/Permission.java
@@ -6,7 +6,8 @@ import com.github.sdorra.ssp.StaticPermissions;
@StaticPermissions(
value = "permission",
permissions = {},
- globalPermissions = {"list", "read", "assign"}
+ globalPermissions = {"list", "read", "assign"},
+ custom = true, customGlobal = true
)
public interface Permission extends PermissionObject {
}
diff --git a/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java b/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java
index 0e3c06e32d..da11400140 100644
--- a/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java
+++ b/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java
@@ -45,7 +45,12 @@ import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import sonia.scm.web.security.AdministrationContext;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
/**
* Helper class for syncing realms. The class should simplify the creation of realms, which are syncing authenticated
@@ -80,22 +85,107 @@ public final class SyncingRealmHelper {
this.groupManager = groupManager;
}
- //~--- methods --------------------------------------------------------------
/**
* Create {@link AuthenticationInfo} from user and groups.
- *
- *
- * @param realm name of the realm
- * @param user authenticated user
- * @param groups groups of the authenticated user
- *
- * @return authentication info
*/
- public AuthenticationInfo createAuthenticationInfo(String realm, User user,
- String... groups) {
- return createAuthenticationInfo(realm, user, ImmutableList.copyOf(groups));
+ public AuthenticationInfoBuilder.ForRealm authenticationInfo() {
+ return new AuthenticationInfoBuilder().new ForRealm();
}
+ public class AuthenticationInfoBuilder {
+ private String realm;
+ private User user;
+ private Collection groups;
+ private boolean external;
+
+ private AuthenticationInfo build() {
+ return SyncingRealmHelper.this.createAuthenticationInfo(realm, user, groups, external);
+ }
+
+ public class ForRealm {
+ private ForRealm() {
+ }
+
+ /**
+ * Sets the realm.
+ * @param realm name of the realm
+ */
+ public ForUser forRealm(String realm) {
+ AuthenticationInfoBuilder.this.realm = realm;
+ return AuthenticationInfoBuilder.this.new ForUser();
+ }
+ }
+
+ public class ForUser {
+ private ForUser() {
+ }
+
+ /**
+ * Sets the user.
+ * @param user authenticated user
+ */
+ public AuthenticationInfoBuilder.WithGroups andUser(User user) {
+ AuthenticationInfoBuilder.this.user = user;
+ return AuthenticationInfoBuilder.this.new WithGroups();
+ }
+ }
+
+ public class WithGroups {
+ private WithGroups() {
+ }
+
+ /**
+ * Build the authentication info without groups.
+ * @return The complete {@link AuthenticationInfo}
+ */
+ public AuthenticationInfo withoutGroups() {
+ return withGroups(emptyList());
+ }
+
+ /**
+ * Set the internal groups for the user.
+ * @param groups groups of the authenticated user
+ * @return The complete {@link AuthenticationInfo}
+ */
+ public AuthenticationInfo withGroups(String... groups) {
+ return withGroups(asList(groups));
+ }
+
+ /**
+ * Set the internal groups for the user.
+ * @param groups groups of the authenticated user
+ * @return The complete {@link AuthenticationInfo}
+ */
+ public AuthenticationInfo withGroups(Collection groups) {
+ AuthenticationInfoBuilder.this.groups = groups;
+ AuthenticationInfoBuilder.this.external = false;
+ return build();
+ }
+
+ /**
+ * Set the external groups for the user.
+ * @param groups external groups of the authenticated user
+ * @return The complete {@link AuthenticationInfo}
+ */
+ public AuthenticationInfo withExternalGroups(String... groups) {
+ return withExternalGroups(asList(groups));
+ }
+
+ /**
+ * Set the external groups for the user.
+ * @param groups external groups of the authenticated user
+ * @return The complete {@link AuthenticationInfo}
+ */
+ public AuthenticationInfo withExternalGroups(Collection groups) {
+ AuthenticationInfoBuilder.this.groups = groups;
+ AuthenticationInfoBuilder.this.external = true;
+ return build();
+ }
+ }
+ }
+
+ //~--- methods --------------------------------------------------------------
+
/**
* Create {@link AuthenticationInfo} from user and groups.
*
@@ -106,13 +196,13 @@ public final class SyncingRealmHelper {
*
* @return authentication info
*/
- public AuthenticationInfo createAuthenticationInfo(String realm, User user,
- Collection groups) {
+ private AuthenticationInfo createAuthenticationInfo(String realm, User user,
+ Collection groups, boolean externalGroups) {
SimplePrincipalCollection collection = new SimplePrincipalCollection();
collection.add(user.getId(), realm);
collection.add(user, realm);
- collection.add(new GroupNames(groups), realm);
+ collection.add(new GroupNames(groups, externalGroups), realm);
return new SimpleAuthenticationInfo(collection, user.getPassword());
}
@@ -161,6 +251,6 @@ public final class SyncingRealmHelper {
}
}
- });
- }
+ });
}
+}
diff --git a/scm-core/src/main/java/sonia/scm/user/User.java b/scm-core/src/main/java/sonia/scm/user/User.java
index cae383a402..3c185ae3b8 100644
--- a/scm-core/src/main/java/sonia/scm/user/User.java
+++ b/scm-core/src/main/java/sonia/scm/user/User.java
@@ -59,7 +59,9 @@ import java.security.Principal;
@StaticPermissions(
value = "user",
globalPermissions = {"create", "list", "autocomplete"},
- permissions = {"read", "modify", "delete", "changePassword"})
+ permissions = {"read", "modify", "delete", "changePassword"},
+ custom = true, customGlobal = true
+)
@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject, ReducedModelObject
diff --git a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java
index 50bde53ae1..b8d6ae909e 100644
--- a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java
+++ b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java
@@ -37,6 +37,7 @@ package sonia.scm.security;
import com.google.common.base.Throwables;
import org.apache.shiro.authc.AuthenticationInfo;
+import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,10 +54,14 @@ import sonia.scm.web.security.PrivilegedAction;
import java.io.IOException;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.util.Arrays.asList;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -106,25 +111,6 @@ public class SyncingRealmHelperTest {
helper = new SyncingRealmHelper(ctx, userManager, groupManager);
}
- /**
- * Tests {@link SyncingRealmHelper#createAuthenticationInfo(String, User, String...)}.
- */
- @Test
- public void testCreateAuthenticationInfo() {
- User user = new User("tricia");
- AuthenticationInfo authInfo = helper.createAuthenticationInfo("unit-test",
- user, "heartOfGold");
-
- assertNotNull(authInfo);
- assertEquals("tricia", authInfo.getPrincipals().getPrimaryPrincipal());
- assertThat(authInfo.getPrincipals().getRealmNames(), hasItem("unit-test"));
- assertEquals(user, authInfo.getPrincipals().oneByType(User.class));
-
- GroupNames groups = authInfo.getPrincipals().oneByType(GroupNames.class);
-
- assertThat(groups, hasItem("heartOfGold"));
- }
-
/**
* Tests {@link SyncingRealmHelper#store(Group)}.
*
@@ -198,4 +184,45 @@ public class SyncingRealmHelperTest {
helper.store(user);
verify(userManager, times(1)).modify(user);
}
+
+ @Test
+ public void builderShouldSetInternalGroups() {
+ AuthenticationInfo authenticationInfo = helper
+ .authenticationInfo()
+ .forRealm("unit-test")
+ .andUser(new User("ziltoid"))
+ .withGroups("internal");
+
+ GroupNames groupNames = authenticationInfo.getPrincipals().oneByType(GroupNames.class);
+ Assertions.assertThat(groupNames.getCollection()).containsOnly("internal");
+ Assertions.assertThat(groupNames.isExternal()).isFalse();
+ }
+
+ @Test
+ public void builderShouldSetExternalGroups() {
+ AuthenticationInfo authenticationInfo = helper
+ .authenticationInfo()
+ .forRealm("unit-test")
+ .andUser(new User("ziltoid"))
+ .withExternalGroups("external");
+
+ GroupNames groupNames = authenticationInfo.getPrincipals().oneByType(GroupNames.class);
+ Assertions.assertThat(groupNames.getCollection()).containsOnly("external");
+ Assertions.assertThat(groupNames.isExternal()).isTrue();
+ }
+
+ @Test
+ public void builderShouldSetValues() {
+ User user = new User("ziltoid");
+ AuthenticationInfo authInfo = helper
+ .authenticationInfo()
+ .forRealm("unit-test")
+ .andUser(user)
+ .withoutGroups();
+
+ assertNotNull(authInfo);
+ assertEquals("ziltoid", authInfo.getPrincipals().getPrimaryPrincipal());
+ assertThat(authInfo.getPrincipals().getRealmNames(), hasItem("unit-test"));
+ assertEquals(user, authInfo.getPrincipals().oneByType(User.class));
+ }
}
diff --git a/scm-plugins/scm-git-plugin/package.json b/scm-plugins/scm-git-plugin/package.json
index 1805f0665b..8d5ac3165b 100644
--- a/scm-plugins/scm-git-plugin/package.json
+++ b/scm-plugins/scm-git-plugin/package.json
@@ -12,6 +12,6 @@
"@scm-manager/ui-extensions": "^0.1.2"
},
"devDependencies": {
- "@scm-manager/ui-bundler": "^0.0.24"
+ "@scm-manager/ui-bundler": "^0.0.25"
}
}
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigInIndexResource.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigInIndexResource.java
index a1120adda4..e6d7546ff4 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigInIndexResource.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigInIndexResource.java
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import sonia.scm.config.ConfigurationPermissions;
import sonia.scm.plugin.Extension;
+import sonia.scm.repository.GitConfig;
import sonia.scm.web.JsonEnricherBase;
import sonia.scm.web.JsonEnricherContext;
@@ -26,7 +27,7 @@ public class GitConfigInIndexResource extends JsonEnricherBase {
@Override
public void enrich(JsonEnricherContext context) {
- if (resultHasMediaType(INDEX, context) && ConfigurationPermissions.list().isPermitted()) {
+ if (resultHasMediaType(INDEX, context) && ConfigurationPermissions.read(GitConfig.PERMISSION).isPermitted()) {
String gitConfigUrl = new LinkBuilder(scmPathInfoStore.get().get(), GitConfigResource.class)
.method("get")
.parameters()
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java
index a9b9e25aca..95215607fe 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitPushOrPullCommand.java
@@ -43,6 +43,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RemoteRefUpdate;
+import org.eclipse.jgit.transport.ScmTransportProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitRepositoryHandler;
@@ -62,7 +63,7 @@ public abstract class AbstractGitPushOrPullCommand extends AbstractGitCommand
{
/** Field description */
- private static final String SCHEME = "scm://";
+ private static final String SCHEME = ScmTransportProtocol.NAME + "://";
/**
* the logger for AbstractGitPushOrPullCommand
@@ -167,7 +168,7 @@ public abstract class AbstractGitPushOrPullCommand extends AbstractGitCommand
}
else
{
- throw new IllegalArgumentException("repository or url is requiered");
+ throw new IllegalArgumentException("repository or url is required");
}
return url;
diff --git a/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/permissions.xml b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/permissions.xml
index da11b5164a..4823cb5f4f 100644
--- a/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/permissions.xml
+++ b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/permissions.xml
@@ -34,10 +34,10 @@
- configuration:read:git
+ configuration:read,write:git
- configuration:write:git
+ repository:git:*
diff --git a/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/repository-permissions.xml b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/repository-permissions.xml
new file mode 100644
index 0000000000..6c93929625
--- /dev/null
+++ b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/repository-permissions.xml
@@ -0,0 +1,7 @@
+
+
+ git
+
+
+
+
diff --git a/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json b/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json
index cd88897e74..578d859c8e 100644
--- a/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json
+++ b/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json
@@ -39,18 +39,28 @@
},
"permissions" : {
"configuration": {
- "read": {
+ "read,write": {
"git": {
- "displayName": "Git Konfiguration lesen",
- "description": "Darf die git Konfiguration lesen."
- }
- },
- "write": {
- "git": {
- "displayName": "Git Konfiguration schreiben",
+ "displayName": "Git Konfiguration ändern",
"description": "Darf die git Konfiguration verändern."
}
}
+ },
+ "repository": {
+ "git": {
+ "*": {
+ "displayName": "Repository-spezifische Git Konfiguration ändern",
+ "description": "Darf die git Konfiguration für alle Repositories verändern."
+ }
+ }
+ }
+ },
+ "verbs": {
+ "repository": {
+ "git": {
+ "displayName": "Git konfigurieren",
+ "description": "Darf die git Konfiguration für dieses Repository verändern."
+ }
}
}
}
diff --git a/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json b/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json
index 551573fb72..bea0a08dc9 100644
--- a/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json
+++ b/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json
@@ -39,18 +39,28 @@
},
"permissions" : {
"configuration": {
- "read": {
+ "read,write": {
"git": {
- "displayName": "Read git configuration",
- "description": "May read the git configuration"
- }
- },
- "write": {
- "git": {
- "displayName": "Write git configuration",
+ "displayName": "Modify git configuration",
"description": "May change the git configuration"
}
}
+ },
+ "repository": {
+ "git": {
+ "*": {
+ "displayName": "Modify repository specific git configuration",
+ "description": "May change the git configuration for repositories"
+ }
+ }
+ }
+ },
+ "verbs": {
+ "repository": {
+ "git": {
+ "displayName": "configure Git",
+ "description": "May change the git configuration for this repository"
+ }
}
}
}
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigInIndexResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigInIndexResourceTest.java
index 665be19788..d6519a0013 100644
--- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigInIndexResourceTest.java
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigInIndexResourceTest.java
@@ -15,6 +15,7 @@ import java.net.URI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini")
public class GitConfigInIndexResourceTest {
@@ -50,7 +51,7 @@ public class GitConfigInIndexResourceTest {
gitConfigInIndexResource.enrich(context);
- assertFalse(root.get("_links").iterator().hasNext());
+ assertTrue(root.get("_links").iterator().hasNext());
}
@Test
diff --git a/scm-plugins/scm-git-plugin/yarn.lock b/scm-plugins/scm-git-plugin/yarn.lock
index 64c47a247d..6438262437 100644
--- a/scm-plugins/scm-git-plugin/yarn.lock
+++ b/scm-plugins/scm-git-plugin/yarn.lock
@@ -707,9 +707,9 @@
version "0.0.2"
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
-"@scm-manager/ui-bundler@^0.0.24":
- version "0.0.24"
- resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.24.tgz#034d5500c79b438c48d8f7ee985be07c4ea46d1e"
+"@scm-manager/ui-bundler@^0.0.25":
+ version "0.0.25"
+ resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.25.tgz#1f65b3ff0ae81559a114c6a8d8cf43856cc6e166"
dependencies:
"@babel/core" "^7.0.0"
"@babel/plugin-proposal-class-properties" "^7.0.0"
@@ -750,7 +750,6 @@
"@scm-manager/ui-extensions@^0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@scm-manager/ui-extensions/-/ui-extensions-0.1.2.tgz#0689427ca45c8e4e045b5b9dbc89036f1d2c45fc"
- integrity sha512-oIkXcc/VWssnK/yjWKC/Wnq5DZ01rArsz76n4X/0DT0hkGNIKmwk/Fdp7OoXiUEb7+aaPjUX1VvDqlTwCNKPmA==
dependencies:
react "^16.4.2"
react-dom "^16.4.2"
diff --git a/scm-plugins/scm-hg-plugin/package.json b/scm-plugins/scm-hg-plugin/package.json
index 849d8a92cb..8d3926f0dd 100644
--- a/scm-plugins/scm-hg-plugin/package.json
+++ b/scm-plugins/scm-hg-plugin/package.json
@@ -9,6 +9,6 @@
"@scm-manager/ui-extensions": "^0.1.2"
},
"devDependencies": {
- "@scm-manager/ui-bundler": "^0.0.24"
+ "@scm-manager/ui-bundler": "^0.0.25"
}
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInIndexResource.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInIndexResource.java
index 3de79b2f81..73c6e2e52f 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInIndexResource.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInIndexResource.java
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import sonia.scm.config.ConfigurationPermissions;
import sonia.scm.plugin.Extension;
+import sonia.scm.repository.HgConfig;
import sonia.scm.web.JsonEnricherBase;
import sonia.scm.web.JsonEnricherContext;
@@ -26,7 +27,7 @@ public class HgConfigInIndexResource extends JsonEnricherBase {
@Override
public void enrich(JsonEnricherContext context) {
- if (resultHasMediaType(INDEX, context) && ConfigurationPermissions.list().isPermitted()) {
+ if (resultHasMediaType(INDEX, context) && ConfigurationPermissions.read(HgConfig.PERMISSION).isPermitted()) {
String hgConfigUrl = new LinkBuilder(scmPathInfoStore.get().get(), HgConfigResource.class)
.method("get")
.parameters()
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java
index cbf7804444..21e27af328 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContext.java
@@ -35,13 +35,10 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.inject.servlet.RequestScoped;
-
/**
*
* @author Sebastian Sdorra
*/
-@RequestScoped
public class HgContext
{
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextProvider.java
index c86588fb27..33477e04b8 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextProvider.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextProvider.java
@@ -35,13 +35,20 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.inject.Inject;
-import com.google.inject.Provider;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.OutOfScopeException;
+import com.google.inject.Provider;
+import com.google.inject.ProvisionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.inject.Inject;
+
/**
+ * Injection provider for {@link HgContext}.
+ * This provider returns an instance {@link HgContext} from request scope, if no {@link HgContext} could be found in
+ * request scope (mostly because the scope is not available) a new {@link HgContext} gets returned.
*
* @author Sebastian Sdorra
*/
@@ -49,36 +56,50 @@ public class HgContextProvider implements Provider
{
/**
- * the logger for HgContextProvider
+ * the LOG for HgContextProvider
*/
- private static final Logger logger =
+ private static final Logger LOG =
LoggerFactory.getLogger(HgContextProvider.class);
//~--- get methods ----------------------------------------------------------
- /**
- * Method description
- *
- *
- * @return
- */
- @Override
- public HgContext get()
- {
- HgContext ctx = context;
+ private Provider requestStoreProvider;
- if (ctx == null)
- {
- ctx = new HgContext();
- logger.trace("context is null, we are probably out of request scope");
- }
-
- return ctx;
+ @Inject
+ public HgContextProvider(Provider requestStoreProvider) {
+ this.requestStoreProvider = requestStoreProvider;
}
- //~--- fields ---------------------------------------------------------------
+ @VisibleForTesting
+ public HgContextProvider() {
+ }
- /** Field description */
- @Inject(optional = true)
- private HgContext context;
+ @Override
+ public HgContext get() {
+ HgContext context = fetchContextFromRequest();
+ if (context != null) {
+ LOG.trace("return HgContext from request store");
+ return context;
+ }
+ LOG.trace("could not find context in request scope, returning new instance");
+ return new HgContext();
+ }
+
+ private HgContext fetchContextFromRequest() {
+ try {
+ if (requestStoreProvider != null) {
+ return requestStoreProvider.get().get();
+ } else {
+ LOG.trace("no request store provider defined, could not return context from request");
+ return null;
+ }
+ } catch (ProvisionException ex) {
+ if (ex.getCause() instanceof OutOfScopeException) {
+ LOG.trace("we are currently out of request scope, failed to retrieve context");
+ return null;
+ } else {
+ throw ex;
+ }
+ }
+ }
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextRequestStore.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextRequestStore.java
new file mode 100644
index 0000000000..ff08c2fcd2
--- /dev/null
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgContextRequestStore.java
@@ -0,0 +1,24 @@
+package sonia.scm.repository;
+
+import com.google.inject.servlet.RequestScoped;
+
+/**
+ * Holds an instance of {@link HgContext} in the request scope.
+ *
+ *
The problem seems to be that guice had multiple options for injecting HgContext. {@link HgContextProvider}
+ * bound via Module and {@link HgContext} bound void {@link RequestScoped} annotation. It looks like that Guice 4
+ * injects randomly the one or the other, in SCMv1 (Guice 3) everything works as expected.
+ *
+ *
To fix the problem we have created this class annotated with {@link RequestScoped}, which holds an instance
+ * of {@link HgContext}. This way only the {@link HgContextProvider} is used for injection.