Skip to content
This repository has been archived by the owner on May 27, 2024. It is now read-only.

Kerberos Single Sign-On does not work #16

Open
acudovs opened this issue Sep 15, 2016 · 25 comments
Open

Kerberos Single Sign-On does not work #16

acudovs opened this issue Sep 15, 2016 · 25 comments

Comments

@acudovs
Copy link

acudovs commented Sep 15, 2016

Kerberos Single Sign-On does not work

I've tried to setup Kerberos Single Sign-On to Graylog 2.1 on my Apache HTTP Server proxy.

My current Apache HTTP Server proxy configuration:

    <Location />
        SSLRequireSSL
        RequestHeader set X-Graylog-Server-URL "https://graylog.example.com/api/"
        ProxyPass http://127.0.0.1:9000/
        ProxyPassReverse http://127.0.0.1:9000/
    </Location>

First of all I've created user [email protected] via Graylog WEB UI /system/authentication/users and configured SSO Plugin /system/authentication/config/sso to trust X-Remote-User HTTP header.

To test SSO plugin works as expected I've added static header to my configuration:

    <Location />
        SSLRequireSSL
        RequestHeader set X-Graylog-Server-URL "https://graylog.example.com/api/"
        RequestHeader set X-Remote-User "[email protected]"
        ProxyPass http://127.0.0.1:9000/
        ProxyPassReverse http://127.0.0.1:9000/
    </Location>

With the above configuration I always login as [email protected] without prompting for password.

So, the Kerberos part uses mod_auth_gssapi https://github.com/modauthgssapi/mod_auth_gssapi

    <Location />
        SSLRequireSSL

        AuthType GSSAPI
        AuthName "Kerberos Login"
        GssapiCredStore keytab:/etc/httpd/conf/krb5.keytab
        GssapiUseSessions On
        Require valid-user

        RequestHeader set X-Graylog-Server-URL "https://graylog.example.com/api/"
        RequestHeader set X-Remote-User %{REMOTE_USER}s

        Session On
        SessionCookieName gssapi_session path=/;httponly;secure;

        ProxyPass http://127.0.0.1:9000/
        ProxyPassReverse http://127.0.0.1:9000/
    </Location>

With the above configuration Apache HTTP Server authenticates me as [email protected] but Graylog API session is not authorized

192.168.0.133 - [email protected] [08/Sep/2016:14:05:19 +0300] "GET / HTTP/1.1" 200 500 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:19 +0300] "GET /config.js HTTP/1.1" 200 136 "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:19 +0300] "GET /assets/polyfill.6469f06d961e83d45607.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:20 +0300] "GET /assets/plugin/org.graylog.plugins.pipelineprocessor.ProcessorPlugin/plugin.org.graylog.plugins.pipelineprocessor.PipelineProcessorPlugin.052c725323b2a784f7b0.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - - [08/Sep/2016:14:05:20 +0300] "GET /api/system/sessions HTTP/1.1" 401 381 "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - - [08/Sep/2016:14:05:20 +0300] "GET /api/system/sessions HTTP/1.1" 401 381 "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:21 +0300] "GET /assets/plugin/org.graylog.plugins.enterprise_integration.EnterpriseIntegrationPlugin/plugin.org.graylog.plugins.enterprise_integration.EnterpriseIntegrationPlugin.cac9c48526f92b69f0dc.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:21 +0300] "GET /assets/plugin/org.graylog.plugins.map.MapWidgetPlugin/plugin.org.graylog.plugins.map.MapWidgetPlugin.2d9b16670c4a97bedae2.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:22 +0300] "GET /api/system/cluster/node HTTP/1.1" 200 223 "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - - [08/Sep/2016:14:05:22 +0300] "GET /api/system/sessions HTTP/1.1" 401 381 "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - - [08/Sep/2016:14:05:22 +0300] "GET /api/system/sessions HTTP/1.1" 401 381 "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:22 +0300] "GET /assets/f9a25466e5ac752f14dfa013fad9730a.jpg HTTP/1.1" 304 - "https://graylog.example.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:23 +0300] "GET /assets/plugin/org.graylog.plugins.auth.sso.SsoAuthPlugin/plugin.org.graylog.plugins.auth.sso.SsoAuthPlugin.2b841b0e8c062b58a186.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:23 +0300] "GET /assets/2.LoginPage.6469f06d961e83d45607.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:23 +0300] "GET /assets/32.32.6469f06d961e83d45607.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:23 +0300] "GET /assets/plugin/org.graylog.plugins.collector.CollectorPlugin/plugin.org.graylog.plugins.collector.CollectorPlugin.2d7e15af839c3b19942b.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"
192.168.0.133 - [email protected] [08/Sep/2016:14:05:23 +0300] "GET /assets/app.6469f06d961e83d45607.js.map HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36"

