Fallback to public organization information
GitHub uses various access scopes for its REST API and users can
choose how much information they allow to access for the integrations.
The narrowest scope is `USER_EMAILl`, which grants only access to the
user's email address. It's important to note that the _Reviewer_ scope
on eclipse.gerrithub.io and review.gerrithub.io is only asking for
access to the email address.
To give users proper permissions in Gerrit we load information about
user teams and organizations. To read those GitHub requires one of
two scopes `org:read` or `user`. None of those are included in the
_Reviewer_ scope. Which led to an exception being thrown.
As we access organizations and teams API's from a cache loader, getting
an exception meant that the value for the given user was never stored.
This then means that each call to user group membership would result in
yet another attempt to load a cache entry and yet another exception. In
the end group membership cache for a user with scope _Reviewer_ will
never be computed. Which will result in poor page load time.
We already have a mitigation mechanism in place, that would fall to
"public organizations" only, when teams cannot be accessed.
Unfortunately, the GitHub REST API endpoint for "public organizations",
was still requiring "org:read" or "user" scopes. This means that for the
_Reviewer_ scope this fallback never worked.
This change adds another fallback, this time to the real "public
organizations" endpoint that doesn't require additional scopes. It also
ensures that we never use `getMyOrganizations()` call directly but
always go through the fallback route.
Bug: Issue 40014763
Change-Id: I9647b9a1b6e30547f7780c785de37aa6ceb8001d
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
index adfe5e3..02889a1 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
@@ -38,6 +38,7 @@
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;
+import org.kohsuke.github.HttpException;
import org.kohsuke.github.connector.GitHubConnector;
import org.kohsuke.github.internal.GitHubConnectorHttpConnectorAdapter;
import org.slf4j.Logger;
@@ -75,9 +76,21 @@
return null;
}
- public Set<String> getMyOrganisationsLogins() throws IOException {
+ public Set<String> getMyOrganisationsLogins(String username) throws IOException {
if (isLoggedIn()) {
- return getHub().getMyOrganizations().keySet();
+ try {
+ return getHub().getMyOrganizations().keySet();
+ } catch (HttpException httpException) {
+ if (!httpException.getMessage().contains("You need at least")) {
+ throw httpException;
+ }
+ log.info(
+ "Cannot access organizations for user '{}': falling back to list of public"
+ + " organisations",
+ username);
+
+ return getHub().getUserPublicOrganizations(username).keySet();
+ }
}
return Collections.emptySet();
}
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java
index 0bca570..20b80bd 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java
@@ -131,7 +131,7 @@
String user = myself.getLogin();
updateSecureConfigWithRetry(
- ghLogin.getHub().getMyOrganizations().keySet(), user, ghLogin.getToken().accessToken);
+ ghLogin.getMyOrganisationsLogins(user), user, ghLogin.getToken().accessToken);
}
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
index a5301e9..8f9c776 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
@@ -97,7 +97,7 @@
private void loadOrganisations(
String username, OrganizationStructure orgsTeams, GitHubLogin ghLogin) throws IOException {
logger.debug("Getting list of public organisations for user '{}'", username);
- Set<String> organisations = ghLogin.getMyOrganisationsLogins();
+ Set<String> organisations = ghLogin.getMyOrganisationsLogins(username);
for (String org : organisations) {
orgsTeams.put(org, EVERYONE_TEAM_NAME);
}