dexidp / dex

OpenID Connect (OIDC) identity and OAuth 2.0 provider with pluggable connectors
https://dexidp.io
Apache License 2.0
9.5k stars 1.71k forks source link

SAML connector - PANIC: nil pointer dereference exception #1757

Closed notjames closed 1 month ago

notjames commented 4 years ago

I'm attempting to set up a SAML2 connector in a k8s cluster for one of our internal environments. While testing this saml setup, the following nil pointer exception happens on every request:

version 2.23.0

2020-07-03 22:28:03.610634 I | http: panic serving 172.16.0.96:60284: runtime error: invalid memory address or nil pointer dereference
goroutine 184 [running]:
net/http.(*conn).serve.func1(0xc000153e00)
        /usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xf0d960, 0x185a270)
        /usr/local/go/src/runtime/panic.go:679 +0x1b2
github.com/beevik/etree.(*Element).dup(0x0, 0x0, 0x9, 0xc000171428)
        /go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:965 +0x37
github.com/beevik/etree.(*Element).Copy(...)
        /go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:350
github.com/russellhaering/goxmldsig.(*ValidationContext).Validate(0xc0000fccc0, 0x0, 0x1086f79, 0x25, 0x1066d29)
        /go/pkg/mod/github.com/russellhaering/goxmldsig@v0.0.0-20180430223755-7acd5e4a6ef7/validate.go:454 +0x38
github.com/dexidp/dex/connector/saml.verifyResponseSig(0xc0000fccc0, 0xc00018a000, 0xa86, 0xa86, 0xa86, 0xa86, 0x0, 0x0, 0x419eae, 0xc000183000)
        /go/src/github.com/dexidp/dex/connector/saml/saml.go:599 +0x1bb
github.com/dexidp/dex/connector/saml.(*provider).HandlePOST(0xc00008eb60, 0x1060101, 0xc000186000, 0xe08, 0xc000037020, 0x19, 0x0, 0x0, 0x0, 0x0, ...)
        /go/src/github.com/dexidp/dex/connector/saml/saml.go:297 +0x12fb
github.com/dexidp/dex/server.(*Server).handleConnectorCallback(0xc000315600, 0x11d5060, 0xc0002ca8c0, 0xc00049de00)
        /go/src/github.com/dexidp/dex/server/handlers.go:455 +0xe54
github.com/dexidp/dex/server.newServer.func7(0x11d5060, 0xc0002ca8c0, 0xc00049de00)
        /go/src/github.com/dexidp/dex/server/server.go:312 +0x175
net/http.HandlerFunc.ServeHTTP(0xc0001465d0, 0x11d5060, 0xc0002ca8c0, 0xc00049de00)
        /usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000180c0, 0x11d5060, 0xc0002ca8c0, 0xc00049dc00)
        /go/pkg/mod/github.com/gorilla/mux@v1.7.3/mux.go:212 +0xe2
github.com/dexidp/dex/server.(*Server).ServeHTTP(0xc000315600, 0x11d5060, 0xc0002ca8c0, 0xc00049dc00)
        /go/src/github.com/dexidp/dex/server/server.go:330 +0x58
net/http.serverHandler.ServeHTTP(0xc0004381c0, 0x11d5060, 0xc0002ca8c0, 0xc00049dc00)
        /usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000153e00, 0x11d82e0, 0xc00015df00)
        /usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

version 2.24.0

2020-07-07 06:34:50.066254 I | http: panic serving 172.16.0.96:44146: runtime error: invalid memory address or nil pointer dereference
goroutine 413 [running]:
net/http.(*conn).serve.func1(0xc000178780)
        /usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xf0eaa0, 0x185b270)
        /usr/local/go/src/runtime/panic.go:679 +0x1b2
github.com/beevik/etree.(*Element).dup(0x0, 0x0, 0x9, 0xc000231428)
        /go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:965 +0x37
github.com/beevik/etree.(*Element).Copy(...)
        /go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:350
github.com/russellhaering/goxmldsig.(*ValidationContext).Validate(0xc000033950, 0x0, 0x108827a, 0x25, 0x1068021)
        /go/pkg/mod/github.com/russellhaering/goxmldsig@v0.0.0-20180430223755-7acd5e4a6ef7/validate.go:454 +0x38
github.com/dexidp/dex/connector/saml.verifyResponseSig(0xc000033950, 0xc0001ae000, 0xa86, 0xa86, 0xa86, 0xa86, 0x0, 0x0, 0x419eae, 0xc0001ac000)
        /go/src/github.com/dexidp/dex/connector/saml/saml.go:606 +0x1bb
github.com/dexidp/dex/connector/saml.(*provider).HandlePOST(0xc00043a750, 0x1060101, 0xc0001ad000, 0xe08, 0xc00036a9e0, 0x19, 0x0, 0x0, 0x0, 0x0, ...)
        /go/src/github.com/dexidp/dex/connector/saml/saml.go:300 +0x1330
github.com/dexidp/dex/server.(*Server).handleConnectorCallback(0xc000143c00, 0x11d63a0, 0xc000432620, 0xc000019700)
        /go/src/github.com/dexidp/dex/server/handlers.go:455 +0xe54
github.com/dexidp/dex/server.newServer.func7(0x11d63a0, 0xc000432620, 0xc000019700)
        /go/src/github.com/dexidp/dex/server/server.go:312 +0x175
net/http.HandlerFunc.ServeHTTP(0xc000065740, 0x11d63a0, 0xc000432620, 0xc000019700)
        /usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0004e40c0, 0x11d63a0, 0xc000432620, 0xc000019500)
        /go/pkg/mod/github.com/gorilla/mux@v1.7.3/mux.go:212 +0xe2
github.com/dexidp/dex/server.(*Server).ServeHTTP(0xc000143c00, 0x11d63a0, 0xc000432620, 0xc000019500)
        /go/src/github.com/dexidp/dex/server/server.go:330 +0x58
net/http.serverHandler.ServeHTTP(0xc0002f2000, 0x11d63a0, 0xc000432620, 0xc000019500)
        /usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc000178780, 0x11d9620, 0xc000185380)
        /usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

The following is our SAML connector config, which is not the only connector we use, but it's the one that's relevant for now:

  config.yaml: |-
    issuer: https://dex-ad.<domain>
    storage:
      type: kubernetes
      config:
        inCluster: true
    logger:
      format: json
      level: debug
    web:
      http: 0.0.0.0:8080
    grpc:
      addr: 0.0.0.0:8090
      tlsCert: /etc/dex/tls/grpc/server/tls.crt
      tlsKey: /etc/dex/tls/grpc/server/tls.key
      tlsClientCA: /etc/dex/tls/grpc/ca/tls.crt
    connectors:
    - type: saml
      id: organization
      name: ORGANIZATION
      config:
        ssoURL: https://adfs.<test domain>/adfs/ls/idpinitiatedSignOn.aspx
        redirectURI: https://dex-ad.<domain>/callback
        entityIssuer: https://dex-ad.<domain>/callback
        usernameAttr: name
        emailAttr: email
        caData: <REDACTED>
      insecureSkipSignatureValidation: false

When attempting to test the authentication, the following happens:

dex logs show output from above.

notjames commented 4 years ago

Doing some more digging into this, the ADFS is sending the following status:

  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Requester">
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy" /></samlp:StatusCode>
  </samlp:Status>

The request still shows persistent even though the config is specifying emailAddress (altered since initial post):

dex config for saml connector:

    - type: saml
      id: <organization>
      name: <ORGANIZATION>
      config:
        ...
        usernameAttr: NameID
        emailAttr: emailAddress
        caData: <REDACTED>
      insecureSkipSignatureValidation: false
      nameIDPolicyFormat: emailAddress

SAML request:

  <NameIDPolicy xmlns="urn:oasis:names:tc:SAML:2.0:protocol"
                AllowCreate="true"
                Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"></NameIDPolicy>
notjames commented 4 years ago

We might have solved one problem, but we're still getting the panic from DEX:

<samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status>

Even with this response, the DEX is panicing:

2020-07-07 20:46:31.066936 I | http: panic serving 172.16.0.96:38280: runtime error: invalid memory address or nil pointer dereference
goroutine 2465 [running]:
net/http.(*conn).serve.func1(0xc00039c280)
        /usr/local/go/src/net/http/server.go:1767 +0x139
panic(0xf0eaa0, 0x185b270)
        /usr/local/go/src/runtime/panic.go:679 +0x1b2
github.com/beevik/etree.(*Element).dup(0x0, 0x0, 0x9, 0xc0001e5428)
        /go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:965 +0x37
github.com/beevik/etree.(*Element).Copy(...)
        /go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:350
github.com/russellhaering/goxmldsig.(*ValidationContext).Validate(0xc0004faba0, 0x0, 0x108827a, 0x25, 0x1068021)
        /go/pkg/mod/github.com/russellhaering/goxmldsig@v0.0.0-20180430223755-7acd5e4a6ef7/validate.go:454 +0x38
github.com/dexidp/dex/connector/saml.verifyResponseSig(0xc0004faba0, 0xc000282000, 0x1933, 0x1935, 0x1933, 0x1935, 0x0, 0x0, 0x419eae, 0xc00034c000)
        /go/src/github.com/dexidp/dex/connector/saml/saml.go:606 +0x1bb
