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

java.lang.NoSuchMethodError for Base64.decodeBase64(String) #131

Closed
medavox opened this issue Jan 6, 2017 · 23 comments
Closed

java.lang.NoSuchMethodError for Base64.decodeBase64(String) #131

medavox opened this issue Jan 6, 2017 · 23 comments

Comments

@medavox
Copy link

medavox commented Jan 6, 2017

Hi, while using your library I encountered the following runtime exception, which crashes my app:

E/AndroidRuntime: FATAL EXCEPTION: main
	 Process: com.xxxx.yyyy, PID: 17510
	 java.lang.NoSuchMethodError: No static method decodeBase64(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
		 at com.xxxx.yyyy.network.RealNetworkController$2.onResponse(RealNetworkController.java:172)
		 at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
		 at android.os.Handler.handleCallback(Handler.java:739)
		 at android.os.Handler.dispatchMessage(Handler.java:95)
		 at android.os.Looper.loop(Looper.java:158)
		 at android.app.ActivityThread.main(ActivityThread.java:7224)
		 at java.lang.reflect.Method.invoke(Native Method)
		 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
		 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

This is caused by your use of the Apache Commons Codec library, in JWTDecoder.java:38:

headerJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[0]));
            payloadJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[1]));

I have investigated the issue, and I believe it's down to an obscure problem with Android.

The Problem

Until recently, Android was bundled with Apache's HttpClient, which depended on Commons Codec.

However, the version originally bundled with Android (1.3) does not contain the static decodeBase64(String) method. Furthermore, this ancient version overrides the version you specify in your lib's build.gradle.

For a better explanation, see this blog post, and these stack overflow posts:

  1. http://stackoverflow.com/a/34473643
  2. http://stackoverflow.com/a/5902269
  3. http://stackoverflow.com/questions/24306695/base64-dependencies-issue-in-android-studio

The reason you (the developers of java-jwt) may not have been experiencing this error and I have, is because this ancient dependency has been removed from android entirely, after SDK 23 (version 6.0), removing the problem.

Unfortunately for me, my app's minimum version is 4.4 (SDK 19), so I suspect that the legacy code is still in my classpath (this is corroborated by the exception message I pasted above:

declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar

This effectively gives your library an undocumented requirement for Android SDK 23 and above!

The Solution

Some people have been using a workaround, but I would recommend that you simply replace your Commons Codec call with the android-internal Base64 implementation. I will be submitting a pull request to this effect, if/when I have time.

TL;DR

You have an obscure bug to do with historical dependencies in Android on Apache Commons Codec.

I'll submit a PR when I can.

@hzalaz
Copy link
Member

hzalaz commented Jan 6, 2017

@medavox we didn't build this library to be used in Android apps

@medavox
Copy link
Author

medavox commented Jan 6, 2017

But it is, and has been. It's on jcenter, and it works (almost) without modification.

If this is not OK then sorry, but i didn't know. It didn't feel too difficult to use, to be Java only. Was not obvious from my discovery path.

Would you still accept a pull request to fix this that doesn't rely on android APIs, or should i find another library?

EDIT: I've checked, and i can't see a separate listing for Android libraries on http://jwt.io/ .

This means the main landing page for searches about JWT doesn't make a distinction between Java and Android JWT libraries, even though for you there is.

Obviously, you don't have control of that site (unless you do), so you may wish to inform them of this.

@hzalaz
Copy link
Member

hzalaz commented Jan 6, 2017

There are more than android libraries in jcenter and not all are usable in an app since the JVM of android has some restrictions compared to regular JVM.

I would accept a PR if it doesn't break any public API of the library and fixes the issue 😄

Also just a quick note, we are not relying on any Android API, the error might be caused by something else, probably our base64 dependency that is not compatible with Android

@medavox
Copy link
Author

medavox commented Jan 6, 2017

I should really have put my above edit in another post, apologies.

Thanks for your quick replies, I'll see if there is a mutually satisfactory fix.

@DuncanTyrell
Copy link

@medavox did you find a fix to this yet? I've just hit the same issue and glad I checked in here. I've used other libs for handling JWTs on Android in the past and am wondering whether to abandon this in favour of one that works, or try and fix this one. If you fancy a catchup about the options some time message me [email protected]. We're also local by the way - I'm based up the road in Leeds.

@hzalaz
Copy link
Member

hzalaz commented Jan 10, 2017

@DuncanTyrell what do you need to do with the JWT? if it's only decode we already have a lib https://github.com/auth0/JWTDecode.Android to do that. It's unusual for an Android app to verify or even sign a token

@DuncanTyrell
Copy link

Thanks for the swift response @hzalaz! I'll have a look at that library - much appreciated.

@DuncanTyrell
Copy link

Yep that seems to do everything I need for now anyway @hzalaz - thanks again for your help and super-responsive turnaround.

@hzalaz hzalaz closed this as completed Feb 23, 2017
laurentyhuel pushed a commit to laurentyhuel/java-jwt that referenced this issue Aug 10, 2017
@rakaadinugroho
Copy link

i have solution for @medavox your problem, i have same problem. and to Sign with RSA256 Algorithm you must have Private Key. the Private Key must be PKCS#8 format. and save to Private.der , because Java cannot read private key except PKCS#8.

and iam not using this library. i use this library https://github.com/jwtk/jjwt

@qwertukg
Copy link

Still have it on Spring application:

