Content Selectors not working in multi-tenant environment

I manage a Nexus 3 OSS version (3.30.1-01) that has multiple companies uploading their dependencies to their own repositories. There are certain dependencies within their repositories that should be accessible by other companies, while keeping everything else private. I have read through all the documentation, scoured the internet for articles covering this topic, and read Nexus developer articles covering how to implement this. However, I have not been able to get Content Selectors working to solve this problem.

Desired Result
When Company A adds a dependency from Company B’s hosted repository to their Maven pom.xml file and they have the appropriate read access, the build should complete properly as it locates the dependency in Company A’s group repository. If Company A adds a dependency from Company B’s hosted repository to their Maven pom.xml file they do not have access to, it should fail stating that Maven could not locate the dependency from Company A’s group repository.


This section will give a general overview of the repositories and their contents for both Company A and Company B.

Company A has the following repositories:

- companyA-maven-hosted (hosts all of Company A's dependencies they create)
- companyB-maven-hosted (provide read access to Company B's dependencies for filtering)
- global-maven-proxy (provides access to Maven Central)

Company B has the following repositories:

- companyB-maven-hosted (hosts all of Company B's dependencies they create)
- companyA-maven-hosted (provide read access to Company A's dependencies for filtering)
- global-maven-proxy (the same as the proxy for Company A)

The contents of the hosted repositories are as follows:

- com
  - companyA
    - dep1
      - { versions of dep1 }
    - dep2
      - { version of dep2 }

- com
  - companyB
    - dep3
      - { versions of dep3 }
    - dep4
      - { versions of dep4 }


This section will give a general overview of the RBAC content selectors, privileges, and roles created to provide the desired result.

I have created multiple roles for each LDAP group (their is an LDAP group for Company A named company-a and an LDAP group for Company B named company-b). These LDAP mappings have the following roles:

- nx-component-upload
- nx-search-read
- companyA-read-maven
- companyA-write-maven
- companyA-read-maven-companyB

- nx-repository-view-maven2-companyA-maven-group-read
- nx-repository-view-maven2-companyA-maven-group-browse

- nx-repository-view-maven2-companyA-maven-hosted-*

- read-companyB-public-deps (this is the Content Selector privilege)

There are the same roles created for Company B that mirror the Company A roles swapping instances of companyA with companyB (e.g. companyB-read-maven and companyB-read-maven-companyA).

The role in question is the companyA-read-maven-companyB role I created. It has a Content Selector privilege (read-companyB-public-deps) I created with the following information:

Content Selector: companyB-public-dependencies
Repository: companyB-maven-hosted
Actions: read,browse

The Content Selector companyB-public-dependencies has the following search expression:

(format == "maven2") and (path =~ "/|/com/|/com/companyB/|/com/companyB/dep3/.*")

Essentially what I’m trying to do with this search expression is provide read and browse access to Company A to the companyB/dep3 dependency (found in companyB-maven-hosted repository) while preventing read and browse access to the companyB/dep4 dependency.

The Problem

Because companyB-maven-hosted is part of Company A’s companyA-maven-group group repository, Company A users see everything from companyB-maven-hosted. For example, when they use the browser and select the companyA-maven-group to see the contents, they will see this:

- com
  - companyB
    - dep3
      - { dep3 versions }
    - dep4
      - { dep4 versions }

I have attempted to change the repository that the companyB-public-dependencies Content Selector applies to companyA-maven-group instead of companyB-maven-hosted, but neither choice works. Regardless of what repository I apply the Content Selector to, Company A users always see all of the contents of the companyB-maven-hosted repository.

I have been able to get this to work if I remove the companyB-maven-hosted repository from the companyA-maven-group group repository, but this requires that Company A now includes the separate repository in their Maven settings.xml file:

// settings.xml for Company A
         <id>companyA-group</id> // this is created later in the <servers> section
         <id>companyB-hosted</id> // this is created later in the <servers> section

From all that I’ve read, there should be a way to place the companyB-maven-hosted repository within Company A’s companyA-maven-group group repository and still apply the Content Selector to filter out any dependencies that should remain private. This would allow the settings.xml file to only point to a singular repository group and everything should be managed by Nexus. However, I am unaware of how to do this. I have seen articles covering Repository Targets, but my Nexus 3 OSS version doesn’t seem to have that appearing in the admin panel. I have surmised that Content Selectors have replaced the concept of Repository Targets. Any assistance would be much appreciated.

Thank you.

Groups don’t consider permissions of members.

Is there no way to control the access of specific repositories while still being part of a group? Or will it require that there be another repository URL reference in the build tools? Are there any articles written by Sonatype devs that outline “best practices” for a multi-tenant environment?

Something similar to this:
It outlines what I’m looking for in terms of Repository Targets, but there’s nothing in the Nexus OSS version I am currently using that provides me the ability to use them.

You are then able to take the repository target and associate it with one or more repositories or repository groups. This creates new C.R.U.D. privileges specific to the repository or group.

At the group repository level you could try to grant read+browse permissions based on content selectors, the effectiveness of this will entirely depend on how well defined artifact naming is by both companies.

Thank you, I hadn’t considered controlling the read+browse permissions on the group being filtered using Content Selectors. I’d imagine the Content Selector expressions would become much more convoluted, but good to know that there is an alternative.

For anyone else reading this topic, the fix would be the following:

In the companyA-read-maven RBAC role, instead of granting unfettered read+browse access to the companyA-maven-group repository (via nx-repository-view-maven2-companyA-maven-group-{read/browse}), I would create a Content Selector that would utilize negative regular expressions to filter out any “private dependencies” Company B does not want to share with Company A. I would then apply this Content Selector privilege to the companyA-read-maven RBAC role to ensure that the group repository will filter out any “private dependencies” from Company B while leaving the rest visible. This would require that the Nexus Admin would need to know each and every “private depenency” from each of the companies/teams, but it is at least possible.

You should definitely be cautious with the number and complexity of the content selectors as they can have an impact on performance for certain features (e.g search, browse) that need to evaluate a large number of components at a time.

Makes sense. I believe we’re going to go with the approach we have now where Content Selectors are on the individual company-maven-hosted repositories (where the total contents will be small) and require that each company ensure they update their settings.xml file to include this secondary repository. Requiring that the Nexus Admin knows each and every single dependency that needs to be kept private would be a cumbersome task.

1 Like