solo-io / gloo

The Feature-rich, Kubernetes-native, Next-Generation API Gateway Built on Envoy
https://docs.solo.io/
Apache License 2.0
4.04k stars 431 forks source link

extauth: error extracting userInfo #5601

Open jmunozro opened 2 years ago

jmunozro commented 2 years ago

Describe the bug Configuring accessTokenValidation>UserinfoUrl, when the UserInfo is returned from the OpenID Provider And if I have an additional passthrough config step afterwards, then the Userinfo payload is not stored correctly into the state map

logs from extauth in debug mode:

{"level":"debug","ts":1637319447.5883396,"logger":"ext-auth.ext-auth-service","msg":"Received auth request","version":"undefined","request":{"attributes":{"source":{"address":{"Address":{"SocketAddress":{"address":"10.4.0.1","PortSpecifier":{"PortValue":50633}}}}},"destination":{"address":{"Address":{"SocketAddress":{"address":"10.4.0.4","PortSpecifier":{"PortValue":8443}}}},"principal":"CN=*"},"context_extensions":{"config_id":"gloo-system.oauth","source_name":"","source_type":"route"},"request":{"time":1637319447.587032,"http":{"body":"","host":"34.77.238.250","fragment":"","method":"GET","path":"/get","scheme":"https","size":0,"query":"","protocol":"HTTP/2","id":"17893797955404907844","headers":{":method":"GET","upgrade-insecure-requests":"1",":path":"/get","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.5","cache-control":"max-age=0","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","x-request-id":"587f51b6-cd2c-4bc7-a136-7eee2092342c","sec-fetch-site":"none","dnt":"1","x-forwarded-proto":"https","sec-fetch-dest":"document","cookie":"session=7FF6EC6RDV737VLKQPD5WW33H6U4WKU62TCEPSBR5UWF3FV4I7S2LF5IORLO22LLZ6LGACABBBWATPAYHOTGRD4LIXMUCYEIMHA2LBA=; id_token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMc0RaWVZaS1hpQXNCNXowQVlETmVjVEk4a2dpUzI2WTZtc3JxYmhmYkRVIn0.eyJleHAiOjE2MzczMTk0ODksImlhdCI6MTYzNzMxOTQyOSwiYXV0aF90aW1lIjoxNjM3MzE5Mzc0LCJqdGkiOiI0NDg2ZDk5ZS1kMjdjLTRmODQtOTFlMy1jYzUzODkyNTVkNjQiLCJpc3MiOiJodHRwOi8vMzQuNzkuNDYuMTcyOjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiODViZTk4NmItYjgxYS00ZmMwLTk5ODYtNzA0MWE3ZjZjNGU1Iiwic3ViIjoiMzU2YWI2Y2YtM2VkMy00MWNjLWJkYmYtMGU2YTgzNmMxNjJmIiwidHlwIjoiSUQiLCJhenAiOiI4NWJlOTg2Yi1iODFhLTRmYzAtOTk4Ni03MDQxYTdmNmM0ZTUiLCJzZXNzaW9uX3N0YXRlIjoiZDNlMjU0MWMtNTA2MS00MzY5LWI0NDAtZjljNWJlMDUyNGEwIiwiYXRfaGFzaCI6IlcwZ3ZoNV9SazdJQXh3RC0xTk5FbGciLCJhY3IiOiIwIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ1c2VyMSIsImVtYWlsIjoidXNlcjFAc29sby5pbyIsImdyb3VwIjoidXNlcnMifQ.EpExCbcP3iI44tSDrZSfe1g7NfErl-algT4-XDoxuBdRPiO3D4FHB4B8kD3EURJU2U3o9hKnSCX5miYEJPgU1FuhZKq3tTRM0C7RR7m0hFHX-4T-QLxuSIw83k12U73btc1fjrA3vL45jZhQcy5xenBnqaZBtj1rNlA_98Tl75r92aDsYI0n1jY_4IjNPFXWG9RUgC28Z43jjQimvZENKZRH48GOEq4vmjGuILkk7whmCdv1qAyASqdsqp_1Tci-mfbp7D5Xm0C0EZ4ZIUzlL4v0b6z8-vza9Ripm4SxHNGTywZ3xMG1h4QG6LtekAIR9Xekx7zE2zRe2IC5o0ML5w; access_token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMc0RaWVZaS1hpQXNCNXowQVlETmVjVEk4a2dpUzI2WTZtc3JxYmhmYkRVIn0.eyJleHAiOjE2MzczMTk0ODksImlhdCI6MTYzNzMxOTQyOSwiYXV0aF90aW1lIjoxNjM3MzE5Mzc0LCJqdGkiOiI5ZDc5MTM0MS1lZmJkLTQxYzAtYjYyNi04MmM4NGUwMzBhMDciLCJpc3MiOiJodHRwOi8vMzQuNzkuNDYuMTcyOjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjM1NmFiNmNmLTNlZDMtNDFjYy1iZGJmLTBlNmE4MzZjMTYyZiIsInR5cCI6IkJlYXJlciIsImF6cCI6Ijg1YmU5ODZiLWI4MWEtNGZjMC05OTg2LTcwNDFhN2Y2YzRlNSIsInNlc3Npb25fc3RhdGUiOiJkM2UyNTQxYy01MDYxLTQzNjktYjQ0MC1mOWM1YmUwNTI0YTAiLCJhY3IiOiIwIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ1c2VyMSIsImVtYWlsIjoidXNlcjFAc29sby5pbyIsImdyb3VwIjoidXNlcnMifQ.LcQ2pVFN4WbvidJi1-VwkgDcudb_yw7cJqLCyjegI3nes7eI0xqPSWwF_cuRmAJ5rSHNLjPQ4FS3UkjcpNNMKVd-C6gb1dEF1r1HBLS9AOYQKc4C7gpjEhnnG6vemHJKbaFgkE0UDqEZ9aWazQAn2CIH6CUPfIMPeF23UK7tC65a3pJGm4g0pIbW25vmJypU3DAZxCjDW4edU-TZTr2csM-0bUp4olbkPZGJiFpLM_eXsixl13xeqLxO2psKBBFx7FkoRG1TeCv8fNS_Qy8q6samqVItm8kxl92WrjLceARH8SSdokys5Y5uj51hsW2_UF2ez7l1j_kvoEpV6X_smQ","sec-fetch-user":"?1",":authority":"34.77.238.250","sec-fetch-mode":"navigate","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0","te":"trailers",":scheme":"https"}}}}}}
{"level":"warn","ts":1637319447.5895257,"logger":"ext-auth.ext-auth-service","msg":"failed to build passthrough filter metadata from AuthorizationRequest.State:map[introspection:map[acr:0 active:true aud:account auth_time:1.637319374e+09 azp:85be986b-b81a-4fc0-9986-7041a7f6c4e5 client_id:85be986b-b81a-4fc0-9986-7041a7f6c4e5 email:user1@solo.io email_verified:false exp:1.637319489e+09 group:users iat:1.637319429e+09 iss:http://34.79.46.172:8080/auth/realms/master jti:9d791341-efbd-41c0-b626-82c84e030a07 preferred_username:user1 realm_access:map[roles:[offline_access uma_authorization]] resource_access:map[account:map[roles:[manage-account manage-account-links view-profile]]] scope:openid profile email session_state:d3e2541c-5061-4369-b440-f9c5be0524a0 sub:356ab6cf-3ed3-41cc-bdbf-0e6a836c162f typ:Bearer username:user1] jwt:eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMc0RaWVZaS1hpQXNCNXowQVlETmVjVEk4a2dpUzI2WTZtc3JxYmhmYkRVIn0.eyJleHAiOjE2MzczMTk0ODksImlhdCI6MTYzNzMxOTQyOSwiYXV0aF90aW1lIjoxNjM3MzE5Mzc0LCJqdGkiOiI0NDg2ZDk5ZS1kMjdjLTRmODQtOTFlMy1jYzUzODkyNTVkNjQiLCJpc3MiOiJodHRwOi8vMzQuNzkuNDYuMTcyOjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiODViZTk4NmItYjgxYS00ZmMwLTk5ODYtNzA0MWE3ZjZjNGU1Iiwic3ViIjoiMzU2YWI2Y2YtM2VkMy00MWNjLWJkYmYtMGU2YTgzNmMxNjJmIiwidHlwIjoiSUQiLCJhenAiOiI4NWJlOTg2Yi1iODFhLTRmYzAtOTk4Ni03MDQxYTdmNmM0ZTUiLCJzZXNzaW9uX3N0YXRlIjoiZDNlMjU0MWMtNTA2MS00MzY5LWI0NDAtZjljNWJlMDUyNGEwIiwiYXRfaGFzaCI6IlcwZ3ZoNV9SazdJQXh3RC0xTk5FbGciLCJhY3IiOiIwIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ1c2VyMSIsImVtYWlsIjoidXNlcjFAc29sby5pbyIsImdyb3VwIjoidXNlcnMifQ.EpExCbcP3iI44tSDrZSfe1g7NfErl-algT4-XDoxuBdRPiO3D4FHB4B8kD3EURJU2U3o9hKnSCX5miYEJPgU1FuhZKq3tTRM0C7RR7m0hFHX-4T-QLxuSIw83k12U73btc1fjrA3vL45jZhQcy5xenBnqaZBtj1rNlA_98Tl75r92aDsYI0n1jY_4IjNPFXWG9RUgC28Z43jjQimvZENKZRH48GOEq4vmjGuILkk7whmCdv1qAyASqdsqp_1Tci-mfbp7D5Xm0C0EZ4ZIUzlL4v0b6z8-vza9Ripm4SxHNGTywZ3xMG1h4QG6LtekAIR9Xekx7zE2zRe2IC5o0ML5w userinfo:map[email:user1@solo.io email_verified:false group:users preferred_username:user1 sub:356ab6cf-3ed3-41cc-bdbf-0e6a836c162f]]","version":"undefined","error":"proto: invalid type: user_info.UserInfo"}
{"level":"debug","ts":1637319447.591514,"logger":"ext-auth.ext-auth-service","msg":"Access denied by auth authService","version":"undefined","authService":"config_2"}

