Problem with useRelayStateDeepLink in Kibana's SAML configuration

Hello, I managed to make the SAML SSO work with a custom IdP (a Laravel app with this package, with both IdP and SP initiated flows.

However, I want to redirect the user to specific dashboards on Kibana, from my Laravel app. ( Security settings in Kibana | Kibana Guide [7.15] | Elastic was the first page I came across.

image

As far as I understood, the RelayState parameter is only used in a IdP initiated flow, and it's purpose is to redirect the user to it's specific URL, after authenticating in the SP (Elastic/Kibana RP). So my idea was to include the dashboard's URLs as a parameter to my IdP SSO flow, for example:

<a href="{{ route('sso', ['RelayState' => rawurlencode('/app/dashboards#/list')]) }}" target="_blank">

If this is correct, then why do I get this response from Kibana after trying the IdP initiated flow?

This is how my SAML Response goes:

image

Why does Kibana tries to go this URL http://localhost:5601/api/security/saml/%2Fapp%2Fdashboards%23%2Flist after http://localhost:5601/api/security/saml?

Am I misunderstanding something? Is it possible to do what I want?

Hi @medina,

I can try to help with this one, but can you share a HAR file that includes full content of this POST http://localhost:5601/api/security/saml/callback? I want to take a look at what came in RelayState POST body parameter.

Best,
Oleg

I can't export a HAR file since the link I click to SSO with Kibana opens a new tab and I lose the request. Using the SAML-tracer I may get all info you want, however doesn't this image https://global.discourse-cdn.com/elastic/original/3X/8/2/8237ac14cf72da2e5133aa84b29635773d7fa01c.png show the RelayState parameter sent as a POST body parameter? It's content is

%2Fapp%2Fdashboards%2Flist

Maybe it wasn't clear in the image.

Yeah, sorry, missed that. Okay, let's try to debug this then:

  • Can you enable verbose logs in Kibana (logging.verbose: true)? This should show us if Kibana correctly recognizes the URL from RelayState
  • Can you share your ES and Kibana configs (without any sensitive details)?

Best,
Oleg

No sensitive data I believe. These are the Kibana's configs I added:

xpack.reporting.roles.enabled: false

elasticsearch.username: "kibana_system"
elasticsearch.password: "changeme"

xpack.security.authc.selector.enabled: true

xpack.security.authc.providers:
  basic.basic1:
    order: 0
    icon: "logoElasticsearch"
    hint: "Login de Administrador"
    description: Entre com o Elasticsearch
  saml.saml2:
    order: 1
    realm: saml2
    useRelayStateDeepLink: true
    description: "Entre como Usuário Interno (Auditoria)"

logging.verbose: true

And the Elastic's configs are:

xpack.security.authc.token.enabled: true

xpack.security.enabled: true
discovery.type: single-node

xpack.security.authc.realms.saml.saml2:
  order: 1
  idp.metadata.path: saml/idp-metadata-windows.xml
  idp.entity_id: "http://localhost:8081/saml/metadata"
  sp.entity_id:  "http://localhost:5601"
  sp.acs: "http://localhost:5601/api/security/saml/callback"
  sp.logout: "http://localhost:5601/logout"
  attributes.principal: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
  attributes.name: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
  attributes.mail: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
  attributes.dn: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier"
  attributes.groups: "http://schemas.xmlsoap.org/claims/Group"
  signing.certificate: saml/saml-sign.crt
  signing.key: saml/saml-sign.key
  encryption.certificate: saml/saml-sign.crt
  encryption.key: saml/saml-sign.key

Thanks, looks good, now let's see what logs tell us.

Where can I get the log file?

Let's just re-configure Kibana to write to the file we know for now:

logging.dest: /some-known-location/kibana.log
logging.verbose: true
logging.json: true

Sorry for taking long, I got the log file... it's huge. What am I looking for in it?

Ok so I looked for "saml" in the log file, and these are the mosts interesting results:

{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","plugins","security","basic","basic1"],"pid":1396,"message":"Trying to authenticate user request to /api/security/saml/%2Fapp%2Fdashboards%2Flist."}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to authenticate user request to /api/security/saml/%2Fapp%2Fdashboards%2Flist"}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","plugins","security","http"],"pid":1396,"message":"Trying to authenticate user request to /api/security/saml/%2Fapp%2Fdashboards%2Flist."}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","plugins","security","http"],"pid":1396,"message":"Authorization header is not presented."}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","plugins","security","authentication"],"pid":1396,"message":"Could not handle authentication attempt"}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","plugins","licensing"],"pid":1396,"message":"Requesting Elasticsearch licensing API"}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","elasticsearch","query","data"],"pid":1396,"message":"200\nGET /_xpack?accept_enterprise=true"}
{"type":"log","@timestamp":"2021-10-18T11:34:38-04:00","tags":["debug","http","server","response"],"pid":1396,"client":{"ip":"127.0.0.1"},"http":{"request":{"method":"GET","mime_type":null,"referrer":"http://localhost:8081/","headers":{"host":"localhost:5601","connection":"keep-alive","sec-ch-ua":"\"Chromium\";v=\"94\", \"Microsoft Edge\";v=\"94\", \";Not A Brand\";v=\"99\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9","sec-fetch-site":"same-site","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","referer":"http://localhost:8081/","accept-encoding":"gzip, deflate, br","accept-language":"pt-BR,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,pl;q=0.5"}},"response":{"body":{"bytes":66},"status_code":401,"headers":{"X-Content-Type-Options":"nosniff","Referrer-Policy":"no-referrer-when-downgrade","kbn-name":"LAPTOP-05UC8NBH","kbn-license-sig":"9b2bbdbd7bcfbe5df3634b91b4832e5b286431dd0f9a9fd79743de85e3f861a8","content-type":"application/json; charset=utf-8","cache-control":"private, no-cache, no-store, must-revalidate","content-length":66},"responseTime":64}},"url":{"path":"/api/security/saml/%2Fapp%2Fdashboards%2Flist","query":""},"user_agent":{"original":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50"},"message":"GET /api/security/saml/%2Fapp%2Fdashboards%2Flist 401 64ms - 66.0B"}


{"type":"log","@timestamp":"2021-10-18T11:57:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to perform a login."}
{"type":"log","@timestamp":"2021-10-18T11:57:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to log in with SAML response payload."}
{"type":"log","@timestamp":"2021-10-18T11:57:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Login has been initiated by Identity Provider."}

{"type":"log","@timestamp":"2021-10-18T11:57:39-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"User will be redirected to the Kibana internal URL specified in \"RelayState\"."}
{"type":"log","@timestamp":"2021-10-18T11:57:39-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Login has been performed with SAML response."}

{"type":"log","@timestamp":"2021-10-18T11:57:40-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to authenticate user request to /api/security/saml/%2Fapp%2Fdashboards%2Flist"}
{"type":"log","@timestamp":"2021-10-18T11:57:40-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to authenticate via state."}

{"type":"log","@timestamp":"2021-10-18T11:57:40-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Request has been authenticated via state."}

{"type":"log","@timestamp":"2021-10-18T11:57:41-04:00","tags":["debug","http","server","response"],"pid":1396,"client":{"ip":"127.0.0.1"},"http":{"request":{"method":"GET","mime_type":null,"referrer":"http://localhost:8081/","headers":{"host":"localhost:5601","connection":"keep-alive","cache-control":"max-age=0","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9","sec-fetch-site":"same-site","sec-fetch-mode":"navigate","sec-fetch-dest":"document","sec-ch-ua":"\"Chromium\";v=\"94\", \"Microsoft Edge\";v=\"94\", \";Not A Brand\";v=\"99\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","referer":"http://localhost:8081/","accept-encoding":"gzip, deflate, br","accept-language":"pt-BR,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,pl;q=0.5"}},"response":{"body":{"bytes":60},"status_code":404,"headers":{"X-Content-Type-Options":"nosniff","Referrer-Policy":"no-referrer-when-downgrade","kbn-name":"LAPTOP-05UC8NBH","kbn-license-sig":"9b2bbdbd7bcfbe5df3634b91b4832e5b286431dd0f9a9fd79743de85e3f861a8","content-type":"application/json; charset=utf-8","cache-control":"private, no-cache, no-store, must-revalidate","content-length":60},"responseTime":108}},"url":{"path":"/api/security/saml/%2Fapp%2Fdashboards%2Flist","query":""},"user_agent":{"original":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50"},"message":"GET /api/security/saml/%2Fapp%2Fdashboards%2Flist 404 108ms - 60.0B"}

https://raw.githubusercontent.com/medina325/kibana_logs/master/kibana.log

these are the log's contents.

Here are the most interesting parts. Login attempt recognizes as the initiated by IdP:

{"type":"log","@timestamp":"2021-10-18T11:57:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to perform a login."}
{"type":"log","@timestamp":"2021-10-18T11:57:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to log in with SAML response payload."}
{"type":"log","@timestamp":"2021-10-18T11:57:38-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Login has been initiated by Identity Provider."}

Kibana managed to perform login and detect that there is a valid URL in the RelayState:

{"type":"log","@timestamp":"2021-10-18T11:57:39-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"User will be redirected to the Kibana internal URL specified in \"RelayState\"."}
{"type":"log","@timestamp":"2021-10-18T11:57:39-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Login has been performed with SAML response."}
{"type":"log","@timestamp":"2021-10-18T11:57:39-04:00","tags":["debug","plugins","security","session","q541aeIPw="],"pid":1396,"message":"Creating a new session."}

Kibana redirects user to the URL from relay state: "status_code":302,"headers":{"location":"%2Fapp%2Fdashboards%2Flist" .... } - that looks correct:

{"type":"log","@timestamp":"2021-10-18T11:57:40-04:00","tags":["debug","http","server","response"],"pid":1396,"client":{"ip":"127.0.0.1"},"http":{"request":{"method":"POST","mime_type":"application/x-www-form-urlencoded","referrer":"http://localhost:8081/","headers":{"host":"localhost:5601","connection":"keep-alive","content-length":"5935","cache-control":"max-age=0","sec-ch-ua":"\"Chromium\";v=\"94\", \"Microsoft Edge\";v=\"94\", \";Not A Brand\";v=\"99\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","upgrade-insecure-requests":"1","origin":"http://localhost:8081","content-type":"application/x-www-form-urlencoded","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9","sec-fetch-site":"same-site","sec-fetch-mode":"navigate","sec-fetch-dest":"document","referer":"http://localhost:8081/","accept-encoding":"gzip, deflate, br","accept-language":"pt-BR,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,pl;q=0.5"}},"response":{"body":{},"status_code":302,"headers":{"location":"%2Fapp%2Fdashboards%2Flist","x-content-type-options":"nosniff","referrer-policy":"no-referrer-when-downgrade","kbn-name":"LAPTOP-05UC8NBH","kbn-license-sig":"9b2bbdbd7bcfbe5df3634b91b4832e5b286431dd0f9a9fd79743de85e3f861a8","cache-control":"private, no-cache, no-store, must-revalidate","set-cookie":"[REDACTED]","content-length":0},"responseTime":2303}},"url":{"path":"/api/security/saml/callback","query":""},"user_agent":{"original":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50"},"message":"POST /api/security/saml/callback 302 2303ms"}

But then we see this:

{"type":"log","@timestamp":"2021-10-18T11:57:40-04:00","tags":["debug","plugins","security","saml","saml2"],"pid":1396,"message":"Trying to authenticate user request to /api/security/saml/%2Fapp%2Fdashboards%2Flist"}

That means that the browser didn't manage to decode URL from location response header (specifically a leading /) and hence treats this location as relative to the current URL ( /api/security/saml/callback), that's how we end up with such a weird redirect.

If I'm not mistaken the standard requires URL in the Location header to be encoded, so I'm curious if it's browser mixing things up.

Can you try in a different browser? Can you try to not encode URL in the RelayState? Just to narrow down the problem.

1 Like

So first I tried Firefox instead of Edge and Chrome and still didn't work. However, by not manually encoding the URL as I did in here:

<a href="{{ route('sso', ['RelayState' => rawurlencode('/app/dashboards#/list')]) }}" target="_blank">

I just left the original deeplink URL as you suggested:

<a href="{{ route('sso', ['RelayState' => '/app/dashboards#/list']) }}" target="_blank">

And it worked! I noticed the url appeared encoded in the request, so maybe some part of the Laravel framework already does that, and by doing it twice it was getting messed up? I really don't know, I'm still a bit surprised it worked after that.

Thank you so much, cannot believe I didn't try that. Would you like me to share any more insights, I updated the repo link I sent before, with the successful logs.

Great, glad to hear that!

Yeah, it's a good guess. The HAR can easily show if there is double-encoding (the info we saw in logs probably went through one round of decoding).

Anyway, if SAML is functioning properly for you now feel free to mark this question as solved (the option in the ... menu for every post).

Let me know if I can help with anything else.

Best,
Oleg

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.