Authenticating Headless Autoscaling Clients - authorization

I have a use case where I need to provide a small CLI application that can be installed on headless servers of customers and transact data over REST APIs. I'm trying to search for a solution which allows the user who is generating tokens for the headless servers and the servers individually as well. I've looked at Auth0 which provides a simple way of doing this. However, the only catch is that the customer will have to generate device tokens corresponding to every server that they have. This will fail if the servers have to autoscale.
Are there more ways to achieve this while not compromising on security with the following identifications possible?
The user generating the token should be identifiable.
The device individually should be identifiable as well.
At any point, if I want I should be able to revoke authorisation from a particular device/server.
At any point, I should be able to revoke authorisation for all devices/servers registered by a particular user.
I asked it here a while back but got no response: https://security.stackexchange.com/questions/262580/authenticating-headless-autoscaling-clients

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

Google Cloud Run - Understanding of Authenticating end users

I have a web application which runs until now with cloud run, but without access restriction. Now it should be available only for certain users.
I read https://cloud.google.com/run/docs/authenticating/end-users and also tried both
mentioned ways: Google-Sign-In and the "Identity Platform" tutorial.
If I understand correctly, you have to program the actual user handling yourself in both variants. For example, determining which email addresses have access to the application, etc.
I was looking for a declarative way where, ideally, I only maintain a list of permitted email addresses and the "cloud run application" is only "magically" linked to this. With the result that only these users get access to the web application. That doesn't seem possible?
Ideally, the actual application should not be changed at all and an upstream layer would take care of the authentication and authorization, possibly in conjunction with the "Identiy Platform".
Best regards and any hint is welcome
Thomas
Let me add some sugar to this to better understand all these.
A Cloud Run application is packaged by you, you maintain the source code, if this is a website, placing a login button and handling authentication is your job to accomplish.
A Cloud Run system which is running all this on a hardware, it doesn't "look into" or handles your application code outside of the "code". Simply put it doesn't know if it's a Java or Python code and how to handle authentication out of the box for you - but read further.
If you require a simple way to authorize look into API Gateway it can be placed "before" Cloud Run. It might not be exactly your use case. These exists only for "API" designed services.
That upstream layer you need is the managed Identity platform, but the CODE should be assembled by you and deployed inside your Cloud Run service. The code will be the UI driven part, the authorization logic is handled by the Identity Platform so it reduces the amount of development time.
Your users would sign up using a dedicated registration page, and sign in by entering their emails and passwords. Identity Platform offers a pre-built authentication UI you can use for these pages, or you can build your own. You might also want to support additional sign-in methods, such as social providers (like Facebook or Google), phone numbers, OIDC, or SAML.
Look into some of the advanced examples to get a feeling how authorization can be customized further: Only allowing registration from a specific domain you could reuse one of these samples to maintain that shortlist of users that you mentioned.
In addition to #Pentium10's answer, you can also make all users authenticate to your app somewhat forcibly. (Imagine you're building an internal portal for your company, or an /admin panel for your app that only certain users/groups can access.)
This sort of use case can be achieved by placing Cloud Identity-Aware Proxy (IAP) in front of your Cloud Run service. That way, all requests go through this proxy that validates the caller. This is not like Identity Platform in the sense that visitors don't create accounts on your website (they use existing Google accounts or other IdPs like ActiveDirectory, or whatever you configure on IAP).
I have a little tutorial at https://github.com/ahmetb/cloud-run-iap-terraform-demo/ since IAP+Cloud Run integration is still not GA and therefore not fully documented.

Can GSuite be accessed by means of API key?

Suppose I have a simple node backend application which when ran needs to connect to a specific GSuite instance, query some things (users, groups, etc.) and then close and not run again until needed, which can mean either a very long time or a few seconds. From what I gathered from Google's documentation there may be multiple ways of doing this, including having an OAuth client and follow the whole flow in setting it up, managing token lifecycle, etc.
However I do NOT want to go with this option for now for various reasons and I am wondering if there is any way of getting access by means of an API Key / secret, like many other 3rd party services allow nowadays. Simply put I would like to generate a key pair somewhere on GSuite, no idea where, and use those keys for auth instead of OAuth, something Google suggests is possible, both on the GSuite Admin app (with a broken link that leads nowhere - not surprising) and on GCloud API and Credentials subpage where you setup credentials (however there it says that API Keys can only be used for very limited resources, none of them having anything to do with GSuite).
I think your best option is to see if what you want to do can be done by a service account. You can create a service account, grant administrator privileges to it in GSuite, enable some APIs, and then that account can do a lot of things without using OAuth directly. The credentials for the service account can then be provided to your application as a json key file, which it can use to authenticate to GSuite. You can also grant service accounts permissions to specific objects like files in Drive, but it doesn't sound like that would be sufficient to your needs.
A guide that may be helpful in the details of how to do this is https://m.fin.com/2017/10/04/navigating-the-google-suite-directory-api/

How to use Google APIs without continuously explicit user consent from a progressive web application?

