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
Surface rawToken for JWT wrapper #757
Conversation
google-http-client/src/main/java/com/google/api/client/json/webtoken/JsonWebSignature.java
Outdated
Show resolved
Hide resolved
google-http-client/src/test/java/com/google/api/client/json/webtoken/JsonWebSignatureTest.java
Outdated
Show resolved
Hide resolved
google-http-client/src/main/java/com/google/api/client/json/webtoken/JsonWebToken.java
Show resolved
Hide resolved
@@ -361,6 +362,12 @@ public String toString() { | |||
return Objects.toStringHelper(this).add("header", header).add("payload", payload).toString(); | |||
} | |||
|
|||
public String getRawToken() { |
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 needs JavaDoc. Also note that the word "raw" does not appear in the RFC. Is there a term in the RFC that does describe this?
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.
cloest term maybe getEncodedToken()
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.
Test failing:
[ERROR] testRawToken(com.google.api.client.json.webtoken.JsonWebSignatureTest) Time elapsed: 0.008 s <<< ERROR!
java.lang.IllegalArgumentException: no JSON input found
at com.google.api.client.json.webtoken.JsonWebSignatureTest.testRawToken(JsonWebSignatureTest.java:52)
@@ -361,6 +362,12 @@ public String toString() { | |||
return Objects.toStringHelper(this).add("header", header).add("payload", payload).toString(); | |||
} | |||
|
|||
public String getRawToken() { |
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.
Reading the spec, I think what this is, is a "compact serialized form". Furthermore, I'm beginning to think it belongs in the JsonWebSignature class rather than JsonWebToken, because it isn't defined for JsonWebToken.
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.
yeah, thats kind of what i meant that i don't know where i'd use the internal method directly (i.,e JsonWebToken.getRawToken()
. i'lonly make this visible to JsonWebToken
class
@@ -482,6 +482,11 @@ private static X509TrustManager getDefaultX509TrustManager() { | |||
return signedContentBytes; | |||
} | |||
|
|||
/** Returns the URL safe Base64 encoded JWS token. */ | |||
public String getRawToken() { |
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.
Since we're unlikely to get the API perfect on the first try, we should mark this @beta to warn users it might change.
@@ -361,6 +362,12 @@ public String toString() { | |||
return Objects.toStringHelper(this).add("header", header).add("payload", payload).toString(); | |||
} | |||
|
|||
public String getRawToken() { |
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.
Since we're unlikely to get the API perfect on the first try, we should mark this @beta to warn users it might change.
@@ -482,6 +482,11 @@ private static X509TrustManager getDefaultX509TrustManager() { | |||
return signedContentBytes; | |||
} | |||
|
|||
/** Returns the URL safe Base64 encoded JWS token. */ | |||
public String getRawToken() { |
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.
@Override
ok, this became a bit more complicated. The classes are structured such that the original so a snippet like this String rawToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikp"
+ "vaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
JsonWebSignature signature = JsonWebSignature.parse(JacksonFactory.getDefaultInstance(), rawToken);
System.out.println(signature.getEncodedToken());
System.out.println(rawToken); gives {
"alg": "HS256",
"typ": "JWT"
}.
{
"iat": 1516239022,
"sub": "1234567890",
"name": "John Doe"
} vs {
"alg": "HS256",
"typ": "JWT"
}.
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
} |
Per the JSON specification "An object is an unordered set of name/value pairs". Nothing here, tests included, should depend on this order. |
The ordering thing doesn't matter for JSON but in this case i'm 'attaching' a singature part of some claims that were in a specifc order to another..the net result is the JWT string representation that the output of these methods isn't valid anymore. For example, if i take a valid
the output of |
The signature should be independent of order as well. If it isn't, then there's a bug somewhere, maybe more than one. Are you saying that
produces a different signature than
|
the order does matter...to sign, basically i'll take
use it as string, covert to base64 then digitally sign that to get the signature which isn't going to produce the same out put if i alter the claims around. |
I need to check the spec, but if that's really how the JWT spec defines signing, then the spec is broken. The usual way of handling this problem is defininf a canonical and reprodubile ordering; e.g. like canonical XML does for attributes. |
Also, I think we might be jumping too fast to code here. This is more complex than I realized and I'm not sure we understand the problem sufficiently well. It's probabaly worth starting with a design doc that lays out the plansd, tradeoffs, and issues involed. |
So I've confirmed that the spec is indeed broken. You will need to figure out how to 'just save and return' the raw token that's passed into the .parse() object w/o marshalling/unmarshalling.... |
yep...thats what i figured (i initially started this thinking the 'easiest' way was to 'just save and retun' the token thats passed in thorugh this public JsonWebSignature parse(String tokenString) ...but then realized there is also a constructor that a constructor which immediately messes up the ordering public JsonWebSignature(
Header header, Payload payload, byte[] signatureBytes, byte[] signedContentBytes) { what that means is while i could use the token passed into I could just throw an exception if someone tries to use that method without going through static |
Can you remove that constructor or make it private? |
i don't think i can remove or make it not visible (it'd break anyone using it (including our tests): i could create second constructor pass through the string format (one that'd set the raw token and then call the existing constructor. public JsonWebSignature(
Header header, Payload payload, byte[] signatureBytes, byte[] signedContentBytes, String encodedToken) at this point, i kinda don't know what to do since there doesn't seem to be a good way out of this |
You could deprecate this constructor. Might be worth doing that if it's definitely broken like this. |
I think I see a way to fix this. We need to canonicalize field order before signing, and do all our own signing. It will need some new runtime exceptions, but should be plausible. I do wonder if it might be easier to build a better library. This class has other problems too, such as exposing mutable internal state. |
@BenWhitehead suggested we look at https://github.com/auth0/java-jwt to see if it might work better than rolling our own. |
ugh...this is a bit of a mess..I'm not sure if canonicalizing before signing is even an option anymore... public JsonWebSignature(
Header header, Payload payload,
byte[] signatureBytes,
byte[] signedContentBytes, precludes us from doing anything since the This means JWT Header, Payload objects used in the code is disconnected from the signature that was itself passed better way maybe to just do a rewrite after annotating as deprecated and use the auth0 stuff |
I think it's legitimate to have the If we use auth0 perhaps that could be an internal implementation detail? |
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Emily Ball <emilyball@google.com>
Adds ability to recall the raw JWT encoded token from
JsonWebSignature
andJsonWebToken
.The current .
toString()
method for both classes returns a JSON object. Its useful to have access to the raw token directly to be used in an http client (asAuthorization: Bearer <rawToken>
, for example)ref:
googleapis/google-auth-library-java#303 (review)