To Reproduce Steps to reproduce the behavior:

# Create a secret to secure the api
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=*"
kubectl create secret tls upstream-tls --key tls.key --cert tls.crt --namespace gloo-system

# Deploy keycloak (first ext-auth)
kubectl create -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/12.0.4/kubernetes-examples/keycloak.yaml
kubectl rollout status deploy/keycloak

export ENDPOINT=$(kubectl -n gloo-system get svc gateway-proxy -o jsonpath='{.status.loadBalancer.ingress[0].*}')
export APP_URL=https://${ENDPOINT}

# Get Keycloak URL and token
KEYCLOAK_URL=http://$(kubectl get service keycloak -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):8080/auth
KEYCLOAK_TOKEN=$(curl -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" "$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" | jq -r .access_token)
# Create initial token to register the client
read -r client token <<<$(curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"expiration": 0, "count": 1}' $KEYCLOAK_URL/admin/realms/master/clients-initial-access | jq -r '[.id, .token] | @tsv')
# Register the client
read -r id secret <<<$(curl -X POST -d "{ \"clientId\": \"${client}\" }" -H "Content-Type:application/json" -H "Authorization: bearer ${token}" ${KEYCLOAK_URL}/realms/master/clients-registrations/default| jq -r '[.id, .secret] | @tsv')
# Add allowed redirect URIs
curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X PUT -H "Content-Type: application/json" -d '{"serviceAccountsEnabled": true, "directAccessGrantsEnabled": true, "authorizationServicesEnabled": true, "redirectUris": ["'${APP_URL}'/callback", "http://portal.example.com/callback"]}' $KEYCLOAK_URL/admin/realms/master/clients/${id}
# Add the group attribute in the JWT token returned by Keycloak
curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"name": "group", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "config": {"claim.name": "group", "jsonType.label": "String", "user.attribute": "group", "id.token.claim": "true", "access.token.claim": "true"}}' $KEYCLOAK_URL/admin/realms/master/clients/${id}/protocol-mappers/models
# Create first user
curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"username": "user1", "email": "user1@solo.io", "enabled": true, "attributes": {"group": "users"}, "credentials": [{"type": "password", "value": "password", "temporary": false}]}' $KEYCLOAK_URL/admin/realms/master/users
# Create secret with client-secret
glooctl create secret oauth --namespace gloo-system --name oauth --client-secret ${secret}

