The ADAL SDK for Android gives you the ability to add support for Work Accounts to your application with just a few lines of additional code. This SDK gives your application the full functionality of Microsoft Azure AD, including industry standard protocol support for OAuth2, Web API integration with user level consent, and two factor authentication support.
Users are trying testapp as an initial sample. It was used for instrumentation app for testing. Update that so that it does not launch activity if user did not enter anything.
User may not set the internet permission in AndroidManifest.xml file. ADAL can detect that before making webrequest or before trying to launch AuthenticationActivity.
daemon not running. starting it now on port 59513 *
daemon started successfully *
WARNING: Data partition already in use. Changes will not persist!
ko:Snapshot storage already in use: d:\workspace\ADAL-Android.android\avd\hudson_en-US_320_768x1280_android-19_x86.avd/snapshots.img
[android] Emulator did not appear to start; giving up
$ C:\android-sdk/platform-tools/adb.exe disconnect localhost:59512
[android] Stopping Android emulator
$ C:\android-sdk/platform-tools/adb.exe kill-server
Recording test results
No test report files were found. Configuration error?
Emma: looking for coverage reports in the provided path: tests/Functional/coverage/coverage.xml
Finished: NOT_BUILT
When ADAL.Jar filed is used as external jar file in Android app than ADAL library crashes looking for class android.security.KeyPairGeneratorSpec$Builder.
Following is the stack for crash.
03-05 22:14:27.908: D/ScenarioHealthApp(875): MainActivity onCreate(), creating AuthenticationContext
03-05 22:14:29.247: V/DefaultTokenCacheStore(875): : Started to initialize storage helper. null
**************>>>>>>>>>>
03-05 22:14:29.318: E/dalvikvm(875): Could not find class 'android.security.KeyPairGeneratorSpec$Builder', referenced from method com.microsoft.adal.StorageHelper.getKeyPairFromAndroidKeyStore
03-05 22:14:29.327: W/dalvikvm(875): VFY: unable to resolve new-instance 101 (Landroid/security/KeyPairGeneratorSpec$Builder;) in Lcom/microsoft/adal/StorageHelper;
03-05 22:14:29.327: D/dalvikvm(875): VFY: replacing opcode 0x22 at 0x003f
03-05 22:14:29.357: D/dalvikvm(875): DexOpt: unable to opt direct call 0x01bf at 0x43 in Lcom/microsoft/adal/StorageHelper;.getKeyPairFromAndroidKeyStore
03-05 22:14:29.378: V/DefaultTokenCacheStore(875): : Finished to initialize storage helper. null
03-05 22:14:29.407: V/AuthenticationContext(875): : CorrelationId generated f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.427: V/AuthenticationContext(875): : Token request started CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.447: V/AuthenticationContext(875): : Checking refresh tokens CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.457: V/AuthenticationContext(875): : Looking for regular refresh token CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.477: V/AuthenticationContext(875): : Looking for Multi Resource Refresh token CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.507: V/AuthenticationContext(875): : Refresh token is not available CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.507: V/AuthenticationContext(875): : Starting Authentication Activity with callback:1087267864 CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.518: V/AuthenticationContext(875): : Put waiting request: 1087267864 CorrelationId: f6362f9d-d783-40bf-91f9-7e0c89352a54. null
03-05 22:14:29.767: D/ScenarioHealthApp(875): MainActivity onStart(), ScenarioCount : 0
03-05 22:14:29.777: D/ScenarioHealthApp(875): MainActivity onResume(), ScenarioCount : 0
03-05 22:14:29.837: W/dalvikvm(875): VFY: unable to resolve static field 2294 (title_confirmation_activity_authentication) in Lcom/microsoft/adal/R$string;
03-05 22:14:29.837: D/dalvikvm(875): VFY: replacing opcode 0x60 at 0x0005
03-05 22:14:29.860: W/dalvikvm(875): VFY: unable to resolve static field 2290 (activity_authentication) in Lcom/microsoft/adal/R$layout;
03-05 22:14:29.875: D/dalvikvm(875): VFY: replacing opcode 0x60 at 0x0007
03-05 22:14:29.877: W/dalvikvm(875): VFY: unable to resolve static field 2291 (login) in Lcom/microsoft/adal/R$menu;
03-05 22:14:29.877: D/dalvikvm(875): VFY: replacing opcode 0x60 at 0x0004
03-05 22:14:29.907: D/AndroidRuntime(875): Shutting down VM
03-05 22:14:29.907: W/dalvikvm(875): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
03-05 22:14:29.967: E/AndroidRuntime(875): FATAL EXCEPTION: main
03-05 22:14:29.967: E/AndroidRuntime(875): java.lang.NoClassDefFoundError: com.microsoft.adal.R$layout
03-05 22:14:29.967: E/AndroidRuntime(875): at com.microsoft.adal.AuthenticationActivity.onCreate(AuthenticationActivity.java:102)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.Activity.performCreate(Activity.java:5104)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.ActivityThread.access$600(ActivityThread.java:141)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.os.Handler.dispatchMessage(Handler.java:99)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.os.Looper.loop(Looper.java:137)
03-05 22:14:29.967: E/AndroidRuntime(875): at android.app.ActivityThread.main(ActivityThread.java:5041)
03-05 22:14:29.967: E/AndroidRuntime(875): at java.lang.reflect.Method.invokeNative(Native Method)
03-05 22:14:29.967: E/AndroidRuntime(875): at java.lang.reflect.Method.invoke(Method.java:511)
03-05 22:14:29.967: E/AndroidRuntime(875): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
03-05 22:14:29.967: E/AndroidRuntime(875): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
03-05 22:14:29.967: E/AndroidRuntime(875): at dalvik.system.NativeStart.main(Native Method)
01-22 18:05:18.115: D/HttpWebRequest(1058): Setting header: x-client-DM
01-22 18:05:18.255: D/HttpWebRequest(1058): Setting header: x-client-SKU
01-22 18:05:18.255: D/HttpWebRequest(1058): Setting header: Accept
01-22 18:05:18.285: D/HttpWebRequest(1058): Setting header: Host
01-22 18:05:18.285: D/HttpWebRequest(1058): Setting header: x-client-Ver
01-22 18:05:18.475: I/Choreographer(1058): Skipped 93 frames! The application may be doing too much work on its main thread.
01-22 18:05:18.925: I/Choreographer(1058): Skipped 37 frames! The application may be doing too much work on its main thread.
01-22 18:05:19.325: D/AuthenticationActivity(1058): AuthenticationActivity onStop
01-22 18:05:19.385: D/HttpWebRequest(1058): Exception:null
01-22 18:05:19.395: D/HttpWebRequest(1058): HttpWebRequest OnPostExecute thread:1058
01-22 18:05:19.445: E/Oauth(1058): SERVER_ERROR: null.
01-22 18:05:19.445: E/Oauth(1058): java.io.EOFException
01-22 18:05:19.445: E/Oauth(1058): at libcore.io.Streams.readAsciiLine(Streams.java:203)
01-22 18:05:19.445: E/Oauth(1058): at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:573)
01-22 18:05:19.445: E/Oauth(1058): at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:821)
01-22 18:05:19.445: E/Oauth(1058): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
01-22 18:05:19.445: E/Oauth(1058): at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:495)
01-22 18:05:19.445: E/Oauth(1058): at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
01-22 18:05:19.445: E/Oauth(1058): at com.microsoft.adal.HttpWebRequest.doInBackground(HttpWebRequest.java:169)
01-22 18:05:19.445: E/Oauth(1058): at com.microsoft.adal.HttpWebRequest.doInBackground(HttpWebRequest.java:1)
01-22 18:05:19.445: E/Oauth(1058): at android.os.AsyncTask$2.call(AsyncTask.java:287)
01-22 18:05:19.445: E/Oauth(1058): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
01-22 18:05:19.445: E/Oauth(1058): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
01-22 18:05:19.445: E/Oauth(1058): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
01-22 18:05:19.445: E/Oauth(1058): at java.lang.Thread.run(Thread.java:856)
Nexus 7 - running Android 4.4.2 (Build# KOT49H).
On loading (based on logs), the webview in AuthenticationActivity (from ADAL) redirects to login.microsoftonline.com
WebView fails on this page with
[INFO:async_pixel_transfer_manager_android.cc(56)] Async pixel transfers not supported
03-07 23:27:11.078: E/qdutils(32175): FBIOGET_FSCREENINFO failed
When I am using refresh token to update expired access token, the new refresh token value I am getting is null. So when new access token is getting expired authentication activity opens and authentication flow starts again. Is this behavior expected or there is bug in a library/server?
Define acquireToken(..) API which does not need android as it's activity.
As discussed with Omer, in many cases when developer selects option neverPrompt or wants to just refresh the token, developer does not need to pass activity as arguments in API.
adal/src/com/microsoft/adal/StorageHelper.java
public String encrypt(String clearText) method uses prefix for encode version. Update that to include encode_length as well.
Using Maven is quite common for Java development. Gradle - Android new build system - is in turn extensively using Maven repositories and artifacts. Official Android IDE (IntelliJ IDEA based) is using Gradle by default.
It would come very handy if ADAL library can be used not only as a project dependency but also as a Maven/Gradle dependency. Providing *.aar deliverable would make ADAL one step closer to developer, expose SDK in a simple well known “*.jar as a dependency” format and fit into Android ecosystem.
Looks like token caching in API < 18 does not work. Here is storage helper loadSecretKeyForAPI method:
if (Build.VERSION.SDK_INT >= 18) {
try {
// androidKeyStore can store app specific self signed cert.// Asymmetric cryptography is used to protect the session// key// used for Encryption and HMacsKey = getSecretKeyFromAndroidKeyStore();
sMacKey = getMacKey(sKey);
sBlobVersion = VERSION_ANDROID_KEY_STORE;
return;
} catch (Exceptione) {
Logger.e(TAG, "Failed to get private key from AndroidKeyStore", "",
ADALError.ANDROIDKEYSTORE_FAILED, e);
}
}
sKey = getSecretKey(AuthenticationSettings.INSTANCE.getSecretKeyData());
sMacKey = getMacKey(sKey);
sBlobVersion = VERSION_USER_DEFINED;
As we can see, in API < 18 sKey obtained using AuthenticationSettings.INSTANCE.getSecretKeyData(). In current implementation it has null value by default, so getSecretKey() throws an exception and encrypt() method (that calls this code) returns null. Returned value is then checked and put in the cache (preferences storage) only if it has non-null value. Therefore items caching seems to be non-working in API < 18 (I am using emulator with API 17). And my question is: what should I do to make caching work?
It would be very convenient to have ADAL artifact on Maven Central. This way Maven applications will be able to simply reference it as dependency.
Now the options are:
Set up maven configuration to automatically download source code, build it and deploy it to local repository. This brings unwanted complexity to configuration and a new module to the application that could have had a single pom.
coverage plugin needs coverege.ec file to generate json post for coveralls. It is missing or not working.
remote object '/data/data/com.microsoft.adal.test/files/coverage.ec' does not exist
Initial acquireToken can be done with/without LoginHint. RefreshToken does not return idtoken. It needs to use same key to store data after refresh token.
When com.microsoft.adal.jar file is included in project as external lib, there is no documentation available in eclipse studio which developer can use it for his programming.
This is must have thing for developer for best experience.
Also add steps in readme file how to set source folder in eclipse for debugging purpose.
What should be the format for authority URL?
For example https://login.windows.net``/common/oauth2/token
I've took some time to look into AADAL and not sure if I have a clear picture of how the second part of the URL is being handled. I've found it in 2 places:
If there was a failure in other instrumentation tests, authentication Activity may wait for input such as incorrect credentials. Next test case needs to cleanup that before sending test input.
There should be a some doc or sample code or clear guidance for application developer how authentication context works and how it can be used to refresh token.
Currently there is no sample which shows how to use authentication context to find where previously acquired token is expired before sending to the resource. If token is expired then show the developer a way how to refresh access token. Show some example code.
Currently my application is acquiring a token in main activity (as there needs to be callback function needed by ADAL lib in activity) and later it starts new activity A2, which uses acquired token. Now app is active overnight on A2 page and token has expired. so in morning user gets an error when trying to use same token. Show some sample code how developer can refresh token on activity A2.
Above scenario is going to be very common for all the developers.