Skip to content

Commit 1b84efd

Browse files
committed
Add GitHub.DependentAuthorizationProvider
Rather than exposing an unsafe wrapper for GitHub instances, I added a base class that can be extended by anyone wanting to implement an authorization provider that needs a GitHub instance to generate it's authorization string.
1 parent c33e78a commit 1b84efd

File tree

12 files changed

+88
-43
lines changed

12 files changed

+88
-43
lines changed

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

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ public class GitHub {
112112
AbuseLimitHandler abuseLimitHandler,
113113
GitHubRateLimitChecker rateLimitChecker,
114114
AuthorizationProvider authorizationProvider) throws IOException {
115-
authorizationProvider.bind(this);
115+
if (authorizationProvider instanceof DependentAuthorizationProvider) {
116+
((DependentAuthorizationProvider) authorizationProvider).bind(this);
117+
}
118+
116119
this.client = new GitHubHttpUrlConnectionClient(apiUrl,
117120
connector,
118121
rateLimitHandler,
@@ -130,14 +133,59 @@ private GitHub(GitHubClient client) {
130133
orgs = new ConcurrentHashMap<>();
131134
}
132135

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+
133177
private static class AuthorizationRefreshGitHubWrapper extends GitHub {
134178

135179
private final AuthorizationProvider authorizationProvider;
136180

137181
AuthorizationRefreshGitHubWrapper(GitHub github, AuthorizationProvider authorizationProvider) {
138182
super(github.client);
139183
this.authorizationProvider = authorizationProvider;
140-
this.authorizationProvider.bind(this);
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+
}
141189
}
142190

143191
@Nonnull

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import com.fasterxml.jackson.databind.*;
44
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
55
import org.apache.commons.io.IOUtils;
6-
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider.UserAuthorizationProvider;
76
import org.kohsuke.github.authorization.AuthorizationProvider;
7+
import org.kohsuke.github.authorization.UserAuthorizationProvider;
88

99
import java.io.FileNotFoundException;
1010
import java.io.IOException;

src/main/java/org/kohsuke/github/authorization/AuthorizationProvider.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.kohsuke.github.authorization;
22

3-
import org.kohsuke.github.GitHub;
4-
53
import java.io.IOException;
64

75
/**
@@ -33,17 +31,6 @@ public interface AuthorizationProvider {
3331
*/
3432
String getEncodedAuthorization() throws IOException;
3533

36-
/**
37-
* Binds this authorization provider to a github instance.
38-
*
39-
* Only needs to be implemented by dynamic credentials providers that use a github instance in order to refresh.
40-
*
41-
* @param github
42-
* The github instance to be used for refreshing dynamic credentials
43-
*/
44-
default void bind(GitHub github) {
45-
}
46-
4734
/**
4835
* A {@link AuthorizationProvider} that ensures that no credentials are returned
4936
*/

src/main/java/org/kohsuke/github/authorization/ImmutableAuthorizationProvider.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public ImmutableAuthorizationProvider(String authorization) {
2626
* oauthAccessToken
2727
*/
2828
public static AuthorizationProvider fromOauthToken(String oauthAccessToken) {
29-
return new UserAuthorizationProvider(String.format("token %s", oauthAccessToken));
29+
return new UserProvider(String.format("token %s", oauthAccessToken));
3030
}
3131

3232
/**
@@ -41,7 +41,7 @@ public static AuthorizationProvider fromOauthToken(String oauthAccessToken) {
4141
* oauthAccessToken
4242
*/
4343
public static AuthorizationProvider fromOauthToken(String oauthAccessToken, String login) {
44-
return new UserAuthorizationProvider(String.format("token %s", oauthAccessToken), login);
44+
return new UserProvider(String.format("token %s", oauthAccessToken), login);
4545
}
4646

4747
/**
@@ -84,7 +84,7 @@ public static AuthorizationProvider fromLoginAndPassword(String login, String pa
8484
String charsetName = StandardCharsets.UTF_8.name();
8585
String b64encoded = Base64.getEncoder().encodeToString(authorization.getBytes(charsetName));
8686
String encodedAuthorization = String.format("Basic %s", b64encoded);
87-
return new UserAuthorizationProvider(encodedAuthorization, login);
87+
return new UserProvider(encodedAuthorization, login);
8888
} catch (UnsupportedEncodingException e) {
8989
// If UTF-8 isn't supported, there are bigger problems
9090
throw new IllegalStateException("Could not generate encoded authorization", e);
@@ -100,21 +100,22 @@ public String getEncodedAuthorization() {
100100
* An internal class representing all user-related credentials, which are credentials that have a login or should
101101
* query the user endpoint for the login matching this credential.
102102
*/
103-
static class UserAuthorizationProvider extends ImmutableAuthorizationProvider {
103+
private static class UserProvider extends ImmutableAuthorizationProvider implements UserAuthorizationProvider {
104104

105105
private final String login;
106106

107-
UserAuthorizationProvider(String authorization) {
107+
UserProvider(String authorization) {
108108
this(authorization, null);
109109
}
110110

111-
UserAuthorizationProvider(String authorization, String login) {
111+
UserProvider(String authorization, String login) {
112112
super(authorization);
113113
this.login = login;
114114
}
115115

116116
@CheckForNull
117-
String getLogin() {
117+
@Override
118+
public String getLogin() {
118119
return login;
119120
}
120121

src/main/java/org/kohsuke/github/authorization/OrgAppInstallationAuthorizationProvider.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import org.kohsuke.github.GHAppInstallation;
55
import org.kohsuke.github.GHAppInstallationToken;
66
import org.kohsuke.github.GitHub;
7-
import org.kohsuke.github.authorization.AuthorizationProvider;
87

98
import java.io.IOException;
109
import java.time.Duration;
@@ -16,12 +15,8 @@
1615
/**
1716
* Provides an AuthorizationProvider that performs automatic token refresh.
1817
*/
19-
public class OrgAppInstallationAuthorizationProvider implements AuthorizationProvider {
18+
public class OrgAppInstallationAuthorizationProvider extends GitHub.DependentAuthorizationProvider {
2019

21-
private GitHub baseGitHub;
22-
private GitHub gitHub;
23-
24-
private final AuthorizationProvider refreshProvider;
2520
private final String organizationName;
2621

2722
private String latestToken;
@@ -43,13 +38,8 @@ public class OrgAppInstallationAuthorizationProvider implements AuthorizationPro
4338
@Deprecated
4439
public OrgAppInstallationAuthorizationProvider(String organizationName,
4540
AuthorizationProvider authorizationProvider) {
41+
super(authorizationProvider);
4642
this.organizationName = organizationName;
47-
this.refreshProvider = authorizationProvider;
48-
}
49-
50-
@Override
51-
public void bind(GitHub github) {
52-
this.baseGitHub = github;
5343
}
5444

5545
@Override
@@ -63,10 +53,7 @@ public String getEncodedAuthorization() throws IOException {
6353
}
6454

6555
private void refreshToken() throws IOException {
66-
if (gitHub == null) {
67-
gitHub = new GitHub.CredentialRefreshGitHubWrapper(this.baseGitHub, refreshProvider);
68-
}
69-
56+
GitHub gitHub = this.gitHub();
7057
GHAppInstallation installationByOrganization = gitHub.getApp()
7158
.getInstallationByOrganization(this.organizationName);
7259
GHAppInstallationToken ghAppInstallationToken = installationByOrganization.createToken().create();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.kohsuke.github.authorization;
2+
3+
import javax.annotation.CheckForNull;
4+
5+
/**
6+
* Interface for all user-related authorization providers.
7+
*
8+
* {@link AuthorizationProvider}s can apply to a number of different account types. This interface applies to providers
9+
* for user accounts, ones that have a login or should query the "/user" endpoint for the login matching this
10+
* credential.
11+
*/
12+
public interface UserAuthorizationProvider extends AuthorizationProvider {
13+
14+
/**
15+
* Gets the user login name.
16+
*
17+
* @return the user login for this provider, or {@code null} if the login value should be queried from the "/user"
18+
* endpoint.
19+
*/
20+
@CheckForNull
21+
String getLogin();
22+
}

src/main/java/org/kohsuke/github/extras/auth/JWTTokenProvider.java renamed to src/main/java/org/kohsuke/github/extras/authorization/JWTTokenProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.kohsuke.github.extras.auth;
1+
package org.kohsuke.github.extras.authorization;
22

33
import io.jsonwebtoken.JwtBuilder;
44
import io.jsonwebtoken.Jwts;

src/test/java/org/kohsuke/github/AbstractGHAppInstallationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import io.jsonwebtoken.Jwts;
44
import org.apache.commons.io.IOUtils;
55
import org.kohsuke.github.authorization.AuthorizationProvider;
6-
import org.kohsuke.github.extras.auth.JWTTokenProvider;
6+
import org.kohsuke.github.extras.authorization.JWTTokenProvider;
77

88
import java.io.File;
99
import java.io.IOException;

src/test/java/org/kohsuke/github/GitHubConnectionTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.kohsuke.github;
22

33
import org.junit.Test;
4-
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider.UserAuthorizationProvider;
4+
import org.kohsuke.github.authorization.UserAuthorizationProvider;
55

66
import java.io.IOException;
77
import java.lang.reflect.Field;

src/test/java/org/kohsuke/github/extras/auth/JWTTokenProviderTest.java renamed to src/test/java/org/kohsuke/github/extras/authorization/JWTTokenProviderTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.kohsuke.github.extras.auth;
1+
package org.kohsuke.github.extras.authorization;
22

33
import org.junit.Test;
44
import org.kohsuke.github.AbstractGitHubWireMockTest;

0 commit comments

Comments
 (0)