Request headers:

GET /api/system/sessions HTTP/1.1
Host: graylog.example.com
Connection: keep-alive
Authorization: Basic dW5kZWZpbmVkOnNlc3Npb24=
Accept: application/json
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36
Content-Type: application/json
Referer: https://graylog.example.com/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,ru;q=0.6
Cookie: gssapi_session=MagBearerToken=XXXYYY

Response headers:

HTTP/1.1 401 Unauthorized
Date: Thu, 08 Sep 2016 11:05:20 GMT
Server: Apache
Set-Cookie: gssapi_session=MagBearerToken=XXXYYY;path=/;httponly;secure;
WWW-Authenticate: Negotiate
Cache-Control: no-cache
Content-Length: 381
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

Seems like request to /api/system/sessions breaks Kerberos auth (header WWW-Authenticate: Negotiate) by adding HTTP header "Authorization: Basic dW5kZWZpbmVkOnNlc3Npb24=".

Environment

  • Apache HTTP Server Version: 2.4.6
  • Graylog Version: 2.1.1
  • Plugin Version: 1.0.3
  • Elasticsearch Version: 2.4.0
  • MongoDB Version: 2.6.12
  • Operating System: CentOS Linux 7.2.1511 (64-bit)
  • Browser version: Google Chrome 53.0.2785.101 (64-bit)
@hc4
Copy link

hc4 commented Sep 16, 2016

I had similar problem (but I'm using squid for kerberos auth)
And my solution was to not authorize with kerberos requests containing session auth (authorization header contains session id as login and "session" as password)

@hc4
Copy link

hc4 commented Sep 16, 2016

Also be sure that XHR requests generated for server name (not ip).
For this web_endpoint_uri should be set to relative (empty string) or http://servername

@acudovs
Copy link
Author

acudovs commented Sep 16, 2016

Could you share your Squid configuration?

@hc4
Copy link

hc4 commented Sep 16, 2016

The key part is that:

acl with_session_or_token req_header Authorization ^Basic\s.+(OnNlc3Npb24=|p0b2tlbg==)$
acl authenticated proxy_auth REQUIRED

http_access allow with_session_or_token
http_access deny !authenticated
http_access allow all

@acudovs
Copy link
Author

acudovs commented Sep 16, 2016

I'm not sure how to mimic this in the Apache configuration.

For Single Sign-On to works properly user session needs to be authenticated using X-Remote-User header. But if I disable Kerberos for some requests to /api/system/sessions the Apache doesn't add X-Remote-User header, authentication fails and Graylog shows standard login form.

@hc4
Copy link

hc4 commented Sep 16, 2016

graylog will work with session auth header only

@hc4
Copy link

hc4 commented Sep 16, 2016

check order of auth providers:
image

@acudovs
Copy link
Author

acudovs commented Sep 16, 2016

It's true only if you already got the session somehow. I've spent hours trying different configurations. But maybe I just can't catch your point. Do you have spare Apache server to test the above configuration yourself? And don't forget to open a browser in incognito mode or you may share some previous session.

@hc4
Copy link

hc4 commented Sep 16, 2016

Actualy I don't want to run Apache :)
But my point is that you need to pass X-Remote-User header only until session will be created.
After that you will have session auth and you no longer need Kerberos auth.
Also it is important to have graylog WEB and graylog REST on same address.

@acudovs
Copy link
Author

acudovs commented Sep 16, 2016

You are just right! I need to create initial session by passing the X-Remote-User header with correct Kerberos user principal in this header but I can't because only Kerberos knows the principal name and it needs to be disabled for the same request. The "chicken or the egg" :) Maybe I should try Squid if it works for you...

But the main problem is that Graylog breaks standard proxy authentication algorithm (including but not limited to Kerberos) by its own unexpected Authorization header.

@hc4
Copy link

hc4 commented Sep 16, 2016

Yep. Sure graylog auth header is a root problem.
But I still can't get a problem.
Send X-Remote-User header using Kerberos until graylog will generate auth header.
After that X-Remote-User is not needed anymore.

This is what I did with squid config.
It checks auth header with session and passes request if header found.
Otherwise it makes Kerberos auth and sends X-Remote-User

@hc4
Copy link

hc4 commented Sep 16, 2016

Myabe the problem is that you sending auth header as undefined:session?

@kroepke
Copy link
Member

kroepke commented Sep 19, 2016

The undefined:session is from the Graylog frontend code, when it tries to find out whether it has a valid session or not.
I'm not sure what you mean by the auth header being the root problem, Graylog is using Basic auth, and has always done that. The SSO plugin only creates a Graylog session based on the externally set trusted headers and does not change anything else about the authentication mechanism.

From my limited Kerberos knowledge, the client needs to follow a few steps to get a valid Kerberos ticket, in which case the client is the Graylog web interface code running in the browser.
We assume Basic auth and this is unlikely to change, to be honest.

@acudovs
Copy link
Author

acudovs commented Sep 19, 2016

Kerberos works as expected, there is no problem with tickets. But Graylog's Basic auth breaks Kerberos auth as both rely on Authorization header. So, technically SSO plugin can't be used for SSO with Apache + Kerberos. At least, until some workaround is found.

@kroepke
Copy link
Member

kroepke commented Sep 19, 2016

Ah, then I misunderstood. So Kerberos is relying on being able to use the Authentication header for itself?

@acudovs
Copy link
Author

acudovs commented Sep 19, 2016

Sure! But not only Kerberos. As soon as "Require valid-user" added to Apache configuration it starts using Authentication header depending on AuthType. And of course everything breaks with unexpected (for Apache) Graylog's "Authorization: Basic undefined:session" header.

@kroepke
Copy link
Member

kroepke commented Sep 19, 2016

Ok, I see. As this is something that needs to changed in Graylog server, I don't think we will be able to do anything about it before 3.0.

@hc4
Copy link

hc4 commented Sep 19, 2016

Squid could be used as workaround.
At least it works for me :)

@hc4
Copy link

hc4 commented Sep 19, 2016

Full working squid3 config:

http_port pub_ip:80 accel
cache_peer 127.0.0.1 parent 80 0 no-query proxy-only

auth_param negotiate program /usr/lib/squid3/negotiate_kerberos_auth -r -s GSS_C_NO_NAME #-d
auth_param negotiate children 10
auth_param negotiate keep_alive on

acl with_session_or_token req_header Authorization ^Basic\s.+(OnNlc3Npb24=|p0b2tlbg==)$
acl authenticated proxy_auth REQUIRED

http_access allow with_session_or_token
http_access deny !authenticated
http_access allow all

request_header_access X-Remote-User deny all
request_header_add X-Remote-User "%ul" authenticated
request_header_add X-Graylog-Server-URL "http://%{Host}>h" all

@kroepke kroepke added this to the 2.2.0 milestone Oct 4, 2016
@saidst
Copy link

saidst commented Oct 10, 2016

@kroepke, I see you have added this to the 2.2.0 milestone.
How do you plan to cope with this issue?
Are you changing the process of session creation, e.g. by stopping to use the Authorization header?

@joschi joschi removed this from the 2.2.0 milestone Jan 4, 2017
@sigmaris
Copy link

sigmaris commented Mar 5, 2018

It is possible to use Kerberos SSO with nginx with some trickery in the config file, and the same may be possible with Apache. This snippet of nginx config works for me:

# Set a variable $passthru_authorization to the original value of any Basic Authorization
# header. We do this because the ngx_http_auth_spnego_module may later overwrite the value!
map $http_authorization $passthru_authorization {
	default                             "";
	"~(?<auth_header_capture>Basic .*)" $auth_header_capture;
}

