nokia / kong-oidc

OIDC plugin for Kong
Apache License 2.0
457 stars 324 forks source link

incorrect expectation of user in response from OIDC OP #8

Closed dogeared closed 6 years ago

dogeared commented 7 years ago

In a typical flow, the response coming back from the OIDC OP has an id_token and an access_token (depending on the response_type used to setup the flow).

Here's a real world response returned form kong-oidc after interacting with Okta's OIDC service (header and signature removed from the access token. You can still inspect the payload):

{
    "id_token": {
        "iat": 1503597747,
        "iss": "https://micah.oktapreview.com/oauth2/aus9vmork8ww5twZg0h7",
        "nonce": "aa6f0c362ad41aefef940daa4fda2b68",
        "email": "micah+okta@afitnerd.com",
        "auth_time": 1503597746,
        "at_hash": "Hj4Kf3zyDomgH4v9GOA2WQ",
        "ver": 1,
        "name": "Micah Silverman",
        "idp": "00o9vaskk2Jt2XFVg0h7",
        "exp": 1503601347,
        "preferred_username": "micah+okta@afitnerd.com",
        "jti": "ID.QioMY8ptmRaUl1ezGi_SZ2yP3JoCBn125VAud3z0Xns",
        "aud": "xdgqP32nYN148gn3gJsW",
        "amr": [
            "pwd"
        ]
    },
    "access_token": "...eyJ2ZXIiOjEsImp0aSI6IkFULmFGS3Ribi12ZldHdk5VLWtFYWlXRG1ZYzJqdE1ieFhiQzlwcE1vOG5xcDgiLCJpc3MiOiJodHRwczovL21pY2FoLm9rdGFwcmV2aWV3LmNvbS9vYXV0aDIvYXVzOXZtb3JrOHd3NXR3WmcwaDciLCJhdWQiOiJodHRwczovL2FmaXRuZXJkLmNvbS90ZXN0IiwiaWF0IjoxNTAzNTk3NzQ3LCJleHAiOjE1MDM2MDEzNDcsImNpZCI6InhkZ3FQMzJuWU4xNDhnbjNnSnNXIiwidWlkIjoiMDB1OXZtZTk5bnh1ZHZ4WkEwaDciLCJzY3AiOlsiYWRkcmVzcyIsInByb2ZpbGUiLCJwaG9uZSIsIm9wZW5pZCIsImVtYWlsIl0sInN1YiI6Im1pY2FoK29rdGFAYWZpdG5lcmQuY29tIiwiZnVsbE5hbWUiOiJNaWNhaCBTaWx2ZXJtYW4ifQ..."
}

After authenticating, Kong is throwing an error:

image

Looking at the error log, I see:

2017/08/24 18:02:27 [error] 6877#0: *15 lua entry thread aborted: runtime error: /usr/local/share/lua/5.1/kong/plugins/oidc/utils.lua:63: attempt to index local 'user' (a nil value)
stack traceback:
coroutine 0:
        /usr/local/share/lua/5.1/kong/plugins/oidc/utils.lua: in function 'injectUser'
        /usr/local/share/lua/5.1/kong/plugins/oidc/handler.lua:43: in function 'access'
        /usr/local/share/lua/5.1/kong.lua:350: in function 'access'
        access_by_lua(nginx-kong.conf:88):2: in function <access_by_lua(nginx-kong.conf:88):1>, client: 127.0.0.1, server: kong, request: "GET /example HTTP/1.1", host: "localhost:8000"

Looking at handler.lua, I see:

    if res then
      utils.injectUser(res.user)
      ngx.req.set_header("X-Userinfo", require("cjson").encode(res.user))
    end

Why is it looking for res.user in the response?

If I change these two lines to use: res.id_token instead, then everything works.

Trojan295 commented 7 years ago

Hmm.. the res.user is the response from the Userinfo endpoint. I'm thinking why doesn't your ID Token have the subject field (sub).

We could use id_token as a fallback, if the user is not set.

dogeared commented 7 years ago

the id_token does have a sub claim.

It looks like the call to /userinfo is failing. Here's what I have in the error.log:

2017/08/24 20:31:07 [error] 6966#0: *9869 [lua] openidc.lua:270: openidc_call_userinfo_endpoint(): accessing userinfo endpoint (https://micah.oktapreview.com/oauth2/aus9vmork8ww5twZg0h7/v1/userinfo) failed: 20: unable to get local issuer certificate, client: 127.0.0.1, server: kong, request: "GET /example/?code=ABsh65c44uqPQcnh_Bdq&state=70e6d54f00eb86dee7985413f6c08156 HTTP/1.1", host: "localhost:8000"

It should be using the access_token (which it has) as a bearer token to hit the /userinfo endpoint.

If I do it from the command line (using httpie) with the access_token, I get a response:

http \
https://micah.oktapreview.com/oauth2/aus9vmork8ww5twZg0h7/v1/userinfo \
Authorization:"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik93bFNJS3p3Mmt1Wk8zSmpnMW5Dc2RNelJhOEV1elY5emgyREl6X3RVRUkifQ..."

here's the response:

{
    "email": "micah+okta@afitnerd.com",
    "email_verified": true,
    "family_name": "Silverman",
    "given_name": "Micah",
    "locale": "en-US",
    "name": "Micah Silverman",
    "preferred_username": "micah+okta@afitnerd.com",
    "sub": "00u9vme99nxudvxZA0h7",
    "updated_at": 1490198843,
    "zoneinfo": "America/Los_Angeles"
}
zandbelt commented 6 years ago

My guess is that X-Userinfo is only to be set when a call to the userinfo endpoint is made and succeeds. If so, I'd use if res.user then as the condition. In your case the call fails because of a certificate verification issue which probably means that you need to set lua_ssl_trusted_certificate.

phirvone commented 6 years ago

FIxed in version 1.0.3.