Skip to content

Commit

Permalink
Add GitHub.DependentAuthorizationProvider
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bitwiseman committed Jan 14, 2021
1 parent c33e78a commit 1b84efd
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 43 deletions.
52 changes: 50 additions & 2 deletions src/main/java/org/kohsuke/github/GitHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ public class GitHub {
AbuseLimitHandler abuseLimitHandler,
GitHubRateLimitChecker rateLimitChecker,
AuthorizationProvider authorizationProvider) throws IOException {
authorizationProvider.bind(this);
if (authorizationProvider instanceof DependentAuthorizationProvider) {
((DependentAuthorizationProvider) authorizationProvider).bind(this);
}

this.client = new GitHubHttpUrlConnectionClient(apiUrl,
connector,
rateLimitHandler,
Expand All @@ -130,14 +133,59 @@ private GitHub(GitHubClient client) {
orgs = new ConcurrentHashMap<>();
}

public static abstract class DependentAuthorizationProvider implements AuthorizationProvider {

private GitHub baseGitHub;
private GitHub gitHub;
private final AuthorizationProvider authorizationProvider;

/**
* An AuthorizationProvider that requires an authenticated GitHub instance to provide its authorization.
*
* @param authorizationProvider
* A authorization provider to be used when refreshing this authorization provider.
*/
@BetaApi
@Deprecated
protected DependentAuthorizationProvider(AuthorizationProvider authorizationProvider) {
this.authorizationProvider = authorizationProvider;
}

/**
* Binds this authorization provider to a github instance.
*
* Only needs to be implemented by dynamic credentials providers that use a github instance in order to refresh.
*
* @param github
* The github instance to be used for refreshing dynamic credentials
*/
synchronized void bind(GitHub github) {
if (baseGitHub != null) {
throw new IllegalStateException("Already bound to another GitHub instance.");
}
this.baseGitHub = github;
}

protected synchronized final GitHub gitHub() {
if (gitHub == null) {
gitHub = new GitHub.AuthorizationRefreshGitHubWrapper(this.baseGitHub, authorizationProvider);
}
return gitHub;
}
}

private static class AuthorizationRefreshGitHubWrapper extends GitHub {

private final AuthorizationProvider authorizationProvider;

AuthorizationRefreshGitHubWrapper(GitHub github, AuthorizationProvider authorizationProvider) {
super(github.client);
this.authorizationProvider = authorizationProvider;
this.authorizationProvider.bind(this);

// no dependent authorization providers nest like this currently, but they might in future
if (authorizationProvider instanceof DependentAuthorizationProvider) {
((DependentAuthorizationProvider) authorizationProvider).bind(this);
}
}

@Nonnull
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/kohsuke/github/GitHubClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import org.apache.commons.io.IOUtils;
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider.UserAuthorizationProvider;
import org.kohsuke.github.authorization.AuthorizationProvider;
import org.kohsuke.github.authorization.UserAuthorizationProvider;

import java.io.FileNotFoundException;
import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.kohsuke.github.authorization;

import org.kohsuke.github.GitHub;

import java.io.IOException;

/**
Expand Down Expand Up @@ -33,17 +31,6 @@ public interface AuthorizationProvider {
*/
String getEncodedAuthorization() throws IOException;

/**
* Binds this authorization provider to a github instance.
*
* Only needs to be implemented by dynamic credentials providers that use a github instance in order to refresh.
*
* @param github
* The github instance to be used for refreshing dynamic credentials
*/
default void bind(GitHub github) {
}

/**
* A {@link AuthorizationProvider} that ensures that no credentials are returned
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public ImmutableAuthorizationProvider(String authorization) {
* oauthAccessToken
*/
public static AuthorizationProvider fromOauthToken(String oauthAccessToken) {
return new UserAuthorizationProvider(String.format("token %s", oauthAccessToken));
return new UserProvider(String.format("token %s", oauthAccessToken));
}

/**
Expand All @@ -41,7 +41,7 @@ public static AuthorizationProvider fromOauthToken(String oauthAccessToken) {
* oauthAccessToken
*/
public static AuthorizationProvider fromOauthToken(String oauthAccessToken, String login) {
return new UserAuthorizationProvider(String.format("token %s", oauthAccessToken), login);
return new UserProvider(String.format("token %s", oauthAccessToken), login);
}

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

private final String login;

UserAuthorizationProvider(String authorization) {
UserProvider(String authorization) {
this(authorization, null);
}

UserAuthorizationProvider(String authorization, String login) {
UserProvider(String authorization, String login) {
super(authorization);
this.login = login;
}

@CheckForNull
String getLogin() {
@Override
public String getLogin() {
return login;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.kohsuke.github.GHAppInstallation;
import org.kohsuke.github.GHAppInstallationToken;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.authorization.AuthorizationProvider;

import java.io.IOException;
import java.time.Duration;
Expand All @@ -16,12 +15,8 @@
/**
* Provides an AuthorizationProvider that performs automatic token refresh.
*/
public class OrgAppInstallationAuthorizationProvider implements AuthorizationProvider {
public class OrgAppInstallationAuthorizationProvider extends GitHub.DependentAuthorizationProvider {

private GitHub baseGitHub;
private GitHub gitHub;

private final AuthorizationProvider refreshProvider;
private final String organizationName;

private String latestToken;
Expand All @@ -43,13 +38,8 @@ public class OrgAppInstallationAuthorizationProvider implements AuthorizationPro
@Deprecated
public OrgAppInstallationAuthorizationProvider(String organizationName,
AuthorizationProvider authorizationProvider) {
super(authorizationProvider);
this.organizationName = organizationName;
this.refreshProvider = authorizationProvider;
}

@Override
public void bind(GitHub github) {
this.baseGitHub = github;
}

@Override
Expand All @@ -63,10 +53,7 @@ public String getEncodedAuthorization() throws IOException {
}

private void refreshToken() throws IOException {
if (gitHub == null) {
gitHub = new GitHub.CredentialRefreshGitHubWrapper(this.baseGitHub, refreshProvider);
}

GitHub gitHub = this.gitHub();
GHAppInstallation installationByOrganization = gitHub.getApp()
.getInstallationByOrganization(this.organizationName);
GHAppInstallationToken ghAppInstallationToken = installationByOrganization.createToken().create();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.kohsuke.github.authorization;

import javax.annotation.CheckForNull;

/**
* Interface for all user-related authorization providers.
*
* {@link AuthorizationProvider}s can apply to a number of different account types. This interface applies to providers
* for user accounts, ones that have a login or should query the "/user" endpoint for the login matching this
* credential.
*/
public interface UserAuthorizationProvider extends AuthorizationProvider {

/**
* Gets the user login name.
*
* @return the user login for this provider, or {@code null} if the login value should be queried from the "/user"
* endpoint.
*/
@CheckForNull
String getLogin();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.kohsuke.github.extras.auth;
package org.kohsuke.github.extras.authorization;

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.jsonwebtoken.Jwts;
import org.apache.commons.io.IOUtils;
import org.kohsuke.github.authorization.AuthorizationProvider;
import org.kohsuke.github.extras.auth.JWTTokenProvider;
import org.kohsuke.github.extras.authorization.JWTTokenProvider;

import java.io.File;
import java.io.IOException;
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/kohsuke/github/GitHubConnectionTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.kohsuke.github;

import org.junit.Test;
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider.UserAuthorizationProvider;
import org.kohsuke.github.authorization.UserAuthorizationProvider;

import java.io.IOException;
import java.lang.reflect.Field;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.kohsuke.github.extras.auth;
package org.kohsuke.github.extras.authorization;

import org.junit.Test;
import org.kohsuke.github.AbstractGitHubWireMockTest;
Expand Down

0 comments on commit 1b84efd

Please sign in to comment.