Closed Bug 1248564 Opened 4 years ago Closed 4 years ago

Default authentication credentials (NTLM, Kerb) used in private mode

Categories

(Core :: Networking: HTTP, defect)

defect
Not set

Tracking

()

RESOLVED FIXED
mozilla48
Tracking Status
firefox48 --- fixed

People

(Reporter: jhorak, Assigned: jhorak)

References

Details

(Whiteboard: [necko-backlog][ntlm])

Attachments

(1 file, 4 obsolete files)

The WWW-Authenticate Response is sent when Firefox is in private mode which is most likely not expected by users. We should avoid sending any WWW-Authenticate response in private mode.
Can you provide a test case/STR so we can reproduce?
STR:
1) set up your Integrated Authentication by steps mentioned: https://developer.mozilla.org/en/docs/Integrated_Authentication 
2) obtain your ticket
3) open private window
4) access to site which send WWW-Authenticate: Negotiate header (use Kerberos or NTLM)
5) site opens as user was sign on while it should not

I'm not sure if Mozilla is using Kerberos somewhere, if so, trying to open page in private window which use Kerberos to authenticate should be sufficient to reproduce this bug.
You can use public FreeIPA demo instance to authenticate against it. All you need is to set krb5.conf to work against it and add '.demo1.freeipa.org' to the list of trusted domains in network.negotiate-auth.trusted-uris.

Just add a following to your krb5.conf:
---------------------------------------
[libdefaults]
 default_realm = DEMO1.FREEIPA.ORG

[realms]
  DEMO1.FREEIPA.ORG = {
    kdc = ipa.demo1.freeipa.org
  }

[domain_realm]
  .demo1.freeipa.org = DEMO1.FREEIPA.ORG
  demo1.freeipa.org = DEMO1.FREEIPA.ORG
----------------------------------------

and you'll be able to obtain tickets for the users defined on the page:

$ export KRB5_CONFIG=$(pwd)/my.krb5.conf
$ export KRB5CCNAME=$(pwd)/my.krb5cc.test
$ kinit admin
<enter password from the page http://www.freeipa.org/page/Demo>
$ mkdir $(pwd)/firefox.profile.test
$ echo 'user_pref("network.negotiate-auth.trusted-uris", ".demo1.freeipa.org");' >>firefox.profile.test/prefs.js
$ export NSPR_LOG_MODULES=negotiateauth:5
$ export NSPR_LOG_FILE=$(pwd)/my.firefox.log
$ firefox -private -new-instance -no-remote --profile $(pwd)/firefox.profile.test https://ipa.demo1.freeipa.org/ipa/session/login_kerberos
$ cat $(pwd)/my.firefox.log
2059835200[7fb4798ab4a0]:   service = ipa.demo1.freeipa.org
2059835200[7fb4798ab4a0]:   using negotiate-gss
2059835200[7fb4798ab4a0]: entering nsAuthGSSAPI::nsAuthGSSAPI()
2059835200[7fb4798ab4a0]: Attempting to load gss functions
2059835200[7fb4798ab4a0]: entering nsAuthGSSAPI::Init()
2059835200[7fb4798ab4a0]: nsHttpNegotiateAuth::GenerateCredentials() [challenge=Negotiate]
2059835200[7fb4798ab4a0]: entering nsAuthGSSAPI::GetNextToken()
2059835200[7fb4798ab4a0]:   leaving nsAuthGSSAPI::GetNextToken [rv=0]
2059835200[7fb4798ab4a0]:   Sending a token of length 1220

You will get an error on the web site, that's fine, because we are not accessing a user-visible part of the site, but the firefox log will show you that firefox actually tried and obtained a Kerberos ticket and sent it to the IPA server. You can verify it with klist:
$ firefox -private -new-instance -no-remote --profile $(pwd)/firefox.profile.test https://ipa.demo1.freeipa.org/ipa/session/login_kerberos
$ klist
Ticket cache: FILE:/home/abokovoy/tmp/my.krb5cc.test
Default principal: admin@DEMO1.FREEIPA.ORG

