Android JWT parsing payload/claims when signed - java

I have a signed JWT String that i get from the server. I do not know the key or rather I don't want to put the key on the client/device.
When using this site with my token: https://jwt.io/ I get the desired result it tells me the Header and payload information.
I cannot find a library on android that does what this website does and i have tried all of them that i could find. The most recognized one to use is: https://github.com/jwtk/jjwt
But this gives me an exception that i cannot parse a signed token which as proven by the other website above is false. another resource i have used is: https://bitbucket.org/b_c/jose4j/wiki/Home
This one at least gave me the header information which is the furthest i have been able to get.
To give context why it is the way it is, the payload contains an expiration time and on the device when the token is about to expire i should prompt the user to re enter their credentials to get a new token. Now this might seem like a security threat because a hacker could manipulate the token on the device, but the server checks the token to make sure it is authentic which is why i do not want the key on the device because this can be mined by a hacker, and make the entire application vulnerable.

If you wanna parse signatured text without using signature :
1- add below dependency :
//JWT
compile 'io.jsonwebtoken:jjwt:0.7.0'
2 - Add below imports :
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
3- Use below code block :
//ref : https://github.com/jwtk/jjwt/issues/135
//you can put your signatured text instead of jws variable.
String jws = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
int i = jws.lastIndexOf('.')
String withoutSignature = jws.substring(0, i+1);
Jwt<Header,Claims> untrusted = Jwts.parser().parseClaimsJwt(withoutSignature);
/*untrusted.getBody().getSubject();
untrusted.getBody().getExpiration();
etc.
*/

Well the answer was pretty simple although in my opinion should be in the framework. But a simple non signed JWT still has the 2 required periods in it but there is nothing after the last one, so i split my JWT on the periods and combined the first and second one with periods and put a period at the end.
String[] splitToken = result.Value.Content.AuthorizationJWTToken.split("\\.");
Jwt parsedToken = Jwts.parser().parse(splitToken[0] + "." + splitToken[1] + ".");
This was usings the https://github.com/jwtk/jjwt library.

You can use jose4j's JWT consumer to do parsing only and not check the claims or signature. Something like the following will parse the token and compare the expiration time to the current time to see if it's expired.
String jwt = "eyJhbGciOiJIUzI1NiJ9" +
".eyJzdWIiOiIxMjM0NTY3ODkwIiwiZXhwIjoxNDUzODE0NjA0LCJuYW1lIjoiSm9obiBEb2UifQ" +
".IXcDDLXEpGN9Po5C-Mz88jUCNYrHxu6TVJLavf0NgT8";
JwtConsumer consumer = new JwtConsumerBuilder()
.setSkipAllValidators()
.setDisableRequireSignature()
.setSkipSignatureVerification()
.build();
JwtClaims claims = consumer.processToClaims(jwt);
NumericDate expirationTime = claims.getExpirationTime();
if (NumericDate.now().isAfter(expirationTime))
{
System.out.println("Token expired at " + expirationTime);
}
else
{
System.out.println("Token is still good until " + expirationTime);
}

parseClaimsJwt() method of Jwt will require a signature. So, right way to do it is:
String jws = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
int i = jws.lastIndexOf('.')
String withoutSignature = jws.substring(0, i+1);
Claims claims = (Claims) = Jwts.parser().parse(withoutSignature).getBody();

Related

Weird Error SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted

I hope you can help me
The Problem
I got this exception mentioned in the title with some cases. My application generates JWT tokens every month with a scheduled process. The problem is that this cases were working fine the corresponding last month but the next one is invalid. For example, i generated tokens last month and were working fine but in some part of the time it started to throw the exception when trying to parse.
As an additional information i have some tokens from 2 months ago that works correctly despite it can be expired.
I haven't made any recent changes to the code and the secret value remains the same. Also i don't think is problem of the exp or expiration value (if this was true i think it will throw ExpiredException)
Actually i'm using in maven the 0.11.1 version in maven for jjwt-api, jjwt-impl and jjwt-jackson dependencies. My application in production stage is deployed in Azure Kubernetes Services with Java 11. The algorithm im using is HS512.
Wrong Token example
eyJhbGciOiJIUzUxMiJ9.eyJkb2N1bWVudFR5cGUiOiJETkkiLCJwcm9jZXNzSWQiOjQ4LCJkb2N1bWVudE51bWJlciI6IjA0OTM4NjIwIiwiZXhwaXJhdGlvbiI6IjIwMjMtMDYtMDEiLCJhZmZpbGlhdGVJZCI6Ijk3NTM3N0pYWVpMNyIsImV4cCI6MTY4NTU5NTYwMH0.NpN5as_YczjzmrBVHrEt9d0ba962PYZZolzgEx3EFQtqyumORqs6vNDLRFowFkKh8sCbqUyQxv57L6FhqhPhRw
Correct Token example
eyJhbGciOiJIUzUxMiJ9.eyJkb2N1bWVudFR5cGUiOiJETkkiLCJwcm9jZXNzSWQiOjM4LCJkb2N1bWVudE51bWJlciI6Ijg1MjAyMTM0IiwiZXhwaXJhdGlvbiI6IjIwMjMtMDMtMDEiLCJhZmZpbGlhdGVJZCI6IjE4NzM1N1pCUkNOMyIsImV4cCI6MTY3NzY0NjgwMH0.CBqKDJcWIs0hq7jy9LTyb1INVTqkWKi0KQgYLCEDR7TUG5lNQBKriO_fvcFhZOZfs6E0DqtDmdtcj1oI2XWbvg
If you guys need more information i can help giving some examples with correct and incorrect tokens.
Regards
Henry.
I share with you some information in order you guys can help me to resolve or get the problem
#Value("${token.exchange.jwt.secret}") private String secret;
#Value("${token.exchange.jwt.expiration}") private Integer expirationMonth;
1.- Generate method
private String doGenerateToken(Map<String, Object> claims) throws NotFoundException {
ZoneId defaultZone = ZoneId.systemDefault();
String fecExpirationClaim = (String) (claims.get(EXPIRATION));
LocalDate localDate = LocalDate.parse(fecExpirationClaim);
if (localDate == null) {
throw new NotFoundException("El Token no tiene fecha de expiración");
}
Date expirationDate = Date.from(localDate.atStartOfDay(defaultZone).toInstant());
SecretKey key = Keys.hmacShaKeyFor(this.secret.getBytes());
return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(key).compact();
}
2.- Decode Method
public Claims getAllClaimsFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(Base64.getEncoder().encodeToString(this.secret.getBytes()))
.build()
.parseClaimsJws(token)
.getBody();
}
I tried to run my application in a simple local environment and got the same error.
Also change my code in the getAllClaimsFromToken method in the setSigningKey using the same key like the generate method like this:
public Claims getAllClaimsFromToken(String token) {
SecretKey key = Keys.hmacShaKeyFor(this.secret.getBytes());
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
but got the same result
I expect all my tokens got parsed correctly again because as i said before it were working correctly time ago.
Regards
Henry.

Creating URL based on an API key in OSRMRoadManager

I've signed up for an API on openrouteservice.org. How do I import it into OSRMRoadManager? I've tried all the combinations from the examples on their website, but my every try results in the 403 error with a comment org.json.JSONException: No value for code and a link to the following:
{
"error": "Daily quota reached or API key unauthorized"
}
(I haven't used that API before, so I couldn't have used up the quota. The key is valid, as I have tested it with the links from the aforementioned website)
My Kotlin code (in my most recent attempt) is as following ([MY_API_KEY] is obviously replacing my real key):
val roadManager = OSRMRoadManager(context, context?.packageName)
(roadManager as OSRMRoadManager).setService("https://api.openrouteservice.org/v2/directions/driving-car/geojson?api_key=[MY_API_KEY]")
val waypoints = ArrayList<GeoPoint>()
waypoints.add(GeoPoint(lastLocLat, lastLocLong)) //last known location
val endPoint = GeoPoint(randomOverlay.getItem(0).point.latitude, randomOverlay.getItem(0).point.longitude) //destination
waypoints.add(endPoint)
val road = roadManager.getRoad(waypoints)
My guess is that the waypoint coordinates should be included differently in the link, but I don't know how to alter that.
openrouteservice directions format is not identical to OSRM, so you cannot use OSRMRoadManager.
If you really - really - want to use openrouteservice, you will have to develop corresponding openrouteserviceRoadManager.
Alternative: use one among the 3 routing services already accessible with OBP. Pros and cons here.

Add JFace Key Scheme Programmatically

I thought about repurposing org.eclipse.jface.bindings.Scheme to store key bindings on a per user base:
String userName = "Bob";
BindingManager bindingManager = ((BindingService) PlatformUI.getWorkbench().getService(IBindingService.class)).getBindingManager();
Scheme scheme = bindingManager.getScheme(userName);
scheme.define(userName, "Scheme for user " + userName, DEFAULT_SCHEME);
bindingManager.setActiveScheme(scheme);
Which works well for some moments, but whenever the schemes get loaded from the preferences (e.g. via CommandPersistence#reRead) only the schemes defined in the plugin.xml will be read and everything else gets discarded.
Especially this method of the class BindingService is a problem:
public final void savePreferences(final Scheme activeScheme,
final Binding[] bindings) throws IOException {
// store everything in preferences, then read everything
// -> custom schemes get removed
BindingPersistence.write(activeScheme, bindings);
// now the removed (undefined) scheme gets set
bindingManager.setActiveScheme(activeScheme);
bindingManager.setBindings(bindings);
}
Since I can't really register all users via plugin.xml, how can I register schemes programmatically?
As a "solution", I just re-implemented the scheme for our use case:
String userName = "Bob";
String keyBindings = MyPlugin.getDefault().getPreferenceStore().getString("keyBindings." + userName);
PlatformUI.getPreferenceStore().setValue(PlatformUI.PLUGIN_ID + ".commands", keyBindings);
This triggers CommandPersistence#reRead as well, but since I don't have my custom scheme this time, it doesn't fail. Now the management of our different schemes is our problem, but at least that way it works.

How to install chef extension via azure sdk

I need to create deployment with role that contains Chef extension via Java Azure SDK. I have next code for setting extension parameters, but it doesn't work.
As an example I use next material in Python http://blogs.msdn.com/b/shwetasblogs/archive/2015/02/19/creating-deployment-amp-customizing-linux-vms-with-python-amp-chef-part-2.aspx
private void withExtension(Role role) {
ArrayList<ResourceExtensionReference> references = new ArrayList<ResourceExtensionReference>();
ResourceExtensionReference reference = new ResourceExtensionReference();
reference.setReferenceName("LinuxChefClient");
reference.setVersion("11.*");
reference.setPublisher("Chef.Bootstrap.WindowsAzure");
reference.setName("LinuxChefClient");
ResourceExtensionParameterValue publicConfig = new ResourceExtensionParameterValue();
publicConfig.setType("Public");
publicConfig.setKey("PublicParams");
String value = "{\n" +
" \"client_rb\": \"chef_server_url \\\"https://<chefServerUri>\\\"\\nnode_name \\\"<vmName>\\\"\\nvalidation_key \\\"/etc/chef/validation.pem\\\"\\nlog_location \\\"/etc/chef/client.log\\\"\\nlog_level :info\\njson_attribs \\\"/etc/chef/role.json\\\"\",\n" +
" \"run_list\": [\"role[base]\"]\n" +
"}";
publicConfig.setValue(value);
ResourceExtensionParameterValue privateConfig = new ResourceExtensionParameterValue();
privateConfig.setType("Private");
privateConfig.setKey("PrivateParams");
privateConfig.setValue("{ \"validation_key\": \"" + VALIDATION_PEM + "\" }");
ArrayList<ResourceExtensionParameterValue> parameterValues = new ArrayList<ResourceExtensionParameterValue>();
parameterValues.add(publicConfig);
parameterValues.add(privateConfig);
reference.setResourceExtensionParameterValues(parameterValues);
references.add(reference);
role.setResourceExtensionReferences(references);
}
It seems that you do not encrypt the value of privateConfig and publicConfig. As this official document description(Request body part), before setting value, we need encrypt those values:
<PublicConfiguration>
base-64-encoded-xsd-for-extension-public-configuration
</PublicConfiguration>
<PrivateConfiguration>
base-64-encoded-xsd-for-extension-private-configuration
</PrivateConfiguration>
Please try to add this code into your project:
value=Base64.encode(value.getBytes(Charset.forName("UTF-8")));
By the way, please share more error information if the above code don't work.
I am not able to add the comment, so asking my questions in Reply -
What is the error that you see?
Is your VM getting created successfully?
George, please answer these questions so that I can help you better. By the way, you can check the blog - http://blogs.msdn.com/b/azureossds/archive/2015/09/08/accessing-vm-extensions-like-chef-using-azure-sdk-for-java-programmatically.aspx
for using Azure sdk for Java to access the extensions. You will have to modify the code to set the extension reference in order to create a new one.
Hope this helps !!

“Invalid signature”: oAuth provider with Django-piston revisited using Scribe as a client

So while working through an implementation of OAuth using Django-Piston I encountered the error mentioned here: "Invalid signature": oAuth provider with Django-piston
The solutions posted previously were not working for me so I began digging deeper into both Piston(https://bitbucket.org/jespern/django-piston/overview) and Scribe (https://github.com/fernandezpablo85/scribe-java).
It turns out that when signing a Scribe request with a JSON String payload, only the OAuth parameters are actually signed. This causes Piston to fail signature validation as Piston signs all of the parameters in the payload in addition to the OAuth parameters.
I was able to modify Piston to only sign the OAuth parameters and everything is now working fine. Being a bit new to OAuth I was not sure if the is the correct fix, one alternative would be to modify Scribe to sign the payload content as well (or perhaps append each parameter in the payload rather than attaching it as a String).
Does anyone have insight into the proper way to address this issue?
The OAuth spec doesn't say anything about payload (not parameters). Some providers do sign it but that's up to them. Not signing the body contents (xml, json, etc) in Scribe it's a design decision and it's not going to change.
In case I made the correct decision here is my fix for Piston:
in class OAuthRequest(object) add this method:
def get_oauth_parameters(self):
"""Get any OAuth parameters."""
parameters = {}
for k, v in self.parameters.iteritems():
# Ignore oauth parameters.
if k.find('oauth_') > -1:
parameters[k] = v
return parameters
and modify this one to call the new method:
def get_normalized_parameters(self):
"""Return a string that contains the parameters that must be signed."""
params = self.get_oauth_parameters()
try:
# Exclude the signature if it exists.
del params['oauth_signature']
except:
pass
# Escape key values before sorting.
key_values = [(escape(_utf8_str(k)), escape(_utf8_str(v))) \
for k,v in params.items()]
# Sort lexicographically, first after key, then after value.
key_values.sort()
# Combine key value pairs into a string.
return '&'.join(['%s=%s' % (k, v) for k, v in key_values])

Categories