Skip to content
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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

junying1
Copy link

Fixes #580 ☕️

Simple implementation modeled after ClientParametersAuthentication.

@junying1 junying1 requested a review from a team as a code owner December 29, 2020 01:01
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Dec 29, 2020
@elharo elharo requested a review from silvolu December 29, 2020 14:19
@elharo elharo changed the title Implement JWT OAuth 2 Client Authentication as HttpExecuteInterceptor. feat: Implement JWT OAuth 2 Client Authentication as HttpExecuteInterceptor. Dec 29, 2020
@junying1 junying1 requested a review from elharo January 1, 2021 21:09
Copy link
Author

@junying1 junying1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested change made.

} else {
String grantType = (String) data.get(GRANT_TYPE_KEY);
if (!grantType.equals(GRANT_TYPE_CLIENT_CREDENTIALS)) {
throw new IllegalArgumentException(GRANT_TYPE_KEY
Copy link
Contributor

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.

Copy link
Author

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?

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

org.junit

Copy link
Author

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.

}

public void intercept(HttpRequest request) {
Map<String, Object> data = Data.mapOf(UrlEncodedContent.getContent(request).getData());
Copy link
Contributor

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.

Copy link
Author

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.

Copy link
Contributor

@elharo elharo left a 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.

@junying1
Copy link
Author

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?

Comment on lines +23 to +31

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>
*

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Comment on lines +74 to +82

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";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import com.google.api.client.http.GenericUrl;
import static org.junit.Assert.assertThrows;
import com.google.api.client.http.GenericUrl;

Comment on lines +24 to +25
import junit.framework.TestCase;
import static org.junit.Assert.assertThrows;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import junit.framework.TestCase;
import static org.junit.Assert.assertThrows;
import junit.framework.TestCase;

Comment on lines +39 to +42
new ClientCredentialsTokenRequest(new MockHttpTransport(), new JacksonFactory(),
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString()));

JWTAuthentication auth =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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);

Comment on lines +65 to +66
JWTAuthentication auth =
new JWTAuthentication(JWT);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
JWTAuthentication auth =
new JWTAuthentication(JWT);
JWTAuthentication auth = new JWTAuthentication(JWT);

Comment on lines +78 to +81
new ClientCredentialsTokenRequest(new MockHttpTransport(), new JacksonFactory(),
new GenericUrl(HttpTesting.SIMPLE_GENERIC_URL.toString()));

JWTAuthentication auth =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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);

Comment on lines +90 to +102

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() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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);
}
});

@Neenu1995 Neenu1995 added the release-please:force-run To run release-please label Aug 12, 2021
@release-please release-please bot removed the release-please:force-run To run release-please label Aug 12, 2021
@lesv
Copy link
Contributor

lesv commented Nov 3, 2021

What's the status of this PR? Should it be closed?

@junying1
Copy link
Author

junying1 commented Nov 3, 2021

It's pending review to be merged. I made the changes as requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JWT Profile for OAuth 2.0 Client Authentication and Authorization Grants
5 participants