Skip to content

Commit 14e609d

Browse files
Merge branch 'main' into main
2 parents da111a0 + 77e2d8f commit 14e609d

File tree

19 files changed

+332
-48
lines changed

19 files changed

+332
-48
lines changed

.github/workflows/maven-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
- name: Maven Install with Code Coverage
7777
run: mvn -B clean install -D enable-ci -Djapicmp.skip --file pom.xml
7878
- name: Codecov Report
79-
uses: codecov/[email protected].1
79+
uses: codecov/[email protected].3
8080
test:
8181
name: test (${{ matrix.os }}, Java ${{ matrix.java }})
8282
runs-on: ${{ matrix.os }}-latest

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@
396396
<plugin>
397397
<groupId>com.github.siom79.japicmp</groupId>
398398
<artifactId>japicmp-maven-plugin</artifactId>
399-
<version>0.17.1</version>
399+
<version>0.17.2</version>
400400
<configuration>
401401
<parameter>
402402
<breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.kohsuke.github.authorization;
2+
3+
import org.kohsuke.github.BetaApi;
4+
import org.kohsuke.github.GHApp;
5+
import org.kohsuke.github.GHAppInstallation;
6+
import org.kohsuke.github.GHAppInstallationToken;
7+
import org.kohsuke.github.GitHub;
8+
9+
import java.io.IOException;
10+
import java.time.Duration;
11+
import java.time.Instant;
12+
import java.util.Objects;
13+
14+
import javax.annotation.Nonnull;
15+
16+
/**
17+
* An AuthorizationProvider that performs automatic token refresh for an organization's AppInstallation.
18+
*/
19+
public class AppInstallationAuthorizationProvider extends GitHub.DependentAuthorizationProvider {
20+
21+
private final AppInstallationProvider appInstallationProvider;
22+
23+
private String authorization;
24+
25+
@Nonnull
26+
private Instant validUntil = Instant.MIN;
27+
28+
/**
29+
* Provides an AuthorizationProvider that performs automatic token refresh, based on an previously authenticated
30+
* github client.
31+
*
32+
* @param appInstallationProvider
33+
* An AppInstallationProvider that the authorization provider will use to retrieve the App.
34+
* @param authorizationProvider
35+
* A authorization provider that returns a JWT token that can be used to refresh the App Installation
36+
* token from GitHub.
37+
*/
38+
@BetaApi
39+
public AppInstallationAuthorizationProvider(AppInstallationProvider appInstallationProvider,
40+
AuthorizationProvider authorizationProvider) {
41+
super(authorizationProvider);
42+
this.appInstallationProvider = appInstallationProvider;
43+
}
44+
45+
@Override
46+
public String getEncodedAuthorization() throws IOException {
47+
synchronized (this) {
48+
if (authorization == null || Instant.now().isAfter(this.validUntil)) {
49+
String token = refreshToken();
50+
authorization = String.format("token %s", token);
51+
}
52+
return authorization;
53+
}
54+
}
55+
56+
private String refreshToken() throws IOException {
57+
GitHub gitHub = this.gitHub();
58+
GHAppInstallation installationByOrganization = appInstallationProvider.getAppInstallation(gitHub.getApp());
59+
GHAppInstallationToken ghAppInstallationToken = installationByOrganization.createToken().create();
60+
this.validUntil = ghAppInstallationToken.getExpiresAt().toInstant().minus(Duration.ofMinutes(5));
61+
return Objects.requireNonNull(ghAppInstallationToken.getToken());
62+
}
63+
64+
/**
65+
* Provides an interface that returns an app to be used by an AppInstallationAuthorizationProvider
66+
*/
67+
@FunctionalInterface
68+
public interface AppInstallationProvider {
69+
/**
70+
* Provides a GHAppInstallation for the given GHApp
71+
*
72+
* @param app
73+
* The GHApp to use
74+
* @return The GHAppInstallation
75+
* @throws IOException
76+
* on error
77+
*/
78+
GHAppInstallation getAppInstallation(GHApp app) throws IOException;
79+
}
80+
}
Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,12 @@
11
package org.kohsuke.github.authorization;
22

33
import org.kohsuke.github.BetaApi;
4-
import org.kohsuke.github.GHAppInstallation;
5-
import org.kohsuke.github.GHAppInstallationToken;
6-
import org.kohsuke.github.GitHub;
7-
8-
import java.io.IOException;
9-
import java.time.Duration;
10-
import java.time.Instant;
11-
import java.util.Objects;
12-
13-
import javax.annotation.Nonnull;
144

