-
Notifications
You must be signed in to change notification settings - Fork 273
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
feat: Implement JWT OAuth 2 Client Authentication as HttpExecuteInterceptor. #582
base: main
Are you sure you want to change the base?
Conversation
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
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.
Requested change made.
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Show resolved
Hide resolved
google-oauth-client/src/main/java/com/google/api/client/auth/oauth2/JWTAuthentication.java
Outdated
Show resolved
Hide resolved
} else { | ||
String grantType = (String) data.get(GRANT_TYPE_KEY); | ||
if (!grantType.equals(GRANT_TYPE_CLIENT_CREDENTIALS)) { | ||
throw new IllegalArgumentException(GRANT_TYPE_KEY |
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.
I'm not sure a runtime exception is appropriate here. It's a gray area. At the very least, the exception needs to be documented.
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.
Agree it's gray. The option I thought about was to just ignore whatever they try to set, since the GRANT_TYPE for JWT authentication has to be "client_credentials". Do you prefer that?
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Outdated
Show resolved
Hide resolved
import com.google.api.client.json.jackson2.JacksonFactory; | ||
import com.google.api.client.testing.http.HttpTesting; | ||
import com.google.api.client.testing.http.MockHttpTransport; | ||
import junit.framework.TestCase; |
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.
org.junit
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.
Implemented the same way as all the other tests in the package. Shouldn't it at least stay consistent? Are you saying don't extend TestCase at all? TestCase is in junit.framework.
google-oauth-client/src/test/java/com/google/api/client/auth/oauth2/JWTAuthenticationTest.java
Show resolved
Hide resolved
} | ||
|
||
public void intercept(HttpRequest request) { | ||
Map<String, Object> data = Data.mapOf(UrlEncodedContent.getContent(request).getData()); |
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.
This method seems to be mutating the internal state of some object. This is very suspicious.
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 purpose of an authentication intercept pretty much requires it. It needs to add the appropriate authentication information into the HTTP request. It's the decorator pattern. In any case, it is implemented exactly like ClientParametersAuthentication already in the package.
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.
All new code must follow the Google Java style guide. No exceptions.
We explicitly do not want consistency with existing code that does not follow the style guide.
Understand. I made the changes requested style changes. However, for the test, are you saying don't extend TestCase any more? |
|
||
import java.io.IOException; | ||
import java.util.Map; | ||
|
||
/** | ||
* Client credentials specified as URL-encoded parameters in the HTTP request body as specified in | ||
* <a href="https://tools.ietf.org/html/rfc7523">JSON Web Token (JWT) Profile | ||
* for OAuth 2.0 Client Authentication and Authorization Grants</a> | ||
* |
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.
import java.io.IOException; | |
import java.util.Map; | |
/** | |
* Client credentials specified as URL-encoded parameters in the HTTP request body as specified in | |
* <a href="https://tools.ietf.org/html/rfc7523">JSON Web Token (JWT) Profile | |
* for OAuth 2.0 Client Authentication and Authorization Grants</a> | |
* | |
* <a href="https://tools.ietf.org/html/rfc7523">JSON Web Token (JWT) Profile for OAuth 2.0 Client | |
* Authentication and Authorization Grants</a> | |
* <p>To use JWT authentication, grant_type must be "client_credentials". If | |
* AuthorizationCodeTokenRequest.setGrantType() is called, set it to | |
* JWTAuthentication.GRANT_TYPE_CLIENT_CREDENTIALS. It can also be left uncalled. Setting it to any | |
* other value causes an IllegalArgumentException. |
|
||
public class JWTAuthentication | ||
implements HttpRequestInitializer, HttpExecuteInterceptor { | ||
|
||
public static final String GRANT_TYPE_KEY = "grant_type"; | ||
|
||
/** Predefined value for grant_type when using JWT **/ | ||
public static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"; | ||
|
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.
public class JWTAuthentication | |
implements HttpRequestInitializer, HttpExecuteInterceptor { | |
public static final String GRANT_TYPE_KEY = "grant_type"; | |
/** Predefined value for grant_type when using JWT **/ | |
public static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"; | |
public class JWTAuthentication implements HttpRequestInitializer, HttpExecuteInterceptor { | |
/** Predefined value for grant_type when using JWT * */ | |
/** Predefined value for client_assertion_type when using JWT * */ | |
public static final String CLIENT_ASSERTION_TYPE = | |
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"; | |
/** @param jwt JWT used for authentication */ |
} else { | ||
String grantType = (String) data.get(GRANT_TYPE_KEY); | ||
if (!grantType.equals(GRANT_TYPE_CLIENT_CREDENTIALS)) { | ||
throw new IllegalArgumentException(GRANT_TYPE_KEY |
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.
throw new IllegalArgumentException(GRANT_TYPE_KEY | |
throw new IllegalArgumentException( | |
GRANT_TYPE_KEY |
|
||
package com.google.api.client.auth.oauth2; | ||
|
||
import com.google.api.client.http.GenericUrl; |
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.
import com.google.api.client.http.GenericUrl; | |
import static org.junit.Assert.assertThrows; | |
import com.google.api.client.http.GenericUrl; |
import junit.framework.TestCase; | ||
import static org.junit.Assert.assertThrows; |
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.
import junit.framework.TestCase; | |
import static org.junit.Assert.assertThrows; | |
import junit.framework.TestCase; |
new ClientCredentialsTokenRequest(new MockHttpTransport(), new JacksonFactory(), | ||
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString())); | ||
|
||
JWTAuthentication auth = |
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.
new ClientCredentialsTokenRequest(new MockHttpTransport(), new JacksonFactory(), | |
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString())); | |
JWTAuthentication auth = | |
new ClientCredentialsTokenRequest( | |
new MockHttpTransport(), | |
new JacksonFactory(), | |
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString())); | |
JWTAuthentication auth = new JWTAuthentication(JWT); |
JWTAuthentication auth = | ||
new JWTAuthentication(JWT); |
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.
JWTAuthentication auth = | |
new JWTAuthentication(JWT); | |
JWTAuthentication auth = new JWTAuthentication(JWT); |
new ClientCredentialsTokenRequest(new MockHttpTransport(), new JacksonFactory(), | ||
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString())); | ||
|
||
JWTAuthentication auth = |
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.
new ClientCredentialsTokenRequest(new MockHttpTransport(), new JacksonFactory(), | |
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString())); | |
JWTAuthentication auth = | |
new ClientCredentialsTokenRequest( | |
new MockHttpTransport(), | |
new JacksonFactory(), | |
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString())); | |
JWTAuthentication auth = new JWTAuthentication(JWT); |
|
||
assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { | ||
@Override | ||
public void run() throws Throwable { | ||
request.executeUnparsed(); | ||
} | ||
}); | ||
} | ||
|
||
public void test_noJWT() { | ||
assertThrows(RuntimeException.class, new ThrowingRunnable() { | ||
@Override | ||
public void run() { |
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.
assertThrows(IllegalArgumentException.class, new ThrowingRunnable() { | |
@Override | |
public void run() throws Throwable { | |
request.executeUnparsed(); | |
} | |
}); | |
} | |
public void test_noJWT() { | |
assertThrows(RuntimeException.class, new ThrowingRunnable() { | |
@Override | |
public void run() { | |
assertThrows( | |
IllegalArgumentException.class, | |
new ThrowingRunnable() { | |
@Override | |
public void run() throws Throwable { | |
request.executeUnparsed(); | |
} | |
}); | |
assertThrows( | |
RuntimeException.class, | |
new ThrowingRunnable() { | |
@Override | |
public void run() { | |
JWTAuthentication auth = new JWTAuthentication(null); | |
} | |
}); |
What's the status of this PR? Should it be closed? |
It's pending review to be merged. I made the changes as requested. |
Fixes #580 ☕️
Simple implementation modeled after ClientParametersAuthentication.