Skip to content

Commit 3f99541

Browse files
authored
Merge pull request #945 from MarcosCela/feat/credential-provider-refresh
Feat/credential provider refresh
2 parents 7e1531d + 1b84efd commit 3f99541

File tree

26 files changed

+1157
-137
lines changed

26 files changed

+1157
-137
lines changed

pom.xml

+7-6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<jacoco.coverage.target.class.method>0.25</jacoco.coverage.target.class.method>
4646
<!-- For non-ci builds we'd like the build to still complete if jacoco metrics aren't met. -->
4747
<jacoco.haltOnFailure>false</jacoco.haltOnFailure>
48+
<jjwt.suite.version>0.11.2</jjwt.suite.version>
4849
</properties>
4950

5051
<build>
@@ -489,20 +490,20 @@
489490
<dependency>
490491
<groupId>io.jsonwebtoken</groupId>
491492
<artifactId>jjwt-api</artifactId>
492-
<version>0.11.2</version>
493-
<scope>test</scope>
493+
<version>${jjwt.suite.version}</version>
494+
<optional>true</optional>
494495
</dependency>
495496
<dependency>
496497
<groupId>io.jsonwebtoken</groupId>
497498
<artifactId>jjwt-impl</artifactId>
498-
<version>0.11.2</version>
499-
<scope>test</scope>
499+
<version>${jjwt.suite.version}</version>
500+
<optional>true</optional>
500501
</dependency>
501502
<dependency>
502503
<groupId>io.jsonwebtoken</groupId>
503504
<artifactId>jjwt-jackson</artifactId>
504-
<version>0.11.2</version>
505-
<scope>test</scope>
505+
<version>${jjwt.suite.version}</version>
506+
<optional>true</optional>
506507
</dependency>
507508
<dependency>
508509
<groupId>com.squareup.okio</groupId>