java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.decodeBase64(Ljava/lang/String;)[B
	at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:32)
	at com.auth0.jwt.JWT.decode(JWT.java:21)
	at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:352)

@lbalmaceda
Copy link
Contributor

@qwertukg please provide a repro project so we can narrow down the problem.

@qwertukg
Copy link

if u talking about repository of project, I can't to pass it. Maybe u need some more information ?

@lbalmaceda
Copy link
Contributor

The original issue on this post is related to the library being used on an Android environment. Android is known to have a different Base64 implementation, and Apache Commons can't be used there because of the JVM. If you say the issue appears also on Spring that worries me, but if I don't know what you're doing I can't help you.
I'm not talking about the original project where you're working on but a simple sample project you can create in the next few minutes and disclose to us where the issue can be reproduced, for us to narrow the cause. Please push it to a public repo. Without that I'll have to route you to https://support.auth0.com

@qwertukg
Copy link

Ok. Will try to reproduce it on a simple project tomorrow. Now just can to say what this project have a lot of dependencies and it's based on spring 3

@lbalmaceda
Copy link
Contributor

Then it should work unless one of your project dependencies uses a different version of apache commons lib that doesn't have that class method. Try searching in the dependency tree if this is the case and see if removing that dependency fixes the problem.

@qwertukg
Copy link

It was commons-codec-1.2 there is no method with signature decodeBase64(String) only decodeBase64(Byte[])

@lbalmaceda
Copy link
Contributor

@qwertukg Ah yes, that's from 2005. The latest version is the one we use.

@trajkovski731
Copy link

And did you fixed it? It has past a lot of time.

@lbalmaceda
Copy link
Contributor

@trajkovski731 this library is not meant to be used on Android (we don't support it up-front). Is that your case or are you having a different error? If so, please post the details either here (if related) or in a separate new issue.

@nanangTriAndika
Copy link

For anyone who struggle using apache common codec inline with android SDK ( especially when got conflict when using Base64 function ), you can use this library. Just pull and compiled the code or download through release tab for lazy programmer =P

https://github.com/nanangTriAndika/customApacheCommonCodec

@qwertukg
Copy link

@trajkovski731 yep, i was fix it by excluding this lib from my dependency tree

vijay033 added a commit to vijay033/Deeplearning4j that referenced this issue Feb 2, 2019
assets/
vector_data1.txt
vector_data2.txt
vector_data3.txt
vector_data4.txt

raw/
stopwords.txt
extended_stopwords.txt

layout/
activity_main.xml

main/java/
MainActivity.java
WordVectorReader.java
WordVectorSaver.java
WordVectorTraining.java

Tried to solve encodeBase64/decodeBase64 compatibility issue between android and jave: auth0/java-jwt#131
@va26
Copy link

va26 commented Feb 12, 2019

I am facing the same problem while trying to use the Google Speech-to-Text API given here. This is what I get in the logs:

    --------- beginning of crash
02-12 12:35:22.504 29178 29178 E AndroidRuntime: FATAL EXCEPTION: main
02-12 12:35:22.504 29178 29178 E AndroidRuntime: Process: com.google.cloud.examples.speechrecognition, PID: 29178
02-12 12:35:22.504 29178 29178 E AndroidRuntime: java.lang.NoSuchMethodError: No static method decodeBase64(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.api.client.util.Base64.decodeBase64(Base64.java:101)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.api.client.util.PemReader.readNextSection(PemReader.java:106)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.api.client.util.PemReader.readFirstSectionAndClose(PemReader.java:135)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.auth.oauth2.ServiceAccountCredentials.privateKeyFromPkcs8(ServiceAccountCredentials.java:296)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.auth.oauth2.ServiceAccountCredentials.fromPkcs8(ServiceAccountCredentials.java:286)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.auth.oauth2.ServiceAccountCredentials.fromJson(ServiceAccountCredentials.java:210)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.auth.oauth2.GoogleCredentials.fromStream(GoogleCredentials.java:174)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.auth.oauth2.GoogleCredentials.fromStream(GoogleCredentials.java:141)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.examples.speechrecognition.MainActivity$mSpeechClient$2$1$1.getCredentials(MainActivity.kt:62)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.examples.speechrecognition.MainActivity$mSpeechClient$2$1$1.getCredentials(MainActivity.kt:45)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:140)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.speech.v1.stub.GrpcSpeechStub.create(GrpcSpeechStub.java:94)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.speech.v1.stub.SpeechStubSettings.createStub(SpeechStubSettings.java:126)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.speech.v1.SpeechClient.<init>(SpeechClient.java:144)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.speech.v1.SpeechClient.create(SpeechClient.java:126)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.examples.speechrecognition.MainActivity$mSpeechClient$2.invoke(MainActivity.kt:61)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.examples.speechrecognition.MainActivity$mSpeechClient$2.invoke(MainActivity.kt:45)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.examples.speechrecognition.MainActivity.getMSpeechClient(Unknown Source:7)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.google.cloud.examples.speechrecognition.MainActivity.onResume(MainActivity.kt:101)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1363)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.app.Activity.performResume(Activity.java:7444)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3805)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3870)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1788)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:106)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:164)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:7036)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
02-12 12:35:22.504 29178 29178 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)

Please help me resolve this. Thank you.

@lbalmaceda
Copy link
Contributor

@va26 As you see in your logs this is not related at all with a class from this SDK. You will have to report it in google's issue tracker instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants