From 77c02aab436610e90b6cb833d79e43431e44f0c3 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Sat, 30 Jul 2016 08:42:38 +0200 Subject: [PATCH] Getting project and repo with sys admin permissions #135 --- CHANGELOG.md | 8 +++- .../bjurr/prnfb/service/UserCheckService.java | 45 +++++++++++++++++-- .../prnfb/service/UserCheckServiceTest.java | 37 ++++++++++++++- 3 files changed, 84 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 908c747..83d3dce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,19 @@ Changelog of Pull Request Notifier for Bitbucket. ## Unreleased +### GitHub [#135](https://github.com/tomasbjerre/pull-request-notifier-for-bitbucket/issues/135) Not permitted to access buttons settings as project/repo admin + Getting project and repo with sys admin permissions + + [4af3fd9f87fa409](https://github.com/tomasbjerre/pull-request-notifier-for-bitbucket/commit/4af3fd9f87fa409) Tomas Bjerre *2016-07-30 06:42:38* + +## 2.32 ### No issue Fine tuning notification confirmation feature * Using AUI flag. * Showing invoked URL and response content. * Also logging error when variable cant be resolved. Was giving up entirely. Will now log and continue trying to resolve other variables. - [cd772334597de1f](https://github.com/tomasbjerre/pull-request-notifier-for-bitbucket/commit/cd772334597de1f) Tomas Bjerre *2016-07-29 22:25:58* + [aee524c305eb666](https://github.com/tomasbjerre/pull-request-notifier-for-bitbucket/commit/aee524c305eb666) Tomas Bjerre *2016-07-29 22:47:15* Add Button Trigger Confirmation Dialog diff --git a/src/main/java/se/bjurr/prnfb/service/UserCheckService.java b/src/main/java/se/bjurr/prnfb/service/UserCheckService.java index 412d2d4..eee2d8f 100644 --- a/src/main/java/se/bjurr/prnfb/service/UserCheckService.java +++ b/src/main/java/se/bjurr/prnfb/service/UserCheckService.java @@ -2,7 +2,9 @@ import static com.atlassian.bitbucket.permission.Permission.PROJECT_ADMIN; import static com.atlassian.bitbucket.permission.Permission.REPO_ADMIN; +import static com.atlassian.bitbucket.permission.Permission.SYS_ADMIN; import static com.google.common.base.Strings.emptyToNull; +import static com.google.common.base.Throwables.propagate; import static com.google.common.collect.Iterables.filter; import static se.bjurr.prnfb.settings.USER_LEVEL.ADMIN; import static se.bjurr.prnfb.settings.USER_LEVEL.EVERYONE; @@ -19,25 +21,30 @@ import com.atlassian.bitbucket.project.ProjectService; import com.atlassian.bitbucket.repository.Repository; import com.atlassian.bitbucket.repository.RepositoryService; +import com.atlassian.bitbucket.user.SecurityService; +import com.atlassian.bitbucket.util.Operation; import com.atlassian.sal.api.user.UserKey; import com.atlassian.sal.api.user.UserManager; import com.atlassian.sal.api.user.UserProfile; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Predicate; public class UserCheckService { private final PermissionService permissionService; private final ProjectService projectService; private final RepositoryService repositoryService; + private final SecurityService securityService; private final SettingsService settingsService; private final UserManager userManager; public UserCheckService(PermissionService permissionService, UserManager userManager, SettingsService settingsService, - RepositoryService repositoryService, ProjectService projectService) { + RepositoryService repositoryService, ProjectService projectService, SecurityService securityService) { this.userManager = userManager; this.settingsService = settingsService; this.permissionService = permissionService; this.projectService = projectService; this.repositoryService = repositoryService; + this.securityService = securityService; } public Iterable filterAllowed(List buttons) { @@ -60,10 +67,10 @@ public boolean isAdmin(UserKey userKey, String projectKey, String repositorySlug repositorySlug = emptyToNull(repositorySlug); if (projectKey != null && repositorySlug == null) { - Project project = this.projectService.getByKey(projectKey); + Project project = getProject(projectKey); return this.permissionService.hasProjectPermission(project, PROJECT_ADMIN); } else if (repositorySlug != null) { - Repository repository = this.repositoryService.getBySlug(projectKey, repositorySlug); + Repository repository = getRepo(projectKey, repositorySlug); return this.permissionService.hasRepositoryPermission(repository, REPO_ADMIN); } return isAdmin; @@ -100,6 +107,22 @@ public boolean isViewAllowed() { return true; } + @VisibleForTesting + private Project getProject(String projectKey) { + try { + return this.securityService// + .withPermission(SYS_ADMIN, "Getting project")// + .call(new Operation() { + @Override + public Project perform() throws Exception { + return UserCheckService.this.projectService.getByKey(projectKey); + } + }); + } catch (Exception e) { + throw propagate(e); + } + } + private boolean isAdminAllowed(USER_LEVEL adminRestriction, @Nullable String projectKey, @Nullable String repositorySlug) { UserKey userKey = this.userManager.getRemoteUser().getUserKey(); @@ -108,6 +131,22 @@ private boolean isAdminAllowed(USER_LEVEL adminRestriction, @Nullable String pro return isAdminAllowedCheck(adminRestriction, isAdmin, isSystemAdmin); } + @VisibleForTesting + Repository getRepo(String projectKey, String repositorySlug) { + try { + return this.securityService// + .withPermission(SYS_ADMIN, "Getting repo")// + .call(new Operation() { + @Override + public Repository perform() throws Exception { + return UserCheckService.this.repositoryService.getBySlug(projectKey, repositorySlug); + } + }); + } catch (Exception e) { + throw propagate(e); + } + } + boolean isAdminAllowedCheck(USER_LEVEL userLevel, boolean isAdmin, boolean isSystemAdmin) { return userLevel == EVERYONE // || isSystemAdmin // diff --git a/src/test/java/se/bjurr/prnfb/service/UserCheckServiceTest.java b/src/test/java/se/bjurr/prnfb/service/UserCheckServiceTest.java index 9185098..9a80a1a 100644 --- a/src/test/java/se/bjurr/prnfb/service/UserCheckServiceTest.java +++ b/src/test/java/se/bjurr/prnfb/service/UserCheckServiceTest.java @@ -12,7 +12,10 @@ import org.junit.Before; import org.junit.Test; +import org.mockito.Matchers; import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import se.bjurr.prnfb.presentation.dto.ON_OR_OFF; import se.bjurr.prnfb.settings.PrnfbButton; @@ -20,18 +23,28 @@ import com.atlassian.bitbucket.permission.PermissionService; import com.atlassian.bitbucket.project.ProjectService; import com.atlassian.bitbucket.repository.RepositoryService; +import com.atlassian.bitbucket.user.EscalatedSecurityContext; +import com.atlassian.bitbucket.user.SecurityService; +import com.atlassian.bitbucket.util.Operation; import com.atlassian.sal.api.user.UserKey; import com.atlassian.sal.api.user.UserManager; import com.atlassian.sal.api.user.UserProfile; public class UserCheckServiceTest { + @Mock + private EscalatedSecurityContext escalatedSecurityContext; + @Mock private PermissionService permissionService; + private String projectKey; @Mock private ProjectService projectService; @Mock private RepositoryService repositoryService; + private String repositorySlug; + @Mock + private SecurityService securityService; @Mock private SettingsService settingsService; private UserCheckService sut; @@ -45,16 +58,32 @@ public class UserCheckServiceTest { public void before() { initMocks(this); this.sut = new UserCheckService(this.permissionService, this.userManager, this.settingsService, - this.repositoryService, this.projectService); + this.repositoryService, this.projectService, this.securityService); + + when(this.securityService.withPermission(Matchers.any(), Matchers.any()))// + .thenReturn(this.escalatedSecurityContext); + when(this.escalatedSecurityContext.call(Matchers.any()))// + .thenAnswer(new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + Operation op = (Operation) invocation.getArguments()[0]; + return (Boolean) op.perform(); + } + }); } @Test public void testThatAdminAllowedCanBeChecked() { - this.sut.isAdminAllowed(null, null); + this.projectKey = null; + this.repositorySlug = null; + this.sut.isAdminAllowed(this.projectKey, this.repositorySlug); } @Test public void testThatAllowedButtonsCanBeFiltered() { + this.projectKey = "p1"; + this.repositorySlug = "r1"; + when(this.userManager.getRemoteUser())// .thenReturn(this.user); when(this.userManager.getRemoteUser().getUserKey())// @@ -77,12 +106,16 @@ public void testThatAllowedButtonsCanBeFiltered() { @Test public void testThatAllowedCanBeChecked() { + this.projectKey = "p1"; + this.repositorySlug = "r1"; + when(this.userManager.getRemoteUser())// .thenReturn(this.user); when(this.userManager.getRemoteUser().getUserKey())// .thenReturn(this.userKey); when(this.userManager.isSystemAdmin(this.userKey))// .thenReturn(true); + PrnfbButton candidate = new PrnfbButton(null, "title", ADMIN, ON_OR_OFF.off, "p1", "r1"); assertThat(this.sut.isAllowedUseButton(candidate))// .isTrue();