src/main/java/org/kohsuke/github/GHEvent.java

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
public enum GHEvent {
1313
CHECK_RUN,
1414
CHECK_SUITE,
15+
CODE_SCANNING_ALERT,
1516
COMMIT_COMMENT,
1617
CONTENT_REFERENCE,
1718
CREATE,

src/main/java/org/kohsuke/github/GitHub.java

+92-18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.fasterxml.jackson.databind.ObjectReader;
2727
import com.fasterxml.jackson.databind.ObjectWriter;
2828
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
29+
import org.kohsuke.github.authorization.AuthorizationProvider;
2930
import org.kohsuke.github.internal.Previews;
3031

3132
import java.io.*;
@@ -94,39 +95,112 @@ public class GitHub {
9495
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <code>/api/v3</code> in the URL. For
9596
* historical reasons, this parameter still accepts the bare domain name, but that's considered
9697
* deprecated. Password is also considered deprecated as it is no longer required for api usage.
97-
* @param login
98-
* The user ID on GitHub that you are logging in as. Can be omitted if the OAuth token is provided or if
99-
* logging in anonymously. Specifying this would save one API call.
100-
* @param oauthAccessToken
101-
* Secret OAuth token.
102-
* @param password
103-
* User's password. Always used in conjunction with the {@code login} parameter
10498
* @param connector
105-
* HttpConnector to use. Pass null to use default connector.
99+
* a connector
100+
* @param rateLimitHandler
101+
* rateLimitHandler
102+
* @param abuseLimitHandler
103+
* abuseLimitHandler
104+
* @param rateLimitChecker
105+
* rateLimitChecker
106+
* @param authorizationProvider
107+
* a authorization provider
106108
*/
107109
GitHub(String apiUrl,
108-
String login,
109-
String oauthAccessToken,
110-
String jwtToken,
111-
String password,
112110
HttpConnector connector,
113111
RateLimitHandler rateLimitHandler,
114112
AbuseLimitHandler abuseLimitHandler,
115-
GitHubRateLimitChecker rateLimitChecker) throws IOException {
113+
GitHubRateLimitChecker rateLimitChecker,
114+
AuthorizationProvider authorizationProvider) throws IOException {
115+
if (authorizationProvider instanceof DependentAuthorizationProvider) {
116+
((DependentAuthorizationProvider) authorizationProvider).bind(this);
117+
}
118+
116119
this.client = new GitHubHttpUrlConnectionClient(apiUrl,
117-
login,
118-
oauthAccessToken,
119-
jwtToken,
120-
password,
121120
connector,
122121
rateLimitHandler,
123122
abuseLimitHandler,
124123
rateLimitChecker,
125-
(myself) -> setMyself(myself));
124+
(myself) -> setMyself(myself),
125+
authorizationProvider);
126126
users = new ConcurrentHashMap<>();
127127
orgs = new ConcurrentHashMap<>();
128128
}
129129

130+
private GitHub(GitHubClient client) {
131+
this.client = client;
132+
users = new ConcurrentHashMap<>();
133+
orgs = new ConcurrentHashMap<>();
134+
}
135+
136+
public static abstract class DependentAuthorizationProvider implements AuthorizationProvider {
137+
138+
private GitHub baseGitHub;
139+
private GitHub gitHub;
140+
private final AuthorizationProvider authorizationProvider;
141+
142+
/**
143+
* An AuthorizationProvider that requires an authenticated GitHub instance to provide its authorization.
144+
*
145+
* @param authorizationProvider
146+
* A authorization provider to be used when refreshing this authorization provider.
147+
*/
148+
@BetaApi
149+
@Deprecated
150+
protected DependentAuthorizationProvider(AuthorizationProvider authorizationProvider) {
151+
this.authorizationProvider = authorizationProvider;
152+
}
153+
154+
/**
155+
* Binds this authorization provider to a github instance.
156+
*
157+
* Only needs to be implemented by dynamic credentials providers that use a github instance in order to refresh.
158+
*
159+
* @param github
160+
* The github instance to be used for refreshing dynamic credentials
161+
*/
162+
synchronized void bind(GitHub github) {
163+
if (baseGitHub != null) {
164+
throw new IllegalStateException("Already bound to another GitHub instance.");
165+
}
166+
this.baseGitHub = github;
167+
}
168+
169+
protected synchronized final GitHub gitHub() {
170+
if (gitHub == null) {
171+
gitHub = new GitHub.AuthorizationRefreshGitHubWrapper(this.baseGitHub, authorizationProvider);
172+
}
173+
return gitHub;
174+
}
175+
}
176+
177+
private static class AuthorizationRefreshGitHubWrapper extends GitHub {
178+
179+
private final AuthorizationProvider authorizationProvider;
180+
181+
AuthorizationRefreshGitHubWrapper(GitHub github, AuthorizationProvider authorizationProvider) {
182+
super(github.client);
183+
this.authorizationProvider = authorizationProvider;
184+
185+
// no dependent authorization providers nest like this currently, but they might in future
186+
if (authorizationProvider instanceof DependentAuthorizationProvider) {
187+
((DependentAuthorizationProvider) authorizationProvider).bind(this);
188+
}
189+
}
190+
191+
@Nonnull
192+
@Override
193+
Requester createRequest() {
194+
try {
195+
// Override
196+
return super.createRequest().setHeader("Authorization", authorizationProvider.getEncodedAuthorization())
197+
.rateLimit(RateLimitTarget.NONE);
198+
} catch (IOException e) {
199+
throw new GHException("Failed to create requester to refresh credentials", e);
200+
}
201+
}
202+
}
203+
130204
/**
131205
* Obtains the credential from "~/.github" or from the System Environment Properties.
132206
*

src/main/java/org/kohsuke/github/GitHubBuilder.java

+40-23
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.kohsuke.github;
22

33
import org.apache.commons.io.IOUtils;
4+
import org.kohsuke.github.authorization.AuthorizationProvider;
5+
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider;
46
import org.kohsuke.github.extras.ImpatientHttpConnector;
57

68
import java.io.File;
@@ -24,16 +26,13 @@ public class GitHubBuilder implements Cloneable {
2426

2527
// default scoped so unit tests can read them.
2628
/* private */ String endpoint = GitHubClient.GITHUB_URL;
27-
/* private */ String user;
28-
/* private */ String password;
29-
/* private */ String oauthToken;
30-
/* private */ String jwtToken;
3129

3230
private HttpConnector connector;
3331

3432
private RateLimitHandler rateLimitHandler = RateLimitHandler.WAIT;
3533
private AbuseLimitHandler abuseLimitHandler = AbuseLimitHandler.WAIT;
3634
private GitHubRateLimitChecker rateLimitChecker = new GitHubRateLimitChecker();
35+
/* private */ AuthorizationProvider authorizationProvider = AuthorizationProvider.ANONYMOUS;
3736

3837
/**
3938
* Instantiates a new Git hub builder.
@@ -61,13 +60,13 @@ static GitHubBuilder fromCredentials() throws IOException {
6160

6261
builder = fromEnvironment();
6362

64-
if (builder.oauthToken != null || builder.user != null || builder.jwtToken != null)
63+
if (builder.authorizationProvider != null)
6564
return builder;
6665

6766
try {
6867
builder = fromPropertyFile();
6968

70-
if (builder.oauthToken != null || builder.user != null || builder.jwtToken != null)
69+
if (builder.authorizationProvider != null)
7170
return builder;
7271
} catch (FileNotFoundException e) {
7372
// fall through
@@ -215,9 +214,20 @@ public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOE
215214
*/
216215
public static GitHubBuilder fromProperties(Properties props) {
217216
GitHubBuilder self = new GitHubBuilder();
218-
self.withOAuthToken(props.getProperty("oauth"), props.getProperty("login"));
219-
self.withJwtToken(props.getProperty("jwt"));
220-
self.withPassword(props.getProperty("login"), props.getProperty("password"));
217+
String oauth = props.getProperty("oauth");
218+
String jwt = props.getProperty("jwt");
219+
String login = props.getProperty("login");
220+
String password = props.getProperty("password");
221+
222+
if (oauth != null) {
223+
self.withOAuthToken(oauth, login);
224+
}
225+
if (jwt != null) {
226+
self.withJwtToken(jwt);
227+
}
228+
if (password != null) {
229+
self.withPassword(login, password);
230+
}
221231
self.withEndpoint(props.getProperty("endpoint", GitHubClient.GITHUB_URL));
222232
return self;
223233
}
@@ -247,9 +257,7 @@ public GitHubBuilder withEndpoint(String endpoint) {
247257
* @return the git hub builder
248258
*/
249259
public GitHubBuilder withPassword(String user, String password) {
250-
this.user = user;
251-
this.password = password;
252-
return this;
260+
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromLoginAndPassword(user, password));
253261
}
254262

255263
/**
@@ -260,7 +268,7 @@ public GitHubBuilder withPassword(String user, String password) {
260268
* @return the git hub builder
261269
*/
262270
public GitHubBuilder withOAuthToken(String oauthToken) {
263-
return withOAuthToken(oauthToken, null);
271+
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromOauthToken(oauthToken));
264272
}
265273