server {
	# put your server directives here
	# ...

	 location / {
		# a trick using fake error codes above 418 to perform internal redirects
		# to named locations
		error_page 463 = @graylog_no_auth;
		error_page 464 = @graylog_with_auth;

		# Check if the request has Basic auth with username="undefined",
		# password="session". this is the first auth-related request from a
		# logged-out client, with an undefined session token
		if ($http_authorization = "Basic dW5kZWZpbmVkOnNlc3Npb24=") {
			# We want to apply Kerberos authentication to this request,
			# so that the request that reaches Graylog has the Remote-User
			# header and the client obtains a proper session token to use
			# in future requests
			return 464;
		}

		# Check if the client sent a session or API token using Basic auth.
		# If they have, we should pass it to Graylog without triggering
		# Kerberos auth, as Graylog should accept it.
		# These possible matches are the different possible base64
		# representations of ":session" or ":token" at the end of the
		# Authorization header
		if ($http_authorization ~ ".+(6c2Vzc2lvbg==|OnNlc3Npb24=|pzZXNzaW9u|p0b2tlbg==|6dG9rZW4=|OnRva2Vu)$") {
			return 463;
		}

		# If there is no session or API token, trigger Kerberos auth.
		if ($http_authorization !~ ".+(6c2Vzc2lvbg==|OnNlc3Npb24=|pzZXNzaW9u|p0b2tlbg==|6dG9rZW4=|OnRva2Vu)$") {
			return 464;
		}
	}

	location @graylog_with_auth {
		# These are the directives which require Kerberos authentication
		auth_gss on;
		auth_gss_keytab /etc/nginx/krb5.keytab;

		# Don't try and use Basic auth credentials to log in to Kerberos
		auth_gss_allow_basic_fallback off;

		# Pass the real IP to Graylog server
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

		# Since in this location we require Kerberos auth, we should have
		# a valid remote user to pass to the Graylog server, which should
		# trust it implicitly and log the user in.
		proxy_set_header Remote-User $remote_user;

		# The ngx_http_auth_spnego_module sets a fake Authorization header,
		# remove it as it'll probably confuse the Graylog server
		proxy_set_header Authorization "";

		# Proxy to Graylog server, assuming it's running on localhost port 9000
		proxy_pass http://127.0.0.1:9000;
	}

	location @graylog_no_auth {
		# Pass the real IP to Graylog server
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

		# Clear the Remote-User header; we aren't doing any SSO in this location
		proxy_set_header Remote-User "";

		# Pass through Basic Authorization header from the client,
		# as it contains Graylog session or API token
		proxy_set_header Authorization $passthru_authorization;

		# Proxy to Graylog server, assuming it's running on localhost port 9000
		proxy_pass http://127.0.0.1:9000;
	}
}

The key thing is to enable or disable Kerberos auth based on the type of Basic auth presented by the client. If the client presents Basic auth with a password of "session" or "token", that means the client is trying to use Graylog session or token-based authentication, with the token in the username, and Kerberos authentication shouldn't be enabled/required. However an exception to that rule is if the username is "undefined" - that's a sign that the client is logged out and so Kerberos authentication should be enabled for that request, to sign them in. After that request, the client should obtain a valid session token, use that for future requests, and no longer require Kerberos auth until their session expires.

@toddlindner
Copy link

This is still a bug. Any chance graylog can move away from misusing the Authorization header?

@kroepke
Copy link
Member

kroepke commented Jul 16, 2020

We will deprecate and remove this plugin in the near future, it was never a good idea in the first place, and as you note its implementation is flawed. For a replacement we need to rework some intervals though and that process is not finished yet. Sorry for the inconvenience.

@audunmg
Copy link

audunmg commented Jul 16, 2020

The idea was good, and with the workarounds it works great. I hope it returns without the need for workarounds.

@toddlindner
Copy link

toddlindner commented Jul 16, 2020

@kroepke I'm not sure you are understanding the issue. There is nothing inherently wrong with the graylog-plugin-auth-sso plugin.

The issue is that Graylog itself (even when the graylog-plugin-auth-sso plugin is disabled) is mis-using the Authorization header for its own session management. If that internal session handling was moved to a header such as "AuthorizationGraylogSession" instead of "Authorization" there would be no issue.

This misuse of the Authorization header interferes with Kerberos implementations that are outside of both graylog and the graylog-plugin-auth-sso plugin.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants