Identity Server 4 and ASP.NET Core Identity - asp.net-core

A project I’m working on consists of a web API, a single page react application, and a mobile application. From each client, the user would need to supply their username and password in order to access protected parts of the web API. I’ve set up an Identity Server 4 authentication server that uses my own implementation of the IProfileService and IResourceOwnerPasswordValidator interfaces because I’m using ASP.NET Core Identity. This allows Identity Server to access the ASP.NET Core Identity UserManager, RoleManager, and SignInManagers to determine if the supplied username and password is valid.
The grant type I have been using for all of this is the “ResourceOwnerPassword” type. I haven’t totally integrated authorization into the single page app, but I can pass a user’s username and password to the identity server and a token is generated that I can add to the header of a request to my API.
I’ve done more research about Identity Server and related technologies because I’m new to all of this. It seems like it is undesirable to use the ResourceOwnerPassword grant type. From what I can tell it seems like I should be using the Implicit grant type, but I don’t fully understand how usernames and passwords fit into that flow. Does anyone have any insight into which type I should be using? Is the system I described only possible using ResourceOwnerPassword grant type?

The resource owner password grant type has this written about it on the IdentityServer docs:
The resource owner password grant type allows to request tokens on
behalf of a user by sending the user’s name and password to the token
endpoint. This is so called “non-interactive” authentication and is
generally not recommended.
There might be reasons for certain legacy or first-party integration
scenarios, where this grant type is useful, but the general
recommendation is to use an interactive flow like implicit or hybrid
for user authentication instead.
(Emphasis is mine)
All other flows involve redirects: the user clicks login on your website and is redirected to an identity server login page instead, they enter their credentials there and then are redirected back to your original webpage.
This is the same using your Google account, for example, to log in to other websites. Google wouldn't want you to enter that users name and password into your own site, because you could steal them, and this is generally why the resource owner password grant type is discouraged.
But if you are doing a first-party integration (i.e. the website is yours, and you trust yourself with the user entering their password on your website) then I don't see what the problem is.
You should have a read (and look at the examples) for the other flows/grant types. They definitely have their place and I am not dismissing them, but if you are doing a first party integration then what are doing should be fine.

Related

Login another salesforce org from salesforce record page

