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); }