Valid starting       Expires              Service principal
16.02.2016 16.02.33  17.02.2016 16.02.30  krbtgt/DEMO1.FREEIPA.ORG@DEMO1.FREEIPA.ORG
16.02.2016 16.02.40  17.02.2016 16.02.30  HTTP/ipa.demo1.freeipa.org@DEMO1.FREEIPA.ORG

Thre is HTTP/ipa.demo1.freeipa.org@DEMO1.FREEIPA.ORG service ticket is present in the ccache while we were in the private browse mode.
Would be great to have the testcase also available for Windows users (AFAIK Honza is a Windows guy ;-))
Seems like it's just about adding a "is in private mode" check to nsHttpNTLMAuth.cpp!CanUseDefaultCredentials.
Summary: WWW-Authenticate Response is send when in private mode → Automatic integrated authentication credentials used in private mode
Summary: Automatic integrated authentication credentials used in private mode → Default authentication credentials (NTLM, Kerb) used in private mode
Whiteboard: [necko-backlog][ntlm]
Assignee: nobody → honzab.moz
Status: NEW → ASSIGNED
Fixing it in nsHttpNTLMAuth.cpp!CanUseDefaultCredentials is not enough for WWW Authenticate: negotiate headers. Attaching fix which should address it, however I'm not able to test NTLM changes. Please have a look.

Try run: https://treeherder.mozilla.org/#/jobs?repo=try&revision=9f5578ba4c06
Attachment #8721374 - Flags: feedback?(honzab.moz)
Comment on attachment 8721374 [details] [diff] [review]
do-not-authenticate-in-private-mode v1

Review of attachment 8721374 [details] [diff] [review]:
-----------------------------------------------------------------