266274
/**
@@ -273,8 +281,21 @@ public GitHubBuilder withOAuthToken(String oauthToken) {
273281
* @return the git hub builder
274282
*/
275283
public GitHubBuilder withOAuthToken(String oauthToken, String user) {
276-
this.oauthToken = oauthToken;
277-
this.user = user;
284+
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromOauthToken(oauthToken, user));
285+
}
286+
287+
/**
288+
* Configures a {@link AuthorizationProvider} for this builder
289+
*
290+
* There can be only one authorization provider per client instance.
291+
*
292+
* @param authorizationProvider
293+
* the authorization provider
294+
* @return the git hub builder
295+
*
296+
*/
297+
public GitHubBuilder withAuthorizationProvider(final AuthorizationProvider authorizationProvider) {
298+
this.authorizationProvider = authorizationProvider;
278299
return this;
279300
}
280301

@@ -287,7 +308,7 @@ public GitHubBuilder withOAuthToken(String oauthToken, String user) {
287308
* @see GHAppInstallation#createToken(java.util.Map) GHAppInstallation#createToken(java.util.Map)
288309
*/
289310
public GitHubBuilder withAppInstallationToken(String appInstallationToken) {
290-
return withOAuthToken(appInstallationToken, "");
311+
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromAppInstallationToken(appInstallationToken));
291312
}
292313

293314
/**
@@ -298,8 +319,7 @@ public GitHubBuilder withAppInstallationToken(String appInstallationToken) {
298319
* @return the git hub builder
299320
*/
300321
public GitHubBuilder withJwtToken(String jwtToken) {
301-
this.jwtToken = jwtToken;
302-
return this;
322+
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromJwtToken(jwtToken));
303323
}
304324

305325
/**
@@ -421,14 +441,11 @@ public GitHubBuilder withProxy(final Proxy p) {
421441
*/
422442
public GitHub build() throws IOException {
423443
return new GitHub(endpoint,
424-
user,
425-
oauthToken,
426-
jwtToken,
427-
password,
428444
connector,
429445
rateLimitHandler,
430446
abuseLimitHandler,
431-
rateLimitChecker);
447+
rateLimitChecker,
448+
authorizationProvider);
432449
}
433450

434451
@Override

0 commit comments

Comments
 (0)