Machine to machine authentication with Google Cloud Endpoints - google-app-engine

CONTEXT
Have created an API using Google Cloud Endpoints (Python) with which numerous low power devices will GET/POST data.
The only communication with the API will be from these custom devices (I own both ends of the communication).
RESEARCH
Looking at authentication, was hoping it would be as simple as using SSL/TLS client certs:
Each remote device will have a client cert signed by a single project CA anyway.
The Google cloud endpoints mandate SSL.
However, only oauth2 appears to be supported; I'm looking for a 'clean' way to implement 'hands off' authentication, ideally utilising the client SSL cert I already have on the client devices.
I have investigated creating 'service' oauth2 accounts, however as I want to protect against a device spoofing another device (one set of credentials for all is not acceptable), I would need to generate a service account for each client device, which would be bulky and horrible to maintain on the API-end.
It seems i'm looming towards needing to add a layer of authentication within my code for each API method, which somewhat defeats the point of utilising the services of Google's cloud endpoints.
QUESTION... Finally
Has anyone had experience in authenticating 'hands off' machine to machine devices at scale against google's cloud endpoint?
Does anyone know of a way of using a client certificate in the Oauth2 authentication process in a way which would be supported by GCE?
Is my only option going to be custom authentication within the API methods based on some crypto data in the POST/GET headers. (or just moving to hosting an API with Apache/NGINX and client-cert auth?)
Regards,
Matt