# Deploy custom server (second ext-auth)
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: extauth-grpcservice
spec:
  selector:
    matchLabels:
      app: grpc-extauth
  replicas: 1
  template:
    metadata:
      labels:
        app: grpc-extauth
    spec:
      containers:
        - name: grpc-extauth
          # Source code: go/src/grpc-service/pkg/auth/v3/auth-with-state.go
          image: gcr.io/solo-test-236622/jesus-passthrough-grpc-service:userinfo2
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9001
---
apiVersion: v1
kind: Service
metadata:
  name: example-grpc-auth-service
  labels:
      app: grpc-extauth
spec:
  ports:
  - port: 9001
    protocol: TCP
  selector:
      app: grpc-extauth
EOF

# Create authconfig with 2 steps
kubectl apply -f - <<EOF
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
  name: oauth
  namespace: gloo-system
spec:
  configs:
    - oauth2:
        oidcAuthorizationCode:
          appUrl: ${APP_URL}
          callbackPath: /callback
          clientId: ${client}
          clientSecretRef:
            name: oauth
            namespace: gloo-system
          issuerUrl: "${KEYCLOAK_URL}/realms/master/"
          logoutPath: /logout
          scopes:
            - email
          # session:
          #   failOnFetchFailure: true
          #   redis:
          #     cookieName: session
          #     options:
          #       host: 'redis.gloo-system.svc.cluster.local:6379'
    - oauth2:
        accessTokenValidation:
          introspection:
            clientId: ${client}
            clientSecretRef:
              name: oauth
              namespace: gloo-system
            introspectionUrl: "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token/introspect"
          userinfoUrl: ${KEYCLOAK_URL}/realms/master/protocol/openid-connect/userinfo
    - passThroughAuth:
        grpc:
          address: 'example-grpc-auth-service.default.svc.cluster.local:9001'
          connectionTimeout: 3s
