SPNEGO: Subsequent Calls after a Successful Negotiation and Authentication
Asked Answered
S

2

3

Over the last few days I have built a proof-of-concept demo using the GSS-API and SPNEGO. The aim is to give users single-sign-on access to services offered by our custom application server via Http RESTful web-services.

A user holding a valid Kerberos Ticket Granting Ticket (TGT) can call the SPNEGO enabled web-service, the Client and Server will negotiate, the user will be authenticated (both by Kerberos and on application level), and will (on successful authentication) have a Service Ticket for my Service Principal in his Ticket Cache.

This works well using CURL with the --negotiate flag as a test client.

On a first pass CURL makes a normal HTTP request with no special headers. This request is rejected by the Server, which adds "WWW-Authenticate: Negotiate" to the response headers, suggesting negotiation. CURL then gets a Service Ticket from the KDC, and makes a second request, this time with Negotiate + the wrapped Service Ticket in the request header (NegTokenInit) The Server then unwraps the ticket, authenticates the user, and (if authentication was successful) executes the requested service (e.g. login).

The question is, what should happen on subsequent service calls from the client to the server? The client now has a valid Kerberos Service Ticket, yet additional calls via CURL using SPNEGO makes the same two passes described above.

As I see it, I have a number of options:

1) Each service call repeats the full 2 pass SPNEGO negotiation (as CURL does). While this maybe the simplest option, at least in theory there will some overhead: both the client and the server are creating and tearing down GSS Contexts, and the request is being sent twice over the network, probably ok for GETs, less so for POSTs, as discusses in the questions below:

Why does the Authorization line change for every firefox request?

Why Firefox keeps negotiating kerberos service tickets?

But is the overhead* noticeable in real-life? I guess only performance testing will tell.

2) The first call uses SPNEGO negotiation. Once successfully authenticated, subsequent calls use application level authentication. This would seem to be the approach taken by Websphere Application Server, which uses Lightweight Third Party Authentication (LTPA) security tokens for subsequent calls.

https://www.ibm.com/support/knowledgecenter/SS7JFU_8.5.5/com.ibm.websphere.express.doc/ae/csec_SPNEGO_explain.html

Initially this seems to be a bit weird. Having successfully negotiated that Kerberos can be used, why fall back to something else? On the other hand, this approach might be valid if GSS-API / SPNEGO can be shown to cause noticeable overhead / performance loss.

3) The first call uses SPNEGO negotiation. Once successfully authenticated and trusted, subsequent calls use GSS-API Kerberos. In which case, I might as well do option 4) below.

4) Dump SPNEGO, use "pure" GSS-API Kerberos. I could exchange the Kerberos tickets via custom Http headers or cookies.

Is there a best practice?

As background: Both the client and server applications are under my control, both are implemented in java, and I know both "speak" Kerberos. I chose SPNEGO as "a place to start" for the proof-of-concept, and for worming my way into the world of Kerberos and Single Sign On, but it is not a hard requirement.

The proof-of-concept runs on OEL Linux servers with FreeIPA (because that is what I have in our dungeons), but the likely application will be Windows / Active Directory.

* or significant compared to other performance factors such as the database, use of XML vs JSON for the message bodies etc.

** If in the future we wanted to allow browser based access to the web services, then SPNEGO would be the way to go.

