After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 587145 - please add GSS-Negotiate support
please add GSS-Negotiate support
Status: RESOLVED FIXED
Product: libsoup
Classification: Core
Component: Misc
2.26.x
Other Linux
: Normal normal
: ---
Assigned To: libsoup-maint@gnome.bugs
libsoup-maint@gnome.bugs
: 698817 758333 (view as bug list)
Depends on:
Blocks: 476922 593569 704869 762097
 
 
Reported: 2009-06-27 17:38 UTC by Emilio Pozuelo Monfort
Modified: 2018-04-17 10:06 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Kerberos patch (122.54 KB, patch)
2011-09-30 09:54 UTC, Mandy Wu
needs-work Details | Review
Check for GSSAPI support (1.27 KB, patch)
2013-01-02 20:50 UTC, Dan Winship
none Details | Review
[wip] Support Negotiate (13.05 KB, patch)
2013-01-02 20:50 UTC, Dan Winship
none Details | Review
Check trusted URIs (6.98 KB, patch)
2013-01-06 22:00 UTC, Guido Günther
none Details | Review
Allow to test negotiate via get.c (6.98 KB, patch)
2013-01-06 22:00 UTC, Guido Günther
none Details | Review
Negotiate support (19.80 KB, patch)
2013-01-28 20:43 UTC, Guido Günther
none Details | Review
patch to handle multiple round trips (3.01 KB, patch)
2015-11-04 17:16 UTC, David Woodhouse
none Details | Review
Final patch (29.45 KB, patch)
2016-03-03 14:27 UTC, Tomas Popela
none Details | Review
fixup! Bug 587145 - please add GSS-Negotiate support (1.06 KB, patch)
2016-03-13 15:54 UTC, Dan Winship
none Details | Review
fixup! Bug 587145 - please add GSS-Negotiate support (2.91 KB, patch)
2016-03-13 15:54 UTC, Dan Winship
none Details | Review
Final patch with docs fixes (31.89 KB, patch)
2016-03-14 10:22 UTC, Tomas Popela
none Details | Review
fixup! Bug 587145 - Add GSS-Negotiate support (2.21 KB, patch)
2016-03-14 12:13 UTC, Dan Winship
none Details | Review
Final patch (32.11 KB, patch)
2016-03-14 14:05 UTC, Tomas Popela
none Details | Review