I have a progressive web application that needs write-access to the Google Drive API for uploading data (media files) the user is creating (either online or offline) in the background while online. It does not really need a server (except for serving the required files, so a static server is sufficient), all of the work could be done on the web application client side.
Since uploading needs to happen on the background, whenever the user is online again (using a service worker and the background sync one-shot API), an access token is not enough for my need (the user can be offline/not use the web application for days) and a refresh token is not supposed to be stored on the web application client side, as far as I understand. Even if it were, I would still need the client secret, which means I have to use a server (or keep the secret within the web application client side, which is a no-no) in order to refresh the token.
It seems like the current ways of using the OAuth2 scheme are at odds with server-less progressive web applications, or I might be missing something. Progressive web applications are more like Chrome applications in this regard, I guess, but I have to supply a Chrome application ID in the Google API console for my application, which I do not (and do not intend to) have and Chrome applications use the Chrome identity API for getting the tokens, which I do not intend to use (and cannot).
I am currently using an actual Node.js server which takes care of the authorization step, keeps the access token and refresh token in a database and returns the existing or new access token to the client, whenever asked. The server is redundant here (and requires a privacy policy for this data which I really do not need to store), I want to do everything using client code, without continuously asking for authorization whenever I upload in the background.
Keeping the refresh token on the web application client side and just reaching out to the server for actually refreshing the access token (nothing must be stored in the server side except the client secret, which is fine), but like I mentioned, I understand the refresh token is not supposed to be kept on the web application side.
Is there a safe and secure way to implement this without a server (or with a server that only gets the refresh token and returns it to the client and refreshes the access token by getting the refresh token from the client)?
It's actually fairly simple, depending on the fine details of your use case.
An important factoid is that once a user has granted permission to your app, he will not have to re-grant it. So you don't need to "continuously asking for authorization whenever I upload in the background". However, the only constraint is that the user must be logged in to Google in order to obtain an Access Token. Normally this isn't an issue, but your app needs to deal with the scenario that a user has logged off from Google, and prompt for login.
All the details are here https://developers.google.com/identity/protocols/OAuth2UserAgent
I suggest avoid the Google JS library because (a) it has its own opinions about the UX, (b) wasn't written with PWAs in mind, (c) has issues on mobile, and (d) is closed source so when it breaks (as it does occasionally), your users are dead in the water until Google fixes it. The page above details the OAuth endpoints so you can easily use them directly. This has the side benefit that adding other cloud storage accounts (AWS, Azure, Drop, etc) is just a case of changing the endpoint URL.
The architecture I use in my PWA is to have my PWA prompt once (and once only) for authorization and then store the user's Gmail address in localStorage. I then have a
hidden iframe which polls once per hour for an Access Token, using the gmail address in a login_hint. This means the iframe is never required to present any UX. The only time UX is required is for the initial auth, which is of course unavoidable, and once per session if the user has logged out of Google.
The only other edge-case you might want to deal with is allowing the user to select between multiple Google accounts, say a personal account and a work domain account.
On a broader point, remember that Google didn't create the OAuth spec so there is little they can do to provide an alternative solution. At an abstract level, auth requires one of the user being present, or secure storage for a permanent token (eg on a server or within a secure store such as Android). Even if we invent OAuth 3, that will still be the case.

Token authentication with rest backend secure enough

I would like to secure my mobile app ( hybrid app, build with ionic framework). On backend site I use the play framework. I would implement the following case. The user of the app should authenticate to rest backend by email and password, if the credentials correct the backend generates an token return ok with the generate token to client, otherwise the backend return bad request. If the user would try to login with incorrect credentials more then 10 times the user would deactivated for 1 hour.
The mobile app would load json data from backend with ajax calls, on each call in header would set the field 'X-AUTH-TOKEN' and the generate token. The backend check the token and if the token is correct the client get data from server with status ok else the client get none data and the status unauthorized. If the user logged out the token would destroyed on server and client side. The token would not change as long as the user is logged in, in worst case the token would not changed over more than many days. I could implement, that on each call the date of last call can saved and if the last call is more than x days in past the server return unauthorized and destroy the token. So the user should logged in. Is the case secure enough, or should I implement more logic?
What you are describing is very similar, if not identical to the many, many implementations of OAuth2. For more information on these types of flows, including diagrams, check out how Google describes their OAuth2 processes here: https://developers.google.com/accounts/docs/OAuth2
I'm not familiar with the play framework but you should speak with framework experts to see if there is a well-tested, battle-hardened oauth2 implementation out there for the Play Framework. If so, you want to use that. You really don't want to (and shouldn't) roll your own implementation unless you know what you're doing and are willing to pay for people to pentest it. Really, please don't do this if unsure.
On the Ionic Framework / Angular / Cordova side, you've basically got it correct, but should always consider some basic security considerations:
My guess is that you'd use local storage to store the access token. In REST we don't have sessions like in a traditional web server scenario so we use the token in lieu of the session. Of course the downside is that local storage can easily be inspected to obtain the access key if someone had either root access on the device and was able to work their way into the app sandbox and knew exactly what api key to grab from local storage, but if someone has root or physical access to the device then you've got a bigger problem, so this isn't a design flaw per-say. To a certain extent, using this method you're relying upon the OS/browser's local storage sandbox to prevent other apps from accessing the local storage in your ionic app. This is a bet I would be willing to make, but you'll need to judge that based on your security vs usability needs.
What you should really be focusing on is protecting the token from people who may be listening on the wire (think coffee shop wifi). This means setting up your auth rest servers to use exclusively HTTPS (don't fail back to HTTP). This may have downsides, but will be worth it to protect your user's data. You also correctly identified using the token header. You should never pass auth tokens in anything but the header or POST data.
Generally speaking, what you are describing should be safe for use in a consumer level app. This assumes you don't unwittingly use any malicious third party code in your app. As always, you should be especially wary of third party code and only use code that you absolutely trust. Any code run from inside your app can access local storage in the Cordova/browser local storage sandbox and could theoretically export the api token for use in other software to access your api. With that said, you asked about authentication and not authorization. Keep in mind that your users need to only have access to do certain things in the app based on user-roles or some sort of ACL. This authorization outside the scope of this answer but you need to ensure that this is done on the server side and has rate limiting or soft-deletes for shared resources to prevent a malicious user from deleting everything.
Good luck with ionic and have fun.