From d345461bd15b8e1a7e53aa516602a63ba2afc310 Mon Sep 17 00:00:00 2001 From: "Andrew M. Stoltz" Date: Tue, 4 Feb 2020 05:43:08 -0600 Subject: [PATCH 1/3] Add REST endpoint for get repository --- .../rest/api/AuthorizingRepositoryManager.java | 2 +- .../rest/api/RepositoriesApiResource.java | 13 +++++++++++++ .../rest/api/RepositoriesApiResourceDoc.java | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java index baf7e68dac..088e4590d2 100644 --- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java +++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java @@ -144,7 +144,7 @@ private void ensureProxyOrGroup(final Repository repository) throws Incompatible } } - private Repository getEditableRepositoryOrThrow(@Nonnull final String name) + public Repository getEditableRepositoryOrThrow(@Nonnull final String name) throws RepositoryNotFoundException { Repository repository = repositoryManager.get(name); diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java index 1eed5252c9..59eb73f655 100644 --- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java +++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java @@ -83,6 +83,19 @@ public Response deleteRepository(@PathParam("repositoryName") final String repos return Response.status(isDeleted ? NO_CONTENT : NOT_FOUND).build(); } + @Override + @GET + @Path("/{repositoryName}") + @RequiresAuthentication + public AbstractApiRepository getRepository(@PathParam("repositoryName") final String repositoryName) { + try { + return convert(authorizingRepositoryManager.getEditableRepositoryOrThrow(repositoryName)); + } catch (RepositoryNotFoundException e) { + log.debug("Repository not found '{}'", repositoryName, e); + throw new WebApplicationMessageException(NOT_FOUND, "\"" + e.getMessage() + "\"", APPLICATION_JSON); + } + } + @Override @RequiresAuthentication @GET diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceDoc.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceDoc.java index 208652568d..b2f3771345 100644 --- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceDoc.java +++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceDoc.java @@ -46,6 +46,13 @@ public interface RepositoriesApiResourceDoc Response deleteRepository(@ApiParam(value = "Name of the repository to delete") final String repositoryName) throws Exception; + @ApiOperation("Get repository") + @ApiResponses(value = {@ApiResponse(code = 200, message = "Repository returned", response = AbstractApiRepository.class), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS), + @ApiResponse(code = 404, message = REPOSITORY_NOT_FOUND)}) + AbstractApiRepository getRepository(@ApiParam(value = "Name of the repository to fetch") final String repositoryName) throws RepositoryNotFoundException; + @ApiOperation("List repositories") @ApiResponses(value = {@ApiResponse(code = 200, message = "Repositories list returned"), @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), From ac3dca199aab26d22a01df06b21de6dbe33c59ea Mon Sep 17 00:00:00 2001 From: "Andrew M. Stoltz" Date: Tue, 4 Feb 2020 19:55:16 -0600 Subject: [PATCH 2/3] Switch getRepository to check read rights, like list --- .../rest/api/AuthorizingRepositoryManager.java | 17 ++++++++++++++++- .../rest/api/RepositoriesApiResource.java | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java index 088e4590d2..c3197cf0af 100644 --- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java +++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/AuthorizingRepositoryManager.java @@ -12,6 +12,7 @@ */ package org.sonatype.nexus.repository.rest.api; +import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; @@ -90,6 +91,20 @@ public boolean delete(@Nonnull final String name) throws Exception { return false; } + /** + * Returns a specific repository which the user has an administrative read privilege to. + */ + public Repository getRepository(@Nonnull final String name) + throws RepositoryNotFoundException + { + Repository repository = repositoryManager.get(name); + if (repository == null) { + throw new RepositoryNotFoundException(); + } + repositoryPermissionChecker.userHasRepositoryAdminPermission(Collections.singletonList(repository), READ); + return repository; + } + /** * Returns the repositories which the user has an administrative read privilege. */ @@ -144,7 +159,7 @@ private void ensureProxyOrGroup(final Repository repository) throws Incompatible } } - public Repository getEditableRepositoryOrThrow(@Nonnull final String name) + private Repository getEditableRepositoryOrThrow(@Nonnull final String name) throws RepositoryNotFoundException { Repository repository = repositoryManager.get(name); diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java index 59eb73f655..e7d32da1fb 100644 --- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java +++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResource.java @@ -89,7 +89,7 @@ public Response deleteRepository(@PathParam("repositoryName") final String repos @RequiresAuthentication public AbstractApiRepository getRepository(@PathParam("repositoryName") final String repositoryName) { try { - return convert(authorizingRepositoryManager.getEditableRepositoryOrThrow(repositoryName)); + return convert(authorizingRepositoryManager.getRepository(repositoryName)); } catch (RepositoryNotFoundException e) { log.debug("Repository not found '{}'", repositoryName, e); throw new WebApplicationMessageException(NOT_FOUND, "\"" + e.getMessage() + "\"", APPLICATION_JSON); From 6ed33e1ab69edd247827d68dbe522d102b7c9071 Mon Sep 17 00:00:00 2001 From: "Andrew M. Stoltz" Date: Sat, 8 Feb 2020 10:59:59 -0600 Subject: [PATCH 3/3] Add Unit Test for new route --- .../rest/api/RepositoriesApiResourceTest.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 components/nexus-repository/src/test/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceTest.java diff --git a/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceTest.java b/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceTest.java new file mode 100644 index 0000000000..13f5167df3 --- /dev/null +++ b/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/rest/api/RepositoriesApiResourceTest.java @@ -0,0 +1,80 @@ +package org.sonatype.nexus.repository.rest.api; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.sonatype.goodies.testsupport.TestSupport; +import org.sonatype.nexus.common.collect.NestedAttributesMap; +import org.sonatype.nexus.repository.Format; +import org.sonatype.nexus.repository.Repository; +import org.sonatype.nexus.repository.Type; +import org.sonatype.nexus.repository.config.Configuration; +import org.sonatype.nexus.repository.rest.api.model.AbstractApiRepository; +import org.sonatype.nexus.repository.types.HostedType; +import org.sonatype.nexus.repository.types.ProxyType; + +import java.util.Collections; +import java.util.Map; + +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.junit.Assert.assertThat; + +public class RepositoriesApiResourceTest extends TestSupport { + private static final String REPOSITORY_1_NAME = "docker-local"; + private static final Format REPOSITORY_1_FORMAT = new Format("docker") {}; + private static final HostedType REPOSITORY_1_TYPE = new HostedType(); + private static final String REPOSITORY_1_URL = "dockerUrl"; + private Repository REPOSITORY_1; + private AbstractApiRepository ABSTRACT_API_REPOSITORY_1; + + @Mock + private AuthorizingRepositoryManager authorizingRepositoryManager; + + @Mock + private ApiRepositoryAdapter defaultAdapter; + + private Map convertersByFormat = Collections.emptyMap(); + + private RepositoriesApiResource underTest; + + @Before + public void setup() throws RepositoryNotFoundException { + REPOSITORY_1 = createMockRepository(REPOSITORY_1_NAME, REPOSITORY_1_FORMAT, REPOSITORY_1_TYPE, REPOSITORY_1_URL, null); + ABSTRACT_API_REPOSITORY_1 = createMockAbstractApiRepository(); + + when(authorizingRepositoryManager.getRepository("docker-local")).thenReturn(REPOSITORY_1); + when(defaultAdapter.adapt(REPOSITORY_1)).thenReturn(ABSTRACT_API_REPOSITORY_1); + + underTest = new RepositoriesApiResource(authorizingRepositoryManager, defaultAdapter, convertersByFormat); + } + + @Test + public void testGetRepository() { + assertThat(underTest.getRepository(REPOSITORY_1_NAME), is(ABSTRACT_API_REPOSITORY_1)); + } + + private static Repository createMockRepository(final String name, final Format format, final Type type, + final String url, final String remoteUrl) { + Repository repository = mock(Repository.class); + when(repository.getName()).thenReturn(name); + when(repository.getFormat()).thenReturn(format); + when(repository.getType()).thenReturn(type); + when(repository.getUrl()).thenReturn(url); + Configuration configuration = mock(Configuration.class); + if (type instanceof ProxyType) { + when(configuration.attributes("proxy")).thenReturn(new NestedAttributesMap( + "proxy", + Collections.singletonMap(remoteUrl, remoteUrl) + )); + } + when(repository.getConfiguration()).thenReturn(configuration); + return repository; + } + + private static AbstractApiRepository createMockAbstractApiRepository() { + AbstractApiRepository repository = mock(AbstractApiRepository.class); + return repository; + } +}