I wrote you an essay:
Consider that Cloud Endpoints basically exists in the application layer of the OSI model, since it communicates via HTTPS requests (it sends HTTP requests within a TLS session). Whether or not Endpoints uses HTTP or HTTPS is not a developer-configurable option - it must be HTTPS.
It uses HTTPS in that the API server has a TLS cert which is used to authenticate the API server. Inside the secure connection, the RPC params and responses are also secured from eavesdropping. This is the extent to which Endpoints "interacts" with TLS - it uses it to establish the session and send HTTP requests inside this session.
So, already I can tell you that you will not be able to have your TLS client certs (not an often-used feature) used to authenticate API clients automatically by endpoints, in the connection setup phase. TLS client certs simply aren't looked at or requested by the Endpoints API server.
Now, while authentication of the API server itself is guaranteed through the API server's TLS cert, authentication of API clients is done via Client IDs or the Users API, which sits in your code and abstracts over the different auth options App Engine offers at present:
OAuth (2.0)
OpenID
So, in order to auth your client devices in one of these two manners and still take advantage of Cloud Endpoints, you will need to find a way for each device to perform an OAuth flow or OpenID flow, your system having provisioned an identity for the respective auth method at the time of that device's initial deployment.
Google (Apps) Accounts option
This will involve creating a Google account (Google's unified SSO) or a Google Apps account managed by a custom domain for each device, and provisioning these accounts' credentials to each respective device. You can read more about custom domain authentication and App Engine auth configuration in general here.
OpenID option (general doc on OpenID with GAE)
This will involve setting up your own OpenID provider on a GCE instance using an OpenID connect library like pyoidc, so that you can provision accounts yourself, or it could involve registering accounts with a known OpenID provider for each device. The first solution is more robust but more time-consuming (OpenID providers can go down temporarily, or deactivate forever, and then your IOT network is out of luck).
Third option using Client IDs
You can of course generate an "installed application" client ID/secret and distribute these to each device in your network. They can use this to authenticate themselves as network devices (as opposed to an attacker's laptop), and then you trust devices to accurately report their own id as a param with each API call. Depending on how hackable your devices are and how widely you intend to distribute them, this scheme doesn't necessarily prevent devices from spoofing each other's id's, although depending on the id generation scheme, you can make it very difficult (each id being a long sufficiently long hash).
If you go this route and you're really concerned about this, you can provision a client ID for each device, but who knows if you'll hit some kind of undocumented limit on number of client IDs per app, and also this will require you to either do it by hand or write a script that logs into the dev console on a headless browser and does what you need.
Fourth crazy option that actually uses the TLS client certs
If you're really set on using both TLS client certs for auth and Cloud Endpoints for your API, you could try to send the client cert in the request, since TLS is encrypting the request data (unless your attacker has found a way to efficiently solve the inverse discrete logarithm problem, in which case they'll probably be too busy attacking more important targets (no offense) and changing the infosec game forever), and then reading and auth'ing the cert in your endpoints method somehow (third party libs uploaded with your app are probably necessary for this).
Fourth realistic option if you have your heart set on TLS client certs
Switch from App Engine to Compute Engine, where you basically have a VM managed and hosted in the same data-centers. On this box, you can implement any kind of connection protocol on any port you like, so you could have incoming API requests (not Endpoints, notice) TLS-authenticated based on teh connecting device's client certs.
Good luck!

Related

Why can't web application type 'Android' be a confidential client?

Using authorization flow and passing the information to the back-channel for the token request we don't need to save the secret in the app.
Why then does Azure force us to use a public type?
Cannot choose for the app to be a 'web' type as the redirectUri is not allowed to be anything other than 'https://foo' which in our case is 'app://auth'
edit: More information
When adding a platform on Azure AD you currently have the option between
web
spa
ios/macOS
android
mobile and desktop application
All of these are public clients except 'web' which can be confidential as the back-end is able to securely store the secret. My question is why is there a difference between web and for example an android application? The android app will communicate the exact same way a front-end application would. But choosing the android app is the only way I can configure the redirectURL for my application
An SPA being public is understandable, but forcing every mobile app to be public is something I do not understand
MOBILE FLOW
This has some differences to a web client. You are meant to use Authorization Code Flow (PKCE) without a client secret, and sign in via a Chrome Custom Tab. See this Curity tutorial for how that looks. Avoid using a web flow for a mobile client though.
MOBILE CLIENT SECRETS
Routing requests via an API that attaches a client secret is not considered standard since an attacker with your client ID and redirect URI could still trigger a flow on app:/auth.
If mobile client secrets are needed then the recommendation is to ensure a different client secret per device. This can be done using Mobile DCR. I don't think Azure supports this however.
HTTPS REDIRECT URIs
In case you're not aware, Android App Links are needed in order for mobile apps to receive authorization responses on HTTPS redirect URIs. I'm pretty sure Azure will support this, and it is a best practice since an attacker cannot get the response. More about this in a blog post of mine.
An "OAuth client" is the application which talks to the Authorization Server. In your case, you don't have a mobile client, as it's in fact the backend which talks to the authorization server. A mobile client should never be configured as confidential. Azure can't assume that all developers will be as thoughtful as you and don't hard-code the secret in their apps.
As #Gary Archer pointed out you should configure your client as a web confidential client and use HTTPS redirect uris as an Android App Link to go back to your app.
Using authorization flow and passing the information to the back-channel for the token request we don't need to save the secret in the app.
It sounds like you relate to a newer Client-Initiated Backchannel Authentication Flow. Azure does probably not support this flow, yet.
Why then does Azure force us to use a public type?
The confidential client and public client terms stems from OAuth 2.
A confidential client is an application that is able to protect its client secret. E.g. a backend application in e.g. Java, Node.js or similar.
A public client is an application that is not able to protect a secret - or where many unique instances exists. E.g. JavaScript Single Page Applications or Mobile applications - this is places where a Secret could be extracted in any client. It is now common to use a Proof Key for Public Exchange when using a Public Client.
Also see What's the difference between Confidential and Public clients? - OAuth in Five Minutes.

React SPA with oidc-client and client secret

I'm building a React SPA on top of a ASP.NET Core API and I want to authenticate with OIDC. Grant type is authorization code and the client does have a client secret.
Since we will be using a client secret, the authorization step that involves the secret has to go through a proxy that we control.
Is this doable in a React SPA with oidc-client?
If the secret is in the client, it's not a secret. :)
Secrets are for server-server authentication, because the secret is secure on a server (we hope so, anyway) and the API granting access has a whitelist of consumers it's granted access to use the secret.
For a SPA, if you're talking about allowing an app to use an API, I believe you're limited to using a CORS whitelist. If you're talking about a user accessing the API via the client, then you're looking at access codes and usernames/password.
PROBLEM
You have a blocking issue with the authentication system, or with usability or getting security to an acceptable level. In your case there is no PKCE support.
PROXYING SOLUTION
Use oidc-client which will add PKCE parameters and your SPA security supports the latest standards.
The client secret will come into play during the authorization code grant and refresh token grant messages.
Messages can be adapted server side to remove PKCE and use a client secret instead. It is quite a complex solution though and not everyone will like it.
It requires a SameSite cookie issued by the web domain. In my case I used an AWS lambda edge function that runs within a CloudFront content delivery network.
WHY DO IT THIS WAY?
In order to fit into an SPA architecture and meet wider goals in areas such as usability, coding model, mobile integration and global web performance. Depends if you feel it is worth the effort.
LINKS
Architecture Goals
Design Pattern
Code Sample you can run
Online AWS SPA
Proxying details

Securing an API from other web apps

I have a react web application with a flask api (I used to use express). The product of this app is the data that it displays. I don't want other people to be able to take that data easily from calling the api.
I want to secure the api such that it can only be accessed by my react app and nothing else. How can I do that?
The only way to truly secure your API is by authenticating your app's user with something like Oauth2 and verify that credential on server-side with something like passport, and make the authorization expire with sessions. AND use SSL so none of that is easily visible through a protocol analyzer.
Sure, you can hard-code some sort of "secret key" with the app, but anyone who want it bad enough will read it off your app or sniff the packets through a packet logger until they find the key.
EDIT: Oh, and as a part of the authorization upon login, provide them with a uniquely generated "API-KEY" as part of identity, so you can validate them upon submission, and if they violate your trust, mark their API key invalid in the server so they can't use them any more.
First, if your client code and API server are running on different domains or ports, configure CORS on your API server to only honor requests that originate from the client code's domain. Second, authenticate legitimate users so that only authorized requests for data are honored. There are lots of 3rd-party libraries to help with authentication.

Difference between WS-Trust, WS-Fed and SAML 1.1/ 2.0 protocols

What's the difference between WS-Trust, WS-Fed and SAML 1.1/ 2.0 protocols?
My understanding on these protocols gets confused when SAML is used as a security token in WS-Trust and WS-Fed protocols.
Interested in knowing in which scenario these protocols used and what makes them different. Your answers will be easy to understand if NO commercial product/ technology references used.
At a high level, WS-* protocols traditionally were used by Microsoft.
SAML-P (P for protocol) was used by the open source movement and hence Java.
WS-Fed has two profiles - active and passive. Active is for WCF (WS-Trust), passive is browser based (WS-Fed via login page).
Both of these use SAML tokens.
Functionally, both WS-Fed and SAML do the same thing wrt. federation
If you federate two ADFS (Microsoft IDP) together you use WS-Fed. If you add in Sharepoint, it also uses WS-Fed. The tokens passed are in the SAML token format.
If you have a Java application that uses Spring, then that will hook in to ADFS via SAML-P. The tokens passed are in the SAML token format.
this question is old but i struggled finding a correct answer online.
A lot of online posts say, that 'passive / browser' clients use WS-Fed and 'active / smart' use WS-Trust. That is probably because the active use case uses by default a url like '/ws-trust/2005' or '/ws-trust/v1.x/'. This does not seem to be 100% accurate. The great and free book: Claims-based Identity, Second Edition helped me with the issue and I finally found a satisfying answer:
The goal of many of these architectures is to enable federation with either a browser or a smart client. Federation with a smart client is based on WS-Trust and WS-Federation Active Requestor Profile.
These protocols describe the flow of communication between smart clients (such as Windows-based applications) and services (such as WCF services) to request a token from an issuer and then pass that token to the service for authorization.
Federation with a browser is based on WS-Federation Passive Requestor Profile, which describes the same communication flow between the browser and web applications. It relies on browser redirects, HTTP GET, and POST to request and pass around tokens.
SAMLP is just a different protocol when it comes to how things are communicated such as the redirection URL and so on, but the differences are not relevant (in most cases) and simply depend what the client supports (e.g. Java will use SAML). The biggest difference is in my opinion that SAMLP allows an Identity Provider initiated Use Case (which is the most secure one in my opinion), where the User starts on the Identity Provider (e.g. the Web Proxy of your ADFS Server, =Claims Provider in MS terms), instead of starting at the Web Service and then getting redirected to the Service Provider (=Relaying Party in MS terms). Also when we are talking about SAML we usually mean SAML 2.0 while WS-Fed uses SAML 1.x Tokens (and MS calls them Tokens, SAML calls them Assertion... its just a signed and possibly encrypted XML, I think theoretically you could use other Tokens in WS-Fed then SAML but i have never heard of anybody actually doing that).

What OpenID Connect authorization flow to authenticate mobile app users?

I am building a cross-platform mobile app that interacts with a RESTful API, and I want to use OpenID Connect to authenticate my users. I will be building my own OpenID Connect provider server.
OpenID.net claims that:
OpenID Connect allows for clients of all types, including browser-based JavaScript and native mobile apps, to launch sign-in flows and receive verifiable assertions about the identity of signed-in users.
However, I can't find any documentation explaining how to actually authenticate for a mobile app client.
This StackExchange answer makes it clear that OpenID Connect does not support the "resource owner password-based grant" flow or the "client credentials" flow.
That just leaves the "authorization code" flow (normally used by server-side apps) and the "implicit grant" flow (normally used by client-side apps). Both of these seem to rely on redirecting the user to the provider's authorisation endpoint, and having the provider redirect back to the client URL. I don't see how this can apply to a mobile app.
Can anyone explain to me (or even better, point me at a tutorial or some example code) which explains how to do this?
Update
To clarify: OpenID Connect relies on the client redirecting the user to the Authorization Endpoint, and then the provider redirecting the user back to the client. In the case where the client isn't a web app, how can this work?
Mobile apps, at least on iOS and Android, can register custom URL schemes so that a redirect from a browser can send the user back to your app along with some query parameters.
So, you can use these flows in a native mobile app, but it involves sending the user to a web browser (either an external browser app or a web view built into your application) in order for them to authenticate with the OP.
A complete article presenting how to implement the "Authorization Code Grant" flow securely on a native mobile app is available here : Building an OpenID Connect flow for mobile. It is based on latest IETF OAuth 2.0 Security Best Current Practice.
Please also note that the use of the "Implicit Grant" flow is now highly discouraged.
I think that the Hybrid flow from the OpenID Connect spec is probably the one which you want to use. OpenID Connect Core Spec.
This does rely upon having a configured return URI, but as James says you would use a custom URI scheme to enable the mobile OS to redirect after login to your own app. Your app would then have an access code which it can use to obtain access tokens as needed (assuming that you are using Oauth2 to protect your back-end API services which the mobile app uses).
There is a vulnerability which would allow a malicious app to hijack your URI scheme and grab the tokens, There is a draft spec to overcome that Proof Key for Code Exchange by OAuth Public Clients which is worth considering implementing.
Using an app scheme URL is the correct answer as noted above. I wanted to add additional clarification since some responses above include links to an article that makes incomplete assertions about a compliant SSO design, and make it unnecessarily complicated for a simple SSO use case. I think google's model is secure and so I might model OIDC interactions with a homegrown IDP after how theirs works.
https://medium.com/klaxit-techblog/openid-connect-for-mobile-apps-fcce3ec3472
The design in this article linked above, as depicted in the diagram on the article, does not work for google's oAuth/OIDC implementation on Android. There are two reasons for this:
Google will not vend any client_secret for an oAuth client that is typed "Android"
Suppose I switch to "Web" application which does have a secret: Google will not allow a redirect_uri other than 'http' or 'https' for an oAuth client that is typed "Web"
Instead, google officially recommends letting the typical mobile flow (and you should also be using PKCE) drop an ID Token on the client, who can then exchange it for a session with the App server:
https://developers.google.com/identity/sign-in/android/backend-auth
This is secure because your IDP should be signing the JWT ID Token with a private key so it can be validated by your system's apps/services and used to assert validated (unexpired) identity intended for a particular OIDC client & audience.
** Do not pass ID Token as authorization on every request, but rather exchange it once with your backend for a secure session context as managed by your application.
Check out MITREid project on github:
MITREid Connect
This project contains an OpenID Connect reference implementation in
Java on the Spring platform, including a functioning server library,
deployable server package, client (RP) library, and general utility
libraries. The server can be used as an OpenID Connect Identity
Provider as well as a general-purpose OAuth 2.0 Authorization Server.

Resources