lhotari commented on a change in pull request #13951: URL: https://github.com/apache/pulsar/pull/13951#discussion_r802828437
########## File path: pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Builder.java ########## @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.client.impl.auth.oauth2; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import org.apache.pulsar.client.api.Authentication; + +/** + * Builder for {@link AuthenticationOAuth2} class. + */ +public final class AuthenticationOAuth2Builder { + + /** + * Create a builder instance. + * + * @return builder + */ + public static AuthenticationOAuth2Builder builder() { + return new AuthenticationOAuth2Builder(); + } + + private double earlyTokenRefreshPercent = AuthenticationOAuth2.EARLY_TOKEN_REFRESH_PERCENT_DEFAULT; + private ScheduledThreadPoolExecutor scheduler; + private ClientCredentialsConfiguration clientCredentialsConfiguration; + + /** + * Set the {@link ClientCredentialsConfiguration} when using the OAuth2 client credentials flow. + * @return builder + */ + public AuthenticationOAuth2Builder setClientCredentialsConfiguration( + ClientCredentialsConfiguration clientCredentialsConfiguration) { + if (clientCredentialsConfiguration == null) { + throw new IllegalArgumentException("ClientCredentialsConfiguration cannot be null."); + } + this.clientCredentialsConfiguration = clientCredentialsConfiguration; + return this; + } + + /** + * @param earlyTokenRefreshPercent - The percent of the expires_in time when the client should start attempting + * to refresh the token. If greater than or equal to 1, it is disabled. See + * {@link AuthenticationOAuth2} for details. + * @return builder + */ + public AuthenticationOAuth2Builder setEarlyTokenRefreshPercent(double earlyTokenRefreshPercent) { + if (earlyTokenRefreshPercent <= 0) { + throw new IllegalArgumentException("EarlyTokenRefreshPercent must be greater than 0."); + } + this.earlyTokenRefreshPercent = earlyTokenRefreshPercent; + return this; + } + + /** + * @param scheduler - The scheduler to use for background refreshes of the token. If null and the + * {@link #earlyTokenRefreshPercent} is less than 1, the client will create an internal scheduler. + * Otherwise, it will use the passed in scheduler. If the caller supplies a scheduler, the + * {@link AuthenticationOAuth2} will not close it. + * @return builder + */ + public AuthenticationOAuth2Builder setEarlyTokenRefreshExecutor(ScheduledThreadPoolExecutor scheduler) { Review comment: similar ########## File path: pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Builder.java ########## @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.client.impl.auth.oauth2; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import org.apache.pulsar.client.api.Authentication; + +/** + * Builder for {@link AuthenticationOAuth2} class. + */ +public final class AuthenticationOAuth2Builder { + + /** + * Create a builder instance. + * + * @return builder + */ + public static AuthenticationOAuth2Builder builder() { + return new AuthenticationOAuth2Builder(); + } + + private double earlyTokenRefreshPercent = AuthenticationOAuth2.EARLY_TOKEN_REFRESH_PERCENT_DEFAULT; + private ScheduledThreadPoolExecutor scheduler; + private ClientCredentialsConfiguration clientCredentialsConfiguration; + + /** + * Set the {@link ClientCredentialsConfiguration} when using the OAuth2 client credentials flow. + * @return builder + */ + public AuthenticationOAuth2Builder setClientCredentialsConfiguration( Review comment: In Pulsar, builders usually don't use `set*` naming convention. it would be good to follow a similar naming convention that has been used in other parts of Pulsar. for example, rename `setClientCredentialsConfiguration` -> `clientCredentialsConfiguration`. ########## File path: pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java ########## @@ -46,27 +46,39 @@ class ClientCredentialsFlow extends FlowBase { public static final String CONFIG_PARAM_ISSUER_URL = "issuerUrl"; public static final String CONFIG_PARAM_AUDIENCE = "audience"; + // Maps to the keyFileUrl public static final String CONFIG_PARAM_KEY_FILE = "privateKey"; public static final String CONFIG_PARAM_SCOPE = "scope"; private static final long serialVersionUID = 1L; private final String audience; - private final String privateKey; + private final String keyFileUrl; Review comment: `keyFileUrl` seems repetitive and conflicting. Is it a File or an URL? What key is it? Perhaps keeping the name `privateKey` and switching to use types would improve clarity. I'd recommend `java.net.URI` class also for URLs. that would make this `URI privateKey`. ########## File path: pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Builder.java ########## @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.client.impl.auth.oauth2; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import org.apache.pulsar.client.api.Authentication; + +/** + * Builder for {@link AuthenticationOAuth2} class. + */ +public final class AuthenticationOAuth2Builder { + + /** + * Create a builder instance. + * + * @return builder + */ + public static AuthenticationOAuth2Builder builder() { + return new AuthenticationOAuth2Builder(); + } + + private double earlyTokenRefreshPercent = AuthenticationOAuth2.EARLY_TOKEN_REFRESH_PERCENT_DEFAULT; + private ScheduledThreadPoolExecutor scheduler; + private ClientCredentialsConfiguration clientCredentialsConfiguration; + + /** + * Set the {@link ClientCredentialsConfiguration} when using the OAuth2 client credentials flow. + * @return builder + */ + public AuthenticationOAuth2Builder setClientCredentialsConfiguration( + ClientCredentialsConfiguration clientCredentialsConfiguration) { + if (clientCredentialsConfiguration == null) { + throw new IllegalArgumentException("ClientCredentialsConfiguration cannot be null."); + } + this.clientCredentialsConfiguration = clientCredentialsConfiguration; + return this; + } + + /** + * @param earlyTokenRefreshPercent - The percent of the expires_in time when the client should start attempting + * to refresh the token. If greater than or equal to 1, it is disabled. See + * {@link AuthenticationOAuth2} for details. + * @return builder + */ + public AuthenticationOAuth2Builder setEarlyTokenRefreshPercent(double earlyTokenRefreshPercent) { + if (earlyTokenRefreshPercent <= 0) { + throw new IllegalArgumentException("EarlyTokenRefreshPercent must be greater than 0."); + } + this.earlyTokenRefreshPercent = earlyTokenRefreshPercent; + return this; + } + + /** + * @param scheduler - The scheduler to use for background refreshes of the token. If null and the + * {@link #earlyTokenRefreshPercent} is less than 1, the client will create an internal scheduler. + * Otherwise, it will use the passed in scheduler. If the caller supplies a scheduler, the + * {@link AuthenticationOAuth2} will not close it. + * @return builder + */ + public AuthenticationOAuth2Builder setEarlyTokenRefreshExecutor(ScheduledThreadPoolExecutor scheduler) { + this.scheduler = scheduler; + return this; + } + + public Authentication build() { + if (clientCredentialsConfiguration == null) { + throw new IllegalArgumentException("ClientCredentialsConfiguration must be set."); Review comment: `IllegalStateException` instead? ########## File path: pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Builder.java ########## @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.client.impl.auth.oauth2; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import org.apache.pulsar.client.api.Authentication; + +/** + * Builder for {@link AuthenticationOAuth2} class. + */ +public final class AuthenticationOAuth2Builder { + + /** + * Create a builder instance. + * + * @return builder + */ + public static AuthenticationOAuth2Builder builder() { + return new AuthenticationOAuth2Builder(); + } + + private double earlyTokenRefreshPercent = AuthenticationOAuth2.EARLY_TOKEN_REFRESH_PERCENT_DEFAULT; + private ScheduledThreadPoolExecutor scheduler; + private ClientCredentialsConfiguration clientCredentialsConfiguration; + + /** + * Set the {@link ClientCredentialsConfiguration} when using the OAuth2 client credentials flow. + * @return builder + */ + public AuthenticationOAuth2Builder setClientCredentialsConfiguration( + ClientCredentialsConfiguration clientCredentialsConfiguration) { + if (clientCredentialsConfiguration == null) { + throw new IllegalArgumentException("ClientCredentialsConfiguration cannot be null."); + } + this.clientCredentialsConfiguration = clientCredentialsConfiguration; + return this; + } + + /** + * @param earlyTokenRefreshPercent - The percent of the expires_in time when the client should start attempting + * to refresh the token. If greater than or equal to 1, it is disabled. See + * {@link AuthenticationOAuth2} for details. + * @return builder + */ + public AuthenticationOAuth2Builder setEarlyTokenRefreshPercent(double earlyTokenRefreshPercent) { Review comment: drop `set` from the method name ########## File path: pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2.java ########## @@ -31,31 +34,100 @@ import org.apache.pulsar.client.api.EncodedAuthenticationParameterSupport; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.impl.AuthenticationUtil; +import org.apache.pulsar.client.impl.Backoff; +import org.apache.pulsar.client.impl.BackoffBuilder; import org.apache.pulsar.client.impl.auth.oauth2.protocol.TokenResult; /** * Pulsar client authentication provider based on OAuth 2.0. + * + * The first call to {@link #getAuthData()} will result in a blocking network call to retrieve the OAuth2.0 token from + * the Identity Provider. After that, there are two behaviors, depending on {@link #earlyTokenRefreshPercent}: + * + * 1. If {@link #earlyTokenRefreshPercent} is less than 1, this authentication class will schedule a runnable to refresh + * the token in n seconds where n is the result of multiplying {@link #earlyTokenRefreshPercent} and the `expires_in` + * value returned by the Identity Provider. If the call to the Identity Provider fails, this class will retry attempting + * to refresh the token using an exponential backoff. If the token is not refreshed before it expires, the Pulsar client + * will make one final blocking call to the Identity Provider. If that call fails, this class will pass the failure to + * the Pulsar client. This proactive approach to token management is good for use cases that want to avoid latency + * spikes from calls to the Identity Provider and that want to be able to withstand short Identity Provider outages. The + * tradeoff is that this class consumes slightly more resources. + * + * 2. If {@link #earlyTokenRefreshPercent} is greater than or equal to 1, this class will not retrieve a new token until + * the {@link #getAuthData()} method is called while the cached token is expired. If the call to the Identity Provider + * fails, this class will pass the failure to the Pulsar client. This lazy approach is good for use cases that are not + * latency sensitive and that will not use the token frequently. + * + * {@link #earlyTokenRefreshPercent} must be greater than 0. It defaults to 1, which means that early token refresh is + * disabled by default. + * + * The current implementation of this class can block the calling thread. + * + * This class is intended to be called from multiple threads, and is therefore designed to be thread-safe. */ @Slf4j public class AuthenticationOAuth2 implements Authentication, EncodedAuthenticationParameterSupport { public static final String CONFIG_PARAM_TYPE = "type"; public static final String TYPE_CLIENT_CREDENTIALS = "client_credentials"; + public static final int EARLY_TOKEN_REFRESH_PERCENT_DEFAULT = 1; // feature disabled by default Review comment: I'll reply separately to the `earlyTokenRefreshPercent` question -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
