-
Notifications
You must be signed in to change notification settings - Fork 214
UserPasswordCredential doesn't support .NET Core #482
Comments
- so that UserCredential can ba overridden in .NET Core library, eg) UserPasswordCredential - regarding to the issue AzureAD#482
This is not supported by design. |
@kpanwar Thanks for getting back to me. Is there any timeline that we can use |
Yes, we will not add support for UserPasswordCredential in .NET core. There are other ways to authenticate as well. See https://github.com/Azure-Samples/active-directory-dotnet-deviceprofile |
We have a daemon service that was authenticating to an API as a user and we were using UserPasswordCredential method to fetch access token (by passing username and password). But when we upgraded the solution to .Net Core (and the latest ADAL package), this has broken. If UserPasswordCredential is no more supported, what is the alternate approach to authenticate non-interactively for the aforementioned scenario? |
Ditto. I'm trying to authenticate against a 3rd party API in an Azure WebJob, which was previously working fine using UserPasswordCredential. What is now the recommended approach here? |
So how would one write a headless client for lets say CRM dynamics which requires an Oath 2.0 authentication to Active Directory to access the web api in .NET core? |
The idea here is that for apps to collect and store a user's username and password is not the correct approach for non-interactive authentication. Here are some details on why you shouldn't do this:
When you have a process running with no user interaction whatsoever, you should refer to the "Application Identity with OAuth 2.0 Client Credentials Grant" case of the "Daemon or Server Application to Web API" scenario. The following ADAL constructs will obtain an access token based on the app's identity only, and authenticate with either a client secret, a client assertion (i.e. a signed JWT token), or a client certificate (which will be used to create a signed JWT token). The resulting access token will not identify a user, and is only suitable when the token is for apps/APIs that have defined app-only permissions:
In scenarios where user interaction is possible, you can use the If your device or platform is incapable of displaying Azure AD's browser-based sign in page (e.g. a device with limited input capabilities), you can use the device flow that @kpanwar has linked to. After the first token acquisition, your app can use the cached refresh token to get a new access token without any further user actions or interactions (as long as nothing has changed that might invalidate the refresh token). |
@psignoret My app works as an api proxy to the crm dynamics online web api (which is protected via AD oauth and application id). That's just the way web api in CRM works, I can't control its auth mechanism. The proxy is fully headless and has no concept or care of a logged in user. Other apps/services leverage this proxy api. There 100% no user interaction whatsoever in any way. Because of this I am forced to use the full .Net stack which supports this CRM web api headless login scenario. None of the links you provided have an acceptable alternative as they all rely on the concept of a logged in user. Obviously this was included in the full .net stack for a reason. This is the only feature holding back my entire solution from using .net core fully. It makes no sense to make the decision that .NET core never needs this and full stack may need it. If you're / Microsoft are so positive this scenario is never needed why is it in the full stack? More details about this is documented here: |
I'd like to present another similar use case just to highlight the obvious need for headless auth / user password credntials. We have a customer portal where our users (construction contractors) can view their quotes (stored in CRM) as well other other business related documents like invoices (Dynamics AX) etc. This portal talks to our backend Web API app service that is only privately accessible. This API needs to call out to CRM's Web API. Our users have no clue about AD, they don't have Microsoft accounts, and barely remember their logins for our site let alone any other. If another login screen came up just to access their quote information, they'd run and never come back. We are a single tenant that wants to display quote information to our customers and we control all access to that data. We have created a non-interactive service account that "should" handle this. I've tried every single workflow I've found. Client Credentials with generated Key, User Password, pure OAuth without ADAL library and using an older version of ADAL that still had UserPasswordCredential. The latter got me very close to successfully accessing the Web API via a fixed service account but received an error claiming consent had not been granted and I found no way to grant this consent. I got in touch with @dstrockis at Azure-Samples/active-directory-dotnet-native-headless#12 (comment) who presented this solution to grant consent: All in all, like the others, I'm having to use the full framework and unfortunately the old OrganizationService to access data which I'm able to do very quickly and easily. I've not tried the solution mentioned above yet but it looks promising. |
Your scenario looks like a perfect candidate for the on-behalf-of flow (which is the only approach I didn't mention in my earlier comment). This flow is briefly described in the Daemon or Server Application to Web API scenario. It is an implementation of part of MS-OAPX (OAuth 2.0 Protocol Extensions), which is an extension to OAuth 2.0 (developed by Microsoft for AD FS). To illustrate how this works, let's suppose you have the following:
With the on-behalf-of flow, the following would happen:
Step 4, above, is very easily invoked with ADAL:
In the signature above, Here's a quick diagram illustrating the token and API requests happening: You can see a working example of this in the active-directory-dotnet-webapi-onbehalfof sample. The on-behalf-of token request is executed in |
@talynone did not specify if his Web API was authenticated using AD or not. However, in my case, our end users are NOT registered in AD. We use AspNet Identity for our client, and the Web API is "internal only" protected via networking rather than user authentication. If the Web API proxy is not AD integrated and the end users themselves are not AD users, I'm fairly certain this flow does not work. Is that accurate? |
@Ro3A hold on, I haven't addressed your scenario. I can't type that fast. 😄. |
Edit (2017-04-08): This response mentions several times that Dynamics 365 (online) does not expose app-only permissions. This is only partly true, and it is possible to call Dynamics 365 with only a an application identity. See comments below for more details. I'm leaving the bulk of this response intact, because it is the case of some services/APIs. Though I encourage you to read through my last response to @talynone, it's not going to help you, since the end-users accessing your app are not necessarily users that can sign in to your Azure AD tenant, let alone users that themselves have permissions to Dynamics CRM Online. (And @talynone, if this is also the case for you, then you should also read this.) @dstrockis' link to @vibronet's blog post with the "consent invoker" tool will indeed work. (I just tried it myself.) The root of your issue is that the resource that you are trying to access, So, let's walk through your options so far:
Edit (2017-04-08): You can use app-only authentication to Dynamics 365 (online). If you're here because of some other resource which doesn't have a work-around like Dynamics does, then continue to read... Since we've exhausted all other options, then I agree that your only choice here is what you're trying to do. This option was removed from ADAL for .NET Core to strongly discourage transporting and persisting user credentials. However, the service (Azure AD) does support the Resource Owner Password Credentials Grant OAuth 2.0 flow, so you can skip using ADAL altogether for getting the token (though of course, you lose all the advantages of ADAL, particularly the token cache). You will need to make the following POST request (line breaks for display only):
This request can be made with a simple You would, of course, ensure that the user account that is being used as a "service account" has a complex password, that the password is stored securely (e.g. in Key Vault), that you are continuously rotating this password, and that the account has the least amount of permissions it needs (not just to CRM Online, but to everything else). I can't say this enough: Only use this approach if you really, truly can't do what you need in any other way. "It's too hard", or "I'm in a hurry" are not a valid reasons for reducing the security of your systems and your data. (Edited to remove reference invoking the Resource Owner Password Credential Grant flow as a confidential client, leaving it only as it would be invoked by a public client.) |
@psignoret - resource owner grant for confidential clients was exposed as an error. We are going to disable that feature soon. |
Ah, thanks @kpanwar. Updated to show instead how a public client would invoke it. |
So all that said, since what you're recommending is a last resort (and nearly a hack since the library doesn't support it), one must assume this use case is very small. From what I've seen across dozens of stack overflow articles and blogs, I believe it's a much larger use case and warrants a better solution. In my case, it seems like AspNet Identity is a no go if the app needs access to AD protected resources. So in the long run, am I better off integrating our app with AD B2C and using the on-behalf-of flow? Even then, I'm not even sure B2C solution would work for us since we have user related tables in our Identity database. Can B2C store user related data? |
@Ro3A, B2C does support storing user related data. |
I'll look into moving that direction then. Thanks for the guidance on this thread guys. |
@Ro3A: Careful though, you can't sign up for services such as CRM Online with an Azure AD B2C tenant. So though you can (and probably should) use Azure AD B2C as the identity service for your application, you won't be able to use the on-behalf-of flow to get access to the CRM Online API in the context of these users. (Because CRM Online won't recognize the user as a user who has permissions in CRM Online.) |
That negates the reason to switch then because we'd be back at square one. I'm hoping you guys see the frustration at this point. This is definitely the most trouble I've ever had interacting with an API especially when the older version of the service is a breeze to connect to. |
@Ro3A: I do see your frustration. Like I said above, unfortunately this is a side-effect of the fact that CRM Online service itself does not currently support the concept of app-only API access, which is what your scenario calls for. Each API or service that is secured by Azure AD declares which permissions it exposes, and whether these permissions are "app-only", or "app+user" permissions. The permissions will generally mirror the service's own authorization strategy. Since, CRM Online currently only exposes app+user permissions, this is a likely indication that the CRM Online service itself also only supports doing authorization based on a user identity. The Resource Owner Password Credentials flow I mentioned above is a supported flow. Support for this was not included in ADAL v3 for .NET Core because it often leads to insecure practices (e.g. hard-coding username/password in a PowerShell script, etc.), but the flow itself is supported by the Azure AD service. (I'll inquire with the Dynamic CRM team if there are any plans to support your scenario in a manner that does not require you to use a "service" user account.) |
This post was written a couple days ago http://phuocle.net/crm/dynamics-365-online-s2s-authentication-full-explain.aspx and says he got it Dynamics CRM API working using client credentials flow. |
@justin-cook Thanks! Indeed, it looks like Dynamics 365 (online) now provides a mechanism to associate an "application user" (and that user's privileges within Dynamics 365) with an app ID. The client can then request an app-only access token to Dynamics 365, and Dynamics 365 will apply authorization based on it's own table (of application user to app ID), rather than OAuth 2.0 scopes and permissions. This approach, while perfectly valid, is particular to Dynamics 365, so I'll update my comments above to clarify with the people of the future that there is a way to do this with Dynamics 365. |
I like to have finger print authentication for my universal app. how can I do that without UserPasswordCredential? Most iPhone banking apps seem to have pwd and id saved but you are saying 'not recommended'. Can you add the feature to .net core and developers will decide if it is used? 'cached refresh token' may work with finger print authentication (not really authentication but lauching)? |
Is it an option for you @markolb81 to move to MSAL.NET: it has U/P in .NET Core: See Username Password in MSAL.NET |
Thanks for the idea @jmprieur , but MSAL.NET only supports User/Password for .NET Framework. Unfortunately I'm forced to use Azure Functions V2 which runs on .NET Standard 2.0. |
Some options tested:
|
Hi ryanshane, thanks for the answer. Your option 3 is the way to go for me now - I already hat that Azure function anyway, so I acquire the token with a raw http-Request to https://login.microsoftonline.com/{TENANT_ID}/oauth2/token which still accepts the request parameters "resource={RESOURCE_URI}&client_id={CLIENT_ID}&grant_type=password&username={USERNAME}&password={PASSWORD}". This way, I do not use any library at all. So, for the moment I am fine, but I understood that it's not very elegant. If there's any possibility to get rid of a service user (and therefore stored credentials), I would do it. Although I think I have a good overview about the possibilities, I am convinced that this is (for now) the one and only feasible solution for my use case. To explain, I will describe it here shortly if anyone is interested: We developed a touchscreen device, allowing the user to book a meeting room via speech recognition on behalf of the user that is being recognized via face recognition. The touchscreen runs an UWP-App in "kiosk-mode" and is publicly usable by any employee. The user interface is restricted to simple touch input (even on-screen keyboard is not an option), face- and voice recognition. To actually access information, the touchscreen accesses an Azure Function which is used as a Proxy to the MS Graph and an SQL Database. Therefore one might understand, that even authentication by remote device (oauth device profile flow) is not feasible, because it will totally blow up the user experience. The easiest technical solution is using app-only permissions (Calendars.ReadWrite), but since they are not granular and immediately give access to all private meetings, I consider that a no-go, even if I manually filter out sensitive information within the proxy azure function. So, the only way to go is operating in a user-context, and since login by the actual user is not possible, a service user is the way to go. That, indeed, causes the next issue when trying to create a meeting on behalf of another user: It requires that every user in the organization which potentially uses that device creates a delegate permission on his calendar to that service user. Let's see if our IT dept. will accept a powershell solution here :) Thanks however for your hints and help! |
@markolb81 : Is it an option for you to migrate to MSAL.NET 2.x? it supports U/P in .NET Core? |
Hey @markolb81 can you elaborate on that endpoint you're using? It only accepts POST? I tried putting the parameters in the posted data but receive 400 bad request. |
Maybe it helps if I just post the function I'm using: public static async Task<string> AcquireTokenAsync(string appId, string tenantId, string username, string password)
{
HttpClient client = new HttpClient();
string tokenEndpoint = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);
var body = $"resource={GRAPH_BASE_URL}&client_id={appId}&grant_type=password&username={username}&password={password}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
var result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith<string>((response) =>
{
return response.Result.Content.ReadAsStringAsync().Result;
});
JObject jobject = JObject.Parse(result);
var token = jobject["access_token"].Value<string>();
return token;
} |
@markolb81 Further to my previous comment, i have done Option 1 by porting this authentication process to a method that can produce the auth token silently in .NET Core without any dependence on the missing UserPasswordCredential class. Please let me know if you spot any potential issues.
|
Hey @psignoret I found your comment really helpful to develop the On-Behalf-Of scenario. It's 2018 and applied it to some ASP NET CORE project and it works fine!! but only when running in IIS Express :( When deploying our app to an instance of IIS and invoking a call to some service using the on behalf-of we get below error: System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure. This is odd because as per log file we are getting the Bearer token fine but error happens when executing AsyncPost on the HttpClient var response = await _httpClient.PostAsync(url, content, cancellationToken).ConfigureAwait(false); Just would like to know if anyone has come across with same Issue in same scenario and if you know what kind of configuration may be missing here. Thanks in advance |
@macosta3 Glad to hear this was helpful! It sounds like your issue is completely unrelated to the ADAL library, so I suggest asking this in a more targeted forum to .NET and IIS (e.g. on StackOverflow). |
@pksorensen, what is your scenario? is it a Web app? |
Its an internal application that will opperate based on customer activity in our product. The application will update office 365 planner tasks to the team. But the api do not allow application accesss and only delegated work. But none of us (the people working in the organization) is signed in, the application is working headless. Ofcause when we start the company, i could manually use a device code and authorize the application with my credentials by opening the devicelogin page. but then at some point it will break and need to reauth and things will stop working if i dont write code that handle this and put things on a queue until its again resigned in. If office 365 planner supported application permissions, then the normal approach would be:
I am going to argument that
|
@pksorensen I get your point for your app operating based on customer activity. Here are a few possible things to try: Did you try the following?
In any case, I'd advise everybody, at that point to update to MSAL.NET. See https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/adalnet4-0-preview#do-you-want-to-migrate-from-adalnet-to-msalnet- |
Its our company, dont we get to decide if our apps can access our planer data :) The signed in user is not related to Azure AD in any way. Signed in users are our customers that do not use office365 and we dont want them to see anything related to azure ad/office 365. So we are back at, it is not less secure to use a password flow over client flow and decided to do the protocol requests ourself (with out any caching). Password resets, its all the same as when an application key expires (except there is not "rolling keys" feature). The admin can also go and wipe keys/passwords for application credentials as they could four the user id :) One last comment would be, that due to you guys trying to make us not make stupid mistakes when using the password flow, you actually is pushing us to do mistakes when we implement our own protocol messages with httpclient, think about that :) Thanks for providing all the resources / links and trying to make us do the right thing. |
Thanks for the context, @pksorensen password reset was an example, and the links explains others (MFA etc...) I'm well aware that not implementing U/P pushes you to re-implement it, which is really not a good idea given all the aspects to take into account. That's the reason why MSAL.NET implements it in .NET Framework and .NET core. For ADAL.NET: we don't want to invest more in ADAL.NET, the future being MSAL. We just want to let you update to MSAL to your own pace. Given your requirement it's probably the right moment for you, and we are committed to helping you in this update. |
I was using ADAL to authorize the dummy user / application when supported to talk with graph api (to alter groups, plans and such). Everything for our internal opperations |
@jmprieur I think it would be a good idea to deprecate this library for new development (if it isn't already), and make a prominent notice at least on the readme page, possibly on the nuget description, too? Would help stop confusion with this. |
@MichelZ : we are working hard on moving MSAL.NET to General Availability (GA). |
Adal works, proven and been working for year, leave it be. If people need MSAL.Net features they will move :) |
Indeed, @pksorensen : we are not going to remove ADAL.NET. As I wrote, people will update if they want at their own pace. But we are not going to add more features in ADAL.NET than there are already |
When the standard list "Resource Owner Credential Flow" why the ADAL doesn't support this? AAD implements the standard but ADAL decides against it. I can see multiple scenarios where this flow is mandatory going with workarounds have more security implications.
I would say not allowing developers to use this flow has more security implications by they implementing it via http or resorting to other workarounds. I don't buy this design decision. |
Hello @ShijuSamuel Therefore we recommend that you move to MSAL.NET which supports ROPC in all platforms: https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token#username--password BTW if you want to access the Microsoft Graph you would have to use MSAL, not ADAL. |
Hi, Team.
When I import this ADAL into my .NET Core library, it complains at the
UserPasswordCredential
class like:It doesn't seem that I can create a custom class inheriting the
UserCredential
class for workaround. Is there any suggestion that I can use theUserPasswordCredential
in .NET Core?Cheers,
The text was updated successfully, but these errors were encountered: