View Issue Details

IDProjectCategoryView StatusLast Update
0003933SOGoWeb Generalpublic2017-06-16 20:10
Reporterckreutzer Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Platform[Server] LinuxOSDebianOS Version8 (Jessie)
Product Version3.2.4 
Summary0003933: SAML authentication does not work with XHR requests
Description

This is a follow-up to 0003884. I wasn't able to reopen it or comment on it.

At least for SAML authentication, this is not fixed. HTTP-POST will not work because there can't be a redirect which POSTs somewhere, so this is usually done with JavaScript.
A solution would be to use HTTP-Artifact, which uses a side channel between IdP and SP to transfer to Assertion.
I modified my SAML IdP to support HTTP-Artifact binding, which shouldn't need a POST from the browser. But as it turns out, Artifact Binding itself isn't implemented - see:
https://github.com/inverse-inc/sogo/blob/0856d56a70622d92000ad1903c23d2ea87727dfb/UI/MainUI/product.plist
https://github.com/inverse-inc/sogo/blob/0856d56a70622d92000ad1903c23d2ea87727dfb/UI/MainUI/SOGoSAML2Actions.m
But it is listed in the generated Metadata, see:
https://github.com/inverse-inc/sogo/blob/0856d56a70622d92000ad1903c23d2ea87727dfb/SoObjects/SOGo/SOGoSAML2Metadata.xml

So probably to resolve this issue, an implementation of HTTP-Artifact binding would be needed.

TagsNo tags attached.

Activities

ckreutzer

ckreutzer

2016-12-12 08:15

reporter   ~0010986

Another solution would be maintaining a (local) session after verification of the assertion that is longer valid than the Assertion itself.
In the Shibboleth SP for example, you can set the duration until the session times out (I think default is 60 minutes, I've set it to 1440min). With inactivity, it times out faster (that should work oob in SOGo, too).

The validation of the eventually timed out assertion can be left up to the application. Both crudesaml and my pam-script-saml have a grace parameter which could be set to the session duration.

ckreutzer

ckreutzer

2016-12-13 12:28

reporter   ~0010991

I've tried setting the Assertions validity duration to 8 hours (and checked it afterwards in the Assertion XML), but the session was gone after 5 mins again.

I found out why the session times out so fast:
https://github.com/inverse-inc/sogo/blob/0856d56a70622d92000ad1903c23d2ea87727dfb/SoObjects/SOGo/SOGoWebAuthenticator.m#L309
https://github.com/inverse-inc/sogo/blob/0856d56a70622d92000ad1903c23d2ea87727dfb/SoObjects/SOGo/SOGoSAML2Session.m#L410

The Assertion is saved in SOGoCache, and when validating the session on a request, the assertion is loaded from SOGoCache. However, with the default configuration the CacheInterval is set to 300 secs, so after 5 mins the Assertion is gone.

Is there any possibility to make at least a workaround by saving to a less volatile storage or to increase the lifetime of only the assertions?
And for the case when the assertion is gone after a given time, how can the bad XHR requests be handled? How is this done with "normal" authentication?

ludovic

ludovic

2016-12-28 19:48

administrator   ~0011120

I guess the proper solution would be:

1- increase the cache saving time for SAML2 by introducing a new parameter - like SOGoSAML2AssertionTimeout

2- add support for HTTP Artifact Binding

Right now, when a XHR call is made to SOGo and the session is expired, SOGo returns HTML content and the XHR code detects that, and redirects the user to the login page.

ckreutzer

ckreutzer

2017-01-02 08:58

reporter   ~0011160

Hi ludovic,

thanks for assessing that. At least point 1 would be very nice!

Right now, when the IdP is returning HTML content (after the redirection from the SOGo SP part to the IdP), nothing happens in my installation (see request order in 3884).

heupink

heupink

2017-01-23 09:58

reporter   ~0011236

We are affected by this as well. Logging into SOGo/dovecot using SAML works nicely, it's just that after five minutes we are redirected to the IdP again. (guessing because the assetion is gone)

It would be very nice if HTTP Artifact Binding could be implemented.

ludovic

ludovic

2017-01-23 16:37

administrator   ~0011237

Yes we plan on implementing that. We need to setup our SAML environment to add support for it.

heupink

heupink

2017-01-23 19:12

reporter   ~0011238

Nice. Thanks.

ckreutzer

ckreutzer

2017-01-24 17:48

reporter   ~0011239

Thanks Ludovic!

Coming back to your comment:
"Right now, when a XHR call is made to SOGo and the session is expired, SOGo returns HTML content and the XHR code detects that, and redirects the user to the login page."
In my case that's not happening. The XHR request to SOGo is redirected to the IdP (302) and the IdP returns HTML with a form containing the SAMLResponse and a litte JavaScript to submit it, but nothing's happening with it.

ludovic

ludovic

2017-01-24 17:51

administrator   ~0011240

@ckreutzer how about when you do the same test with SOGo v2?

ludovic

ludovic

2017-03-01 16:24

administrator   ~0011399

Try tomorrow's nightly build.

ckreutzer

ckreutzer

2017-03-02 06:27

reporter   ~0011405

Hi Ludovic,

I'll try it in the evening (UTC+0200) and report back.

Regarding comment 11240: Haven't seen any notification for that one. I currently have no v2 test system running, but I'll try to manage that. I probably can't install them on the same machine using the repository?

ckreutzer

ckreutzer

2017-03-02 19:36

reporter   ~0011407

I tried it running the latest nightly (3.2.7.20170302-1).

I let SOGoCacheInterval time out and choose another Mail in the INBOX.
/SOGo/so/<user>/Mail/0/folderINBOX/<ID>/view is called, response is 302 Redirect to the IdP.
The IdP returns HTML containing a form for the POST-Binding, which is usually submitted using JavaScript. SOGo doesn't seem to handle the response.

This is the trace for the Initiator of the "view" request in the Chrome Dev Tools... doesn't tell me much, but maybe it gives you the ability to track down how it is handled:
(anonymous) @ angular.js:12433
p @ angular.js:12178
(anonymous) @ angular.js:11930
(anonymous) @ angular.js:16689
$eval @ angular.js:18017
$digest @ angular.js:17827
$apply @ angular.js:18125
(anonymous) @ angular.js:26813
dg @ angular.js:3617
d @ angular.js:3605

ludovic

ludovic

2017-03-03 14:17

administrator   ~0011417

Try again with the latest nightly build.

ckreutzer

ckreutzer

2017-03-05 11:59

reporter   ~0011431

Last edited: 2017-03-05 12:01

Hi Ludovic,

I tried it again today with the latest nightly (3.2.7.20170305-1).

In my case, it's still not working. However I think I know what the problem is. heupink was so kind to give me a test user on his system to follow the requests.

His IdP, Keycloak, returns a HTTP 401 when it isn't able to authorize via Kerberos. Then your error handler jumps in, loads the recover page in the iFrame, which is redirected, the session is refreshed and all is working again.

However in my case, when the redirect from the SOGo XHR request is happening, my IdP (SimpleSAMLphp) is returning a HTTP 200 since it directly reauthorized using the cookies. Probably your error handler then doesn't kicks in, as the request was successful (however not your expected response was returned).

The AuthInterceptor (UI/WebServerResources/js/Common/Common.app.js#L240) also doesn't seem to handle that:
1) L245/6: You're checking against the response content, however my HTML header looks a bit different (example below). Especially my response has no closing ">" after the "html" (no HTML5).
2) Is there a reason not to check the reponse headers for the returned Content-Type?

Of course the iFrame solution is more beautiful than the reload by AuthInterceptor, but I could arrange with that, too :)
Another option would be to apply the same logic in the AuthInterceptor as in the ErrorInterceptor.

Example of my IdPs response:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;>
<html xmlns="http://www.w3.org/1999/xhtml&quot; xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>POST data</title>
</head>
<body onload="document.getElementsByTagName('input')[0].click();">

&lt;noscript>
    <p><strong>Note:</strong> Since your browser does not support JavaScript, you must press the button below once to proceed.</p> 
&lt;/noscript> 

&lt;form method=&quot;post&quot; action=&quot;https://example.com/SOGo/saml2-signon-post&quot;>
&lt;!-- Need to add this element and call click method, because calling submit()
on the form causes failed submission if the form has another element with name or id of submit.
See: https://developer.mozilla.org/en/DOM/form.submit#Specification -->
&lt;input type=&quot;submit&quot; style=&quot;display:none;&quot; />

<input type="hidden" name="SAMLResponse" value="[... Gibberish ...]" />
<noscript>
<button type="submit" class="btn">Submit</button>
</noscript>
</form>

</body>
</html>
Headers:
HTTP/1.1 200 OK
Content-type: text/html; charset=UTF-8
Content-Length: 10013
Date: Sun, 05 Mar 2017 11:43:06 GMT
Server: lighttpd/1.4.45

Thanks again for giving it a try!

Best regards,
Christoph