Description Emilio Pozuelo Monfort 2009-06-27 17:38:24 UTC
[ From http://bugs.debian.org/532052 ]

I run a web server that uses Negotiate (Kerberos 5) for authentication.
libsoup2.4-1 does not support this, and so epiphany-webkit does not work
where epiphany-gecko does.

Similar support is present in libneon and libcurl; it would be great if
support could be added to libsoup.
Comment 1 Guido Günther 2009-10-01 20:20:19 UTC
I do have a basic implementation for this which I need to clean up.
Comment 2 Guido Günther 2009-10-02 16:42:09 UTC
Here's a basic patch:

http://git.debian.org/?p=users/agx/libsoup.git;a=summary

that works with the get testcase.
Comment 3 Dan Winship 2009-10-02 17:25:43 UTC
This code is a good start.

However, the split between SoupAuthManager and SoupAuthManagerNTLM is broken, and this makes it more broken; it ought to be possible to have a session that can use both NTLM and Negotiate auth, and that wouldn't be possible with this patch.

The right way to fix this is to have a single SoupAuthManager that can handle both "normal" and "connection-based" auths, and can handle more than one different kind of connection-based auth. So, parts of SoupAuthManagerNTLM would be squashed into SoupAuthManager, and parts would be squashed into SoupAuthNTLM. We would probably need a new SoupAuth subclass for connection-based auths, and SoupAuthNTLM and SoupAuthNegotiate would derive from that.

If you'd like to work on that, then feel free to bug me with more questions if you have any. I'm not likely to get to this myself in the 2.30 release cycle.
Comment 4 Guido Günther 2009-10-03 17:23:08 UTC
(In reply to comment #3)
> This code is a good start.
> 
> However, the split between SoupAuthManager and SoupAuthManagerNTLM is broken,
> and this makes it more broken; it ought to be possible to have a session that
> can use both NTLM and Negotiate auth, and that wouldn't be possible with this
> patch.

Yes this was just a basic path to get become a bit familiar with libsoup. I'm aware that this breaks NTLM and there's also more work needed on the Negotiate side.

> The right way to fix this is to have a single SoupAuthManager that can handle
> both "normal" and "connection-based" auths, and can handle more than one
> different kind of connection-based auth. So, parts of SoupAuthManagerNTLM would
> be squashed into SoupAuthManager, and parts would be squashed into
> SoupAuthNTLM. We would probably need a new SoupAuth subclass for
> connection-based auths, and SoupAuthNTLM and SoupAuthNegotiate would derive
> from that.
> 
> If you'd like to work on that, then feel free to bug me with more questions if
> you have any. I'm not likely to get to this myself in the 2.30 release cycle.

Although progress will be slow on my end since I'm short on free time I'd really would like to see this merged so pointers on howto get the restructuring of SoupAuth and SoupAuthManager done will be appreciated.
Comment 5 Dan Winship 2009-10-13 20:03:36 UTC
OK, first, you should say "Negotiate", not "GSSAPI" (eg, "SoupAuthNegotiate"), to be consistent with the other auth types, which all have the same names as the name used in the Authorize/WWW-Authenticate headers.

You'll have to create a SoupAuthConnectionBased class (or whatever it would be called) as a subclass of SoupAuth, make SoupAuthNTLM and SoupAuthNegotiate be subclasses of that, and then figure out how to move all the NTLM-specific code from SoupAuthManagerNTLM into SoupAuthNTLM (and likewise from SoupAuthManagerGSSAPI to SoupAuthNegotiate). Presumably you'll need to add some new virtual methods to SoupAuthConnectionBased to implement the various steps. When you're done, soup-auth-manager-ntlm.c will have only "generic" code, that is basically the common portions of the current soup-auth-manager-ntlm and soup-auth-manager-gssapi, and that code should be able to drive both NTLM auth via SoupAuthNTLM, and GSSAPI auth via SoupAuthNegotiate.

Then once that's working, the next step is to get rid of the separate SoupAuthManagerNTLM, by just pushing all of that code down into SoupAuthManager. When you're done, SoupAuthManager shouldn't have any explicit references to either NTLM or Negotiate; it should see the WWW-Authenticate header, find the appropriate SoupAuth type (as SoupAuthManager already does), and then see that the SoupAuth type is actually a SoupAuthConnectionBased subclass, and do the appropriate thing from there.


Also, for extra credit points, if there is a mod_auth_negotiate for Apache, it would be great to add some tests to tests/auth-test.c using it, to show that it all works right and to make sure we don't break things later.
Comment 6 Dan Winship 2009-11-07 00:05:59 UTC
*** Bug 601031 has been marked as a duplicate of this bug. ***
Comment 7 Brian J. Murrell 2009-11-07 14:50:07 UTC
Maybe I'm totally on glue here and the patch in comment #2 is completely unsuitable for Negotiate with proxies (assuming one is fine with nuking NTLM in the process) but I'm trying to give it whirl here.

The first major bit of logic that seems to fail is in create_auth() where it's looking for Proxy-Authenticate that includes a challenge.  Since Negotiate provides no challenge, it is never selected.  So it seems we have a wrong assumption here that every scheme is challenge based.

Hrm.  The more I look at it, the more this patch just doesn't seem to deal with the proxy authentication, just web server authentication.  Am I correct?
Comment 8 Guido Günther 2009-11-07 14:53:48 UTC
Proxy authentication hasn't been looked at yet. The code needs to be redone (comment #3). Afterwards adding proxy auth shouldn't be too hard.
Comment 9 Guido Günther 2009-11-08 13:39:49 UTC
That said removing the assumption that every proxy auth sends a challenge can be removed in parallel. So instead of a challenge we're just seeing:

> HTTP/1.1 407 Proxy Authentication Required
> Proxy-Authenticate: Negotiate

Which means we shouldn't bail out of create_auth() in the case we're seeing "Negotiate" in the header.

I'll try to have a look during next week (given I find some free time) so any help based on the above git repo would be welcome.
Comment 10 Guido Günther 2009-11-08 14:13:06 UTC
(In reply to comment #5)
> OK, first, you should say "Negotiate", not "GSSAPI" (eg, "SoupAuthNegotiate"),
> to be consistent with the other auth types, which all have the same names as
> the name used in the Authorize/WWW-Authenticate headers.
Fixed that part now at:

http://git.debian.org/?p=users/agx/libsoup.git;a=summary
Comment 11 Guido Günther 2009-11-30 19:52:14 UTC
Hi Dan,
Rereading what you wrote in c#5: Negotiate isn't connection based, it's message based. It's different from e.g. digest auth though since the challenge is empty (WWW-Authenticate: Negotiate) and after sending the authentication to the server we get a response that we can verify. Above git now works like a charme with epiphany and nautilus webdav.
Comment 12 Dan Winship 2009-12-19 12:50:04 UTC
(In reply to comment #11)
> Hi Dan,
> Rereading what you wrote in c#5: Negotiate isn't connection based, it's message
> based.

By "connection based", I mean the way that NTLM auth works; once you authenticate a single request, every request that follows that one on the same TCP connection is also considered to be authenticated automatically. This is different from the way that Basic and Digest work, which is that a request is only authenticated if it actually includes a valid Authorization header, and so you have to continue sending Authorization with every request. So by that definition, isn't Negotiate connection-based? (The mozilla code returns "CONNECTION_BASED" from nsHttpNegotiateAuth::GetAuthFlags(), suggesting that it is.)
Comment 13 Guido Günther 2009-12-19 14:32:04 UTC
(now what a coincidence I just sent you a mail about howto proceed).

At least mod_auth_kerb in Apache and Apple's Calendarserver  doesn't seem to implement it that way. I'm seeing a 401 Negotiate on every request. RFC 4559 doesn't look like this either.
Comment 14 Guido Günther 2009-12-19 14:40:22 UTC
However: http://www.chromium.org/developers/design-documents/http-authentication states that it can be connection based. So moving the way you suggested in c#5 looks reasonable.
Comment 15 Guido Günther 2010-06-20 11:28:31 UTC
I recently updated the branch:

http://git.debian.org/?p=users/agx/libsoup.git;a=summary

so support heimdal. This is still not mergeable but works quiet reliably here.
Comment 16 David Woodhouse 2010-07-17 10:43:50 UTC
I'm about to try to implement Exchange Web Services support (the protocol which obsoleted MAPI in Exchange 2007+), so this would be extremely useful. Any idea when it will be mergeable/merged?
Comment 17 Dan Winship 2010-07-17 15:23:23 UTC
It can be merged as soon as it's mergeable. :)

Guido's branch still implements Negotiate by breaking NTLM, and that needs to be fixed per comment 3.

The "auth-features" branch of http://gnome.org/~danw/libsoup.git would be a slightly better starting point than current git master. It tweaks how SoupSession/SoupAuthManager work so you can enable and disable specific auth types, replacing the current "use-ntlm" flag. This is important because we definitely want Negotiate to be disabled by default, because it's generally considered a security issue to just send a kerberos ticket to any web server that requests it. (IE only does Negotiate with servers in the "intranet" domain, and Firefox on Linux has an about:config setting that has to be manually editted, listing domains you're willing to do Negotiate auth with.) So anyway, we only want apps to be using Negotiate if they're taking the security issues into consideration, so there has to be some way for them to enable it, and the stuff on that branch provides this.

also:
(In reply to comment #14)
> However:
> http://www.chromium.org/developers/design-documents/http-authentication states
> that it can be connection based. So moving the way you suggested in c#5 looks
> reasonable.

I'm pretty sure "can be connection based" here means, if you use persistent connections, then it's connection based. Of course if either the client or the server refuses to allow persistent connections, then you'd need to authenticate each request, since you'd have a new connection every time.
Comment 18 Guido Günther 2010-07-18 20:28:20 UTC
I wonder it would help the Exchange Web Service support to already merge the bulk of libauth-*negotiate.[ch]. This wouldn't break anything since the patch that disabled NTLM in favour of GSSAPI is a separate one. That way enabling GSSAPI would be only a one line patch away.

That said I'll try to have a look at the auth-features branch during the week, given I find some free time.
Comment 19 Dan Winship 2010-07-30 09:07:35 UTC
I've pushed a bunch more code to the "auth-features" branch of http://gnome.org/~danw/libsoup.git, which gets us a good chunk of the way to being able to support both NTLM and Negotiate. There's still one hard-coded reference to NTLM in soup-auth-manager.c, which sort of needs to be there to support the idea of "try NTLM even before the server has said that it supports it". I need to make NTLM work more like the other auths, where it doesn't try using it until after the server has indicated that it supports it.
Comment 20 David Woodhouse 2010-07-30 09:09:16 UTC
Note also that we should be delegating NTLM to the Samba ntlm_auth helper tool if it's available, so we don't need to be given the user's password.
Comment 21 Guido Günther 2010-10-11 11:16:38 UTC
(In reply to comment #19)
> I've pushed a bunch more code to the "auth-features" branch of
> http://gnome.org/~danw/libsoup.git, which gets us a good chunk of the way to
> being able to support both NTLM and Negotiate. 

I finally got around to have a look at the "auth-features" code and I fully agree that it'll be very simple to add my negotiate code on top of that once "auth-features" is working and mergeable by itself.

I've worked a bit on fixing up the auth-features branch at:

http://git.debian.org/?p=users/agx/libsoup.git;a=shortlog;h=refs/heads/auth-features

With the fixes there I get through tests/ntlm-test. Could you have a look and comment on what's needed to get that merged (or at least have it as a branch on git.gnome.org) so we can put negotiate on top? 

It'd be great to have this in shape for GNOME 3.0.
Comment 22 Guido Günther 2010-10-14 15:06:19 UTC
Hi Dan,
I have moved the negotate stuff over to auth-features too now:

http://git.debian.org/?p=users/agx/libsoup.git;a=shortlog;h=refs/heads/negotiate

There are still a couple of blind spots but I'd appreciate feedback if this is moving into the right direction.
Comment 23 David Woodhouse 2011-03-20 22:59:30 UTC
If I wanted to implement NTLMv2 session support, and support for using an ntlm_auth helper for single-sign-on, which tree is it best to work from? Guido's tree mentioned in comment 21? What prospect of that getting merged any time soon?

(Since Samba/winbind is a PITA to set up, there's a simple tool at http://david.woodhou.se/ntlm_auth_v2.c which takes its place, for the purpose of testing NTLM single-sign-on.)

While on the topic of connection-based auth mechanisms, it would also be nice to set an 'Expect: 100-continue' *only* if submitting a SoupMessage on a connection which isn't already authenticated. The client has no way of knowing that in advance, right?
Comment 24 Guido Günther 2011-03-22 00:17:48 UTC
Hi David,
My branch is pretty much outdated towards current master. However I would be happy to update this once I got some feedback if this is heading into the right direction.
Cheers,
 -- Guido
Comment 25 Dan Winship 2011-04-26 17:09:10 UTC
OK, I've pushed my totally-work-in-progress stuff to the ntlm branch of git://github.com/danwinship/libsoup.git

The idea I'd been working with was that you'd use soup_auth_manager_use_auth() (or some similar method on SoupSession) to tell the auth manager that it should automatically try NTLM for a given host, and possibly also that would be the API for telling it that it was safe to use Negotiate for a particular host.

Then, the connection-vs-normal auth stuff in SoupAuthManager could be simplified, because we wouldn't need any "magically create a connection-based auth even though no one asked for it" code path; you'd only create the connection-based auth if either we had already seen an NTLM/Negotiate auth for that connection, or if the app had preloaded it via soup_auth_manager_use_auth().

The code is not currently in a working state, but I'm unlikely to pick it up again any time soon.

If you want to ignore that code and work from Guido's current branch instead, that's also possible. The "mergeable" criteria are:

    - Doesn't break evolution-exchange

    - NTLM and Negotiate are enabled by using
      soup_session_add_feature_by_type(), and it's possible to enable both
      of them on a given session.

    - Negotiate doesn't automatically send your kerberos credentials to
      random hosts without the app telling it what hosts are OK (per
      comment 17)
Comment 26 Guido Günther 2011-05-14 11:58:48 UTC
I've updated my code to the lates libsoup and addressed comment #17 by introducing a environment varianble:

http://git.debian.org/?p=users/agx/libsoup.git;a=commit;h=0f28d1ac3f3545842093825ad0531b6a6fa25a95

In the long run I think we need to have a global setting (maybe set via g-c-c's network module) and application specific settings but for now I'd like to keep this self contained in libsoup.
Comment 27 Sri Ramkrishna 2011-07-25 21:35:47 UTC
I'm curious as to why "evolution-exchange" is a blocker for merging?  My experience with evolution-exchange is that it's fairly broken and that the evoluiton-web-services plugin is a lot more saner, and stable and has active support.

Guido - great work on this!
Comment 28 Dan Winship 2011-07-26 23:07:58 UTC
(In reply to comment #27)
> I'm curious as to why "evolution-exchange" is a blocker for merging?  My
> experience with evolution-exchange is that it's fairly broken and that the
> evoluiton-web-services plugin is a lot more saner, and stable and has active
> support.

At the time I wrote the comment, evolution-exchange was in the Desktop release set, and so breaking NTLM would mean another official part of GNOME would regress. Now the Desktop set no longer exists (though evolution-exchange is listed in bugzilla under "Applications", while evolution-ews is still "Other"). But the general idea is still the same. "Make sure that apps that were able to speak NTLM to Windows servers before are still able to speak NTLM to Windows servers after." Feel free to use evolution-ews as the test case rather than evolution-exchange.
Comment 29 Mandy Wu 2011-09-30 09:54:09 UTC
Created attachment 197862 [details] [review]
Kerberos patch

Combined with Dan and Guido's code. Modified according to comment #5, comment #17 and comment #25.

Please help take some time to review it to see if anything need more adjustment, like the soup-auth-manager. 

I did some testing before I merged with upstream code. After I merged with upstream, I got SOUP_STATUS_SSL_FAILED running my test program. Anything I missed?

Be default, all auth types is added to the auth_manager. Application need to use use soup_session_use_auth to tell libsoup to use which auth type. If app does not call this function, neither NTLM or Negotiate will be used.

To test it with Negotiate, use soup_session_use_auth (sess, SOUP_TYPE_AUTH_NEGOTIATE, trusted_hosts);

To test with NTLM, use use soup_session_use_auth (sess, SOUP_TYPE_AUTH_NTLM, NULL); Or soup_session_sync_new_with_options(SOUP_SESSION_USE_NTLM, TRUE, NULL) still work.

I will add corresponding test case later. 

Thanks!
Comment 30 Dan Winship 2011-09-30 12:32:02 UTC
(In reply to comment #29)
> I did some testing before I merged with upstream code. After I merged with
> upstream, I got SOUP_STATUS_SSL_FAILED running my test program. Anything I
> missed?

You need to update glib-networking to get a bugfix there.
Comment 31 Dan Winship 2011-10-04 19:30:55 UTC
Review of attachment 197862 [details] [review]:

ok, this is a start, but it not's all the way there

::: configure.ac
@@ +347,3 @@
+dnl *** GSSAPI / Negotiate ***
+dnl **************************
+AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)

the krb5 config stuff needs to work like... hm, I guess there aren't any other examples in libsoup... look at, say, the configuration for libproxy in glib-networking. There needs to be an AC_ARG_WITH, and there should be three behaviors: if they pass --with-krb5, then krb5 is required, and configure should error out if it's not found. If they pass --without-krb5, then it shouldn't even check for it. And if they don't pass either, then it should check, but not error out if it's not found.

::: libsoup/Makefile.am
@@ +14,3 @@
 	$(SQLITE_CFLAGS)		\
 	$(GNOME_KEYRING_CFLAGS)
+	$(KRB5_CFLAGS)

need a "\" at the end of the previous line

@@ +56,3 @@
 	soup-auth-domain-digest.h \
+	soup-auth-negotiate.h	\
+	soup-auth-ntlm.h	\

Why are these getting installed? We don't install soup-auth-basic.h or soup-auth-digest.h.

@@ +116,3 @@
 	soup-auth.c			\
+	soup-auth-connbased.h		\
+	soup-auth-connbased.c		\

you don't need to add .h files to _SOURCES if they're in _HEADERS

::: libsoup/soup-auth-basic.h
@@ +9,3 @@
 #include "soup-auth.h"
 
+#define SOUP_TYPE_AUTH_BASIC            (soup_auth_basic_get_type ())

soup-auth-basic.h is not installed; by moving this here, you make it inaccessible to people, meaning

  soup_session_disable_feature_by_type (session, SOUP_TYPE_AUTH_BASIC);

would no longer work. (Likewise for the soup-auth-digest changes)

::: libsoup/soup-auth-manager.c
@@ +25,3 @@
+#include "soup-auth-connbased.h"
+#include "soup-auth-ntlm.h"
+#include "soup-auth-negotiate.h"

soup-auth-manager.c should not need to include soup-auth-ntlm.h or soup-auth-negotiate.h

@@ +133,3 @@
 
+	g_hash_table_foreach (priv->connections_by_id,
+			      free_connection_foreach, NULL);

The existing code is probably inconsistent, but it's better to use g_hash_table_new_full() when creating it, so you can pass a free_func that will get called any time an item is removed. Then at finalize time, all you have to do is g_hash_table_destroy()

@@ -145,3 @@
-	feature_interface->add_feature = add_feature;
-	feature_interface->remove_feature = remove_feature;
-	feature_interface->has_feature = has_feature;

None of this stuff should be changed

@@ +255,3 @@
+	priv->use_auth_type = type;
+	if (hosts)
+		priv->trusted_hosts = g_strdup (hosts);

No, you need to be able to call this multiple times, and you can call it for either NTLM or Negotiate auths, and you pass a single hostname each time, and SoupAuthManager will need to keep a hash table or something recording what hosts allow which types.

@@ +316,3 @@
+	conn->auth = g_object_new (type, NULL);
+	if (g_type_is_a (type, SOUP_TYPE_AUTH_NEGOTIATE))
+		soup_auth_negotiate_set_hosts (SOUP_AUTH (conn->auth), priv->trusted_hosts);

again, there must be no explicit references to either NTLM or Negotiate within soup-auth-manager.c

::: libsoup/soup-auth-manager.h
@@ +34,3 @@
 
+void soup_auth_manager_add_type          (SoupAuthManager *manager,
+					  GType            type);

You shouldn't need to make these methods public. See the comments in soup-session.c

::: libsoup/soup-auth-ntlm.c
@@ +21,3 @@
 #include "soup-headers.h"
 #include "soup-message.h"
+#include "soup-message-private.h"

what does it need that for?

::: libsoup/soup-auth.c
@@ -149,3 +149,3 @@
 				     "Authentication realm",
 				     NULL,
-				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+				     G_PARAM_READWRITE));

what is this change needed for?

::: libsoup/soup-session.c
@@ -195,3 +199,3 @@
 			  G_CALLBACK (auth_manager_authenticate), session);
-	soup_session_feature_add_feature (SOUP_SESSION_FEATURE (auth_manager),
-					  SOUP_TYPE_AUTH_BASIC);
+	soup_auth_manager_add_type (auth_manager, SOUP_TYPE_AUTH_BASIC);
+	soup_auth_manager_add_type (auth_manager, SOUP_TYPE_AUTH_DIGEST);

So, these should stay as soup_session_feature_add_feature(). I suspect that what happened here is that my ntlm branch dates to before that API was added, and so it was doing things in a slightly different way, and you just copied that over. But it should keep using the soup_session_feature_add_feature() way. Most of the changes in soup-session.c should be reverted.

@@ +975,3 @@
 		break;
 	case PROP_USE_NTLM:
+		soup_session_use_auth (session, SOUP_TYPE_AUTH_NTLM, NULL);

this assumes that the value is "TRUE", but it might be "FALSE"

::: libsoup/soup-auth-connbased.c
@@ +1,3 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-auth-connbased.c: HTTP CONNBASED Authentication helper

looks like a bad search and replace. "HTTP connection-based authentication helper"

::: libsoup/soup.h
@@ +14,3 @@
 #include <libsoup/soup-auth.h>
+#include <libsoup/soup-auth-ntlm.h>
+#include <libsoup/soup-auth-negotiate.h>

probably wrong; the type macros should be moved to soup-auth.h instead
Comment 32 Mandy Wu 2011-10-25 06:00:55 UTC
Dan, thanks a lot for the feedbacks and sorry for late response. My Linux box is down for bad sectors and I have to re-install it and all data is lost... I will set it up and work on the bug asap.
Comment 33 James Cape 2012-04-13 11:45:49 UTC
Mandy,

Any luck with your Linux box?
Comment 34 Dan Winship 2013-01-02 20:50:15 UTC
I've just landed a large reworking of NTLM auth / SoupAuthManager, which includes parts of some of the earlier hacking branches.

I'm attaching a rebased version of what I think was the most recent version of Guido's SoupAuthNegotiate. Not tested at all yet, but in theory, it ought to work and address the first two requirements from comment 25 (but not the "what hosts is it safe to send creds to" issue).

Another problem here is that I'd like to avoid a hard dependency on krb5-libs... But it seems like this is a situation where using dlopen and having no explicit dependency would work fine; if libkrb5 isn't present, then obviously the user isn't using kerberos, so SoupAuthNegotiate doesn't need to be able to work.
Comment 35 Dan Winship 2013-01-02 20:50:32 UTC
Created attachment 232570 [details] [review]
Check for GSSAPI support
Comment 36 Dan Winship 2013-01-02 20:50:34 UTC
Created attachment 232571 [details] [review]
[wip] Support Negotiate
Comment 37 Guido Günther 2013-01-03 19:52:44 UTC
(In reply to comment #34)
> I've just landed a large reworking of NTLM auth / SoupAuthManager, which
> includes parts of some of the earlier hacking branches.
> 
> I'm attaching a rebased version of what I think was the most recent version of
> Guido's SoupAuthNegotiate. Not tested at all yet, but in theory, it ought to
> work and address the first two requirements from comment 25 (but not the "what
> hosts is it safe to send creds to" issue).

Very cool. I grabbed those and pushed these at:

http://anonscm.debian.org/gitweb/?p=users/agx/libsoup.git;a=summary

together with another patch that adds -N to get.c. A simple test fetching pages worked. I'll add back the trusted URI checks I had coded already during the next days together with some other minor fixes. This should address the third requirement.

> Another problem here is that I'd like to avoid a hard dependency on
> krb5-libs... But it seems like this is a situation where using dlopen and
> having no explicit dependency would work fine; if libkrb5 isn't present, then
> obviously the user isn't using kerberos, so SoupAuthNegotiate doesn't need to
> be able to work.

This could get messy with different Kerberos implementations (MIT, Heimdal, Shishi). Is a dependeny on libkrb5 that bad? It's on almost any Linux system anyways and evolution depends on it already.
Comment 38 Dan Winship 2013-01-03 20:07:30 UTC
(In reply to comment #37)
> > Another problem here is that I'd like to avoid a hard dependency on
> > krb5-libs... But it seems like this is a situation where using dlopen and
> > having no explicit dependency would work fine; if libkrb5 isn't present, then
> > obviously the user isn't using kerberos, so SoupAuthNegotiate doesn't need to
> > be able to work.
> 
> This could get messy with different Kerberos implementations (MIT, Heimdal,
> Shishi). Is a dependeny on libkrb5 that bad? It's on almost any Linux system
> anyways and evolution depends on it already.

There are always people who don't like any given dependency. And libkrb5 is *available* on almost any Linux system, but it's not necessarily installed, and there are people who will complain about having libsoup pull krb5-libs in.

Dunno. I guess we can just add the dep and see if anyone complains.
Comment 39 Guido Günther 2013-01-06 22:00:00 UTC
Created attachment 232882 [details] [review]
Check trusted URIs

Check trusted uris on new requests
    
The trusted uris are currently parsed from the enivronment variable
SOUP_AUTH_TRUSTED_URIS that has the uris separated by commas like:
    
SOUP_AUTH_TRUSTED_URIS="foo.example.com,bar.example.com:443"
SOUP_AUTH_TRUSTED_URIS="http://foo.example.com,https://bla.example.com"
SOUP_AUTH_TRUSTED_URIS="https://"
Comment 40 Guido Günther 2013-01-06 22:00:56 UTC
Created attachment 232883 [details] [review]
Allow to test negotiate via get.c
Comment 41 Guido Günther 2013-01-10 06:32:52 UTC
I pushed some improvements here:

http://anonscm.debian.org/gitweb/?p=users/agx/libsoup.git;a=commit;h=2f9ad978458744bff5a1ffdcc3aa42ef0822220e

stores GSS Error information into a GError however I'm unsure what's the desired way to make this available to the application.

http://anonscm.debian.org/gitweb/?p=users/agx/libsoup.git;a=commit;h=57496356e1b87618cf117e2311c23d3dbf546bc8

Verifies the server response. Since this header is sent with the 2xx request just setting the auth status to failed isn't enough to make the request fail. I wonder what's the best way to proceed from here. Requeue the message?
Comment 42 Dan Winship 2013-01-11 15:51:16 UTC
OK, https://bugzilla.mozilla.org/show_bug.cgi?id=17578#c209 explains the threat model behind needing "trusted URIs"; because Negotiate auth (or NTLM via /usr/bin/ntlm_auth) won't need to pop up any username/password dialog, if a man-in-the-middle can trick your browser into sending requests to a site that uses Negotiate auth, then the browser will authenticate to it without the user having any clue it's even happening, and then the MITM can use your credentials to do arbitrary things against that server. (This is basically the same issue as the "firesheep" vulnerability, where a MITM tricks your browser into sending requests to sites that you're logged in to with cookies.)

If you only send Negotiate requests to https sites, then you're safe. And if you only send Negotiate requests to sites within your "intranet" where there are assumed to be no MITMs, then you're safe. Which is what IE does, but Firefox and Epiphany don't have a concept of "intranet", which is why Firefox went with "trusted URIs" instead; you're supposed to set it to only match URIs within your intranet.

(It's possible that NetworkManager will support "network zones" / "trusted networks" at some point though...)

So anyway... I think an environment variable is an OK workaround for now... Also, soup_auth_manager_use_auth() will allow programs like evolution to tell libsoup that it definitely wants to use Negotiate when talking to a particular server.
Comment 43 Guido Günther 2013-01-11 20:12:46 UTC
(In reply to comment #42)
> OK, https://bugzilla.mozilla.org/show_bug.cgi?id=17578#c209 explains the threat
> model behind needing "trusted URIs"; because Negotiate auth (or NTLM via
> /usr/bin/ntlm_auth) won't need to pop up any username/password dialog, if a
> man-in-the-middle can trick your browser into sending requests to a site that
> uses Negotiate auth, then the browser will authenticate to it without the user
> having any clue it's even happening, and then the MITM can use your credentials
> to do arbitrary things against that server. (This is basically the same issue
> as the "firesheep" vulnerability, where a MITM tricks your browser into sending
> requests to sites that you're logged in to with cookies.)
> 
> If you only send Negotiate requests to https sites, then you're safe. And if
> you only send Negotiate requests to sites within your "intranet" where there
> are assumed to be no MITMs, then you're safe. Which is what IE does, but
> Firefox and Epiphany don't have a concept of "intranet", which is why Firefox
> went with "trusted URIs" instead; you're supposed to set it to only match URIs
> within your intranet.

So should we default to https:// if the env_var is unset? 

> (It's possible that NetworkManager will support "network zones" / "trusted
> networks" at some point though...)

As an improvement we could use a GSettings key to store the trusted URIs so we can at least make this accessible via g-c-c at some point but it might make more sense to get some basic negotiate support in first.

Any comments on the other [wip] parts (Retrieving GSS Error information and verifying the server response)?
Comment 44 Guido Günther 2013-01-28 20:43:11 UTC
Created attachment 234656 [details] [review]
Negotiate support

I'm attaching the current state of the negotiate support as can be found on 

git://git.debian.org/~agx/public_git/libsoup.git

Open issues are:

* Verification of server response not exported to application (only printed as a g_warning if it fails)
* Detailed GSS error information not exported to the application (only printed as a warnong)
* trusted URIs can only be set via env var (should probably become a GSetting)

I'd appreciate any comments what would be necessary to get this applied or how to progress in the above issues.
Comment 45 Guido Günther 2013-02-17 16:34:15 UTC
Ping?
Comment 46 David Woodhouse 2013-05-22 12:55:29 UTC
The git uri in comment 44 doesn't seem to work; it's browseable at http://anonscm.debian.org/gitweb/?p=users/agx/libsoup.git or you can check out from git://anonscm.debian.org/users/agx/libsoup.git
Comment 47 Dan Winship 2013-05-22 14:39:56 UTC
Comment on attachment 234656 [details] [review]
Negotiate support

OK, sorry for dropping this; I realized it wasn't going to be ready to commit in time for 3.8, and then it totally fell off my radar after that. Let's make sure to get this in for 3.10.


>+AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
>+if test "x$KRB5_CONFIG" != "xnone"; then
>+    KRB5_LIBS="`${KRB5_CONFIG} --libs gssapi`"
>+    KRB5_CFLAGS="`${KRB5_CONFIG} --cflags gssapi`"

So, still wondering about whether we want this as a hard dep, and then it occurred to me that we also need a test program (like tests/ntlm-test), because otherwise the code will certainly get broken at some point. But we can't require a fully-working kerberos setup just to run "make check".

So that led to the idea that we could have the kerberos support be built into its own "libsoup-krb5.so" (or something), which would be dynamically loaded at runtime (and Negotiate would be unsupported if libsoup-krb5.so was not present). And then we can provide a separate hack version of libsoup-krb5.so that doesn't actually do real kerberos, for use by the test program (a la tests/ntlm-test-helper.c).

(This can happen later on once all the other issues are fixed though.)

>+	priv->trusted_uris = parse_trusted_uris();

The trusted URIs are global; you should parse them into a static variable from soup_auth_negotiate_class_init() rather than re-parsing them each time a SoupAuthNegotiate is created.

>+	SoupAuthNegotiatePrivate *priv = \
>+		SOUP_AUTH_NEGOTIATE_GET_PRIVATE (negotiate);

don't need "\" there

>+	if (conn->state > SOUP_NEGOTIATE_RECEIVED_CHALLENGE) {
>+		/* We already authenticated, but then got another 401.
>+		 * That means "permission denied", so don't try to
>+		 * authenticate again.
>+		 */
>+		conn->state = SOUP_NEGOTIATE_FAILED;

Seeing this part reminds me that there have been some bugfixes to soup-auth-ntlm.c since you wrote this, and we need to make sure to copy the equivalent fixes over to negotiate.

>+		else {
>+			/* FIXME: report further upward? */
>+			g_warning("gssapi step failed: %s", err->message);
>+
>+		}

I'm not sure what the app would do with an error message here even if we did have some way to pass it back up... I guess there could be soup_message_get_error_message() or something maybe...

What does Firefox do? Do they try to pass GSSAPI error messages up to higher levels?

>+	g_error_free(err);

This will g_return_if_fail() if err is NULL. You need an "if", or else use
g_clear_error (&err).

Also, here and in many other places, there should be a space before the "(".

>+	space = g_strdup (source_uri->path);
>+
>+	/* Strip query and filename component */

Oops, that comment is wrong. It should be just "Strip filename component". (I've fixed it in soup-auth-basic and soup-auth-ntlm now.)

>+static void
>+soup_auth_negotiate_authenticate (SoupAuth *auth, const char *username,
>+				  const char *password)
>+{
>+	SoupAuthNegotiatePrivate *priv = SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth);
>+
>+	g_return_if_fail (username != NULL);
>+	priv->username = g_strdup (username);
>+}

If we're not going to make use of the passed-in password, then we don't want to allow this to even be called.

Normally, soup_auth_authenticate() should only be called as a result of the auth manager emitting "authenticate". So, we need to make sure that never happens for SoupAuthNegotiate. This might require adding some new flag so that SoupAuthManager understands this.

If soup_auth_negotiate_authenticate() does get called, it should probably mark the auth as *NOT* authenticated, since it's not actually able to make use of the username and password passed-in by the caller. (Perhaps it could check if the username matches the kerberos credentials?)

>+static gboolean
>+soup_auth_negotiate_is_authenticated (SoupAuth *auth)
>+{
>+	return SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth)->username != NULL;
>+}

Likewise, this should just check that the user has kerberos credentials.

>+static gboolean
>+soup_auth_negotiate_is_ready (SoupAuth *auth,
>+			      SoupMessage *msg)
>+{
>+	SoupAuthNegotiate* negotiate = SOUP_AUTH_NEGOTIATE(auth);
>+	return check_auth_trusted_uri(negotiate, msg);
>+}

check_auth_trusted_uri() should happen from update_connection(); you want to return FALSE from there if the URI is not trusted, so that soup_auth_new() will fail to even create a SoupAuth for it in that case.

Also, you need to implement SoupConnectionAuth's is_connection_ready(), not SoupAuth's is_ready(), because you need to check the connection state (in addition to checking is_authenticated()).

>+	auth_headers = soup_message_headers_get_list (msg->response_headers,
>+						      "WWW-Authenticate");
>+	parts = g_strsplit(auth_headers, " ", 0);
>+	if (g_strv_length(parts) != 2) {

You should probably also sanity-check that parts[0] is "Negotiate". Given which, you don't really need to strsplit it. Just check the prefix and then skip over that. Oh, and soup_message_headers_get_one(), not get_list().

>+	g_signal_handlers_disconnect_matched (msg,
>+			      G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_FUNC,
>+			      0, 0, NULL,
>+			      G_CALLBACK(check_server_response),
>+			      state);

g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (check_server_response), state);

>+static gboolean
>+soup_auth_negotiate_is_connection_ready (SoupConnectionAuth *auth,

Oh, this never gets called in the current code, because you're overriding is_ready(). But see the comments there.


>+/* Parses a comma separated liste of URIS from the environment. This needs to be

typo ("liste")

>+ * extended later similar to proxy resolution */

not sure what that comment means?

>+	gchar **t_s_hp = NULL, **t_h_p = NULL;
>+	const gchar *t_h = NULL;
>+	gint t_h_len;

ugh. Use longer names.

>+	/* split trusted uri into scheme and host/port */
>+	if (strstr (trusted, "://")) {

It would be better to just store the trusted_uris as a list of SoupURIs, so you don't have to re-parse them every time here. And then, comparing schemes is just a matter of "msg_uri->scheme == trusted_uri->scheme", because they're interned strings.

>+	     * sure it is either an exact match, or prefixed with a dot. We
>+	     * don't want to match "foobar.com" to match "bar.com" */

drop the first "to match": We don't want "foobar.com" to match "bar.com"

/* Also, comments should
 * be written like this.
 */

>+			/* we don't want to example.com to match fooexample.com

"we don't want example.com to match fooexample.com"

(Would it make sense to share code with soup-cookie here?)

>+	/* We only use the uri list for negotiate auth for now */
>+	if (g_ascii_strcasecmp (soup_auth_get_scheme_name(SOUP_AUTH(negotiate)),
>+				"negotiate"))

this code will never get called for non-negotiate auths

>+	if (!priv->trusted_uris) {
>+		return FALSE;
>+	}

weren't we going to default to allowing all https URIs by default?

>+		if (match_base_uri(msg, priv->trusted_uris[i]))
>+			g_warning("matched");

obviously that has to go :)
Comment 48 David Woodhouse 2013-05-22 15:14:09 UTC
(In reply to comment #47)
> So, still wondering about whether we want this as a hard dep, and then it
> occurred to me that we also need a test program (like tests/ntlm-test), because
> otherwise the code will certainly get broken at some point. But we can't
> require a fully-working kerberos setup just to run "make check".

Isn't GSSAPI support usually provided by a libgssapi_krb5.so which is loaded with dlopen()? See http://putty-aes-ni.googlecode.com/svn-history/r106/trunk/Putty/unix/uxgss.c for example.

If we do it that way, the test setup can load its *own* GSSAPI library instead of using the real one. And the hard dependency (even in binary distribution packages) is avoided.

> I'm not sure what the app would do with an error message here even if we did
> have some way to pass it back up... I guess there could be
> soup_message_get_error_message() or something maybe...

There would be some way to display it to the user; either as a normal part of the UI, or at *least* in debugging output or logs.

> What does Firefox do? Do they try to pass GSSAPI error messages up to higher
> levels?

Firefox is stunningly broken in this respect. It completely fails to report errors. At all. We have one internal site which doesn't allow modern, sane Kerberos tickets and we have to add 'allow_weak_crypto' and enable DES keys in /etc/krb5.conf. But nobody *knew* this because there's no sane error reporting in Firefox. It just locks up and fails to redraw itself for five minutes while it does Kerberos stuff in blocking mode on its main thread, then asks you for a password.

Do not use Firefox as an exemplar here :)
  
> >+static gboolean
> >+soup_auth_negotiate_is_authenticated (SoupAuth *auth)
> >+{
> >+	return SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth)->username != NULL;
> >+}
> 
> Likewise, this should just check that the user has kerberos credentials.


... that are currently valid. Trying to obtain a ticket can be slow; please don't bother if you *know* the TGT is already expired.
Comment 49 Dan Winship 2013-05-22 15:30:54 UTC
(In reply to comment #48)
> Isn't GSSAPI support usually provided by a libgssapi_krb5.so

yes

> which is loaded with dlopen()?

I *think* the normal behavior is to link against it at build time. But yes, we could probably do it that way instead.

> Firefox is stunningly broken in this respect. It completely fails to report
> errors. At all. We have one internal site which doesn't allow modern, sane
> Kerberos tickets and we have to add 'allow_weak_crypto' and enable DES keys in
> /etc/krb5.conf. But nobody *knew* this

Mm. Yes. Been there, failed that.

> It just locks up and fails to redraw itself for five minutes while
> it does Kerberos stuff in blocking mode on its main thread

Hate! We should avoid that too, eventually.

(GTask makes it easy to move the work off to another thread. (Assuming libgssapi_krb5 is internally thread-safe...) Then we'd need a soup_auth_update_sync() that takes a GCancellable, and soup_auth_update_async() for the async case. And another API to say whether you actually need to *use* soup_auth_update_async(), because you don't want to do the extra asynchrony for all the other auth types that are guaranteed to not block in update() anyway.)
Comment 50 Guido Günther 2013-06-03 15:20:50 UTC
Thanks for the review!

(In reply to comment #47)
> I'm not sure what the app would do with an error message here even if we did
> have some way to pass it back up... I guess there could be
> soup_message_get_error_message() or something maybe...

Yes, we should probably add this but maybe we can also defer this and stick to g_warning for the moment as we do now?

> What does Firefox do? Do they try to pass GSSAPI error messages up to higher
> levels?

As David noted the Mozilla products aren't a very good example in this area.

> >+static void
> >+soup_auth_negotiate_authenticate (SoupAuth *auth, const char *username,
> >+				  const char *password)
> >+{
> >+	SoupAuthNegotiatePrivate *priv = SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth);
> >+
> >+	g_return_if_fail (username != NULL);
> >+	priv->username = g_strdup (username);
> >+}
> 
> If we're not going to make use of the passed-in password, then we don't want to
> allow this to even be called.

O.k.

> 
> Normally, soup_auth_authenticate() should only be called as a result of the
> auth manager emitting "authenticate". So, we need to make sure that never
> happens for SoupAuthNegotiate. This might require adding some new flag so that
> SoupAuthManager understands this.
> 
> If soup_auth_negotiate_authenticate() does get called, it should probably mark
> the auth as *NOT* authenticated, since it's not actually able to make use of
> the username and password passed-in by the caller. (Perhaps it could check if
> the username matches the kerberos credentials?)

That wouldn't have any value since these might differ. 

> 
> >+static gboolean
> >+soup_auth_negotiate_is_authenticated (SoupAuth *auth)
> >+{
> >+	return SOUP_AUTH_NEGOTIATE_GET_PRIVATE (auth)->username != NULL;
> >+}
> 
> Likewise, this should just check that the user has kerberos credentials.

Which is about impossible to do since not even a TGT indicates that we might be able to authenticate with the server. E.g. the TGT might be from a completely different realm.

I've rebased the current version on top of git master and will tackle the other parts soonish.
Comment 51 Guido Günther 2013-06-04 21:53:58 UTC
I've updated the code g_module_load a libsoup-gss.so that contains all the GSSAPI related stuff:

http://anonscm.debian.org/gitweb/?p=users/agx/libsoup.git 

Many of the other review comments are addressed there too. I'll still have to look into the is_connection_ready vs. is_ready part though.
Comment 52 David Woodhouse 2013-06-26 15:50:48 UTC
Slightly bemused by the latest commit in that tree, which moves the GSSAPI stuff into a separate library, ostensibly so that libsoup doesn't have to depend on libkrb5. Have you *tried* removing the krb5-libs package on a recent distribution? Almost everything *else* depends on it anyway. It just isn't worth jumping through those hoops, surely/

And of course you still have the option of building *without* Kerberos support for the Gentoo users.
Comment 53 Guido Günther 2013-06-26 18:06:34 UTC
(In reply to comment #52)
> Slightly bemused by the latest commit in that tree, which moves the GSSAPI
> stuff into a separate library, ostensibly so that libsoup doesn't have to
> depend on libkrb5. Have you *tried* removing the krb5-libs package on a recent
> distribution? Almost everything *else* depends on it anyway. It just isn't
> worth jumping through those hoops, surely/

Well, I read that Dan kind of insisted on having it split out and now that it's done it will ease making it testable without a real KDC. I hope to get around to continue to work on libsoup during the next days.
Comment 54 David Woodhouse 2014-07-23 23:58:33 UTC
Negotiate auth should be using SPNEGO not basic KRB5. P;ease provide the SPNEGO OID to gss_init_sec_context() instead of GSS_C_NO_OID.

static const char spnego_OID[] = "\x2b\x06\x01\x05\x05\x02";
static const gss_OID_desc gss_mech_spnego = {
        6,
        &spnego_OID
};

 s/GSS_C_NO_OID/(gss_OID) &gss_mech_spnego/

And please use GSS_C_NT_HOSTBASED_SERVICE and "HTTP@host" for importing the name instead of GSS_C_NT_PRINCIPAL_NAME and "HTTP/host". If you do both of those, then automatic NTLMSSP authentication should work too. Negotiate isn't just about Kerberos :)

We also need to deal with the fact that it *might* be connection-based authentication (if "Persistent-Auth: true"), or it might be message-based. Have both of those been tested?

You can drop the 'username' field completely, can't you? It's never used.
Unless you actually want to start supporting gss_acquire_cred_with_password() to *obtain* credentials...? But I suspect that's best left for a later improvement.

You could at least try gss_acquire_cred() in your is_authenticated() function, because if you have *no* credentials (for any mechanism) then you're fairly sure to fail.
Comment 55 David Woodhouse 2014-07-24 01:26:55 UTC
Looks like check_server_response() requires a WWW-Authenticate: header in the final successful response, too. That isn't always going to be there.
Comment 56 Dan Winship 2015-02-10 11:57:15 UTC
[mass-moving all "UNCONFIRMED" libsoup bugs to "NEW" after disabling the "UNCONFIRMED" status for this product now that bugzilla.gnome.org allows that. bugspam-libsoup-20150210]
Comment 57 David Woodhouse 2015-03-18 16:18:19 UTC
Note that NTLM single-sign-on can now be provided by GSS-NTLMSSP as well as /usr/bin/ntlm_auth, so once we have GSSAPI support we should probably switch to using it for NTLM single-sign-on too.
Comment 58 Tomas Popela 2015-10-30 08:00:21 UTC
Hi,
I took a work from Guido, rebased it on top of the current master and tried to address the issues that were raised here (and definitely introduced new ones ;) ).

You can find the current code on wip/tpopela/negotiate branch [0].

Dan, can you please look at it?

[0] - https://git.gnome.org/browse/libsoup/log/?h=wip/tpopela/negotiate
Comment 59 David Woodhouse 2015-10-30 20:35:52 UTC
Not working here (with SPNEGO using GSS-NTLMSSP not Kerberos). Here's an example authentication using curl+negotiate...

$ kdestroy; curl -v --negotiate -u : https://pki.intel.com/PkiWeb/ 

> GET /PkiWeb/ HTTP/1.1

< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Negotiate

> GET /PkiWeb/ HTTP/1.1
> Authorization: Negotiate YEAGBisGAQUFAqA2MDSgDjAMBgorBgEEAYI3AgIKoiIEIE5UTE1TU1AAAQAAABeCCKAAAAAAAAAAAAAAAAAAAAAA

< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Negotiate oYIBEzCCAQ+gAwoBAaEMBgorBgEEAYI3AgIKooH5BIH2TlRMTVNTUAACAAAABgAGADgAAAAVgomiwUuqXLvcSNUAAAAAAAAAALgAuAA+AAAABgGxHQAAAA9BAE0AUgACAAYAQQBNAFIAAQAUAEEAWgBTAFAASwBJAFcARQBCADEABAAkAGEAbQByAC4AYwBvAHIAcAAuAGkAbgB0AGUAbAAuAGMAbwBtAAMAOgBBAFoAUwBQAEsASQBXAEUAQgAxAC4AYQBtAHIALgBjAG8AcgBwAC4AaQBuAHQAZQBsAC4AYwBvAG0ABQAcAGMAbwByAHAALgBpAG4AdABlAGwALgBjAG8AbQAHAAgAs39byFET0QEAAAAA

> GET /PkiWeb/ HTTP/1.1
> Authorization: Negotiate oYGwMIGtoAMKAQGigaUEgaJOVExNU1NQAAMAAAAYABgAQAAAABgAGABYAAAABgAGAHAAAAAQABAAdgAAABwAHACGAAAAAAAAAKIAAAAVgomi0SU8l7M13XkAAAAAAAAAAAAAAAAAAAAAHsbqoOURohV2t49uRIhcYBRSnnSW8DEFRwBFAFIAZAB3AG8AbwBkAGgAbwB1AEQAVwBPAE8ARABIAE8AVQAtAEwASQBOAFUAWAA=

< HTTP/1.1 200 OK


And here's the same, attempted with libsoup:

$ ./examples/get -d -N https://pki.intel.com/PkiWeb/ -c /etc/pki/tls/cert.pem 

> GET /PkiWeb/ HTTP/1.1

< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Negotiate

> GET /PkiWeb/ HTTP/1.1
> Authorization: Negotiate YEAGBisGAQUFAqA2MDSgDjAMBgorBgEEAYI3AgIKoiIEIE5UTE1TU1AAAQAAABeCCKAAAAAAAAAAAAAAAAAAAAAA

(lt-get:62142): libsoup-WARNING **: Unspecified GSS failure.  Minor code may provide more information No Kerberos credentials available

(lt-get:62142): libsoup-WARNING **: Unspecified GSS failure.  Minor code may provide more information No Kerberos credentials available
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Negotiate oYIBEzCCAQ+gAwoBAaEMBgorBgEEAYI3AgIKooH5BIH2TlRMTVNTUAACAAAABgAGADgAAAAVgomiz9nHBRzlcJMAAAAAAAAAALgAuAA+AAAABgGxHQAAAA9BAE0AUgACAAYAQQBNAFIAAQAUAEEAWgBTAFAASwBJAFcARQBCADEABAAkAGEAbQByAC4AYwBvAHIAcAAuAGkAbgB0AGUAbAAuAGMAbwBtAAMAOgBBAFoAUwBQAEsASQBXAEUAQgAxAC4AYQBtAHIALgBjAG8AcgBwAC4AaQBuAHQAZQBsAC4AYwBvAG0ABQAcAGMAbwByAHAALgBpAG4AdABlAGwALgBjAG8AbQAHAAgAEZVfMVIT0QEAAAAA
Comment 60 David Woodhouse 2015-10-30 20:37:28 UTC
You need to be feeding that second Negotiate response back into gss_init_sec_context() for the *same* context as the first one. It's a negotiation and you have to handle multiple rounds. Not just send a single 'ticket' and expect it to succeed immediately.
Comment 61 David Woodhouse 2015-11-01 11:26:49 UTC
I note we aren't even ending up in soup_gss_client_step() the second time.
Comment 62 Tomas Popela 2015-11-02 08:03:43 UTC
Thank you David for the feedback and also for another test server as I was testing it against some RH ones and it was working there. Do you recall if the previous version from Guido was working correctly?
Comment 63 Guido Günther 2015-11-02 09:26:31 UTC
As far as I remember I never finished support for several round trips.
Comment 64 Alexander Bokovoy 2015-11-02 11:39:18 UTC
Tomas, I think logic in soup_gss_client_step() is wrong. As David pointed out, you need to call gss_init_sec_context() with the same context as far as you get back maj_stat equal to GSS_S_CONTINUE_NEEDED. This is what actually GSS-API expects you to do.

As an example, see the code in MIT krb5 tests: https://github.com/krb5/krb5/blob/master/src/tests/gss-threads/gss-client.c#L217
Comment 65 David Woodhouse 2015-11-04 17:16:09 UTC
Created attachment 314844 [details] [review]
patch to handle multiple round trips

Not sure how correct this is, but it basically works for my simple testing so I'll attach it as a proof of concept.

In soup_auth_negotiate_add_connection() we distinguish between a plain 'WWW-Authenticate: Negotiate' which instructs us to start negotiation, and the same header but actually carrying a token and continuing an existing session.

We need to fix things so that we only register the got_headers signal handler once, and also stop crashing in check_server_response() if soup_gss_client_step() returns something *other* than AUTH_GSS_COMPLETE while not setting its GError.

I haven't looked at how this copes with GSSAPI authentication being a per-message thing, rather than per-connection. Presumably the second request on a given connection will get 401/WWW-Authenticate: Negotiate... and we'll fail because we've already tried? Or we succeed because we reset the state when the first request succeeded? How would I test that?

Not sure if we need to handle the MS 'Persistent-Auth' header which tells us it's actually done per-connection auth. Or whether we just get away with *not* seeing a 401 on our next request?
Comment 66 Alexander Bokovoy 2016-01-13 16:52:45 UTC
Ok, I finally was able to test David's patch. It worked for me with FreeIPA and Ipsilon setup. Now I need to actually enable Negotiate feature on sessions in webkitgtk so that Epiphany would be able to complete negotiation with Ipsilon:

soup_session_add_feature_by_type(session, SOUP_TYPE_AUTH_NEGOTIATE);

Once done, I can look into other errors David mentions.
Comment 67 Alexander Bokovoy 2016-01-16 22:12:31 UTC
Small update: I had offline discussion with Tomas and he provided me with test builds that made Fedora 23 GNOME version to work fine against both FreeIPA and Red Hat's internal Kerberos infrastructure. There are some issues in automated rebuilds with COPR infra so packages are not available yet for wider testing but hopefully we'll get closer to make this bug fixed real time soon.
Comment 68 David Woodhouse 2016-01-16 22:42:51 UTC
Do you have a test setup that requires multiple round-trips? Typically, Kerberos does not. But GSS-NTLMSSP does.
Comment 69 Dan Winship 2016-02-05 15:24:00 UTC
reviewing wip/tpopela/negotiate commit-by-commit first, and then I'll review the end state afterward

> Rebased Guido Günther's work from [0] on top of 2.52.0

Should probably be "Author: Guido Günther ..." ?

(I didn't actually review this commit yet, but will review it as part of the overall review.)

> Use SPNEGO authentication instead of basic KRB5
> Use GSS_C_NT_HOSTBASED_SERVICE and "HTTP@host" in gss_import_name

David's name is misspelled as "Dawid" in these commit messages.

> wip

Uh, needs a better commit message. :). I guess you're planning to rebase at some point.

>+parse_trusted_uris (void)

>+	for (i = 0; i < g_strv_length (uris); i++) {

would be nice to not call g_strv_length() on every iteration of the loop.

>+		/* Is the supplied URI is valid append it to the list */
>+		if ((uri = soup_uri_new (uris[i])))
>+			trusted_uris = g_slist_append (trusted_uris, uri);

Typo in the comment ("Is" -> "If"). And since the order of trusted_uris doesn't matter, g_slist_prepend() would be better. (OK, in both of these cases, O(n^2) doesn't really matter because n will be small, but I'd still rather have them "right" so people don't copy that code elsewhere later where it does matter.)

>+	/* if the msg host ends with host from the trusted uri, then make
>+	 * sure it is either an exact match, or prefixed with a dot. We

We do basically the same thing in two other places in libsoup (cookies and soup-tld). Would be cool to abstract it...

>+	if (!trusted_uris)
>+                return g_ascii_strncasecmp (msg_uri->scheme, "https", 5) == 0;

return msg_uri->scheme == SOUP_URI_SCHEME_HTTPS

>+	/* FIXME does https://bugzilla.gnome.org/show_bug.cgi?id=755617 apply here as well? */

Yes

> Make the libgssapi a hard dependency of libsoup

There should be an AC_ARG_WITH(krb5), and if with_krb5=yes, then you should AC_MSG_ERROR() if you don't find krb5-config, and if with_krb5=no, then don't even look for krb5-config. And an AC_ARG_WITH(krb5-config-path) would be good too, like the existing AC_ARG_WITH(ntlm-auth-path).

> Include the config.h in the soup-auth.h otherwise Negotiate symbols won't be defined

You can't include config.h from headers that get installed.

We probably want to define SoupAuthNegotiate unconditionally, and just have it not work if libsoup was built without krb5 support. And maybe add a "soup_auth_negotiate_supported" variable or something if people need to be able to figure out if it works. (Like soup_ssl_supported, though that's vestigial now.)

And don't have a -D in the pkg-config file. In particular, people need to check this at run time, not compile time.
Comment 70 David Woodhouse 2016-02-05 15:42:46 UTC
For the autoconf bits, feel free to lift the portable GSSAPI detection/finding bits from http://git.infradead.org/users/dwmw2/openconnect.git/blob/HEAD:/configure.ac#l691

And please refer to it as GSSAPI support, not Kerberos support :)
Comment 71 Dan Winship 2016-02-06 12:38:12 UTC
examples/get.c:

>+               soup_session_add_feature_by_type(session,
>+                                                SOUP_TYPE_AUTH_NEGOTIATE);

space before the "("


libsoup/soup-auth-manager.c:

>@@ -485,6 +489,11 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,

>+#if LIBSOUP_HAVE_GSSAPI
>+       if (SOUP_IS_AUTH_NEGOTIATE (auth))
>+               return;
>+#endif

This shouldn't explicitly reference Negotiate auth: if this is needed, you should add a virtual method "soup_auth_can_authenticate()" or "soup_auth_accepts_password()" or something, and check that here. (And you should check it at the very beginning of authenticate_auth(), not in the middle.) However, it seems like it might be better to just have SoupAuthNegotiate's is_authenticated() always return TRUE? (Or does that have other bad effects?


libsoup/soup-auth-negotiate.c:

>+/* -*- Mode: C; tabstop: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

"tab-width", not "tabstop". (Emacs complains loudly if you try to open the file with a bad variable name there.)

>+#include <gssapi/gssapi.h>
>+#include <gssapi/gssapi_krb5.h>

Is gssapi_krb5.h still used?

>+static const char spnego_OID[] = "\x2b\x06\x01\x05\x05\x02";
>+static const gss_OID_desc gss_mech_spnego = { 6, (void *) &spnego_OID };

static const guint8 spnego_OID[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 };
static const gss_OID_desc gss_mech_spnego = { sizeof (spnego_OID), &spnego_OID };

>+static void
>+remove_server_response_handler (SoupMessage *msg, gpointer state);
>+static void
>+check_server_response (SoupMessage *msg, gpointer state);

no newline after "void"

> +soup_auth_negotiate_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,

I'm not sure if you addressed this comment from comment 47:

> Seeing this part reminds me that there have been some bugfixes to
> soup-auth-ntlm.c since you wrote this, and we need to make sure to copy
> the equivalent fixes over to negotiate.

(particularly the state transitions on error. Some of the changes in the NTLM code may be specific to the external-auth-helper stuff, but I think some aren't.)

>+       if (!check_auth_trusted_uri (negotiate, msg)) {
>+               conn->state = SOUP_NEGOTIATE_FAILED;

It doesn't absolutely necessarily have to happen now, but eventually there needs to be an API for an app to explicitly indicate that a given URI should be trusted as well. (If you configure "exchange.example.com" as your email server, you shouldn't need to also set SOUP_AUTH_TRUSTED_URIS. Also, epiphany might want to allow you to set trusted URIs from within its UI, etc.) It's possible that soup_auth_manager_use_auth() might be this API...

>+       } else if (!strncmp(header, "Negotiate ", 10)) {

space before "("

>+       } else {
>+               g_warning("Bogus hdr '%s'\n", header);

This code can't be reached. At this point, header is guaranteed either to be "Negotiate" or to start with "Negotiate ".

>+soup_auth_negotiate_authenticate (SoupAuth *auth, const char *username,

>+       /* FIXME mark auth as not authenticated */

need to address this (in whatever way makes things work)

>+               g_warning ("%s", err->message);

eventually we need to do something better with these...

>+check_server_response (SoupMessage *msg, gpointer state)

>+       if (ret != AUTH_GSS_COMPLETE) {
>+               if (err)
>+                       g_warning ("%s", err->message);
>+               conn->state = SOUP_NEGOTIATE_FAILED;
>+       }

David's comment about multiple steps still applies, and it may be as simple as just allowing AUTH_GSS_CONTINUE here...


libsoup/soup-status.h:

>+       SOUP_STATUS_GSSAPI_FAILED,

This never gets returned to the user, so it shouldn't be exposed here. Just use some other value instead (like SOUP_STATUS_UNAUTHORIZED).
Comment 72 Tomas Popela 2016-02-06 15:36:29 UTC
Thank you Dan for the review!

(In reply to Dan Winship from comment #69)
> reviewing wip/tpopela/negotiate commit-by-commit first, and then I'll review
> the end state afterward
> 
> > Rebased Guido Günther's work from [0] on top of 2.52.0
> 
> Should probably be "Author: Guido Günther ..." ?
> 
> (I didn't actually review this commit yet, but will review it as part of the
> overall review.)
> 
> > Use SPNEGO authentication instead of basic KRB5
> > Use GSS_C_NT_HOSTBASED_SERVICE and "HTTP@host" in gss_import_name
> 
> David's name is misspelled as "Dawid" in these commit messages.

Sorry David about that :/.

> > wip
> 
> Uh, needs a better commit message. :). I guess you're planning to rebase at
> some point.

I have a different strategy here. I plan to squash the wip/tpopela/negotiate into one commit (with multiple authors specified) and commit it to the master branch afterwards.

> Typo in the comment ("Is" -> "If").

This was already addressed by the commit before the review.

> > Make the libgssapi a hard dependency of libsoup
> 
> There should be an AC_ARG_WITH(krb5), and if with_krb5=yes, then you should
> AC_MSG_ERROR() if you don't find krb5-config, and if with_krb5=no, then
> don't even look for krb5-config. And an AC_ARG_WITH(krb5-config-path) would
> be good too, like the existing AC_ARG_WITH(ntlm-auth-path).

(In reply to David Woodhouse from comment #70)
> For the autoconf bits, feel free to lift the portable GSSAPI
> detection/finding bits from
> http://git.infradead.org/users/dwmw2/openconnect.git/blob/HEAD:/configure.
> ac#l691
> 
> And please refer to it as GSSAPI support, not Kerberos support :)

Thank you David, I will try to use it.

> > Include the config.h in the soup-auth.h otherwise Negotiate symbols won't be defined
> 
> You can't include config.h from headers that get installed.

This was already addressed by the commit before the review.
Comment 73 Tomas Popela 2016-02-06 15:44:39 UTC
(In reply to Dan Winship from comment #71)
> libsoup/soup-auth-manager.c:
> 
> >@@ -485,6 +489,11 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
> 
> >+#if LIBSOUP_HAVE_GSSAPI
> >+       if (SOUP_IS_AUTH_NEGOTIATE (auth))
> >+               return;
> >+#endif
> 
> This shouldn't explicitly reference Negotiate auth: if this is needed, you
> should add a virtual method "soup_auth_can_authenticate()" or
> "soup_auth_accepts_password()" or something, and check that here. (And you
> should check it at the very beginning of authenticate_auth(), not in the
> middle.) However, it seems like it might be better to just have
> SoupAuthNegotiate's is_authenticated() always return TRUE? (Or does that
> have other bad effects?
 
For this we could reuse the "soup_auth_negotiate_supported" variable that we will introduce.
 
> >+static const char spnego_OID[] = "\x2b\x06\x01\x05\x05\x02";
> >+static const gss_OID_desc gss_mech_spnego = { 6, (void *) &spnego_OID };
> 
> static const guint8 spnego_OID[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 };
> static const gss_OID_desc gss_mech_spnego = { sizeof (spnego_OID),
> &spnego_OID };

The cast to (void *) needs to stay there as per https://docs.oracle.com/cd/E19683-01/816-1331/reference-20/index.html otherwise:

soup-auth-negotiate.c:66:68: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-array-qualifiers]
 static const gss_OID_desc gss_mech_spnego = { sizeof (spnego_OID), &spnego_OID };
Comment 74 Tomas Popela 2016-02-06 15:56:24 UTC
(In reply to Tomas Popela from comment #73)
> (In reply to Dan Winship from comment #71)
> > libsoup/soup-auth-manager.c:
> > 
> > >@@ -485,6 +489,11 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
> > 
> > >+#if LIBSOUP_HAVE_GSSAPI
> > >+       if (SOUP_IS_AUTH_NEGOTIATE (auth))
> > >+               return;
> > >+#endif
> > 
> > This shouldn't explicitly reference Negotiate auth: if this is needed, you
> > should add a virtual method "soup_auth_can_authenticate()" or
> > "soup_auth_accepts_password()" or something, and check that here. (And you
> > should check it at the very beginning of authenticate_auth(), not in the
> > middle.) However, it seems like it might be better to just have
> > SoupAuthNegotiate's is_authenticated() always return TRUE? (Or does that
> > have other bad effects?
>  
> For this we could reuse the "soup_auth_negotiate_supported" variable that we
> will introduce.

Sorry I didn't read the comment carefully, so my reply doesn't apply..
Comment 75 Ray Strode [halfline] 2016-02-15 22:00:25 UTC
So I haven't had a chance to look over this patch in detail or try it yet, but I just wanted to point out Allan's Mockups here:

https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin

Note, the UI forces the user to associate a specific kerberos identity with a specific website.  

It would be bad if, after landing this libsoup patch (and the webkit one), any website could return 401/WWW-Authenticate and find out all kerberos realms I currently have a tgt for.  account.gnome.org shouldn't see NSA.GOV etc

Does the patch have that problem?
Comment 76 Alexander Bokovoy 2016-02-16 08:15:31 UTC
(In reply to Ray Strode [halfline] from comment #75)
> So I haven't had a chance to look over this patch in detail or try it yet,
> but I just wanted to point out Allan's Mockups here:
> 
> https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin
Thanks, I was intending to add them here too.

> Note, the UI forces the user to associate a specific kerberos identity with
> a specific website.  
The UI design tries to allow users to make a choice of putting the site to a white or black list with regards to GSSAPI authentication on a first use of that GSSAPI principal against that site.


> It would be bad if, after landing this libsoup patch (and the webkit one),
> any website could return 401/WWW-Authenticate and find out all kerberos
> realms I currently have a tgt for.  account.gnome.org shouldn't see NSA.GOV
> etc
> 
> Does the patch have that problem?
No, it doesn't, and this is by design of GSSAPI Kerberos: you do not communicate with a site until your KDC gave you a ticket to it.

If GNOME.ORG's KDC doesn't know about HTTP/foo.nsa.gov, it will not be able to issue a ticket to it, thus you'll get a failure in libsoup and communication with GSSAPI against foo.nsa.gov will not continue without foo.nsa.gov being able to see anything GSSAPI-related from your side.

However, with GSSAPI SPNEGO running NTLMSSP mechanism this could still cause communication against foo.nsa.gov after asking you about username and password to perform NTLMSSP if corresponding GSSAPI mechanism is available in the system. Luckily, on Linux it could only be in the case of gss-ntlmssp module installed and properly configured to use winbindd, and even then it would be limited to a specific Samba domain that winbindd is running in.
Comment 77 David Woodhouse 2016-02-16 10:20:45 UTC
(In reply to Ray Strode [halfline] from comment #75)
> So I haven't had a chance to look over this patch in detail or try it yet,
> but I just wanted to point out Allan's Mockups here:
> 
> https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin
> 
> Note, the UI forces the user to associate a specific kerberos identity with
> a specific website.  

How does this work when you need GSS-Negotiate but you have no Kerberos identity at all?
Comment 78 David Woodhouse 2016-02-16 10:33:06 UTC
(In reply to Alexander Bokovoy from comment #76)
> If GNOME.ORG's KDC doesn't know about HTTP/foo.nsa.gov, it will not be able
> to issue a ticket to it, thus you'll get a failure in libsoup and
> communication with GSSAPI against foo.nsa.gov will not continue without
> foo.nsa.gov being able to see anything GSSAPI-related from your side.

Is that true even when IAKERB is used? 
 
> However, with GSSAPI SPNEGO running NTLMSSP mechanism this could still cause
> communication against foo.nsa.gov after asking you about username and
> password to perform NTLMSSP if corresponding GSSAPI mechanism is available
> in the system. Luckily, on Linux it could only be in the case of gss-ntlmssp
> module installed and properly configured to use winbindd, and even then it
> would be limited to a specific Samba domain that winbindd is running in.

This paragraph is a little confusing to me. To be clear: GSS-NTLMSSP operates *without* asking the user for a password, if configured appropriately (usually in a system joined to an AD domain).

For NTLM especially, there is merit in limiting which systems you attempt to authenticate to automatically. But *please* do not make the mistake of designing that whitelist/blacklist/whatever to work *only* with Kerberos identities.
Comment 79 Mantas Mikulėnas (grawity) 2016-02-16 10:48:55 UTC
(In reply to Alexander Bokovoy from comment #76)
> (In reply to Ray Strode [halfline] from comment #75)
> > So I haven't had a chance to look over this patch in detail or try it yet,
> > but I just wanted to point out Allan's Mockups here:
> > 
> > https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin
> Thanks, I was intending to add them here too.
> 
> > Note, the UI forces the user to associate a specific kerberos identity with
> > a specific website.  
> The UI design tries to allow users to make a choice of putting the site to a
> white or black list with regards to GSSAPI authentication on a first use of
> that GSSAPI principal against that site.
> 
> 
> > It would be bad if, after landing this libsoup patch (and the webkit one),
> > any website could return 401/WWW-Authenticate and find out all kerberos
> > realms I currently have a tgt for.  account.gnome.org shouldn't see NSA.GOV
> > etc
> > 
> > Does the patch have that problem?
> No, it doesn't, and this is by design of GSSAPI Kerberos: you do not
> communicate with a site until your KDC gave you a ticket to it.
> 
> If GNOME.ORG's KDC doesn't know about HTTP/foo.nsa.gov, it will not be able
> to issue a ticket to it, thus you'll get a failure in libsoup and
> communication with GSSAPI against foo.nsa.gov will not continue without
> foo.nsa.gov being able to see anything GSSAPI-related from your side.


Is it still true when you have tickets from *both* GNOME.ORG and NSA.GOV? Even ignoring cross-realm trusts, recent versions of MIT Krb5 with DIR: ccache format can store a 'collection' of tickets from various separate realms in a single cache. (I use this to access both personal and work servers at once.)
Comment 80 Alexander Bokovoy 2016-02-16 10:52:18 UTC
One more update. If you don't have [domain_realm] translation mapping configured in krb5.conf for the specific domain and realm pair, libkrb5 can try to ask your KDC for a referral to a target service's realm, in case your realm and the target realm have a cross-realm trust established. Your GNOME.ORG KDC then would see a client user@GNOME.ORG asking for a referral for NSA.GOV but as it doesn't know anything about NSA.GOV, the whole flow would stop here.

Of course, this can be considered a privacy leak. The way to avoid it right now is to have explicit mapping between the domain and realm in [domain_realm] that would prevent asking for a cross-realm TGT in the absence of an explicit [capaths] configuration showing that GNOME.ORG does trust directly or indirectly NSA.GOV.

Once cross-realm TGT is obtained, a client will then use it to talk to NSA.GOV KDC to request a service ticket to the original site's service. Your own KDC in GNOME.ORG realm will not be able to see this request as the request will always be done against NSA.GOV's KDCs. All your KDC would see is a request for krbtgt/NSA.GOV@GNOME.ORG.

Going forward, a solution to it would be to use anonymous PKINIT infrastructure to request a TGT as WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS, then attempt to get a cross-realm TGT with it, and analyze if that one is actually obtainable. This would prevent disclosure of an identity to your own KDC who is asking for a cross-realm TGT to NSA.GOV and in case of a success it would give you an ability to provide user with a way to confirm the action prior to requesting HTTP/foo.nsa.gov@NSA.GOV.

The problem with anonymous PKINIT configuration is that (1) not many KDCs support it, and (2) those that support, limit it typically only to a TGT obtained with AS request. FreeIPA currently falls to (1), though I have patches that will make it working for FreeIPA 4.4, but will default to (2) once it ready. The (2), though, would be not prevent us from 'sensing' for a cross-realm TGT which means we can use this method without really exposing the identity of the user.

Below is a small example. I have my KDC configured to accept anonymous PKINIT and I have a cross-realm trust between VDA.LI and SAMBA-AD.VDA.LI realms:
------------------------------------------------------------
$ KRB5CCNAME=./krb5cc.test kinit -n
$ KRB5CCNAME=./krb5cc.test klist -Aef
Ticket cache: FILE:./krb5cc.test
Default principal: WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS

Valid starting       Expires              Service principal
16.02.2016 12.36.03  17.02.2016 12.36.02  krbtgt/VDA.LI@VDA.LI
	Flags: FIAa, Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96 
$ KRB5CCNAME=./krb5cc.test kvno krbtgt/SAMBA-AD.VDA.LI@VDA.LI
kvno: KDC policy rejects request while getting credentials for krbtgt/SAMBA-AD.VDA.LI@VDA.LI
------------------------------------------------------------

On the KDC side I can see in krb5kdc.log:
krb5kdc[12210](info): TGS_REQ (6 etypes {18 17 16 23 25 26}) 192.168.5.136: ANONYMOUS NOT ALLOWED: authtime 0,  WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS for krbtgt/SAMBA-AD.VDA.LI@VDA.LI, KDC policy rejects request

This is due to option 'restrict_anonymous_to_tgt' in kdc.conf:
[kdcdefaults]
restrict_anonymous_to_tgt = true

If I change it to 'false', I'll be able to obtain cross-realm TGT as well:
------------------------------------------------------------
$ KRB5CCNAME=./krb5cc.test kvno krbtgt/SAMBA-AD.VDA.LI@VDA.LI
krbtgt/SAMBA-AD.VDA.LI@VDA.LI: kvno = 1
$ KRB5CCNAME=./krb5cc.test klist -Aef
Ticket cache: FILE:./krb5cc.test
Default principal: WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS

Valid starting       Expires              Service principal
16.02.2016 12.36.03  17.02.2016 12.36.02  krbtgt/VDA.LI@VDA.LI
	Flags: FIAa, Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96 
16.02.2016 12.40.42  17.02.2016 12.36.02  krbtgt/SAMBA-AD.VDA.LI@VDA.LI
	Flags: FATa, Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96 
------------------------------------------------------------

But this is not very practical from security point of view, so with 'restrict_anonymous_to_tgt = true' I can see the difference if a target cross-realm TGT does not exist:
------------------------------------------------------------
$ KRB5CCNAME=./krb5cc.test kvno krbtgt/SAMBA.VDA.LI@VDA.LI
kvno: Server krbtgt/SAMBA.VDA.LI@VDA.LI not found in Kerberos database while getting credentials for krbtgt/SAMBA.VDA.LI@VDA.LI
------------------------------------------------------------
and in KDC logs we would see
krb5kdc[3178](info): TGS_REQ (6 etypes {18 17 16 23 25 26}) 192.168.5.136: UNKNOWN_SERVER: authtime 0,  WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS for krbtgt/SAMBA.VDA.LI@VDA.LI, Server not found in Kerberos database

Thus, using this method I can 'sense' if SAMBA-AD.VDA.LI realm is trusted by VDA.LI without exposing my identity explicitly.

We still aren't there so that's why I asked Allan to sketch a UI for a first user's use of the principal to prevent such situations at UI level. However, even with your GNOME.ORG KDC having trust to NSA.GOV realm, all GNOME.ORG KDC would see is a request for krbtgt/NSA.GOV@GNOME.ORG, not a request to obtain a service ticket to HTTP/foo.nsa.gov@NSA.GOV -- this request will only be seen by NSA.GOV KDCs.
Comment 81 Alexander Bokovoy 2016-02-16 11:09:07 UTC
(In reply to David Woodhouse from comment #78)
> (In reply to Alexander Bokovoy from comment #76)
> > If GNOME.ORG's KDC doesn't know about HTTP/foo.nsa.gov, it will not be able
> > to issue a ticket to it, thus you'll get a failure in libsoup and
> > communication with GSSAPI against foo.nsa.gov will not continue without
> > foo.nsa.gov being able to see anything GSSAPI-related from your side.
> 
> Is that true even when IAKERB is used? 
Current patch to libsoup does not ask for IAKERB mechanism so there is no way upper layers would get forced to do so.

If IAKERB mechanism would be used, no leak to GNOME.ORG KDC would happen either because TGS_REQ would be performed by foo.nsa.gov on behalf the client.


> > However, with GSSAPI SPNEGO running NTLMSSP mechanism this could still cause
> > communication against foo.nsa.gov after asking you about username and
> > password to perform NTLMSSP if corresponding GSSAPI mechanism is available
> > in the system. Luckily, on Linux it could only be in the case of gss-ntlmssp
> > module installed and properly configured to use winbindd, and even then it
> > would be limited to a specific Samba domain that winbindd is running in.
> 
> This paragraph is a little confusing to me. To be clear: GSS-NTLMSSP
> operates *without* asking the user for a password, if configured
> appropriately (usually in a system joined to an AD domain).
You are correct on this.

> For NTLM especially, there is merit in limiting which systems you attempt to
> authenticate to automatically. But *please* do not make the mistake of
> designing that whitelist/blacklist/whatever to work *only* with Kerberos
> identities.
I tried to make sure we use GSSAPI credential principal here, not only Kerberos identities.
Comment 82 Alexander Bokovoy 2016-02-16 11:10:39 UTC
(In reply to Mantas Mikulėnas from comment #79)
> Is it still true when you have tickets from *both* GNOME.ORG and NSA.GOV?
> Even ignoring cross-realm trusts, recent versions of MIT Krb5 with DIR:
> ccache format can store a 'collection' of tickets from various separate
> realms in a single cache. (I use this to access both personal and work
> servers at once.)
Yes, please see my commend #80, as it has more details on what happens in such case and how it could be mitigated.
Comment 83 Alexander Bokovoy 2016-02-16 11:23:23 UTC
(In reply to David Woodhouse from comment #77)
> (In reply to Ray Strode [halfline] from comment #75)
> > So I haven't had a chance to look over this patch in detail or try it yet,
> > but I just wanted to point out Allan's Mockups here:
> > 
> > https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin
> > 
> > Note, the UI forces the user to associate a specific kerberos identity with
> > a specific website.  
> 
> How does this work when you need GSS-Negotiate but you have no Kerberos
> identity at all?
At this stage no request to initialize credentials is made in the UI, this is planned to be done in 3.22. The UI flow is described here: https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin#Ticket_Acquisition
Comment 84 Guido Günther 2016-02-16 12:26:51 UTC
(In reply to Alexander Bokovoy from comment #83)
> (In reply to David Woodhouse from comment #77)
> > (In reply to Ray Strode [halfline] from comment #75)
> > > So I haven't had a chance to look over this patch in detail or try it yet,
> > > but I just wanted to point out Allan's Mockups here:
> > > 
> > > https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin
> > > 
> > > Note, the UI forces the user to associate a specific kerberos identity with
> > > a specific website.  
> > 
> > How does this work when you need GSS-Negotiate but you have no Kerberos
> > identity at all?
> At this stage no request to initialize credentials is made in the UI, this
> is planned to be done in 3.22. The UI flow is described here:
> https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin#Ticket_Acquisition

krb5-auth-dialog has had rudimentary DBUS-API for these kind of things since about 2009. It would only pop up a dialog without a ticket available s.th. similar could be triggered if we find Negotiate header in one of the trusted realms.
Comment 85 Alexander Bokovoy 2016-02-16 12:57:33 UTC
(In reply to Guido Günther from comment #84)
> (In reply to Alexander Bokovoy from comment #83)
> > > How does this work when you need GSS-Negotiate but you have no Kerberos
> > > identity at all?
> > At this stage no request to initialize credentials is made in the UI, this
> > is planned to be done in 3.22. The UI flow is described here:
> > https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin#Ticket_Acquisition
> 
> krb5-auth-dialog has had rudimentary DBUS-API for these kind of things since
> about 2009. It would only pop up a dialog without a ticket available s.th.
> similar could be triggered if we find Negotiate header in one of the trusted
> realms.
It would make sense to file separate bugs to cover all these UI improvements, blocked by this bug.

Matthias recorded some notes from our devconf.cz meeting between Red Hat's desktop teams and FreeIPA developers: https://wiki.gnome.org/MatthiasClasen/KerberosNotes, these are based on the slides I made for it: https://talks.vda.li/talks/2016/desktop-integration-effort-gssapi.pdf, and around the lines of the talks I did at GUADEC'15, FOSDEM'16, and devconf.cz'16.
Comment 86 David Woodhouse 2016-02-16 13:42:13 UTC
(In reply to Alexander Bokovoy from comment #83)
> (In reply to David Woodhouse from comment #77)
> > How does this work when you need GSS-Negotiate but you have no Kerberos
> > identity at all?
>
> At this stage no request to initialize credentials is made in the UI, this
> is planned to be done in 3.22. The UI flow is described here:
> https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin#Ticket_Acquisition

Nono. I think you miss the point.

I don't have a Kerberos TGT.
I don't need a Kerberos TGT.
I don't want a Kerberos TGT.

I only want libsoup to use GSSAPI (and WWW-Authenticate: Negotiate) to authenticate to the server using SPNEGO.
Comment 87 David Woodhouse 2016-02-16 13:47:32 UTC
(In reply to Alexander Bokovoy from comment #81)
> (In reply to David Woodhouse from comment #78)

> > Is that true even when IAKERB is used? 
> Current patch to libsoup does not ask for IAKERB mechanism so there is no
> way upper layers would get forced to do so.

The current patch to libsoup asks for SPNEGO, doesn't it? It certainly *should*. 

And MIT Kerberos (as shipped by Fedora at least) will attempt IAKERB automatically unless it's explicitly disabled. Does that not leak information about which Kerberos realms the client is a membor of, even when the server has no service principal within those realms?
Comment 88 Alexander Bokovoy 2016-02-16 14:58:48 UTC
(In reply to David Woodhouse from comment #86)
> (In reply to Alexander Bokovoy from comment #83)
> > (In reply to David Woodhouse from comment #77)
> > > How does this work when you need GSS-Negotiate but you have no Kerberos
> > > identity at all?
> >
> > At this stage no request to initialize credentials is made in the UI, this
> > is planned to be done in 3.22. The UI flow is described here:
> > https://wiki.gnome.org/Design/Whiteboards/EnterpriseLogin#Ticket_Acquisition
> 
> Nono. I think you miss the point.
> 
> I don't have a Kerberos TGT.
> I don't need a Kerberos TGT.
> I don't want a Kerberos TGT.
> 
> I only want libsoup to use GSSAPI (and WWW-Authenticate: Negotiate) to
> authenticate to the server using SPNEGO.
This should work already with the patches to libsoup/webkitgtk, isn't it? You said it should not also be asking username/password on a configured system too.

(In reply to David Woodhouse from comment #87)
> (In reply to Alexander Bokovoy from comment #81)
> > (In reply to David Woodhouse from comment #78)
> 
> > > Is that true even when IAKERB is used? 
> > Current patch to libsoup does not ask for IAKERB mechanism so there is no
> > way upper layers would get forced to do so.
> 
> The current patch to libsoup asks for SPNEGO, doesn't it? It certainly
> *should*. 
> 
> And MIT Kerberos (as shipped by Fedora at least) will attempt IAKERB
> automatically unless it's explicitly disabled. Does that not leak
> information about which Kerberos realms the client is a membor of, even when
> the server has no service principal within those realms?
IAKERB will be used if corresponding mechanism is requested. libsoup() calls gss_inquire_cred() with NULL for list of requested mechanisms which causes libkrb5 to use the first mechanism defined for the GSSAPI module. In case of Kerberos, it would be krb5 mech glue. See gss_inquire_cred() implementation:
-----------------------------------------------------------------
    /* Determine mechanism and mechanism credential. */
    if (cred_handle != GSS_C_NO_CREDENTIAL) {
        union_cred = (gss_union_cred_t) cred_handle;
        if (union_cred->count <= 0)
            return (GSS_S_DEFECTIVE_CREDENTIAL);
        mech_cred = union_cred->cred_array[0];
        mech = gssint_get_mechanism(&union_cred->mechs_array[0]);
    } else {
        union_cred = NULL;
        mech_cred = GSS_C_NO_CREDENTIAL;
        mech = gssint_get_mechanism(GSS_C_NULL_OID);
    }
-----------------------------------------------------------------

In our case cred_handle will be GSS_C_NO_CREDENTIAL and thus gssint_get_mechanism(GSS_C_NULL_OID) will be called. The latter will do following:
-----------------------------------------------------------------

        /* Check if the mechanism is already loaded. */
        aMech = g_mechList;
        if (oid == GSS_C_NULL_OID)
                oid = aMech->mech_type;
        while (aMech != NULL) {
                if (g_OID_equal(aMech->mech_type, oid) && aMech->mech) {
                        k5_mutex_unlock(&g_mechListLock);
                        return aMech->mech;
                } else if (aMech->int_mech_type != GSS_C_NO_OID &&
                           g_OID_equal(aMech->int_mech_type, oid)) {
                        k5_mutex_unlock(&g_mechListLock);
                        return aMech->int_mech;
                }
                aMech = aMech->next;
        }
-----------------------------------------------------------------

e.g. it will return the first mechanism defined for the module. Thus, libsoup negotiate support will never get to iakerb.
Comment 89 David Woodhouse 2016-02-16 15:15:40 UTC
(In reply to Alexander Bokovoy from comment #88)
> (In reply to David Woodhouse from comment #86)
> > I only want libsoup to use GSSAPI (and WWW-Authenticate: Negotiate) to
> > authenticate to the server using SPNEGO.
> This should work already with the patches to libsoup/webkitgtk, isn't it?
> You said it should not also be asking username/password on a configured
> system too.

Yes, this *currently* works fine with the patches discussed above. I'm just concerned by the following sentence, from comment 75:

"Note, the UI forces the user to associate a specific kerberos identity with a specific website."

That sounds very much like someone *forgot* that GSSAPI isn't just for Kerberos, and was about to break things for non-Kerberos GSSAPI usage. I was just trying to ensure that didn't happen.

> e.g. it will return the first mechanism defined for the module. Thus,
> libsoup negotiate support will never get to iakerb.

Yes, but when that mechanism *fails*, because the KDC has no matching SPN for the server we're trying to talk to, don't we fall back to the next mechanisms in the list? Which include GSS-NTLMSSP and IAKERB.

I've *seen* Firefox attempting IAKERB when the basic KRB5 mechanism fails. And none of that is application-specific — Firefox is just asking for SPNEGO and not messing with the underlying list of enabled mechanisms, just like libsoup.
Comment 90 Alexander Bokovoy 2016-02-16 15:43:31 UTC
According to https://git.gnome.org/browse/libsoup/tree/libsoup/soup-auth-negotiate.c?h=wip/tpopela/negotiate#n514, current implementation only uses gss_mech_spnego to request for when talking to a remote server. This means no IAKERB is explicitly asked, only standard krb5 oid (or the wrong krb5 oid) and NTLMSSP are used.

I agree with you on the UI changes which need to make sure GSSAPI principal is used there and properly translated into a native form by gss_display_name() without assumption it is only a Kerberos principal.
Comment 91 David Woodhouse 2016-02-16 16:04:22 UTC
(In reply to Alexander Bokovoy from comment #90)
> According to
> https://git.gnome.org/browse/libsoup/tree/libsoup/soup-auth-negotiate.
> c?h=wip/tpopela/negotiate#n514, current implementation only uses
> gss_mech_spnego to request for when talking to a remote server. This means
> no IAKERB is explicitly asked, only standard krb5 oid (or the wrong krb5
> oid) and NTLMSSP are used.

Hm, isn't that exactly what Firefox is doing too? And I've definitely seen MIT Krb5 attempting IAKERB within Firefox...
Comment 92 Alexander Bokovoy 2016-02-16 16:20:06 UTC
It is a bit more complex. Firefox implements several authentication packages in nsAuthFactory, there is pure Kerberos one ("kerb-gss"), there is SPNEGO-based one ("negotiate-gss"). Depending on a platform and user preferences it does select a proper authentication factory at runtime.
Comment 93 David Woodhouse 2016-02-16 16:23:57 UTC
(In reply to Alexander Bokovoy from comment #92)
> It is a bit more complex. Firefox implements several authentication packages
> in nsAuthFactory, there is pure Kerberos one ("kerb-gss"), there is
> SPNEGO-based one ("negotiate-gss"). Depending on a platform and user
> preferences it does select a proper authentication factory at runtime.

If what you say above is true, surely *neither* kerb-gss nor negotiate-gss would have used IAKERB?
Comment 94 Alexander Bokovoy 2016-02-16 18:18:56 UTC
(In reply to David Woodhouse from comment #93)
> (In reply to Alexander Bokovoy from comment #92)
> > It is a bit more complex. Firefox implements several authentication packages
> > in nsAuthFactory, there is pure Kerberos one ("kerb-gss"), there is
> > SPNEGO-based one ("negotiate-gss"). Depending on a platform and user
> > preferences it does select a proper authentication factory at runtime.
> 
> If what you say above is true, surely *neither* kerb-gss nor negotiate-gss
> would have used IAKERB?
'kerb-gss' is enforcing use of gss_krb5_mech_oid, 'negotiate-gss' is enforcing use of gss_spnego_mech_oid, that's the difference. For MIT Kerberos 5 implementation this means different GSSAPI mechanisms will be loaded. 

So I looked deeper at this.

As you may ask for different Kerberos oids in your SPNEGO tunneling, IAKERB may occur there. But currently IAKERB is not the preferred mechanism negotiated via SPNEGO; initiators should request it explicitly. If the initiator has a ticket for the target service, then IAKERB will be skipped, even if the IAKERB mechanism was requested. 

However, SPNEGO only chooses those mechanisms for which it could obtain credentials. This means that if we don't have a ticket, krb5 mech would be skipped and IAKERB would be skipped as well in case if there is no way to specify credentials, e.g. if SPENGO was provided with a credential from gss_acquire_cred(), not gss_acquire_cred_from() or gss_acquire_cred_with_password() for Kebreros case. But in those cases gss_acquire_cred_*() calls would directly request TGT from the KDC.

For properly configured NTLMSSP use of it inside SPNEGO would just work, but not for IAKERB unless an initiator is doing something special to use it.

This can be demonstrated with gss-client/gss-server demo applications provided with MIT Kerberos 5 packages:

[on the server side]
# KRB5_TRACE=/dev/stderr gss-server -port 12800 -keytab /etc/httpd/conf/ipa.keytab -iakerb HTTP@id.vda.li
starting...

[on the client side]
$ KRB5CCNAME=/tmp/does-not-exist  KRB5_TRACE=/dev/stderr gss-client -port 12800 -spnego -iakerb id.vda.li HTTP@id.vda.li foo
GSS-API error setting neg mechs: A required input parameter could not be read
GSS-API error setting neg mechs: No credentials were supplied, or the credentials were unavailable or inaccessible
GSS-API error setting neg mechs: (null)

[server side said for this]
reading token flags: 0 bytes read

[client side again]
$ KRB5CCNAME=/tmp/does-not-exist  KRB5_TRACE=/dev/stderr gss-client -port 12800 -krb5 id.vda.li HTTP@id.vda.li foo
GSS-API error initializing context: Unspecified GSS failure.  Minor code may provide more information
GSS-API error initializing context: No Kerberos credentials available (default cache: /tmp/does-not-exist)

[server side said for this]
reading token flags: 0 bytes read

[client side again]
$ KRB5CCNAME=/tmp/does-not-exist  KRB5_TRACE=/dev/stderr gss-client -port 12800 -spnego  id.vda.li HTTP@id.vda.li foo
Sending init_sec_context token (size=66)...continue needed...reading token flags: 0 bytes read

[server side said for this]
Received token (size=66): 
60 40 06 06 2b 06 01 05 05 02 a0 36 30 34 a0 0e 
30 0c 06 0a 2b 06 01 04 01 82 37 02 02 0a a2 22 
04 20 4e 54 4c 4d 53 53 50 00 01 00 00 00 17 82 
08 a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 
GSS-API error accepting context: No credentials were supplied, or the credentials were unavailable or inaccessible
GSS-API error accepting context: Unknown error

As you can see, when I force IAKERB from the initiator side (gss-client), if there are no credentials, nothing can be done because SPNEGO mechanism filters out those mechs which would not be possible to use with a credential that was passed to SPNEGO.

If I add -user/-password pair to gss-client, the app will first try to obtain the ticket from the KDC and then will successfully complete the SPNEGO with krb5 mechanism but we are not interested in that. IAKERB is not used in any other case either.

Again, gss-client and gss-server do force using IAKERB if asked. libsoup or Firefox don't.
Comment 95 David Woodhouse 2016-02-16 19:47:58 UTC
I suspect this digression is making too much noise in the bug and we should take it to email. But I was seeing IAKERB used when I *did* have a TGT (and before I had GSS-NTLMSSP implemented as an alternative to fall back to). It happened when direct communication with the KDC showed that there was no matching SPN to obtain a service ticket for. Quite why we thought IAKERB would help, I have no idea. But that's what was happening. cf. https://bugzilla.redhat.com/1117963 which was IAKERB, I think. And there were others...
Comment 96 Tomas Popela 2016-03-03 14:27:22 UTC
Created attachment 322984 [details] [review]
Final patch

Here is the final patch to commit. It was reviewed by Dan, Alexander and Simo as well.
Comment 97 Brian J. Murrell 2016-03-03 14:58:26 UTC
(In reply to Tomas Popela from comment #96)
> 
> Here is the final patch to commit. It was reviewed by Dan, Alexander and
> Simo as well.

I have to admit that this makes me a little giddy.

Does this now require GNOME tools to conform and use any new interfaces or will they all just automatically get this SSO love?

I'm dreaming of the day that I can greatly simplify my proxy configuration to remove all of the whitelisting that was necessary because of the lack of available authentication.

Nice work everyone!
Comment 98 Tomas Popela 2016-03-03 15:16:29 UTC
(In reply to Brian J. Murrell from comment #97)
> Does this now require GNOME tools to conform and use any new interfaces or
> will they all just automatically get this SSO love?

Libsoup consumers needs to explicitly enable it in the SoupSession that they are using. Once it will be enabled in WebKitGtk+ the Epiphany, WebKit2 port of Midori, Gnome Online Accounts and others can use it.
Comment 99 Dan Winship 2016-03-13 15:28:15 UTC
Comment on attachment 322984 [details] [review]
Final patch

>Subject: [PATCH 1/1] Bug 587145 - please add GSS-Negotiate support

can you just change this to "Add GSS-Negotiate support" ?

I realized docs are missing; I'll attach another patch in a second, and then you can squash them together and push it.
Comment 100 Dan Winship 2016-03-13 15:54:22 UTC
Created attachment 323799 [details] [review]
fixup! Bug 587145 - please add GSS-Negotiate support

for API consistency, we need to G_DEFINE_TYPE SoupAuthNegotiate
whether or not we have GSSAPI support
Comment 101 Dan Winship 2016-03-13 15:54:48 UTC
Created attachment 323800 [details] [review]
fixup! Bug 587145 - please add GSS-Negotiate support

add docs

(Doesn't actually completely work: soup_auth_negotiate_supported
doesn't end up in the docs for some reason? Shrug.)
Comment 102 Tomas Popela 2016-03-14 10:22:50 UTC
Created attachment 323846 [details] [review]
Final patch with docs fixes

Changes in this patch:
 * change the subject of the patch
 * incorporate the changes from Dan
 * add soup_auth_can_authenticate to docs
 * remove the SOUP_AVAILABLE_IN_2_54 macro from the soup_auth_negotiate_supported
   declaration as it is preventing its inclusion in the docs
Comment 103 Dan Winship 2016-03-14 12:13:36 UTC
Created attachment 323861 [details] [review]
fixup! Bug 587145 - Add GSS-Negotiate support

Can't remove SOUP_AVAILABLE_IN_2_54 from soup_auth_negotiate_available
or else it doesn't get exported... we can figure this out better later.
Comment 104 Tomas Popela 2016-03-14 14:05:33 UTC
Created attachment 323871 [details] [review]
Final patch

Changes in the latest patch:
 * Incorporated changes from Dan
 * If the GSS-Negotiate support is not enabled set its strength to 0
 * Rework the soup_auth_negotiate_supported to be function instead of variable
Comment 105 Tomas Popela 2016-03-14 14:08:18 UTC
Fixed with the following commit:

commit 6a8826f0d25459c943719b88f22619f22b81c547
Author: Guido Guenther <agx@sigxcpu.org>
Date:   Wed Mar 2 15:20:16 2016 +0100

    Bug 587145 - Add GSS-Negotiate support
    
    If a "WWW-Authenticate: Negotiate" HTTP header is spotted libsoup will check if
    the host is on blacklist and the authentication fails if so. Otherwise the host
    is compared against a trusted URIs (if the trusted URIs list is not set all
    the HTTPS requests are trusted by default) and then processed. The trusted URIs
    list and blacklist are both created when a SoupNegotiateAuth is created. The
    trusted URIs list (blacklist) is parsed from the SOUP_GSSAPI_TRUSTED_URIS (
    SOUP_GSSAPI_BLACKLIST_URIS) environment variable that expects the URIs be comma
    separated (e.g. "http://www.example.com,https://www.test.com:80"). Then the
    request is processed by the GSS library (the SPNEGO mechanism is used) which
    produces a token that is send back to the server in the next request. The reply
    is then again processed by the GSS library and the authentication succeeds by
    receiving the GSS_S_COMPLETE status or we continue negotiating when the
    GSS_S_CONTINUE_NEEDED is received.
    
    The SoupAuth object is marked as not authenticated if a user will try to call
    the soup_auth_authenticate() with the credentials provided as this is not
    supported.
    
    If the libsoup is configured with GSS-Negotiate support, a Kerberos library with
    GSSAPI support needs to be available on the system (MIT Kerberos was tested
    while working on this). Developers can check whether the libsoup was
    compiled with the GSS-Negotiate support enabled by checking the
    soup_auth_negotiate_supported() function.
    
    To easily test the GSS-Negotiate functionality a new argument "N" was added to
    the examples/get utility.
    
    A support for NTLMSSP is provided by this patch given that a Kerberos library
    supports NTLMSSP mechanism via GSSAPI. For MIT Kerberos one can use gss-ntlmssp
    module, https://fedorahosted.org/gss-ntlmssp/.
    
    Co-Authored-By: Tomas Popela <tpopela@redhat.com>
    Co-Authored-By: David Woodhouse <dwmw2@infradead.org>
    Co-Authored-By: Dan Winship <danw@gnome.org>
Comment 106 David Woodhouse 2016-03-14 16:23:59 UTC
Tested with NTLMSSP auth, seems to work fine (after I downgrade Fedora's krb5-libs package, but I'm not blaming you for that). Thanks.
Comment 107 Brian J. Murrell 2016-07-03 01:58:43 UTC
Are there any docs/examples that I can use or point other developers at as to what they need to do with their apps to make them get the SSO love that this wonderful work provides?
Comment 108 Brian J. Murrell 2016-07-03 02:27:34 UTC
So, if I build examples/get, am I supposed to be able to do:

$ ./get -p http://proxy:3128/ -N http://www.google.com/

and Negotiate authentication should be done with the proxy at "proxy:3128"?  Because for me, the result of the above is:
 
/: 407 Proxy Authentication Required

Surely the problem is PEBKAC here but I'm not sure what it is.

This is on Fedora 24 which AFAICT, should have this patch in it now.

Of course, I have tickets for the realm that proxy is in.  Chrome works fine with them, for example.
Comment 109 Dan Winship 2016-07-05 15:03:56 UTC
This patch didn't cover proxy authentication; there's a bug for that (bug 601031) but no one is working on it that I know of. Patches would be welcome.
Comment 110 Brian J. Murrell 2016-07-06 19:54:31 UTC
(In reply to Dan Winship from comment #109)
> This patch didn't cover proxy authentication;

Oh, pity.  :-(

> there's a bug for that (bug
> 601031)

Oh, I know the reporter on that one.  He's a really great guy.  :-)

So it seems that I knew at some point that there was separation between this work and that work.
Comment 111 Brian J. Murrell 2016-07-06 20:13:06 UTC
So is proof that this is working that epiphany will authenticate me to a website (freeipa for example) using my kerberos tickets?  It must be.  I can't imagine how I would be authenticating otherwise since I don't get prompted or anything.

But yeah, Proxy-Authenticate is what I really want.

Does the work landed here make that any easier?
Comment 112 Dan Winship 2016-07-11 14:02:07 UTC
Well, this doesn't get us any closer to proxy-auth-via-NTLM, but it means that proxy-auth-via-Negotiate is now just as easy/hard as proxy-auth-via-NTLM.
Comment 113 Debarshi Ray 2017-01-06 18:00:14 UTC
*** Bug 758333 has been marked as a duplicate of this bug. ***
Comment 114 Debarshi Ray 2018-04-17 10:06:09 UTC
*** Bug 698817 has been marked as a duplicate of this bug. ***