I was wondering if it was possible to login to different salesforce environments (Sandboxes, scratch orgs, production env, etc) using either Apex/LWC/Aura (or anything that I can make a quick action to). For example, I have a list of credential records, with the username and password, and I would like to have a login button that creates a separate tab that can automatically redirect to that specific instance and log in.
Currently, if a user wants to login to a particular instance, they have to either go to test.salesforce.com or login.salesforce.com (depending on if it's a sandbox or production) manually, then copy the password and username in. The ideal situation is to have a login button that can do this automatically from the record page where the username and password is located.
I think previously this could have been accomplished through the URL, but salesforce has recently patched this out due to security concerns. Is there another good way to do this?
It sounds like you're trying to solve two specific challenges:
Your users need to be able to manage very high volume of credentials.
You need authentication to survive password resets.
The clear solution, in my mind, is to use the OAuth Web Server flow to execute initial authentication and then store the refresh token that results from this flow. This token survives password resets, and may be used more or less indefinitely to create new access tokens - which users can then use to log in via a frontdoor link.
There's an out-of-the-box tool that does this already: the Salesforce CLI. You can authenticate orgs to its toolchain, name them, and subsequently access them with a single command (sfdx force:org:open). Users that prefer a GUI can access the exact same functions in Visual Studio Code.
If you're hellbent on doing custom development to handle this use case, you can, but you need to be very careful of the security implications. As one example, you could implement an LWC + Apex solution that executed the relevant OAuth flows against orgs and stored the resulting data in an sObject, then allowing users to click a button to generate a new access token and do a one-click login.
But... if you do this, you're storing highly sensitive credentials in an sObject, which can be accessed by your system administrators and potentially other users who have relevant permissions. That data could be exfiltrated from your Salesforce instance by an attacker and misused. There's all kinds of risks involved in storing that kind of credential, especially if any of them unlock orgs that contain PII or customer data.
One of the two best answers for that (the other one being 'pure Apex' and relatively more complex) is using Flow.
"You can use a login flow to customize the login experience and integrate business processes with Salesforce authentication. Common use cases include collecting and updating user data at login, configuring multi-factor authentication, or integrating third-party strong authentication methods.enter image description here"
"You can use login flows to interact with external third-party authentication providers by using an API.
For example, Yubico offers strong authentication using a physical security key called a YubiKey. Yubico also provides an example Apex library and login flow on GitHub. The library supplies Apex classes for validating YubiKey one-time passwords (OTPs). The classes allow Salesforce users to use a YubiKey as a second authentication factor at login. For more information, see yubikey-salesforce-client.
You can also implement a third-party SMS or voice delivery service, like Twilio or TeleSign, to implement an SMS-based multi-factor authentication and identity verification flow. For more information, see Deploy Third-Party SMS-Based Multi-Factor Authentication."
learn more here: enter link description here

Do users of a third party app accessing our API's have to log in with us even if they've already authenticated with their their system?

We have a third party company developing a mobile app and they want to call our API's. Our API is protected with Identity Server 4 which uses OpenID Connect and OAuth2. In order to access our API's would their app have to pop open a mobile browser so the user can log into our system? What if users already authenticated with the third party's identity provider? Seems like that would create a negative user experience to authenticate two different times while using the app.
My understanding is we would add their app as a client in Identity Server using the authorization code grant. Would we add their identity provider as an identity provider that our Identity Server can call?
Any help on this would be greatly appreciated. I've researched myself into a hole.
would their app have to pop open a mobile browser so the user can log into our system?
You are pretty much right on your assumptions that their app would have to somehow initiate oidc flow to allow the users of the mobile app to authenticate with the authority of your API (identity provider).
Seems like that would create a negative user experience to authenticate two different times while using the app.
It seems that this is what's holding you back. Firstly, that mobile app's identity provider is separate from your API's authority and it is important to understand that the "user" authenticated with the other identity provider means close to nothing to your API because the token has been issued by a different authority and it's not even a "user" from your user base.
My understanding is we would add their app as a client in Identity Server using the authorization code grant.
Yes, but check also Authorization Code grant with PKCE which adds extra security measures.
Would we add their identity provider as an identity provider that our Identity Server can call?
Yes, you will need to do that, but this is just a start of the things you would need to do to achieve what you are looking for. Because you already have Identity Server 4 in place, I assume your systems already have an established user base, therefore if you just redirect to the external identity provider, once a user authenticates there and the token is issued back - that kinda means nothing because you don't have any kind of mapping from the user of the third party system to the user of your system.
There is pretty much nothing out of the box in Identity Server 4 that will help you with this, but one way to tackle this is to implement some sort of account linking mechanism, where the users would first have to "link" their account in your system with the account in the third party system. With account linked, you would have means to issue claims related to your system.
Identity Server 4 absolutly has out of the box solutions for this. If they didn't, what would be the point calling themselve a OAuth 2.0 framework?
You do not need to initiated a oidc flow like stated. What does that even mean anyway? oidc is connection protocol, not a flow. Flows include hybrid, implicit, clientcredential, etc.
You could obtain an access token for your 3rd party app a number of ways all use the token endpoint built into identity server 4 specifically for creating access tokens The most common is using the ClientCredential flow, where you gain a bearer token by hitting the identity server 4 token endpoint passing the client_credentials grant type with the ClientId of the client they want to access, a shared secret supplied by you, and the api scope they are attempting to access.
Another option is you could create a user for this client on Identity Server 4, then gain an access token using the ResourceOwnerPassword flow by hitting the token endpoint passing the password grant type, clientId, username, and password, again along with the api scope they want to access.
For information on how to do all of the above check out his link. It will help you on your way.
http://docs.identityserver.io/en/latest/endpoints/token.html

is oauth2 only used when there is a third party authorization?

I am reading about oauth2 now, and trying to understand its purpose. From all the resouces I read, it seems like oauth2 is only used when a webapp (say a game app) that has some users and the app wants to access a user's Facebook or Google data (some sort of data such as name or email, etc). This part is clear to me. However, things that remain unclear to me are the following:
For example: If I have a webapp, and I want the users of my webapp to log into the webapp with their login and passwords (just like how you do it with gmail) without using any third party. Does oauth2 also serve this type of authorization?
I have seen webapps, where they just let users sign up with IDs and passwords, then they salt the passwords and store the salts in the database. So when a user logs in later, they salt the password the user entered, and compare this salt to the salt in the database (created during the signup). If equal, then the user logged in. This does NOT seem like oath at all to me. So if this is not oauth, what standard is this? And are there any other standards for "direct login" like this?
Assume that I want to allow users to sign up and log in to my website, but let them log in via a third party (like Facebook or Google). This is just for authorization purposes and assume that my app has no plan to post on their facebook or request their facebook data except that I may want to use their facebook email as the user ID for my webapp. Does oauth2 serve this type of authorization?
Sorry for the naive questions, because I only read about oauth recently.
For sign-up/login without 3rd-party, as Kevin pointed out, each programming/web framework usually comes with a popular library that once, it will generate all the sign-up/login pages, database tables, flow, etc., for you. The only thing you then do is call a method provided by the library that returns the current signed in user, in your backend code when you need to figure out who the user is.
Using salted password scheme is NOT related you OAuth2 at all as you pointed out. It is a widely used scheme for local authentication because it has many benefits but I will just highlight 2 here:
a. A password when transmitted from user to server for authentication over the Internet is not sent in cleartext but rather in hashed format. Thus even if it were eavesdropped, the password will not be divulged.
b. Since each password is salted, even 2 same passwords will not have the same hash because each have different salt. Thus even if a password hash was eavesdropped, it cannot be reused at another service that the user uses the same password because the other service expected a password hash generated with a different salt.
OAuth2 is all about Authorization (asking a user for permission to perform something on her behalf at another web service, e.g., ask a user for permission to access her email address registered on Facebook). Using it for Authentication can be insecure (for OAuth2 implicit flow). Why? The end result of OAuth2 is an access key associated with a permission, e.g., 'permission to access email address'. When you use the OAuth2 result (access key) for authentication, it means that you are making the assumption that 'permission to access email address' means the user successfully authenticated with Facebook, which she did, so it seems fine. However, imagine if another site also uses OAuth2 for authentication as you did; if it receives an access key with 'permission to access email address' it will assume that you have authenticated with Facebook so it will grant you access to the account belonging to the email address. You could actually use the access key you got from a user, and login as her in the other site, and vice versa.
To use OAuth2 for authentication, you need to use it with OpenID Connect (OIDC), because the end result of OAuth2-OIDC contains an id_token with the aud (audience) field identifying who the access key is for (https://openid.net/specs/openid-connect-core-1_0.html#IDToken), which prevents the access key from being reused where it is not intended. The full explanation with easy-to-understand diagrams is here: https://www.slideshare.net/KhorSoonHin/the-many-flavors-of-oauth/36?src=clipshare
Another very simple but perhaps unnerving to a security-conscious way to do use OAuth2 for login is to use the Resource Owner Password Credential, where your website acts as a middle-man between the user, and OAuth2 provider (Facebook).
Show 'Login with Facebook' button
When user clicks on button, prompt user for Facebook username/password
Use the username/password to login to Facebook to confirm authentication and get access token.
If you don't have to time to read in-depth about OAuth2, perhaps this side-by-side comparison of all the OAuth2 flow can help.
This is courtesy of https://blog.oauth.io/introduction-oauth2-flow-diagrams/
You could use OAuth for local logins like this, but you don't have to. It might be easier, depending on available libraries, and it might make sense if you anticipate making your service available to third-parties in the future. For many sites, though, using OAuth for local logins would be overkill.
Standards are most useful when different actors need to speak a common language so they can interoperate. For local logins you don't need a standard because you're not interacting with any third parties. Many web frameworks include their own variation on the same basic flow.
I think you're asking whether OAuth makes sense for authentication (establishing identity) when you don't actually need any authorization (permission to access third-party resources). It can indeed be used that way, but lots of people will warn against it since it wasn't designed for that and has some security weaknesses in that context. See, for example, Common pitfalls for authentication using OAuth.

Is OAuth 2.0 redundant/unnecessary if the client is the same as the resource owner?

In section 1.1 of RFC 6749, there are four roles: resource owner, resource server, client, and authorization server.
Does OAuth become redundant or unnecessary if the client and the resource owner are the same entity?
For example, I have a closed API and a front-facing web server. (The front-facing web server would be both the client and the resource owner.) I am trying to decide whether to switch to OAuth 2 authentication instead of using the current username/password authentication method. Is there any added security for moving to OAuth 2 if the API remains closed to third-party applications? (That is, no third-parties will ever have access to the API.)
Thanks!
In the case where the Resource Owner and Client/Resource Server roles coincide OAuth 2.0 may become less relevant from a security point of view, since one of the primary objectives of OAuth not to expose primary credentials of the user to the client becomes moot. That is also the reason why the so-called Resource Owner Password Credentials grant is considered to be a legacy/deprecated flow.
However, it may still make sense to follow the OAuth 2.0 pattern for a number of reasons:
the ability to leverage a standardized protocol through stock libraries and
frameworks without relying on custom code
the fact that in your case the Resource Server is still made strictly OAuth 2.0 compliant, dealing with Clients presenting access tokens, irrespective of what the Client/Resource Owner relationship/implementation is; this would make it easier to allow for 3rd-party client access in a future scenario
the fact that you concentrate verification of user credentials on a single path between Client and Authorization Server so each of your Resource Servers don't need to be bothered by checking user credentials individually, possibly dealing with different authentication mechanisms
and perhaps most importantly, also security-wise: once the user has authenticated through the Client using his primary credentials, the Authorization Server can issue a refresh token as well as an access token; the Client can store and use the refresh token to a new access token when the old one expires; this frees the Client from storing the primary user credentials if it wants to keep accessing the API for a long period of time without requiring explicit user interaction and authentication and makes the resulting system less vulnerable for leakage/loss of user credentials since the user credentials (password) are not stored in the Clients
If you have the following issue then you should use OAuth;
Let's say you a Gmail like web mail provider. Some of your users are using a third party app which logs in into your user's account and auto replies certain emails for you. Or you are Facebook like social network web site where some of your users use a third party app which analyzes your friend networks and prints a 2D graph for you. In this case your users are giving away their usernames and passwords. How would they prevent a certain third party app accessing their account after they gave away their username and password? Simply by changing their password. Now you have another problem; other third party apps won't be able to access the user's account. Then the user have to re-give away his password to other apps he trusts. Now this is problem too because it is not user friendly. OAuth is simply a temporary password that your user gives away to a third party app developer. He can revoke it whenever he wants without changing his own password.
Other than that OAuth is unnecessary. Just use a session cookie if you are not going to have third party app developers. It is a random string stored in user side. And on the server side will have whatever you want. Just look how PHP sessions are used and stored on server side. You can define their lifespan and refresh time automatically from php.ini.

Can I use extension to pass login and password to OpenID provider?

There will be login page via OpenID controlled by an extension. Can I ask for URL and pass in the extension and then pass it OP by use of extension? If no what kind of data can be transferred to OP from RP by an extension? If yes, how scalable it is, do I have to write separate code of each OP, or will the standard help me?
Also in unlikely case of XY problem - I need some sort of data that will allow me to authenticate OpenID user offline (after at least one successful online login). So if I was the one to provide login and password text fields I would be able to use user's password hash it and use for offline auth. And yes I need to use OpenID rather that other system, because this is the requirement. Sorry, It's kind of ugly problem.
I don't think you're supposed to pass a user id/password to the OpenID provider (or at least not password). The idea behind OpenID is that the provider takes care of the login, thus the web application utilizing OpenID will have no knowledge of the login credentials. OpenID provides you with some authorization information, such as the nickname, fullname, email, etc. This information, coupled with the OpenID of the user itself, should be enough provide you with unique authentication for that user without the need to have a password.
Your application needs to allow the user to go to the OpenID provider's page, enter their credentials there, and once authenticated you will get a response from OpenID indicating whether the authentication is successful and subsequently providing you with the user's information.
Update
Like I mentioned in my comments: the OpenID standard does not define a way in which you can send a password to an OpenID provider. So you can't use the OpenID standard in the manner you're envisioning it.
Update 2.0
Let's take myOpenID for example: in order to use myOpenID as an OpenID provider you have to register your domain with OpenID. Alternately, you can enable OpenID for your website by contacting Janrian (the owners of myOpenID), but I'm going to say you're still going to have to register a website with them. In either case, you must have a landing page on your domain, or on your website, which accepts an authentication response from the OpenID provider (in this case myOpenID). So let's look at what's required:
You must spoof a web browser when you're making the web request to the myOpenID provider.
In that web request, you have fill in the form which takes in the client's password (again, you have to spoof the client doing that).
You have to have a service of some sort running on a website registered with an OpenID provider (such as myOpenID).
You will have to send a message (HTTP) to the service that you're expecting an authentication response for a specific user (and provide it with a way to call you back when the user is authenticated).
That service will take any incoming authentication response from the OpenID provider.
The service will match that authentication with the user ID that you told it to expect in step 4.
The service will send your application the authentication response (callback).
You must accept the authentication response from that service.
The hardest part will probably be step 1 and 2, but there should be plenty of tutorials online that can show you how to do this (sorry I didn't have time to look up specific ones).
In any case, that's how I would imagine you may be able to do this, but it's far from trivial and I've never seen it done before.
Part of the reason why OpenID is so popular is exactly because people don't have to share their credentials with the service provider (i.e. your app), they only share it with the OpenID provider. The other thing you should think about is whether or not users will agree to use the OpenID in the manner that you want them to use it. In other words, one of the main reasons why people use OpenID providers is so that they avoid doing exactly what you're asking them to do: give you their password!
Update 3.0
You can register your domain with myOpenID by going to the new domain registration page: https://www.myopenid.com/new_domain