Sumach answered 17/4, 2017 at 17:56 Comment(7)
FYI this was a real issue for the Hadoop ecosystem because Kerberos was intended to authenticate again 1 service on 1 host, not 5 svcs on 5800 hosts... What they implemented was (a) for RPC calls, a delegation token (kind of MD5 hash shared among peer svc hosts) and (b) for REST calls and UIs, a signed cookie (except for WebHDFS that uses the std token)Kofu
It's all Open Source so you can inspect their code -- and the JIRA that explains the rationale of the "signed cookie" in great length, with objections/argumentation/etc. (I think it was about securing YARN UI with SPNego...)Kofu
Or, you can even install a Hadoop sandbox from Horton or Cloudera, enable Kerberos for internal svcs and also for UIs, and see what happens with cURL and friends (except against WebHDFS - see above)Kofu
Side note about "browser-based access" and "Active Directory" -- you know the Microsoft ecosystem uses SSPI and not GSSAPI, right? So that you will have to re-engineer a large part of your PoC...?Kofu
About the JIRA mentioned above > issues.apache.org/jira/browse/HADOOP-7119Kofu
@SamsonScharfrichter my Server / Service Principal will remain in Java, even when running on Windows, so unless I have missed a trick GSSAPI remains relevantSumach
Related: https://mcmap.net/q/1564906/-web-application-kerberos-authentication-is-the-proper-way-to-combine-with-cookies/3571Publias
T
3
  1. To answer your first question, GSS-SPNEGO may include multiple round trips. It is not limited to just two. You should implement a session handling and upon successful authentication issue a session cookie that client should be presenting on each request. When this cookie is invalid, server would force you to re-authenticate. This way you would only incur negotiate costs when that is really needed.

  2. Depending on your application design you can choose different approaches for authentication. In FreeIPA we have been recommending to have a front-end authentication and allow applications to re-use the fact that front-end did authenticate the user. See http://www.freeipa.org/page/Web_App_Authentication for detailed description of different approaches.

I would recommend you to read the link referenced above and also check materials done by my colleague: https://www.adelton.com/ He is author of a number of Apache (and nginx) modules that help to decouple authentication from actual web applications when used with FreeIPA.

Tojo answered 19/4, 2017 at 15:11 Comment(3)
I almost posted this question on the FreeIPA Users mailing list given the high amount of Kerberos knowhow there...Sumach
yes multiple round trips are possible using SPENGO, as is a single trip: the client can get a service ticket upfront and append it to the Authenticate header. I intend updating my answer with a python demo of this soon.Sumach
sorry, I meant Authorization header, not Authenticate.Sumach
S
0

On re-reading my question, the question I was really asking was:

a) Is the overhead of SPNEGO significant enough that it makes sense to use if for a authorisation only, and that "something else" should be used for subsequent service calls?

or

b) Is the overhead of SPNEGO NOT significant in the greater scheme of things, and can be used for all service calls?

The answer is: It depends on the case; and key to finding out, is to measure the performance of service calls with and without SPNEGO.

Today I ran 4 basic test cases using:

  1. a simple "ping" type web-service, without SPNEGO
  2. a simple "ping" type web-sevice, using SPNEGO
  3. a call to the application's login service, without SPNEGO
  4. a call to the application's login service, using SPNEGO

Each test was called from a ksh script looping for 60 seconds, and making as many calls via CURL as possible in that time.

In the first test runs I measured:

Without SPNEGO

  • 15 pings
  • 11 logins

With SPENGO

  • 8 pings
  • 8 logins

This initially indicated that using SPNEGO I could only make half as many calls. However, on reflection, the overall volume of calls measured seemed low, even given the poorly specified Virtual Machines being used.

After some googling and tuning, I reran all the tests calling CURL with the -4 flag for IPV4 only. This gave the following:

Without SPNEGO

  • 300+ pings
  • 100+ logins

With SPNEGO

  • 19 pings
  • 14 logins

This demonstrates a significant difference with and without SPNEGO!

While I need to do further testing with real-world services that do some backend processing, this suggests that there is a strong case for "using something else" for subsequent service calls after authentication via SPNEGO.

In his comments Samson documents a precedent in the Hadoop world, and adds the additional architectural consideration of Highly Distributed / Available Service Principals

Sumach answered 18/4, 2017 at 13:31 Comment(3)
Additional consideration: do you have a dedicated KDC (e.g. an Active Directory replica), or do you have to share it with other critical apps (e.g. Windows auth, network drives auth, Exchange auth...) which means that you must not "accidentally" cripple the shared KDC with a DDoS-like event (e.g. timeouts in your own server triggering a "reconnection avalanche"... these things happen)Kofu
You may "accept" the answer to your own question as the solution here. Please do this. It turns the checkbox from gray to green and those are the types of questions I like to dig into when I don't have a lot of time to browse this site.Carothers
@JohnRSmith, tx, I am aware of that, and plan on doing so within the next few days, but first I will give my answer an edit based on the latest test findings, and on another SO question that indirectly has major influence on this questionSumach

© 2022 - 2024 — McMap. All rights reserved.