github.com/dexidp/dex/connector/saml.(*provider).HandlePOST(0xc00044de10, 0x1060101, 0xc00034e500, 0x219c, 0xc0000c7420, 0x19, 0x0, 0x0, 0x0, 0x0, ...)
        /go/src/github.com/dexidp/dex/connector/saml/saml.go:300 +0x1330
github.com/dexidp/dex/server.(*Server).handleConnectorCallback(0xc0004a1300, 0x11d63a0, 0xc0003b0380, 0xc000214000)
        /go/src/github.com/dexidp/dex/server/handlers.go:455 +0xe54
github.com/dexidp/dex/server.newServer.func7(0x11d63a0, 0xc0003b0380, 0xc000214000)
        /go/src/github.com/dexidp/dex/server/server.go:312 +0x175
net/http.HandlerFunc.ServeHTTP(0xc00056cb40, 0x11d63a0, 0xc0003b0380, 0xc000214000)
        /usr/local/go/src/net/http/server.go:2007 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000140c0, 0x11d63a0, 0xc0003b0380, 0xc000197200)
        /go/pkg/mod/github.com/gorilla/mux@v1.7.3/mux.go:212 +0xe2
github.com/dexidp/dex/server.(*Server).ServeHTTP(0xc0004a1300, 0x11d63a0, 0xc0003b0380, 0xc000197200)
        /go/src/github.com/dexidp/dex/server/server.go:330 +0x58
net/http.serverHandler.ServeHTTP(0xc0004421c0, 0x11d63a0, 0xc0003b0380, 0xc000197200)
        /usr/local/go/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc00039c280, 0x11d9620, 0xc0003d8c80)
        /usr/local/go/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384
notjames commented 4 years ago

Seems like we finally got something going where the saml status was successful but the data returned was encrypted. The problem is that the response, even encrypted, throws a panic. Is the SAML connector like...beta?

So we're getting an encrypted payload, but since there is only one certificate for transport, it isn't immediately obvious on how to set up the adfs to encrypt the transport but to not encrypt the payload. If someone could help with that, that would be great!

malawskim commented 4 years ago

I've got very similar issue.

GRuuuuu commented 1 year ago

@notjames Hi, I have the exact same issue...

$ ./bin/dex serve examples/config-adfs.yaml

time="2022-12-13T11:55:26Z" level=info msg="Dex Version: 576f990d257d9dd63e283cf379960e50506e8bcc-dirty, Go Version: go1.19.3, Go OS/ARCH: linux amd64"
time="2022-12-13T11:55:26Z" level=info msg="config using log level: debug"
time="2022-12-13T11:55:26Z" level=info msg="config issuer: https://instana-sds.garagekr.com:5556/dex"
time="2022-12-13T11:55:26Z" level=info msg="config storage: sqlite3"
time="2022-12-13T11:55:26Z" level=info msg="config static client: OidcClientCekorea"
time="2022-12-13T11:55:26Z" level=info msg="config connector: adfs"
time="2022-12-13T11:55:26Z" level=info msg="config connector: dex"
time="2022-12-13T11:55:26Z" level=info msg="config refresh tokens rotation enabled: true"
time="2022-12-13T11:55:26Z" level=info msg="listening (https) on 0.0.0.0:5556"
2022/12/13 11:55:40 http2: panic serving 219.248.202.23:63438: runtime error: invalid memory address or nil pointer dereference
goroutine 93 [running]:
net/http.(*http2serverConn).runHandler.func1()
        /usr/local/go/src/net/http/h2_bundle.go:5904 +0x125
panic({0x1361b80, 0x2197930})
        /usr/local/go/src/runtime/panic.go:884 +0x212
github.com/beevik/etree.(*Element).dup(0x0, 0x0)
        /home/vpcuser/go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:965 +0x36
github.com/beevik/etree.(*Element).Copy(...)
        /home/vpcuser/go/pkg/mod/github.com/beevik/etree@v1.1.0/etree.go:350
github.com/russellhaering/goxmldsig.(*ValidationContext).Validate(0xc0003fe680?, 0xc0003b0f00?)
        /home/vpcuser/go/pkg/mod/github.com/russellhaering/goxmldsig@v1.2.0/validate.go:486 +0x27
github.com/dexidp/dex/connector/saml.verifyResponseSig(0x1741c00?, {0xc0003b0f00, 0x2028, 0x2028})
        /home/vpcuser/dex/connector/saml/saml.go:616 +0x1b9
