*/
package org.sonar.plugins.core.security;
+import com.google.common.collect.ImmutableSet;
+import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.security.ResourcePermissioning;
+import java.util.Set;
+
public class ApplyProjectRolesDecorator implements Decorator {
private final ResourcePermissioning resourcePermissioning;
+ private final Set<String> QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.SUBVIEW);
public ApplyProjectRolesDecorator(ResourcePermissioning resourcePermissioning) {
this.resourcePermissioning = resourcePermissioning;
public void decorate(Resource resource, DecoratorContext context) {
if (shouldDecorateResource(resource)) {
+ LoggerFactory.getLogger(ApplyProjectRolesDecorator.class).info("Grant default permissions to {}", resource.getKey());
resourcePermissioning.grantDefaultRoles(resource);
}
}
private boolean shouldDecorateResource(Resource resource) {
- return resource.getId() != null && isProject(resource) && !resourcePermissioning.hasRoles(resource);
+ return resource.getId() != null && QUALIFIERS.contains(resource.getQualifier()) && !resourcePermissioning.hasRoles(resource);
}
- private boolean isProject(Resource resource) {
- return Qualifiers.PROJECT.equals(resource.getQualifier()) || Qualifiers.VIEW.equals(resource.getQualifier());
- }
}
*/
package org.sonar.plugins.core.security;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.ibatis.session.SqlSession;
import org.sonar.api.BatchExtension;
import org.sonar.api.Properties;
import org.sonar.api.Property;
import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.security.ResourcePermissioning;
private void grantDefaultRoles(Resource resource, String role, SqlSession session) {
UserMapper userMapper = session.getMapper(UserMapper.class);
RoleMapper roleMapper = session.getMapper(RoleMapper.class);
- String[] groupNames = settings.getStringArrayBySeparator("sonar.role." + role + "." + resource.getQualifier() + ".defaultGroups", ",");
+
+ String strategy = getStrategy(resource);
+ String[] groupNames = settings.getStringArrayBySeparator("sonar.role." + role + "." + strategy + ".defaultGroups", ",");
for (String groupName : groupNames) {
GroupRoleDto groupRole = new GroupRoleDto().setRole(role).setResourceId(new Long(resource.getId()));
if (DefaultGroups.isAnyone(groupName)) {
}
}
- String[] logins = settings.getStringArrayBySeparator("sonar.role." + role + "." + resource.getQualifier() + ".defaultUsers", ",");
+ String[] logins = settings.getStringArrayBySeparator("sonar.role." + role + "." + strategy + ".defaultUsers", ",");
for (String login : logins) {
UserDto user = userMapper.selectUserByLogin(login);
if (user != null) {
}
}
}
+
+ /**
+ * This is workaround to support old versions of the Views plugin.
+ * If the Views plugin does not define default permissions, then the standard permissions are re-used for new views.
+ */
+ @VisibleForTesting
+ String getStrategy(Resource resource) {
+ String qualifier = resource.getQualifier();
+ String result;
+ if (Qualifiers.PROJECT.equals(qualifier)) {
+ result = qualifier;
+
+ } else if (hasRoleSettings(UserRole.ADMIN, qualifier) || hasRoleSettings(UserRole.USER, qualifier) || hasRoleSettings(UserRole.CODEVIEWER, qualifier)) {
+ result = qualifier;
+ } else {
+ result = Qualifiers.PROJECT;
+ }
+ return result;
+ }
+
+ private boolean hasRoleSettings(String role, String qualifier) {
+ return settings.getString("sonar.role." + role + "." + qualifier + ".defaultGroups") != null
+ || settings.getString("sonar.role." + role + "." + qualifier + ".defaultUsers") != null;
+ }
}
/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * Sonar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
+* Sonar, open source software quality management tool.
+* Copyright (C) 2008-2012 SonarSource
+* mailto:contact AT sonarsource DOT com
+*
+* Sonar is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or (at your option) any later version.
+*
+* Sonar is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with Sonar; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+*/
package org.sonar.plugins.core.security;
import org.junit.Before;
import org.sonar.api.resources.Project;
import org.sonar.api.security.ResourcePermissioning;
+import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.*;
public class ApplyProjectRolesDecoratorTest {
private ApplyProjectRolesDecorator decorator;
@Before
- public void before() {
+ public void init() {
resourcePermissioning = mock(ResourcePermissioning.class);
decorator = new ApplyProjectRolesDecorator(resourcePermissioning);
}
@Test
- public void doNotApplySecurityWhenExistingPermissions() {
+ public void alwaysExecute() {
+ assertThat(decorator.shouldExecuteOnProject(new Project("project"))).isTrue();
+ }
+
+ @Test
+ public void doNotGrantDefaultRolesWhenExistingPermissions() {
Project project = new Project("project");
project.setId(10);
when(resourcePermissioning.hasRoles(project)).thenReturn(true);
}
@Test
- public void applySecurityWhenNoPermissions() {
+ public void grantDefaultRolesWhenNoPermissions() {
Project project = new Project("project");
project.setId(10);
when(resourcePermissioning.hasRoles(project)).thenReturn(false);
package org.sonar.plugins.core.security;
import org.junit.Test;
+import org.sonar.api.Properties;
+import org.sonar.api.Property;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.security.DefaultGroups;
import org.sonar.core.persistence.AbstractDaoTestCase;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class DefaultResourcePermissioningTest extends AbstractDaoTestCase {
// does not exist
assertThat(permissioning.hasRoles(new Project("not_found"))).isFalse();
}
+
+ @Test
+ public void use_default_project_roles_when_old_version_of_views_plugin() {
+ DefaultResourcePermissioning permissioning = new DefaultResourcePermissioning(new Settings(), getMyBatis());
+ Resource view = mock(Resource.class);
+ when(view.getQualifier()).thenReturn(Qualifiers.VIEW);
+
+ assertThat(permissioning.getStrategy(view)).isEqualTo(Qualifiers.PROJECT);
+ }
+
+ @Test
+ public void use_existing_view_roles() {
+ Settings settings = new Settings();
+ settings.setProperty("sonar.role.admin.VW.defaultUsers", "sonar-administrators");
+
+ DefaultResourcePermissioning permissioning = new DefaultResourcePermissioning(settings, getMyBatis());
+ Resource view = mock(Resource.class);
+ when(view.getQualifier()).thenReturn(Qualifiers.VIEW);
+
+ assertThat(permissioning.getStrategy(view)).isEqualTo(Qualifiers.VIEW);
+ }
+
+ @Test
+ public void use_existing_default_view_roles() {
+ Settings settings = new Settings(new PropertyDefinitions(RecentViewPlugin.class));
+
+ DefaultResourcePermissioning permissioning = new DefaultResourcePermissioning(settings, getMyBatis());
+ Resource view = mock(Resource.class);
+ when(view.getQualifier()).thenReturn(Qualifiers.VIEW);
+
+ assertThat(permissioning.getStrategy(view)).isEqualTo(Qualifiers.VIEW);
+ }
+
+ @Properties({
+ @Property(key = "sonar.role.user.VW.defaultUsers", defaultValue = "sonar-users", name = "")
+ })
+ static class RecentViewPlugin {
+
+ }
}
\ No newline at end of file
return hasSourceCode;
}
+ public boolean hasProperty(String key) {
+ Preconditions.checkNotNull(key);
+ return properties.containsKey(key);
+ }
+
/**
* Returns the value of the property for this resource type.
*
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
+import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
public static final Predicate<ResourceType> AVAILABLE_FOR_FILTERS = new Predicate<ResourceType>() {
public boolean apply(@Nullable ResourceType input) {
- return input != null && Boolean.TRUE.equals(input.getBooleanProperty("availableForFilters"));
+ return input != null && input.getBooleanProperty("availableForFilters");
}
};
return Collections2.filter(typeByQualifier.values(), predicate);
}
+ public Collection<ResourceType> getAllWithPropertyKey(final String propertyKey) {
+ return Collections2.filter(typeByQualifier.values(), new Predicate<ResourceType>() {
+ public boolean apply(@Nullable ResourceType input) {
+ return input != null && input.hasProperty(propertyKey);
+ }
+ });
+ }
+
+ public Collection<ResourceType> getAllWithPropertyValue(final String propertyKey, final String propertyValue) {
+ return Collections2.filter(typeByQualifier.values(), new Predicate<ResourceType>() {
+ public boolean apply(@Nullable ResourceType input) {
+ return input != null && Objects.equal(propertyValue, input.getStringProperty(propertyKey));
+ }
+ });
+ }
+
+ public Collection<ResourceType> getAllWithPropertyValue(final String propertyKey, final boolean propertyValue) {
+ return Collections2.filter(typeByQualifier.values(), new Predicate<ResourceType>() {
+ public boolean apply(@Nullable ResourceType input) {
+ return input != null && input.getBooleanProperty(propertyKey) == propertyValue;
+ }
+ });
+ }
+
public List<String> getChildrenQualifiers(String qualifier) {
ResourceTypeTree tree = getTree(qualifier);
if (tree != null) {
ResourceType def = ResourceType.builder("qualifier").build();
assertThat(def.getBooleanProperty("availableForFilters")).isFalse();
}
+
+ @Test
+ public void hasProperty() {
+ ResourceType def = ResourceType.builder("qualifier").build();
+ assertThat(def.hasProperty("foo")).isFalse();
+
+ def = ResourceType.builder("qualifier").setProperty("foo", "bar").build();
+ assertThat(def.hasProperty("foo")).isTrue();
+ }
}
import java.util.Collection;
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
-import static org.junit.internal.matchers.IsCollectionContaining.hasItems;
+import static org.fest.assertions.Assertions.assertThat;
public class ResourceTypesTest {
private ResourceTypeTree viewsTree = ResourceTypeTree.builder()
- .addType(ResourceType.builder(Qualifiers.VIEW).setProperty("availableForFilters", "true").build())
- .addType(ResourceType.builder(Qualifiers.SUBVIEW).build())
- .addRelations(Qualifiers.VIEW, Qualifiers.SUBVIEW)
- .addRelations(Qualifiers.SUBVIEW, Qualifiers.PROJECT)
- .build();
+ .addType(ResourceType.builder(Qualifiers.VIEW).setProperty("availableForFilters", "true").build())
+ .addType(ResourceType.builder(Qualifiers.SUBVIEW).build())
+ .addRelations(Qualifiers.VIEW, Qualifiers.SUBVIEW)
+ .addRelations(Qualifiers.SUBVIEW, Qualifiers.PROJECT)
+ .build();
private ResourceTypeTree defaultTree = ResourceTypeTree.builder()
- .addType(ResourceType.builder(Qualifiers.PROJECT).setProperty("availableForFilters", "true").build())
- .addType(ResourceType.builder(Qualifiers.DIRECTORY).build())
- .addType(ResourceType.builder(Qualifiers.FILE).build())
- .addRelations(Qualifiers.PROJECT, Qualifiers.DIRECTORY)
- .addRelations(Qualifiers.DIRECTORY, Qualifiers.FILE)
- .build();
+ .addType(ResourceType.builder(Qualifiers.PROJECT).setProperty("availableForFilters", "true").build())
+ .addType(ResourceType.builder(Qualifiers.DIRECTORY).build())
+ .addType(ResourceType.builder(Qualifiers.FILE).build())
+ .addRelations(Qualifiers.PROJECT, Qualifiers.DIRECTORY)
+ .addRelations(Qualifiers.DIRECTORY, Qualifiers.FILE)
+ .build();
- private ResourceTypes types = new ResourceTypes(new ResourceTypeTree[] {viewsTree, defaultTree});
+ private ResourceTypes types = new ResourceTypes(new ResourceTypeTree[]{viewsTree, defaultTree});
@Test
public void get() {
- assertThat(types.get(Qualifiers.PROJECT).getQualifier(), is(Qualifiers.PROJECT));
+ assertThat(types.get(Qualifiers.PROJECT).getQualifier()).isEqualTo(Qualifiers.PROJECT);
// does not return null
- assertThat(types.get("xxx").getQualifier(), is("xxx"));
+ assertThat(types.get("xxx").getQualifier()).isEqualTo("xxx");
}
@Test
public void getAll() {
- assertThat(types.getAll().size(), is(5));
- assertThat(qualifiers(types.getAll()), hasItems(
- Qualifiers.PROJECT, Qualifiers.DIRECTORY, Qualifiers.FILE, Qualifiers.VIEW, Qualifiers.SUBVIEW));
+ assertThat(qualifiers(types.getAll())).containsOnly(Qualifiers.PROJECT, Qualifiers.DIRECTORY, Qualifiers.FILE, Qualifiers.VIEW, Qualifiers.SUBVIEW);
}
@Test
public void getAll_predicate() {
Collection<ResourceType> forFilters = types.getAll(ResourceTypes.AVAILABLE_FOR_FILTERS);
- assertThat(forFilters.size(), is(2));
- assertThat(qualifiers(forFilters), hasItems(Qualifiers.PROJECT, Qualifiers.VIEW));
+ assertThat(qualifiers(forFilters)).containsOnly(Qualifiers.PROJECT, Qualifiers.VIEW).doesNotHaveDuplicates();
+ }
+
+ @Test
+ public void getAllWithPropertyKey() {
+ assertThat(qualifiers(types.getAllWithPropertyKey("availableForFilters"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
+ }
+
+ @Test
+ public void getAllWithPropertyValue() {
+ assertThat(qualifiers(types.getAllWithPropertyValue("availableForFilters", "true"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
+ assertThat(qualifiers(types.getAllWithPropertyValue("availableForFilters", true))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
+ assertThat(qualifiers(types.getAllWithPropertyValue("availableForFilters", false))).containsOnly(Qualifiers.SUBVIEW, Qualifiers.DIRECTORY, Qualifiers.FILE);
}
@Test
public void getChildrenQualifiers() {
- assertThat(types.getChildrenQualifiers(Qualifiers.PROJECT).size(), is(1));
- assertThat(types.getChildrenQualifiers(Qualifiers.PROJECT), hasItem(Qualifiers.DIRECTORY));
- assertThat(types.getChildrenQualifiers(Qualifiers.SUBVIEW), hasItem(Qualifiers.PROJECT));
- assertThat(types.getChildrenQualifiers("xxx").isEmpty(), is(true));
- assertThat(types.getChildrenQualifiers(Qualifiers.FILE).isEmpty(), is(true));
+ assertThat(types.getChildrenQualifiers(Qualifiers.PROJECT)).containsExactly(Qualifiers.DIRECTORY);
+ assertThat(types.getChildrenQualifiers(Qualifiers.SUBVIEW)).containsExactly(Qualifiers.PROJECT);
+ assertThat(types.getChildrenQualifiers("xxx")).isEmpty();
+ assertThat(types.getChildrenQualifiers(Qualifiers.FILE)).isEmpty();
}
@Test
public void getChildren() {
- assertThat(qualifiers(types.getChildren(Qualifiers.PROJECT)), hasItem(Qualifiers.DIRECTORY));
- assertThat(qualifiers(types.getChildren(Qualifiers.SUBVIEW)), hasItem(Qualifiers.PROJECT));
+ assertThat(qualifiers(types.getChildren(Qualifiers.PROJECT))).contains(Qualifiers.DIRECTORY);
+ assertThat(qualifiers(types.getChildren(Qualifiers.SUBVIEW))).contains(Qualifiers.PROJECT);
}
@Test
public void getLeavesQualifiers() {
- assertThat(types.getLeavesQualifiers(Qualifiers.PROJECT).size(), is(1));
- assertThat(types.getLeavesQualifiers(Qualifiers.PROJECT), hasItem(Qualifiers.FILE));
+ assertThat(types.getLeavesQualifiers(Qualifiers.PROJECT)).containsExactly(Qualifiers.FILE);
- assertThat(types.getLeavesQualifiers(Qualifiers.DIRECTORY).size(), is(1));
- assertThat(types.getLeavesQualifiers(Qualifiers.DIRECTORY), hasItem(Qualifiers.FILE));
+ assertThat(types.getLeavesQualifiers(Qualifiers.DIRECTORY)).containsExactly(Qualifiers.FILE);
- assertThat(types.getLeavesQualifiers(Qualifiers.VIEW).size(), is(1));
- assertThat(types.getLeavesQualifiers(Qualifiers.VIEW), hasItem(Qualifiers.PROJECT));
+ assertThat(types.getLeavesQualifiers(Qualifiers.VIEW)).containsExactly(Qualifiers.PROJECT);
- assertThat(types.getLeavesQualifiers("xxx").size(), is(0));
+ assertThat(types.getLeavesQualifiers("xxx")).isEmpty();
}
@Test
public void getTree() {
- assertThat(qualifiers(types.getTree(Qualifiers.VIEW).getTypes()), hasItems(Qualifiers.VIEW, Qualifiers.SUBVIEW));
- assertThat(types.getTree("xxx"), nullValue());
+ assertThat(qualifiers(types.getTree(Qualifiers.VIEW).getTypes())).containsOnly(Qualifiers.VIEW, Qualifiers.SUBVIEW).doesNotHaveDuplicates();
+ assertThat(types.getTree("xxx")).isNull();
}
@Test(expected = IllegalStateException.class)
public void failOnDuplicatedQualifier() {
ResourceTypeTree tree1 = ResourceTypeTree.builder()
- .addType(ResourceType.builder("foo").build())
- .build();
+ .addType(ResourceType.builder("foo").build())
+ .build();
ResourceTypeTree tree2 = ResourceTypeTree.builder()
- .addType(ResourceType.builder("foo").build())
- .build();
+ .addType(ResourceType.builder("foo").build())
+ .build();
- new ResourceTypes(new ResourceTypeTree[] {tree1, tree2});
+ new ResourceTypes(new ResourceTypeTree[]{tree1, tree2});
}
static Collection<String> qualifiers(Collection<ResourceType> types) {
</tr>
<tr class="even">
<td valign="top">
- <b>Role: Code viewers</b><br/><span class="small gray">Ability to view source code of a project.</span></td>
+ <b>Role: Code Viewers</b><br/><span class="small gray">Ability to view source code of a project.</span></td>
<td valign="top" style="word-break:break-all;width:35%;">
<span id="u-codeviewer"><%= default_project_users('codeviewer', @qualifier).map{|u| h u.name}.join(', ') -%></span>
(<%= link_to "select", {:action => 'edit_default_project_users', :role => 'codeviewer', :redirect => 'projects', :qualifier => @qualifier}, :class => 'link-action', :id => 'selectu-codeviewer' -%>)