Skip to content

Commit

Permalink
fixup! Add support for PATs in GitHub Enterprise server
Browse files Browse the repository at this point in the history
  • Loading branch information
vinokurig committed Nov 12, 2023
1 parent a7dcfbf commit f9aa72b
Show file tree
Hide file tree
Showing 14 changed files with 60 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -190,21 +190,21 @@ private Optional<PersonalAccessToken> doGetPersonalAccessToken(
|| trimmedUrl.equals(StringUtils.trimEnd(scmServerUrl, '/')))) {
String token =
new String(Base64.getDecoder().decode(secret.getData().get("token"))).trim();
String providerName = annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME);
String tokenName = annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_NAME);
String tokenId = annotations.get(ANNOTATION_SCM_PERSONAL_ACCESS_TOKEN_ID);
String organization = annotations.get(ANNOTATION_SCM_ORGANIZATION);
Optional<String> scmUsername =
scmPersonalAccessTokenFetcher.getScmUsername(
new PersonalAccessTokenParams(
trimmedUrl, providerName, tokenId, token, organization));
trimmedUrl, tokenName, tokenId, token, organization));
if (scmUsername.isPresent()) {
PersonalAccessToken personalAccessToken =
new PersonalAccessToken(
trimmedUrl,
annotations.get(ANNOTATION_CHE_USERID),
organization,
scmUsername.get(),
providerName,
tokenName,
tokenId,
token);
return Optional.of(personalAccessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheSubject, String s

try {
oAuthToken = oAuthAPI.getToken(AzureDevOps.PROVIDER_NAME);
String tokenName = NameGenerator.generate(OAUTH_2_PREFIX, 5);
String tokenName =
NameGenerator.generate(OAUTH_2_PREFIX, 5) + "_" + AzureDevOps.PROVIDER_NAME;
String tokenId = NameGenerator.generate("id-", 5);
Optional<Pair<Boolean, String>> valid =
isValid(
Expand Down Expand Up @@ -173,4 +174,8 @@ private String getLocalAuthenticateUrl() {
private Boolean isValidScmServerUrl(String scmServerUrl) {
return azureDevOpsScmApiEndpoint.equals(trimEnd(scmServerUrl, '/'));
}

public String getProviderName() {
return AzureDevOps.PROVIDER_NAME;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class BitbucketServerPersonalAccessTokenFetcher implements PersonalAccess
private static final Logger LOG =
LoggerFactory.getLogger(BitbucketServerPersonalAccessTokenFetcher.class);

private static final String TOKEN_NAME_TEMPLATE = "che-token-<%s>-<%s>";
private static final String TOKEN_NAME_TEMPLATE = "che-token-<%s>-<%s>_bitbucket-server";
public static final Set<String> DEFAULT_TOKEN_SCOPE =
ImmutableSet.of("PROJECT_WRITE", "REPO_WRITE");
private final BitbucketServerApiClient bitbucketServerApiClient;
Expand Down Expand Up @@ -178,4 +178,8 @@ public Optional<Pair<Boolean, String>> isValid(PersonalAccessTokenParams params)
return Optional.empty();
}
}

public String getProviderName() {
return "bitbucket-server";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/** Representation of a bitbucket Server URL, allowing to get details from it. */
public class BitbucketServerUrl extends DefaultFactoryUrl {

private final String NAME = "bitbucket";
private final String NAME = "bitbucket-server";

/** Hostname of bitbucket URL */
private String hostName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public void shouldSetScmInfoIntoDevfileV2() throws Exception {
// then
ScmInfo scmInfo = factory.getScmInfo();
assertNotNull(scmInfo);
assertEquals(scmInfo.getScmProviderName(), "bitbucket");
assertEquals(scmInfo.getScmProviderName(), "bitbucket-server");
assertEquals(scmInfo.getRepositoryUrl(), "http://bitbucket.2mcl.com/scm/~test/repo.git");
assertEquals(scmInfo.getBranch(), "foobar");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void setup() throws MalformedURLException {
234345345,
23534534,
90,
"che-token-<user987>-<che.server.com>",
"che-token-<user987>-<che.server.com>_bitbucket-server",
"2340590skdf3<0>945i0923i4jasoidfj934ui50",
bitbucketUser,
ImmutableSet.of("PROJECT_WRITE", "REPO_WRITE"));
Expand All @@ -92,7 +92,7 @@ public void setup() throws MalformedURLException {
234345345,
23534534,
90,
"che-token-<user987>-<che.server.com>",
"che-token-<user987>-<che.server.com>_bitbucket-server",
"34545<0>945i0923i4jasoidfj934ui50",
bitbucketUser,
ImmutableSet.of("REPO_READ"));
Expand All @@ -102,7 +102,7 @@ public void setup() throws MalformedURLException {
234345345,
23534534,
90,
"che-token-<user987>-<che.server.com>",
"che-token-<user987>-<che.server.com>_bitbucket-server",
"3456\\<0>945//i0923i4jasoidfj934ui50",
bitbucketUser,
ImmutableSet.of("PROJECT_READ", "REPO_READ"));
Expand Down Expand Up @@ -147,7 +147,7 @@ public void shouldBeAbleToFetchPersonalAccessToken()
when(bitbucketServerApiClient.getPersonalAccessTokens()).thenReturn(Collections.emptyList());

when(bitbucketServerApiClient.createPersonalAccessTokens(
eq("che-token-<user987>-<che.server.com>"),
eq("che-token-<user987>-<che.server.com>_bitbucket-server"),
eq(ImmutableSet.of("PROJECT_WRITE", "REPO_WRITE"))))
.thenReturn(bitbucketPersonalAccessToken);
// when
Expand All @@ -170,7 +170,7 @@ public void shouldDeleteExistedCheTokenBeforeCreatingNew()
when(bitbucketServerApiClient.getPersonalAccessTokens())
.thenReturn(ImmutableList.of(bitbucketPersonalAccessToken, bitbucketPersonalAccessToken2));
when(bitbucketServerApiClient.createPersonalAccessTokens(
eq("che-token-<user987>-<che.server.com>"),
eq("che-token-<user987>-<che.server.com>_bitbucket-server"),
eq(ImmutableSet.of("PROJECT_WRITE", "REPO_WRITE"))))
.thenReturn(bitbucketPersonalAccessToken3);
// when
Expand All @@ -194,7 +194,7 @@ public void shouldRethrowUnExceptionsOnCreatePersonalAccessTokens()
doThrow(ScmBadRequestException.class)
.when(bitbucketServerApiClient)
.createPersonalAccessTokens(
eq("che-token-<user987>-<che.server.com>"),
eq("che-token-<user987>-<che.server.com>_bitbucket-server"),
eq(ImmutableSet.of("PROJECT_WRITE", "REPO_WRITE")));
// when

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheSubject, String s
}
try {
oAuthToken = oAuthAPI.getToken(OAUTH_PROVIDER_NAME);
String tokenName = NameGenerator.generate(OAUTH_PROVIDER_NAME, 5);
String tokenName = NameGenerator.generate(OAUTH_PROVIDER_NAME, 5) + "_" + OAUTH_PROVIDER_NAME;
;
String tokenId = NameGenerator.generate("id-", 5);
Optional<Pair<Boolean, String>> valid =
isValid(
Expand Down Expand Up @@ -185,4 +186,8 @@ private boolean isValidScope(Set<String> scopes) {
&& (scopes.contains(DEFAULT_ACCOUNT_READ_TOKEN_SCOPE)
|| scopes.contains(DEFAULT_ACCOUNT_WRITE_TOKEN_SCOPE));
}

public String getProviderName() {
return OAUTH_PROVIDER_NAME;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ public void shouldReturnToken() throws Exception {
bitbucketPersonalAccessTokenFetcher.fetchPersonalAccessToken(
subject, BitbucketApiClient.BITBUCKET_SERVER);
assertNotNull(token);
assertTrue(token.getScmTokenName().endsWith("_bitbucket"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public abstract class AbstractGithubPersonalAccessTokenFetcher
private final OAuthAPI oAuthAPI;

/** GitHub API client. */
private GithubApiClient githubApiClient;
private final GithubApiClient githubApiClient;

/** Name of this OAuth provider as found in OAuthAPI. */
private final String providerName;
Expand Down Expand Up @@ -124,6 +124,10 @@ public abstract class AbstractGithubPersonalAccessTokenFetcher
this.providerName = providerName;
}

public String getProviderName() {
return this.providerName;
}

@Override
public PersonalAccessToken fetchPersonalAccessToken(Subject cheSubject, String scmServerUrl)
throws ScmUnauthorizedException, ScmCommunicationException, UnknownScmProviderException {
Expand All @@ -135,7 +139,7 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheSubject, String s
}
try {
oAuthToken = oAuthAPI.getToken(providerName);
String tokenName = NameGenerator.generate(OAUTH_2_PREFIX, 5);
String tokenName = NameGenerator.generate(OAUTH_2_PREFIX, 5) + "_" + providerName;
String tokenId = NameGenerator.generate("id-", 5);
Optional<Pair<Boolean, String>> valid =
isValid(
Expand Down Expand Up @@ -205,25 +209,21 @@ public Optional<Boolean> isValid(PersonalAccessToken personalAccessToken) {

@Override
public Optional<Pair<Boolean, String>> isValid(PersonalAccessTokenParams params) {
if (githubApiClient == null || !githubApiClient.isConnected(params.getScmProviderUrl())) {
if (providerName.equals(params.getScmTokenName())) {
githubApiClient = new GithubApiClient(params.getScmProviderUrl());
} else {
LOG.debug("not a valid url {} for current fetcher ", params.getScmProviderUrl());
return Optional.empty();
}
}
GithubApiClient apiClient =
githubApiClient.isConnected(params.getScmProviderUrl())
? githubApiClient
: new GithubApiClient(params.getScmProviderUrl());
try {
if (params.getScmTokenName() != null && params.getScmTokenName().startsWith(OAUTH_2_PREFIX)) {
Pair<String, String[]> pair = githubApiClient.getTokenScopes(params.getToken());
Pair<String, String[]> pair = apiClient.getTokenScopes(params.getToken());
return Optional.of(
Pair.of(
containsScopes(pair.second, DEFAULT_TOKEN_SCOPES) ? Boolean.TRUE : Boolean.FALSE,
pair.first));
} else {
// TODO: add PAT scope validation
// No REST API for PAT-s in Github found yet. Just try to do some action.
GithubUser user = githubApiClient.getUser(params.getToken());
GithubUser user = apiClient.getUser(params.getToken());
return Optional.of(Pair.of(Boolean.TRUE, user.getLogin()));
}
} catch (ScmItemNotFoundException | ScmCommunicationException | ScmBadRequestException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public void shouldReturnToken() throws Exception {
PersonalAccessToken token =
githubPATFetcher.fetchPersonalAccessToken(subject, wireMockServer.url("/"));
assertNotNull(token);
assertTrue(token.getScmTokenName().endsWith("_github"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ public PersonalAccessToken fetchPersonalAccessToken(Subject cheSubject, String s
OAuthToken oAuthToken;
try {
oAuthToken = oAuthAPI.getToken(OAUTH_PROVIDER_NAME);
String tokenName = NameGenerator.generate(OAUTH_2_PREFIX, 5);
String tokenName = NameGenerator.generate(OAUTH_2_PREFIX, 5) + "_" + OAUTH_PROVIDER_NAME;
;
String tokenId = NameGenerator.generate("id-", 5);
Optional<Pair<Boolean, String>> valid =
isValid(
Expand Down Expand Up @@ -232,4 +233,8 @@ private GitlabApiClient getApiClient(String scmServerUrl) {
? new GitlabApiClient(scmServerUrl)
: null;
}

public String getProviderName() {
return OAUTH_PROVIDER_NAME;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public void shouldReturnToken() throws Exception {
PersonalAccessToken token =
oAuthTokenFetcher.fetchPersonalAccessToken(subject, wireMockServer.url("/"));
assertNotNull(token);
assertTrue(token.getScmTokenName().endsWith("_gitlab"));
}

@Test(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ PersonalAccessToken fetchPersonalAccessToken(Subject cheUser, String scmServerUr
Optional<Boolean> isValid(PersonalAccessToken personalAccessToken)
throws ScmCommunicationException, ScmUnauthorizedException;

/** Returns the scm provider name for which this fetcher is applicable. */
String getProviderName();

/**
* Checks whether the provided personal access token is valid by fetching user info from the scm
* provider. Also checks whether the token has expected scope of permissions if the provider API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ public boolean isValid(PersonalAccessToken personalAccessToken)
* fetchers return an scm username, return it. Otherwise, return null.
*/
public Optional<String> getScmUsername(PersonalAccessTokenParams params)
throws UnknownScmProviderException, ScmUnauthorizedException, ScmCommunicationException {
throws UnknownScmProviderException {
String providerName =
params.getScmTokenName().indexOf("_") > 0
? params.getScmTokenName().split("_")[1]
: params.getScmTokenName();
for (PersonalAccessTokenFetcher fetcher : personalAccessTokenFetchers) {
Optional<Pair<Boolean, String>> isValid = fetcher.isValid(params);
if (isValid.isPresent() && isValid.get().first) {
return Optional.of(isValid.get().second);
if (fetcher.getProviderName().equals(providerName)) {
Optional<Pair<Boolean, String>> isValidOptional = fetcher.isValid(params);
return isValidOptional.map(p -> p.second);
}
}
return Optional.empty();
Expand Down

0 comments on commit f9aa72b

Please sign in to comment.