github.com/dexidp/dex/connector/saml.(*provider).HandlePOST(0xc0000b7d40, {0x0?, 0x0?}, {0xc0004c2000?, 0xedb2bb0b7?}, {0xc000487fa0, 0x19})
        /home/vpcuser/dex/connector/saml/saml.go:310 +0x1b5
github.com/dexidp/dex/server.(*Server).handleConnectorCallback(0xc0000e0280, {0x174dc00, 0xc0006623c0}, 0xc00067c800)
        /home/vpcuser/dex/server/handlers.go:451 +0xbcf
github.com/dexidp/dex/server.newServer.func7({0x174dc00, 0xc0006623c0}, 0xc00067c800)
        /home/vpcuser/dex/server/server.go:377 +0x129
net/http.HandlerFunc.ServeHTTP(0xc00067c700?, {0x174dc00?, 0xc0006623c0?}, 0x0?)
        /usr/local/go/src/net/http/server.go:2109 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000f2480, {0x174dc00, 0xc0006623c0}, 0xc0005f6500)
        /home/vpcuser/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/dexidp/dex/server.(*Server).ServeHTTP(0x0?, {0x174dc00?, 0xc0006623c0?}, 0x5?)
        /home/vpcuser/dex/server/server.go:402 +0x32
net/http.serverHandler.ServeHTTP({0x720d80?}, {0x174dc00, 0xc0006623c0}, 0xc0005f6500)
        /usr/local/go/src/net/http/server.go:2947 +0x30c
net/http.initALPNRequest.ServeHTTP({{0x174f1f8?, 0xc00036f110?}, 0xc00037e700?, {0xc000161860?}}, {0x174dc00, 0xc0006623c0}, 0xc0005f6500)
        /usr/local/go/src/net/http/server.go:3556 +0x245
net/http.(*http2serverConn).runHandler(0x174a2e8?, 0x226b320?, 0x0?, 0x0?)
        /usr/local/go/src/net/http/h2_bundle.go:5911 +0x78
created by net/http.(*http2serverConn).processHeaders
        /usr/local/go/src/net/http/h2_bundle.go:5641 +0x5b9

Did you solve this issue?

+) config which I use

- type: saml
  id: dex
  name: SAML2.0
  config:
    ssoURL: https://adfs.xxx.com/adfs/ls/idpinitiatedsignon
    ca: /home/vpcuser/dex/xxx.pem
    redirectURI: https://aaa:5556/dex/callback
    entityIssuer: https://aaa:5556/dex/callback
    usernameAttr: username
    emailAttr: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
    nameIDPolicyFormat: emailAddress
notjames commented 1 year ago

I no longer work for them but no, I never resolved that issue. However, we use SAML2 with dex at my current employer and it works so my assumption (though I don't have time to check right now) is likely a misconfiguration of the SAML IDP? Not 100% sure.

GRuuuuu commented 1 year ago

I solved this issue, But still I don't know what is the exact reason. leave my solution here just for reference.

What I did: removed ca in config, and set insecureSkipSignatureValidation: true
like this ->

  config:
    ssoURL: https://xxx.com/adfs/ls/idpinitiatedsignon
    insecureSkipSignatureValidation: true
    #ca: /home/vpcuser/dex/abcd.pem
    redirectURI: https://aaa/dex/callback
    entityIssuer: https://aaa/dex/callback
    usernameAttr: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
    emailAttr: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
    nameIDPolicyFormat: emailAddress
    groupAttr: http://schemas.microsoft.com/ws/2008/06/identity/claims/role

Just my assumption, maybe dex could not find out CA file or could not use CA file properly...? or CA file which I used was wrong

v1pz3n commented 1 year ago

@GRuuuuu I do not recommend keeping this configuration in production, it is very important that you validate the response signature.

You can consider my example below, it worked on AWS SSO.

    dex.config: |
      logger:
        level: debug
        format: json
      connectors:
        - type: saml
          id: sso-id
          name: SSO-NAME
          config:
            entityIssuer: your_custom_issuer
            ssoURL: https://portal.sso.us-east-1.amazonaws.com/saml/assertion/XXXXXXXXX
            caData: | 
              LS0XXXXXXXXXXXX
            usernameAttr: username
            emailAttr: email
            groupsAttr: groups

In your IDP, you also need to configure the following

User attribute in the application | Maps to this string value | Format Subject | ${user:subject} | persistent ** on AWS this is mandatory, it won't make any difference if it's another IdP groups | your_group_name | basic email | your_email_idp_attribute | basic username | your_username_idp_attribute | basic

the caData value must be the content of the certificate in base64 on a single line

I ended up preferring to customize the entityIssuer but you can use the callback url itself as long as you configure it in your IdP as well, usually it's the audience