155
/**
166
* An AuthorizationProvider that performs automatic token refresh for an organization's AppInstallation.
177
*/
18-
public class OrgAppInstallationAuthorizationProvider extends GitHub.DependentAuthorizationProvider {
19-
20-
private final String organizationName;
21-
22-
private String authorization;
23-
24-
@Nonnull
25-
private Instant validUntil = Instant.MIN;
8+
@Deprecated
9+
public class OrgAppInstallationAuthorizationProvider extends AppInstallationAuthorizationProvider {
2610

2711
/**
2812
* Provides an AuthorizationProvider that performs automatic token refresh, based on an previously authenticated
@@ -33,31 +17,13 @@ public class OrgAppInstallationAuthorizationProvider extends GitHub.DependentAut
3317
* @param authorizationProvider
3418
* A authorization provider that returns a JWT token that can be used to refresh the App Installation
3519
* token from GitHub.
20+
*
21+
* @deprecated Replaced by {@link AppInstallationAuthorizationProvider}
3622
*/
3723
@BetaApi
24+
@Deprecated
3825
public OrgAppInstallationAuthorizationProvider(String organizationName,
3926
AuthorizationProvider authorizationProvider) {
40-
super(authorizationProvider);
41-
this.organizationName = organizationName;
42-
}
43-
44-
@Override
45-
public String getEncodedAuthorization() throws IOException {
46-
synchronized (this) {
47-
if (authorization == null || Instant.now().isAfter(this.validUntil)) {
48-
String token = refreshToken();
49-
authorization = String.format("token %s", token);
50-
}
51-
return authorization;
52-
}
53-
}
54-
55-
private String refreshToken() throws IOException {
56-
GitHub gitHub = this.gitHub();
57-
GHAppInstallation installationByOrganization = gitHub.getApp()
58-
.getInstallationByOrganization(this.organizationName);
59-
GHAppInstallationToken ghAppInstallationToken = installationByOrganization.createToken().create();
60-
this.validUntil = ghAppInstallationToken.getExpiresAt().toInstant().minus(Duration.ofMinutes(5));
61-
return Objects.requireNonNull(ghAppInstallationToken.getToken());
27+
super(app -> app.getInstallationByOrganization(organizationName), authorizationProvider);
6228
}
6329
}

src/test/java/org/kohsuke/github/OrgAppInstallationAuthorizationProviderTest.java renamed to src/test/java/org/kohsuke/github/AppInstallationAuthorizationProviderTest.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
package org.kohsuke.github;
22

33
import org.junit.Test;
4+
import org.kohsuke.github.authorization.AppInstallationAuthorizationProvider;
45
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider;
56
import org.kohsuke.github.authorization.OrgAppInstallationAuthorizationProvider;
67

78
import java.io.IOException;
89

910
import static org.hamcrest.CoreMatchers.equalTo;
1011
import static org.hamcrest.CoreMatchers.notNullValue;
12+
import static org.hamcrest.CoreMatchers.startsWith;
1113

1214
// TODO: Auto-generated Javadoc
15+
1316
/**
14-
* The Class OrgAppInstallationAuthorizationProviderTest.
17+
* The Class AppInstallationAuthorizationProviderTest.
1518
*/
16-
public class OrgAppInstallationAuthorizationProviderTest extends AbstractGHAppInstallationTest {
19+
public class AppInstallationAuthorizationProviderTest extends AbstractGHAppInstallationTest {
1720

1821
/**
1922
* Instantiates a new org app installation authorization provider test.
2023
*/
21-
public OrgAppInstallationAuthorizationProviderTest() {
24+
public AppInstallationAuthorizationProviderTest() {
2225
useDefaultGitHub = false;
2326
}
2427

@@ -48,7 +51,8 @@ public void invalidJWTTokenRaisesException() throws IOException {
4851
*/
4952
@Test
5053
public void validJWTTokenAllowsOauthTokenRequest() throws IOException {
51-
OrgAppInstallationAuthorizationProvider provider = new OrgAppInstallationAuthorizationProvider("hub4j-test-org",
54+
AppInstallationAuthorizationProvider provider = new AppInstallationAuthorizationProvider(
55+
app -> app.getInstallationByOrganization("hub4j-test-org"),
5256
ImmutableAuthorizationProvider.fromJwtToken("bogus-valid-token"));
5357
gitHub = getGitHubBuilder().withAuthorizationProvider(provider)
5458
.withEndpoint(mockGitHub.apiServer().baseUrl())
@@ -59,4 +63,27 @@ public void validJWTTokenAllowsOauthTokenRequest() throws IOException {
5963
assertThat(encodedAuthorization, equalTo("token v1.9a12d913f980a45a16ac9c3a9d34d9b7sa314cb6"));
6064
}
6165

66+
/**
67+
* Lookup of an app by id works as expected
68+
*
69+
* @throws IOException
70+
* Signals that an I/O exception has occurred.
71+
*/
72+
@Test
73+
public void validJWTTokenWhenLookingUpAppById() throws IOException {
74+
AppInstallationAuthorizationProvider provider = new AppInstallationAuthorizationProvider(
75+
// https://github.com/organizations/hub4j-test-org/settings/installations/12129901
76+
app -> app.getInstallationById(12129901L),
77+
jwtProvider1);
78+
gitHub = getGitHubBuilder().withAuthorizationProvider(provider)
79+
.withEndpoint(mockGitHub.apiServer().baseUrl())
80+
.build();
81+
String encodedAuthorization = provider.getEncodedAuthorization();
82+
83+
assertThat(encodedAuthorization, notNullValue());
84+
// we could assert on the exact token with wiremock, but it would make the update of the test more complex
85+
// do we really care, getting a token should be enough.
86+
assertThat(encodedAuthorization, startsWith("token ghs_"));
87+
}
88+
6289
}

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

Lines changed: 3 additions & 2 deletions
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.OrgAppInstallationAuthorizationProvider;
4+
import org.kohsuke.github.authorization.AppInstallationAuthorizationProvider;
55

66
import java.io.IOException;
77
import java.util.List;
@@ -22,7 +22,8 @@ public class GHAuthenticatedAppInstallationTest extends AbstractGHAppInstallatio
2222
*/
2323
@Override
2424
protected GitHubBuilder getGitHubBuilder() {
25-
OrgAppInstallationAuthorizationProvider provider = new OrgAppInstallationAuthorizationProvider("hub4j-test-org",
25+
AppInstallationAuthorizationProvider provider = new AppInstallationAuthorizationProvider(
26+
app -> app.getInstallationByOrganization("hub4j-test-org"),
2627
jwtProvider1);
2728
return super.getGitHubBuilder().withAuthorizationProvider(provider);
2829
}

0 commit comments

Comments
 (0)