You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GitHubRestClient.java 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.auth.github;
  21. import com.github.scribejava.core.model.OAuth2AccessToken;
  22. import com.github.scribejava.core.model.OAuthRequest;
  23. import com.github.scribejava.core.model.Response;
  24. import com.github.scribejava.core.model.Verb;
  25. import com.github.scribejava.core.oauth.OAuth20Service;
  26. import java.io.IOException;
  27. import java.net.HttpURLConnection;
  28. import java.util.List;
  29. import java.util.concurrent.ExecutionException;
  30. import org.sonar.api.utils.log.Logger;
  31. import org.sonar.api.utils.log.Loggers;
  32. import static java.lang.String.format;
  33. import static org.sonar.auth.OAuthRestClient.executePaginatedRequest;
  34. import static org.sonar.auth.OAuthRestClient.executeRequest;
  35. public class GitHubRestClient {
  36. private static final Logger LOGGER = Loggers.get(GitHubRestClient.class);
  37. private final GitHubSettings settings;
  38. public GitHubRestClient(GitHubSettings settings) {
  39. this.settings = settings;
  40. }
  41. GsonUser getUser(OAuth20Service scribe, OAuth2AccessToken accessToken) throws IOException {
  42. String responseBody = executeRequest(settings.apiURL() + "user", scribe, accessToken).getBody();
  43. LOGGER.trace("User response received : {}", responseBody);
  44. return GsonUser.parse(responseBody);
  45. }
  46. String getEmail(OAuth20Service scribe, OAuth2AccessToken accessToken) throws IOException {
  47. String responseBody = executeRequest(settings.apiURL() + "user/emails", scribe, accessToken).getBody();
  48. LOGGER.trace("Emails response received : {}", responseBody);
  49. List<GsonEmail> emails = GsonEmail.parse(responseBody);
  50. return emails.stream()
  51. .filter(email -> email.isPrimary() && email.isVerified())
  52. .findFirst()
  53. .map(GsonEmail::getEmail)
  54. .orElse(null);
  55. }
  56. List<GsonTeam> getTeams(OAuth20Service scribe, OAuth2AccessToken accessToken) {
  57. return executePaginatedRequest(settings.apiURL() + "user/teams", scribe, accessToken, GsonTeam::parse);
  58. }
  59. /**
  60. * Check to see that login is a member of organization.
  61. *
  62. * A 204 response code indicates organization membership. 302 and 404 codes are not treated as exceptional,
  63. * they indicate various ways in which a login is not a member of the organization.
  64. *
  65. * @see <a href="https://developer.github.com/v3/orgs/members/#response-if-requester-is-an-organization-member-and-user-is-a-member">GitHub members API</a>
  66. */
  67. boolean isOrganizationMember(OAuth20Service scribe, OAuth2AccessToken accessToken, String organization, String login)
  68. throws IOException, ExecutionException, InterruptedException {
  69. String requestUrl = settings.apiURL() + format("orgs/%s/members/%s", organization, login);
  70. OAuthRequest request = new OAuthRequest(Verb.GET, requestUrl);
  71. scribe.signRequest(accessToken, request);
  72. Response response = scribe.execute(request);
  73. int code = response.getCode();
  74. switch (code) {
  75. case HttpURLConnection.HTTP_MOVED_TEMP:
  76. case HttpURLConnection.HTTP_NOT_FOUND:
  77. case HttpURLConnection.HTTP_NO_CONTENT:
  78. LOGGER.trace("Orgs response received : {}", code);
  79. return code == HttpURLConnection.HTTP_NO_CONTENT;
  80. default:
  81. throw unexpectedResponseCode(requestUrl, response);
  82. }
  83. }
  84. private static IllegalStateException unexpectedResponseCode(String requestUrl, Response response) throws IOException {
  85. return new IllegalStateException(format("Fail to execute request '%s'. HTTP code: %s, response: %s", requestUrl, response.getCode(), response.getBody()));
  86. }
  87. }