::: extensions/auth/nsHttpNegotiateAuth.cpp
@@ +93,5 @@
>                                         nsISupports **continuationState,
>                                         bool *identityInvalid)
>  {
> +    // Do not use Negotiate auth in private mode
> +    NS_ENSURE_TRUE(CanProcessNegotiateAuth(authChannel), NS_ERROR_NOT_AVAILABLE);

I don't understand the purpose - why do you want to block Negoate at all when in PB mode ???


This bug is just about default creds being sent out.

@@ +204,5 @@
>                                           uint32_t *flags,
>                                           char **creds)
>  {
> +    // Do not use Negotiate auth in private mode
> +    NS_ENSURE_TRUE(CanProcessNegotiateAuth(authChannel), NS_ERROR_NOT_AVAILABLE);

same here...

::: netwerk/protocol/http/nsHttpNTLMAuth.cpp
@@ +189,5 @@
>  {
> +    // Do not try to logging with default credentials when in private mode
> +    nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(channel);
> +    if (NS_UsePrivateBrowsing(bareChannel))
> +        return false;

if () {
}
Attachment #8721374 - Flags: feedback?(honzab.moz) → feedback-
My original report was about responding to WWW-Authenticate header in private mode. I should specify it more closely like, responding to WWW-Authenticate: negotiate. Sorry about that.

We think that sending the same kerberos ticket in normal and private mode breaks privacy. Kerberos ticket is something which one can consider private data and user might not expect that they ticket can be send while using private mod.
(In reply to Jan Horak from comment #8)
> My original report was about responding to WWW-Authenticate header in
> private mode. I should specify it more closely like, responding to
> WWW-Authenticate: negotiate. Sorry about that.

Our intend is to NOT send any cached credentials in response automatically.  When there are session-cached credentials, then (in non PB mode) we prefill Authorization header on every requests it applies to.  When you open a PB window, the credentials cache (AFAIK) is not used, so users have to reenter credentials again.  This applies to any schema.

> 
> We think that sending the same kerberos ticket in normal and private mode
> breaks privacy. Kerberos ticket is something which one can consider private
> data and user might not expect that they ticket can be send while using
> private mod.

Maybe I misunderstand something.  

The bug is about not letting NTLM to use default user credentials in PB mode.  The change to CanUseDefaultCredentials does that.

In PB mode, we don't use any previously cached credentials.  If you authenticate a Negotiate session via kerberos in non-PB windows, then switching to PB will not reuse the ticket.  The cached credentials are simply not found.  We isolate the caches for PB and non-PB.

So, making nsHttpNegotiateAuth::ChallengeReceived hard-fail in PB mode is IMO crazy.  

You still can set credentials as you want (or simply press cancel) in a PB window.  That authenticated session tho will then be a different session than the one established in a non-PB window.

If you believe not, then we need to find out why.
I can't speak of NTLM, but when using WWW-authenticate: negotiate method (like SSPI or GSS) and having it configured in your profile according to [1]  then there is no difference whenever you are in private mode or not. It both works now. The PB only affects the cache, as seen there [2] - by the mIsPrivate variable.  If the cache is not hit, it simply continue to the nsHttpNegotiateAuth implementation [3] and start to negotiate by sending (for example) kerberos token. We think that it should not happen in PB. 

The patch disables using negotiate in PB completely. Servers usually fallback to baseauth (maybe Alexander could verify this statement) which when filled, it is cashed in the current PB session and is later reused if required.

[1] https://developer.mozilla.org/en/docs/Integrated_Authentication
[2] http://mxr.mozilla.org/mozilla-central/source/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
[3] http://mxr.mozilla.org/mozilla-central/source/extensions/auth/nsHttpNegotiateAuth.cpp
And it seems that user is not prompt for Kerberos credentials, because it does not have no API for that, see comment:
http://mxr.mozilla.org/mozilla-central/source/extensions/auth/nsHttpNegotiateAuth.cpp#72

From my experience servers usually fallback to WWW-authenticate: baseauth. That's why prompt show up when negotiate for some reason fails.
When we talk about "it does not have API", what API do you mean by that? 

GSSAPI has extensions that allow to obtain credentials with a password, gss_acquire_cred_with_password().

SSPI has SspiPromptForCredentials() (https://msdn.microsoft.com/en-us/library/windows/desktop/dd401714%28v=vs.85%29.aspx) to request Windows to pop-up a dialog to obtain credentials.

However, this bug is about PB mode negotiating authentication automatically against sites allowed to use GSSAPI/SSPI in case there are default credentials available. What I'd like to see is to prevent this automated leak of authentication in PB mode unless user has an explicit way to allow it.
Thanks for all the detailed info.  I think I understand more what needs to be done here.

For NTLM we want to disallow sending default credentials.  That the patch v1 does correctly.

For Negotiate, as there is no code for prompting the user (and we don't intend to implement it) and we simply go always to the AD server, the whole negotiate process has to be bypassed.  The patch outlines the idea, but does it wrong.

The correct way is to add TestPBMode(authChannel) function at this place:
http://hg.mozilla.org/mozilla-central/annotate/d848a5628d80/extensions/auth/nsHttpNegotiateAuth.cpp#l116

|allowed| should be false when in PB mode simply.  You can also add a preference allowing use of Negotiate in PB mode.
Assignee: honzab.moz → jhorak
Thanks for pointing me to the right direction. Please have a look.
Attachment #8721374 - Attachment is obsolete: true
Attachment #8724067 - Flags: review?(honzab.moz)
Comment on attachment 8724067 [details] [diff] [review]
do-not-authenticate-in-private-mode2.patch

Review of attachment 8724067 [details] [diff] [review]:
-----------------------------------------------------------------

Looks good.  I'll quickly check the final version to be landed.

::: extensions/auth/nsHttpNegotiateAuth.cpp
@@ +55,5 @@
>  //-----------------------------------------------------------------------------
>  
> +// Return false when channel belongs to Private browsering.
> +static bool
> +TestPBMode(nsIHttpAuthenticableChannel *authChannel)

TestNotInPBMode?

@@ +58,5 @@
> +static bool
> +TestPBMode(nsIHttpAuthenticableChannel *authChannel)
> +{
> +    nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(authChannel);
> +    if (NS_UsePrivateBrowsing(bareChannel)) {

See CanUseDefaultCredentials, add the same assertion

@@ +61,5 @@
> +    nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(authChannel);
> +    if (NS_UsePrivateBrowsing(bareChannel)) {
> +        return false;
> +    }
> +    return true;

just do:

return !NS_UsePrivateBrowsing(..);

::: netwerk/protocol/http/nsHttpNTLMAuth.cpp
@@ +188,5 @@
>                           bool isProxyAuth)
>  {
> +    // Do not try to logging with default credentials when in private mode
> +    nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(channel);
> +    if (NS_UsePrivateBrowsing(bareChannel))

add MOZ_ASSERT(bareChannel)

it's always expected the object impls this interface, but we want to express it this way even more.

@@ +189,5 @@
>  {
> +    // Do not try to logging with default credentials when in private mode
> +    nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(channel);
> +    if (NS_UsePrivateBrowsing(bareChannel))
> +        return false;

if () {
}
Attachment #8724067 - Flags: review?(honzab.moz) → feedback+
Thanks for the feedback. I hope I've addressed all your comments. Please have a look.

Another try run: https://treeherder.mozilla.org/#/jobs?repo=try&revision=67e5e66afff0
Attachment #8724067 - Attachment is obsolete: true
Attachment #8727395 - Flags: review?(honzab.moz)
Fixed typo in comment.
Attachment #8727395 - Attachment is obsolete: true
Attachment #8727395 - Flags: review?(honzab.moz)
Attachment #8727397 - Flags: review?(honzab.moz)
Comment on attachment 8727397 [details] [diff] [review]
do-not-authenticate-in-private-mode2.patch

Review of attachment 8727397 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks! Please just update the comments as suggested.

::: extensions/auth/nsHttpNegotiateAuth.cpp
@@ +53,5 @@
>  #define kNegotiateLen  (sizeof(kNegotiate)-1)
>  
>  //-----------------------------------------------------------------------------
>  
> +// Return false when channel belongs to Private browsing.

Return false when the channel comes from a Private browsing window.

::: netwerk/protocol/http/nsHttpNTLMAuth.cpp
@@ +186,5 @@
>  static bool
>  CanUseDefaultCredentials(nsIHttpAuthenticableChannel *channel,
>                           bool isProxyAuth)
>  {
> +    // Do not try to logging with default credentials when in private mode

Prevent using default credentials for authentication when we are in the private browsing mode.  It would cause a privacy data leak.
Attachment #8727397 - Flags: review?(honzab.moz) → review+
Thanks for the review, attaching patch with fixed comments. Copying review+ from previous patch.

Rerun try build because I was worried about previous Windows XP/8 results: https://treeherder.mozilla.org/#/jobs?repo=try&revision=f30b76be487c&selectedJob=17764007
Attachment #8727397 - Attachment is obsolete: true
Attachment #8727926 - Flags: review+
Attachment #8727926 - Flags: checkin?
Attachment #8727926 - Flags: checkin? → checkin+
https://hg.mozilla.org/mozilla-central/rev/0793f99fca8f
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla48
Depends on: 1291700
Duplicate of this bug: 914227
Depends on: 1313016
Depends on: 1315680
Pushed by ryanvm@gmail.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/d1ef75d52b01
Pref to send default NTLM creds in PB, Always send default creds to proxies in PB. r=jduell
(In reply to Pulsebot from comment #24)
> Pushed by ryanvm@gmail.com:
> https://hg.mozilla.org/integration/mozilla-inbound/rev/d1ef75d52b01
> Pref to send default NTLM creds in PB, Always send default creds to proxies
> in PB. r=jduell

This was actually bug 1313016. Backed out and relanded with the correct bug #.
Hi,

How can I enable this? I would like to use SSO/Integrated Authentication in Private mode. It should be an optional feature.

Any way to enable this please?

Thanks.
(In reply to wizk11 from comment #26)
> Hi,
> 
> How can I enable this? I would like to use SSO/Integrated Authentication in
> Private mode. It should be an optional feature.

network.auth.private-browsing-sso
You need to log in before you can comment on or make changes to this bug.