EOF

# Create vs with everything
kubectl apply -f - <<EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: demo
  namespace: gloo-system
spec:
  sslConfig:
    secretRef:
      name: upstream-tls
      namespace: gloo-system
  virtualHost:
    domains:
      - '*'
    routes:
      - matchers:
          - prefix: /
        options:
          extauth:
            configRef:
              name: oauth
              namespace: gloo-system
        routeAction:
          single:
            upstream:
              name: default-httpbin-8000
              namespace: gloo-system
EOF

# Now open a browser
/opt/google/chrome/chrome $APP_URL/get

# Authenticate with user1/password, and check in the logs that the token is captured in custom extauth server
kubectl logs deploy/extauth-grpcservice

Expected behavior userinfo is extracted and available in the state

Additional context Add any other context about the problem here, e.g.

This is the userinfo returned from the endpoint, lgtm:

curl -H "Authorization: Bearer eyJhbGciOiJSU...." http://34.79.46.172:8080/auth/realms/master/protocol/openid-connect/userinfo                   

{"sub":"356ab6cf-3ed3-41cc-bdbf-0e6a836c162f","email_verified":false,"preferred_username":"user1","email":"user1@solo.io","group":"users"}
github-actions[bot] commented 1 month ago

This issue has been marked as stale because of no activity in the last 180 days. It will be closed in the next 180 days unless it is tagged "no stalebot" or other activity occurs.