heupink

heupink

2017-03-06 09:53

reporter   ~0011432

Just wanted to mention that in my keycloak config, kerberos authentication is switched OFF. So as it is now (and as you tested it) my keycloak is not supposed to attempt kerberos. (just thought I'd mention it)

ludovic

ludovic

2017-03-06 16:24

administrator   ~0011442

Lowering to minor.

@ckreutzer - can you provide a test account for me and ssh access to a test server? I would like to see it in action.

ckreutzer

ckreutzer

2017-03-07 20:00

reporter   ~0011454

@heupink:
That's possible, but the IdP still tries it :)

See the following header:
HTTP/1.1 401 Unauthorized
Date: Tue, 07 Mar 2017 19:54:29 GMT
Server: WildFly/10
Cache-Control: no-store, must-revalidate, max-age=0
X-Powered-By: Undertow/1
WWW-Authenticate: Negotiate
Content-Type: text/html
Content-Length: 592
Set-Cookie: [...]
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive

That's the response to the redirected view-Request (you can see that in Chrome Dev Tools). A normal browser will just show the response body (the login form or, in this case, just a JavaScript-submitted form) or if it understands Kerberos, send the ticket.
And the Status 401 is why the ErrorInterceptor is catching that response (Status is not 200 OK) ;)

@ludovic:
I've managed to setup a test server where I can give you SSH access to. Would you please contact me via mail sending me a public key to setup for logging in? In response I'll send you the URL and credentials for the test server.

However, I'm 90% sure I've figured the problem out above.

ludovic

ludovic

2017-03-07 20:04

administrator   ~0011455

Contact me by email, my address is all around the planet.

heupink

heupink

2017-06-10 18:11

reporter   ~0011915

Last edited: 2017-06-10 18:35

Can I ask what the status of this bug is? Is this supposed to be fixed/implemented/finished/closed?

Reason I'm asking is, that in my testing, as soon as I switch from ldap to saml2 auth, I start seeing many errors like:

GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed

switching back to ldap gets rid of those. (trying with 3.2.9 currently)

ludovic

ludovic

2017-06-16 15:37

administrator   ~0011968

IIRC, it worked for you.

SOGo nor SOPE does not use at all glib - so I don't know where/how that error comes from.

ckreutzer

ckreutzer

2017-06-16 15:45

reporter   ~0011971

These are coming from liblasso. Sadly, there is no real alternative to it...

I've been looking for some time for a C/C++ SAML library to replace the PHP in pam_script_saml, but liblasso doesn't allow you to extract the assertion, IIRC. And all builds I patched (like the AUF guys https://wiki.auf.org/wikiteki/Projet/SOGo/TestsSAML) and built myself gave these errors, too.

heupink

heupink

2017-06-16 20:10

reporter   ~0011979

ah ok, thanks for explaining, ckruetzer!

Issue History

Date Modified Username Field Change
2016-12-08 19:50 ckreutzer New Issue
2016-12-12 08:15 ckreutzer Note Added: 0010986
2016-12-13 12:28 ckreutzer Note Added: 0010991
2016-12-28 19:48 ludovic Note Added: 0011120
2017-01-02 08:58 ckreutzer Note Added: 0011160
2017-01-23 09:58 heupink Note Added: 0011236
2017-01-23 16:37 ludovic Note Added: 0011237
2017-01-23 19:12 heupink Note Added: 0011238
2017-01-24 17:48 ckreutzer Note Added: 0011239
2017-01-24 17:51 ludovic Note Added: 0011240
2017-03-01 16:24 ludovic Note Added: 0011399
2017-03-02 06:27 ckreutzer Note Added: 0011405
2017-03-02 19:36 ckreutzer Note Added: 0011407
2017-03-03 14:17 ludovic Note Added: 0011417
2017-03-05 11:59 ckreutzer Note Added: 0011431
2017-03-05 12:01 ckreutzer Note Edited: 0011431
2017-03-06 09:53 heupink Note Added: 0011432
2017-03-06 16:24 ludovic Severity major => minor
2017-03-06 16:24 ludovic Note Added: 0011442
2017-03-07 20:00 ckreutzer Note Added: 0011454
2017-03-07 20:04 ludovic Note Added: 0011455
2017-06-10 18:11 heupink Note Added: 0011915
2017-06-10 18:35 heupink Note Edited: 0011915
2017-06-16 15:37 ludovic Note Added: 0011968
2017-06-16 15:45 ckreutzer Note Added: 0011971
2017-06-16 20:10 heupink Note Added: 0011979