Open jospete opened 8 years ago
Managed to get Android working with Android ADAL 2.0.3-alpha on this fork. Going through all of the ADAL sources and this plugin's implementation has me thinking that ADAL isn't really mean't for B2C. Is this the case??
I'm currently working off of the native mobile B2C implementations for Android and iOS to convert the plugin's features
Just updated ADALiOS to 3.0.0-pre.2 and it works as expected for B2C, will have this in the patched plugin soon
Plugin version in repo master has been recently updated to use ADALiOS 2.2.2 instead of 1.x - could you please see if version 2.2.2 is enough to enable this scenario or we should bump to 3.x?
cordova plugin add https://github.com/AzureAD/azure-activedirectory-library-for-cordova
Honestly, we have never tested plugin for B2C case. @jospete in your fork did you have to change any plugin internal implementation/logic to make it working or you just bumped native SDKs? I'm looking on the Android changes and see new policy
param and other modifications and not sure whether they are enhancements or must have to enable B2C scenario working.
After reading B2C Docs it looks like there is extra work required for B2C support other than just bumping native libraries. I'll discuss whether we plan to add B2C support w/ plugin owners.
After learning a significant amount about how this plugin works and how it interacts with the ADAL libraries, the differences between the current plugin state and what B2C requires will basically boil down to that "policy" parameter, and possibly B2C's odd Oauth2 endpoints that require a "v2.0" intermediate (/oauth2/v2.0/authorize instead of /oauth2/authorize, /v2.0/oauth2/token instead of /oauth2/token)
From what I've seen so far, Android ADAL v2.0.1-alpha and ADALiOS v3.0.0-pre.2 both remedy the policy bit and, even though the endpoints they generate are different from B2C, the updated versions still end up working.
I used the Native B2C Android Project which has Android ADAL v2.0.1-alpha required by its build.gradle, and the v3.0.0-pre.2 Tagged ADALiOS Sample to prove out that the policy works correctly with both those versions.
To answer your question about ADALiOS 2.2.2, I pulled the sample for that tag from here and there doesn't seem to be a place to put a custom policy, so I'm afraid this won't work.
I guess I'd like the libraries to be updated to add support for custom policies, and not so much to support B2C - policies seem to be the connecting factor in all of this for me.
To add to this, I tried adding the policy as an extraQueryParameter "p" on plugin version 0.7.1 and 0.7.2-dev, did not work on either. That's what led to here.
@jospete, thank you for extra info!
Update on plugin v0.7.2-dev - I've successfully gotten my custom policy to show in the prompt using these parameters:
var opts = {
tenant: "*******.onmicrosoft.com",
resourceUrl: "https://login.microsoftonline.com",
redirectUrl: "https://*********.com/b2c/auth/return",
clientId: "f6dad784-f7d3-412c-92bd-*********",
userId: LocalStorage.get(USER_ID, null),
extraParams: "p=B2C_1_sign-in-up-policy&scope=openid"
}
...
authContext.acquireTokenAsync(
opts.resourceUrl,
opts.clientId,
opts.redirectUrl,
opts.userId,
opts.extraParams
)
However, I get an invalid_grant error when trying to authenticate (tested with Android):
08-18 10:10:01.385: E/HttpWebRequest(17004): SERVER_ERROR:2016-08-18 15:10:01-f5f5e3d2-7408-471b-9358-b9531c6398a6-IOException:https://login.microsoftonline.com/********.onmicrosoft.com/oauth2/token ver:1.1.18 08-18 10:10:01.386: V/HttpWebRequest(17004): 2016-08-18 15:10:01-f5f5e3d2-7408-471b-9358-b9531c6398a6-Status code:400 ver:1.1.18 08-18 10:10:01.388: V/HttpWebRequest(17004): 2016-08-18 15:10:01-f5f5e3d2-7408-471b-9358-b9531c6398a6-Response is received ver:1.1.18 08-18 10:10:01.389: V/Oauth(17004): 2016-08-18 15:10:01-f5f5e3d2-7408-471b-9358-b9531c6398a6-Token request does not have exception ver:1.1.18 08-18 10:10:01.391: V/Oauth(17004): 2016-08-18 15:10:01-8af074c2-9335-4c9e-ab88-c9105363c089-OAuth2 error:invalid_grant Description:AADSTS70000: Authentication failed: Authorization Code is malformed or invalid. 08-18 10:10:01.391: V/Oauth(17004): Trace ID: 8bcbb46d-5b68-4bd8-bed7-279c1f82dfd5 08-18 10:10:01.391: V/Oauth(17004): Correlation ID: 8af074c2-9335-4c9e-ab88-c9105363c089 08-18 10:10:01.391: V/Oauth(17004): Timestamp: 2016-08-18 15:10:00Z ver:1.1.18 08-18 10:10:01.392: V/Oauth(17004): 2016-08-18 15:10:01-8af074c2-9335-4c9e-ab88-c9105363c089-Response correlationId:8af074c2-9335-4c9e-ab88-c9105363c089 ver:1.1.18 08-18 10:10:01.393: V/AuthenticationContext(17004): 2016-08-18 15:10:01-8af074c2-9335-4c9e-ab88-c9105363c089-OnActivityResult processed the result. Request authority:https://login.microsoftonline.com/*******.onmicrosoft.com resource:https://login.microsoftonline.com clientid:f6dad784-f7d3-412c-92bd-**** ver:1.1.18 08-18 10:10:01.394: E/AuthenticationContext(17004): AUTH_FAILED:2016-08-18 15:10:01-8af074c2-9335-4c9e-ab88-c9105363c089- ErrorCode:invalid_grant ErrorDescription:AADSTS70000: Authentication failed: Authorization Code is malformed or invalid. 08-18 10:10:01.394: E/AuthenticationContext(17004): Trace ID: 8bcbb46d-5b68-4bd8-bed7-279c1f82dfd5 08-18 10:10:01.394: E/AuthenticationContext(17004): Correlation ID: 8af074c2-9335-4c9e-ab88-c9105363c089 08-18 10:10:01.394: E/AuthenticationContext(17004): Timestamp: 2016-08-18 15:10:00Z ver:1.1.18 08-18 10:10:01.395: V/AuthenticationContext(17004): 2016-08-18 15:10:01-8af074c2-9335-4c9e-ab88-c9105363c089-Remove waiting request: 15564375 ver:1.1.18 08-18 10:10:01.408: I/chromium(17004): [INFO:CONSOLE(3281)] "AzureB2C.authenticate() error: { 08-18 10:10:01.408: I/chromium(17004): "code": "AUTH_FAILED", 08-18 10:10:01.408: I/chromium(17004): "details": { 08-18 10:10:01.408: I/chromium(17004): "errorDescription": " ErrorCode:invalid_grant ErrorDescription:AADSTS70000: Authentication failed: Authorization Code is malformed or invalid.\r\nTrace ID: 8bcbb46d-5b68-4bd8-bed7-279c1f82dfd5\r\nCorrelation ID: 8af074c2-9335-4c9e-ab88-c9105363c089\r\nTimestamp: 2016-08-18 15:10:00Z", 08-18 10:10:01.408: I/chromium(17004): "errorCode": "AUTH_FAILED" 08-18 10:10:01.408: I/chromium(17004): } 08-18 10:10:01.408: I/chromium(17004): }", source: file:///android_asset/www/app.js (3281) 08-18 10:10:01.414: I/chromium(17004): [INFO:CONSOLE(729)] "User: login error: { 08-18 10:10:01.414: I/chromium(17004): "code": "AUTH_FAILED", 08-18 10:10:01.414: I/chromium(17004): "details": { 08-18 10:10:01.414: I/chromium(17004): "errorDescription": " ErrorCode:invalid_grant ErrorDescription:AADSTS70000: Authentication failed: Authorization Code is malformed or invalid.\r\nTrace ID: 8bcbb46d-5b68-4bd8-bed7-279c1f82dfd5\r\nCorrelation ID: 8af074c2-9335-4c9e-ab88-c9105363c089\r\nTimestamp: 2016-08-18 15:10:00Z", 08-18 10:10:01.414: I/chromium(17004): "errorCode": "AUTH_FAILED" 08-18 10:10:01.414: I/chromium(17004): } 08-18 10:10:01.414: I/chromium(17004): }", source: file:///android_asset/www/app.js (729)
Same issue on iOS:
2016-08-18 10:41:27.162 VerifEye[1103:4119518] AzureB2C.acquireTokenAsync()... 2016-08-18 10:41:45.388 VerifEye[1103:4120417] ADAL [2016-08-18 15:41:45 - C6375BDD-C65F-4BC7-9B2C-E2307C951146] ERROR: Error raised: (Domain: "ADOAuthServerErrorDomain" Code: AD_ERROR_SERVER_OAUTH ProtocolCode: "invalid_grant" Details: "AADSTS70000: Authentication failed: Authorization Code is malformed or invalid. Trace ID: d85c4a2f-6926-49f3-b533-e5b92f923019 Correlation ID: c6375bdd-c65f-4bc7-9b2c-e2307c951146 Timestamp: 2016-08-18 15:41:22Z" 2016-08-18 10:41:45.395 VerifEye[1103:4119518] AzureB2C.authenticate() error: { "line": 36, "column": 34, "sourceURL": "file:///Users/jnoel/Library/Developer/CoreSimulator/Devices/9D32B7FB-329A-49FA-8A7F-D9E9CB0517D6/data/Containers/Bundle/Application/D5E0802C-3CE4-4755-B533-720A2D750106/VerifEye.app/www/plugins/cordova-plugin-ms-adal/www/CordovaBridge.js", "code": "invalid_grant", "details": { "errorCode": "AD_ERROR_SERVER_OAUTH", "statusCode": 2, "error": "invalid_grant", "errorDescription": "AADSTS70000: Authentication failed: Authorization Code is malformed or invalid.\r\nTrace ID: d85c4a2f-6926-49f3-b533-e5b92f923019\r\nCorrelation ID: c6375bdd-c65f-4bc7-9b2c-e2307c951146\r\nTimestamp: 2016-08-18 15:41:22Z" } }
@sgrebnov I think updating the libraries appropriately will fix the Oauth2 problems listed above, but as you said, the library updates will entail some fairly significant plugin changes as far as API calls and Type definitions.
The current decision is to wait till new version of native libs are officially released because we can't switch to pre-released versions and then review this work item one more time. In a mean time, it looks like that passing custom policy via query param is the simplest way to make B2C scenario supported. @jospete thank you for all details provided and your experiments.
I am not able to run this B2C sample.
Also can you highlight on when it will be officially supported or any updates?
@EatonIoT If you're talking about the sample on my fork, I didn't update it to work with the patch. Try following the installation and sample usage on the patched readme for your project.
B2C will probably be officially supported when Android ADAL 2.0.3-alpha and iOS ADAL 3.0.0-pre6 (and whatever the working alpha for Windows is) go into production - this seems to be a few months off though.
@jospete I am not able to run your B2C sample code. I took ADAL cordova sample, remove "cordova-plugin-ms-adal" and add your plugin. I am changing www/js/index.js file with following :
` var params = {
redirectUrl: "urn:ietf:wg:oauth:2.0:oob", // default to use
resourceUrl:"*******-e163-****-8ad5-*********",
extraQueryParams: "nux=1", // all the updated libraries have this
authority: "https://login.microsoftonline.com/*******.onmicrosoft.com",
clientId: "********-e163-****-8ad5-************", /
policy: "****",
userId: null, // don't need to track this in most cases
};
var app = {
// Invoked when Cordova is fully loaded.
onDeviceReady: function() {
document.getElementById('search').addEventListener('click', app.authenticate);
},
// Shows user authentication dialog if required.
authenticate: function () {
var authContext = new window.Microsoft.ADAL.AuthenticationContext(params.authority);
authContext.acquireTokenAsync(
params.resourceUrl,
params.clientId,
params.redirectUrl,
params.userId,
params.extraQueryParams,
params.policy
);
console.log("Call for acquireTokenAsync");
authContext.tokenCache.readItems().then(app.parseCache, app.loudSignIn);
`
But I am not able to redirect to azure login page. I also tried with npm install and gulp ios-update-adal commands for ADALiOS framework but it gives following error
[13:45:36] Starting 'ios-script'...
[13:45:36] Starting 'ios-move-script'...
[13:45:36] Finished 'ios-move-script' after 28 ms
[13:45:36] Starting 'ios-run-script'...
'.' is not recognized as an internal or external command,
operable program or batch file.
[13:45:36] 'ios-run-script' errored after 22 ms
[13:45:36] Error: Command `./build_sdk.sh` failed with exit code 1
at ChildProcess.exithandler (child_process.js:751:12)
at ChildProcess.emit (events.js:110:17)
at maybeClose (child_process.js:1015:16)
at Socket.<anonymous> (child_process.js:1183:11)
at Socket.emit (events.js:107:17)
at Pipe.close (net.js:485:12)
[13:45:36] 'ios-update-adal' errored after 1.7 min
[13:45:36] Error: [object Object]
Hi, I am using ADAL on Android. Calling authenticationContext.acquireTokenSilentSync leads me to this type of error. As far as I understand the context it says, that the refresh token is failed (broken?) and it cannot get me a new id token with it. Morover, because I use Silent method, he cannot prompt me with user name and password so it fails. What I may have been doing wrong in here?
com.microsoft.aad.adal.AuthenticationException: Refresh token is failed and prompt is not allowed at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1229) at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1158) at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1145) at com.microsoft.aad.adal.AuthenticationContext.access$500(AuthenticationContext.java:55) at com.microsoft.aad.adal.AuthenticationContext$3.call(AuthenticationContext.java:1094) at com.microsoft.aad.adal.AuthenticationContext$3.call(AuthenticationContext.java:1089) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:833
Hi, Has the plugin been updated to support Azure AD B2C.
@rifhanakram, it hasn't yet, unfortunately
@vladimir-kotikov Thanks for the update :)
Any news on when B2C support is coming?
if you have an web app hosted on azure app service and authentication and authorization for that app is handled via Azure B2C and if you want your Mobile App also to be authenticated and authorized via B2C you can use the Azure App Service Auth Lib for Cordova to do this. This is a use case i came across. i used server directed flow :). Hope this will be helpful for someone
Any news on when B2C support is coming?
Any news on when B2C support is coming?
Hi, is there any news about this, are you going to support B2C on the plugin soon?
@jospete is the your patch currently working with B2c? I'm trying to use it without success to show the policy sign in screen.
I am using @jospete patch in a POC but the token refresh does not work.
@jospete I tried using your patch for my cordova app. Everything seems working except that I need to send scopes to the authorization URL according to my needs but it looks like they are hardcoded to be offline_access&openid&profile all the time and hence I am getting duplicate scope error when I try to send scopes in extraQueryParams. Could you please let me know if there is any way that I can send my scopes to the authorization URL?
@jospete I have used your patch plugin for B2C into my cordova app, it is working fine, I am able to see the login page with B2C login provider. But from couple of days back I am facing issue in two of the scenerios:
1. Google login in ios (require two times login for the first time arrived user)
Details: For the first time when google ask for credentials and just after submission it returns something like this
Failed to acquire token: {
"line": 36,
"column": 34,
"soureceURL": ".../www/plugins/cordova-plugin-ms-adal-b2c-patch/www/CordovaBridge.js",
"code": "NATIVE_METHOD_GENERAL_FAILURE",
"details": {
"errorCode": null,
"statusCode": 2,
"error": null,
"errorDescription": "The operation was cancelled"
}
}
And again I am sending user to login page but when trying to login second time it is taking credentials entered during first time logged in successfully.
2. Facebook login in andriod (not able to login)
Details: Always giving error like this
{
"code": "AUTHORIZATION_CODE_NOT_EXCHANGED_FOR_TOKEN",
"details": {
"errorDescription": "Authorization code not exchanged for token",
"errorCode": "AUTHORIZATION_CODE_NOT_EXCHANGED_FOR_TOKEN"
}
}
[NOTE: There is one exception case when user starting fresh to sign in using facebook, after taking credentials it lands to the user details form where email and name are already showing as pre-filled and just submit that form it logged in successfully.]
Any Idea?
Any news? Almost two years and no updates yet?
@matteobortolazzo Doesn't look like either of the native libraries fixed the oauth url issue for B2C.
For reference, here's the culprit code I ran into back when this was breaking for me:
The B2C Docs state how the url is supposed to be structured (oauth2/v2.0/authorize), but the underlying libraries don't follow this pattern.
Neither of the native libraries have been touched in ~2 years so I don't see this ever getting fixed.
@jospete Do you still use your patch in your project? Does your solution support password reset?
I wrote a class that uses Cordova InAppBrowser and Angular HTTPClient to do the OAuth2.0 authorization code flow. Docs for B2C https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-oauth-code Docs for OAuth2.0 for Cordova https://www.thepolyglotdeveloper.com/2016/01/using-an-oauth-2-0-service-within-an-ionic-2-mobile-app/
@matteobortolazzo That's probably the way that the B2C devs intended for everyone to implement login for cordova.
@jospete I was able to implement the B2C Authentication using your library but when I get the response the userInfo property is empty, do you have any clue why this is happening?
I wrote a class that uses Cordova InAppBrowser and Angular HTTPClient to do the OAuth2.0 authorization code flow. Docs for B2C https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-oauth-code Docs for OAuth2.0 for Cordova https://www.thepolyglotdeveloper.com/2016/01/using-an-oauth-2-0-service-within-an-ionic-2-mobile-app/
Would you share you work here, so we can get some ideas on how to manage this? Also, while you say you are supporting the Cordova implement via InAppBrowser, did you implement flow for web?
@abcox I imagine the general usage would be:
Construct a URL to mimic sign-in or sign-up: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-oauth-code#use-a-sign-in-policy
Open the URL using the in-app-browser plugin: https://ionicframework.com/docs/native/in-app-browser/#create
Listen for the redirect_uri callback: https://stackoverflow.com/questions/37366838/handling-redirect-uri-in-ionic-for-external-api https://ionicframework.com/docs/native/in-app-browser/#on
Get a token with the OAuth token url: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-oauth-code#2-get-a-token
@matteobortolazzo is this more or less what you did?
@jospete Yes, the working solution was using SafariViewController and Custom URL Schema. Do the login, redirect to yourapp://redirect, listen to handleOpenURL, get the code and request a new access token.
@jospete, @matteobortolazzo: thanks for your inputs... this is the high-level (pseudocode) that I am implementing. The difficulty is around how to implement in a way that would have the correct page shown whether or not the user is signed in, or is coming back from a sign in/up...
For example, in the case of a successful sign-in, the redirect_url string that is permitted only allows me to navigate back to the root site (in test this is localhost:8100). On successful sign-in this results in navigation to localhost:8100/null (a blank page). If I navigate back, it goes to the page that was last loaded before window.open was invoked.
How to manage the navigation around the results of the window.open ?
The other issue is about how to successfully add a callback function to the window.open ?
Are there any good examples of how to implement the Azure B2C in an Ionic app handling both mobile and web clients ?
Hi, is there an update on this? Will there ever be support for Azure B2C on the Ionic framework?
At the moment when trying to trigger my login page for the user - cordova is redirecting to a _blank page. This code however works fine in a standard Angular 6 Application. When the same code is used on Ionic the popup window 1. Either doesn't show up on web 2. When it does show up through an iOS/Android emulator, the window is blank
Any help would be really appreciated.
Also trying to implement B2C on Ionic - any updates on this team?
@sambowenhughes - did you ever have any luck?
@jjgriff93 Have a look at OAuth 2.0 authorization code flow in Azure Active Directory B2C.
@AndyThurgood and I got B2C Auth tenant authenticating through an ionic app using this method.
Documentation isn't great but if you get stuck:
1. Getting a valid CODE from B2C: The following request to B2C will return a valid CODE as long as the params passed along are correct:
Post Request (Form Encoded): https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/oauth2/v2.0/authorize?p={User Flow Name}v2&client_id={Client ID}&response_type=code&redirect_uri={Redirect URI}&response_mode=query&scope=openid%20offline_access&state=12345
2. Getting the access token: Post Request (Form Encoded): https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/oauth2/v2.0/token?p={User Flow Name}
Body:
client_id:{Client ID}
scope: openid offline_access
redirect_uri: {Redirect URI}
grant_type: authorization_code
code: {Code received from the original request}
What this will return is a valid access token to speak to your services (Assuming your services are using this method of authentication).
Thanks @sambowenhughes - so you managed to get this working on a native app as well as running in the web? Did you use a library for this or code it yourself?
I've managed to implement the above utilising the angular-oauth2-oic package which works in the web but havent yet figured out how this will work in Android or iOS
Yeah so using OAuth 2.0 authorization code flow in Azure Active Directory B2C we managed to get an Ionic App authenticating against our B2C tenant on both Android and iOS.
The problem we had was we wanted our users to be able to authenticate using their existing accounts through another client (Ionic app).
We used a mixture of InAppBrowser and Cordova Advanced HTTP to get the valid access token for our services.
Our code looked something like this: When the user clicks login on the homepage we trigger the code_flow login form within the InAppBrowser.
public async login(){
// InAppBrowser with url and options for request to login
var browser = this.inAppBrowser.create('{url_query_used_to_get_code}', '_blank', {
location: 'yes',
clearcache: 'yes',
toolbar: 'yes',
zoom: 'no'
});
// When the browser has stopped loading do the following
browser.on("loadstop").subscribe(event=>{
// Get the event url into a param variable
var params = new URLSearchParams(event.url)
// If the params response has a code present
if(params.has('code')){
// Get the code
var code = params.get('code');
this.getAccessToken(code);
browser.close();
}
});
}
If the login is successful we pass the code over to 'getAccessToken(code)' which makes a second call to Azure to return a valid Access Token:
public getAccessToken(code) {
var headers = {'Content-Type': 'application/x-www-form-urlencoded'};
var url = "{code_flow_url_of_your_policy}";
// Set the body to what microsoft needs in order to process the request
var body = {
"client_id" : "{Client-Id}",
"scope" : "openid offline_access",
"redirect_uri" : "https://login.microsoftonline.com/tfp/oauth2/nativeclient",
"grant_type": "authorization_code",
"code": code
}
// Use the native HTTP client to post to B2C
this.nativeHttp.post(url, body, headers)
.then(data => {
var response = JSON.parse(data.data)
var accessToken = response.id_token;
this.accessToken = accessToken;
})
.catch(error => {
console.log("ERROR:"+JSON.stringify(error))
});
}
100% not the nicest approach but we hit a lot of walls when going about this.
@sambowenhughes: that's great. Is there any repo you can share with the full ionic/spa solution? I'm struggling to find documentation and a concrete example step by step of how to make it work. Thanks a lot.
Issue Description
I'm using this plugin in an ionic app to authenticate with Azure AD B2C, but after much trial and error documented by this stackoverflow post, I've come to the conclusion that the hardcoded Oauth2 extension "oauth2/authorize" in this file (and most likely the other Oauth2 native implementations as well) is breaking the B2C endpoint requirement of "oauth2/v2.0/authorize" specified in the B2C Docs
Would it be possible to add a "b2c" attribute to AuthenticationContext definition so the resulting AuthenticationRequest object will know to use the appropriate endpoints?
Repro Environment Details