-
Notifications
You must be signed in to change notification settings - Fork 1.5k
fix: handle caching when detecting a repo requires auth #4471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gibfahn
wants to merge
1
commit into
GoogleContainerTools:master
Choose a base branch
from
gibfahn:fix_auth
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+172
−60
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,6 +48,7 @@ | |
| import java.util.Optional; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
| import java.util.function.Consumer; | ||
| import java.util.function.Supplier; | ||
| import java.util.stream.Stream; | ||
| import javax.annotation.Nullable; | ||
| import javax.annotation.concurrent.ThreadSafe; | ||
|
|
@@ -65,6 +66,8 @@ public static class Factory { | |
|
|
||
| @Nullable private String userAgent; | ||
| @Nullable private Credential credential; | ||
| Supplier<RegistryUnauthorizedExceptionHandler> registryUnauthorizedExceptionHandlerSupplier = | ||
| RegistryClient::defaultRegistryUnauthorizedExceptionHandler; | ||
|
|
||
| private Factory( | ||
| EventHandlers eventHandlers, | ||
|
|
@@ -86,6 +89,20 @@ public Factory setCredential(@Nullable Credential credential) { | |
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the supplier for the registry unauthorized exception handler. | ||
| * | ||
| * @param registryUnauthorizedExceptionHandlerSupplier the supplier for the exception handler | ||
| * @return this | ||
| */ | ||
| public Factory setUnauthorizedExceptionHandlerSupplier( | ||
| Supplier<RegistryUnauthorizedExceptionHandler> | ||
| registryUnauthorizedExceptionHandlerSupplier) { | ||
| this.registryUnauthorizedExceptionHandlerSupplier = | ||
| registryUnauthorizedExceptionHandlerSupplier; | ||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the value of {@code User-Agent} in headers for registry requests. | ||
| * | ||
|
|
@@ -104,7 +121,12 @@ public Factory setUserAgent(@Nullable String userAgent) { | |
| */ | ||
| public RegistryClient newRegistryClient() { | ||
| return new RegistryClient( | ||
| eventHandlers, credential, registryEndpointRequestProperties, userAgent, httpClient); | ||
| eventHandlers, | ||
| credential, | ||
| registryUnauthorizedExceptionHandlerSupplier, | ||
| registryEndpointRequestProperties, | ||
| userAgent, | ||
| httpClient); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -231,6 +253,8 @@ static Multimap<String, String> decodeTokenRepositoryGrants(String token) { | |
|
|
||
| private final EventHandlers eventHandlers; | ||
| @Nullable private final Credential credential; | ||
| private final Supplier<RegistryUnauthorizedExceptionHandler> | ||
| registryUnauthorizedExceptionHandlerSupplier; | ||
| private final RegistryEndpointRequestProperties registryEndpointRequestProperties; | ||
| @Nullable private final String userAgent; | ||
| private final FailoverHttpClient httpClient; | ||
|
|
@@ -254,11 +278,14 @@ static Multimap<String, String> decodeTokenRepositoryGrants(String token) { | |
| private RegistryClient( | ||
| EventHandlers eventHandlers, | ||
| @Nullable Credential credential, | ||
| Supplier<RegistryUnauthorizedExceptionHandler> registryUnauthorizedExceptionHandlerSupplier, | ||
| RegistryEndpointRequestProperties registryEndpointRequestProperties, | ||
| @Nullable String userAgent, | ||
| FailoverHttpClient httpClient) { | ||
| this.eventHandlers = eventHandlers; | ||
| this.credential = credential; | ||
| this.registryUnauthorizedExceptionHandlerSupplier = | ||
| registryUnauthorizedExceptionHandlerSupplier; | ||
| this.registryEndpointRequestProperties = registryEndpointRequestProperties; | ||
| this.userAgent = userAgent; | ||
| this.httpClient = httpClient; | ||
|
|
@@ -595,6 +622,16 @@ private static boolean isBearerAuth(@Nullable Authorization authorization) { | |
| return authorization != null && "bearer".equalsIgnoreCase(authorization.getScheme()); | ||
| } | ||
|
|
||
| /** | ||
| * Obtains the event handlers. This is intended to be used by the {@link | ||
| * RegistryUnauthorizedExceptionHandler}. | ||
| * | ||
| * @return the event | ||
| */ | ||
| public EventHandlers getEventHandlers() { | ||
| return eventHandlers; | ||
| } | ||
|
|
||
| @Nullable | ||
| @VisibleForTesting | ||
| String getUserAgent() { | ||
|
|
@@ -610,7 +647,8 @@ String getUserAgent() { | |
| */ | ||
| private <T> T callRegistryEndpoint(RegistryEndpointProvider<T> registryEndpointProvider) | ||
| throws IOException, RegistryException { | ||
| int bearerTokenRefreshes = 0; | ||
| Supplier<RegistryUnauthorizedExceptionHandler> handlerSupplier = | ||
| this.registryUnauthorizedExceptionHandlerSupplier; | ||
| while (true) { | ||
| try { | ||
| return new RegistryEndpointCaller<>( | ||
|
|
@@ -623,18 +661,37 @@ private <T> T callRegistryEndpoint(RegistryEndpointProvider<T> registryEndpointP | |
| .call(); | ||
|
|
||
| } catch (RegistryUnauthorizedException ex) { | ||
| handlerSupplier = handlerSupplier.get().handle(this, ex); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| static class DefaultRegistryUnauthorizedExceptionHandler | ||
| implements RegistryUnauthorizedExceptionHandler { | ||
| int bearerTokenRefreshes = 0; | ||
|
|
||
| public Supplier<RegistryUnauthorizedExceptionHandler> handle( | ||
| final RegistryClient registryClient, final RegistryUnauthorizedException ex) | ||
| throws RegistryException { | ||
| { | ||
| if (ex.getHttpResponseException().getStatusCode() | ||
| != HttpStatusCodes.STATUS_CODE_UNAUTHORIZED | ||
| || !isBearerAuth(authorization.get()) | ||
| || !isBearerAuth(registryClient.authorization.get()) | ||
| || ++bearerTokenRefreshes >= MAX_BEARER_TOKEN_REFRESH_TRIES) { | ||
| throw ex; | ||
| } | ||
|
|
||
| // Because we successfully did bearer authentication initially, getting 401 here probably | ||
| // means the token was expired. | ||
| String wwwAuthenticate = ex.getHttpResponseException().getHeaders().getAuthenticate(); | ||
| authorization.set(refreshBearerAuth(wwwAuthenticate)); | ||
| registryClient.authorization.set(registryClient.refreshBearerAuth(wwwAuthenticate)); | ||
|
|
||
| return () -> this; | ||
| } | ||
|
Comment on lines
+676
to
690
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This extra pair of braces is unnecessary and makes the code slightly harder to read. It's best to remove it for simplicity and to maintain a consistent coding style. if (ex.getHttpResponseException().getStatusCode()
!= HttpStatusCodes.STATUS_CODE_UNAUTHORIZED
|| !isBearerAuth(registryClient.authorization.get())
|| ++bearerTokenRefreshes >= MAX_BEARER_TOKEN_REFRESH_TRIES) {
throw ex;
}
// Because we successfully did bearer authentication initially, getting 401 here probably
// means the token was expired.
String wwwAuthenticate = ex.getHttpResponseException().getHeaders().getAuthenticate();
registryClient.authorization.set(registryClient.refreshBearerAuth(wwwAuthenticate));
return () -> this; |
||
| } | ||
| } | ||
|
|
||
| public static RegistryUnauthorizedExceptionHandler defaultRegistryUnauthorizedExceptionHandler() { | ||
| return new DefaultRegistryUnauthorizedExceptionHandler(); | ||
| } | ||
| } | ||
26 changes: 26 additions & 0 deletions
26
...c/main/java/com/google/cloud/tools/jib/registry/RegistryUnauthorizedExceptionHandler.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package com.google.cloud.tools.jib.registry; | ||
|
|
||
| import com.google.cloud.tools.jib.api.RegistryException; | ||
| import com.google.cloud.tools.jib.api.RegistryUnauthorizedException; | ||
| import java.io.IOException; | ||
| import java.util.function.Supplier; | ||
|
|
||
| public interface RegistryUnauthorizedExceptionHandler { | ||
|
|
||
| /** | ||
| * Handle the exception caught by the registry client when it attempted to communicate with the | ||
| * registry. | ||
| * | ||
| * <p>The most obvious action is to simply throw {@code ex}. Other possible actions are to | ||
| * reauthenticate the client. | ||
| * | ||
| * @param registryClient the registry client which may be reconfigured | ||
| * @param ex the exception being handled on behalf of the client | ||
| * @return a supplier to use if another exception occurs on the next retry | ||
| * @throws IOException if an I/O error occurs | ||
| * @throws RegistryException if a registry error occurs | ||
| */ | ||
| Supplier<RegistryUnauthorizedExceptionHandler> handle( | ||
| RegistryClient registryClient, RegistryUnauthorizedException ex) | ||
| throws IOException, RegistryException; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of double braces
{{ ... }}and the accompanying comment is unconventional and harms code readability. While it might be intended to minimize diff noise, prioritizing long-term code clarity is generally better. Future maintainers could find this pattern confusing. I recommend removing the extra braces and the comment.