Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OIDC - Keycloak - Login Error #21259

Open
marcossilvestrini opened this issue Nov 28, 2024 · 2 comments
Open

OIDC - Keycloak - Login Error #21259

marcossilvestrini opened this issue Nov 28, 2024 · 2 comments
Assignees
Labels
area/oidc more-info-needed The issue author need to provide more details and context to the issue

Comments

@marcossilvestrini
Copy link

marcossilvestrini commented Nov 28, 2024

I'm having trouble using Keycloak as authentication in my Harbor.
I deployed it with this values(chart release: 1.16.0):

# https://github.com/goharbor/harbor-helm/blob/main/values.yaml
harbor:
  expose:
    type: ingress
    tls:
      enabled: true
      certSource: secret
      auto:
        commonName: harbor.local
      secret:
        secretName: "harbor-tls"
    ingress:
      controller: default
      className: "nginx"
      hosts:
        core: harbor.local
      harbor:
        annotations: {}
        labels: {}
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        ingress.kubernetes.io/ssl-redirect: "true"
        ingress.kubernetes.io/proxy-body-size: "0"
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
        nginx.ingress.kubernetes.io/proxy-body-size: "0"
        nginx.ingress.kubernetes.io/server-snippet: |
          if ($request_uri ~* ^/v2/([a-zA-Z0-9]+)/(manifests|blobs|tags)/?(.*)$) {
            set $dockerio_extra_project "/library";
          }

    loadBalancer:
      name: harbor
      IP: ""
      ports:
        httpPort: 80
        httpsPort: 443
      annotations: {}
      sourceRanges: []
  externalURL: https://harbor.local
  persistence:
    enabled: true
    resourcePolicy: "keep"
    persistentVolumeClaim:
      registry:
        storageClass: ""
        accessMode: ReadWriteOnce
        size: 50Gi
      jobservice:
        jobLog:
          storageClass: ""
          accessMode: ReadWriteOnce
          size: 10Gi
      database:
        storageClass: ""
        accessMode: ReadWriteOnce
        size: 10Gi
      redis:
        storageClass: ""
        accessMode: ReadWriteOnce
        size: 10Gi
      trivy:
        storageClass: ""
        accessMode: ReadWriteOnce
        size: 10Gi
    imageChartStorage:
      disableredirect: false
      type: filesystem
      filesystem:
        rootdirectory: /storage
  existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD
  harborAdminPassword: <path:harbor/data/cluster#HARBOR_ADMIN_PASS>
  ipFamily:
    ipv6:
      enabled: false
    ipv4:
      enabled: true
  updateStrategy:
    type: "Recreate"
  logLevel: debug
  secretKey: <path:harbor/data/cluster#HARBOR_ADMIN_PASS>
  existingSecretSecretKey: ""
  proxy:
    httpProxy:
    httpsProxy:
    noProxy: 127.0.0.1,localhost,.local,.internal
    components:
      - core
      - jobservice
      - trivy
  metrics:
    enabled: true
    core:
      path: /metrics
      port: 8001
    registry:
      path: /metrics
      port: 8001
    jobservice:
      path: /metrics
      port: 8001
    exporter:
      path: /metrics
      port: 8001

    serviceMonitor:
      enabled: true
      additionalLabels: {}
      interval: ""
      metricRelabelings: []
  cache:
    enabled: true
    expireHours: 730
  nginx:
    image:
      repository: goharbor/nginx-photon
      tag: v2.12.0
    replicas: 1

  portal:
    image:
      repository: goharbor/harbor-portal
      tag: v2.12.0
    replicas: 1

  core:
    image:
      repository: goharbor/harbor-core
      tag: v2.12.0
    replicas: 1

  jobservice:
    image:
      repository: goharbor/harbor-jobservice
      tag: v2.12.0
    replicas: 1

  registry:
    registry:
      image:
        repository: goharbor/registry-photon
        tag: v2.12.0
    controller:
      image:
        repository: goharbor/harbor-registryctl
        tag: v2.12.0
    replicas: 1

  trivy:
    enabled: true
    image:
      repository: goharbor/trivy-adapter-photon
      tag: v2.12.0
    replicas: 1
    debugMode: false
    vulnType: "os,library"
    severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
    ignoreUnfixed: false
    insecure: false
    securityCheck: "vuln"
    timeout: 5m0s

  database:
    type: internal
    internal:
      image:
        repository: goharbor/harbor-db
        tag: v2.12.0
      password: <path:harbor/data/cluster#HARBOR_POSTGRES_PASSWORD>
      shmSizeLimit: 512Mi
    external:
      host: "192.168.0.1"
      port: "5432"
      username: "user"
      password: "password"
      coreDatabase: "registry"
      existingSecret: ""
      sslmode: "disable"
    maxIdleConns: 100
    maxOpenConns: 900

  redis:
    type: internal
    internal:
      image:
        repository: goharbor/redis-photon
        tag: v2.12.0

  exporter:
    replicas: 1
    revisionHistoryLimit: 10
    image:
      repository: goharbor/harbor-exporter
      tag: v2.12.0
    cacheDuration: 23
    cacheCleanInterval: 14400
    priorityClassName:

My harbor oidc configurations:

OIDC Provider Name 
keycloak

OIDC Endpoint 
https://keycloak.local/realms/production

OIDC Client ID
harbor

OIDC Client Secret
foobarbeer

OIDC Scope 
openid,profile,email,offline_access

Verify Certificate 
true

My keycloak client:

{
  "clientId": "harbor",
  "name": "harbor",
  "description": "Harbor client",
  "rootUrl": "https://harbor.local",
  "adminUrl": "https://harbor.local",
  "baseUrl": "https://harbor.local",
  "surrogateAuthRequired": false,
  "enabled": true,
  "alwaysDisplayInConsole": false,
  "clientAuthenticatorType": "client-secret",
  "secret": "my-secret-here",
  "redirectUris": [
    "https://harbor.local/c/oidc/callback"
  ],
  "webOrigins": [
    "https://harbor.local"
  ],
  "notBefore": 0,
  "bearerOnly": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": true,
  "publicClient": false,
  "frontchannelLogout": true,
  "protocol": "openid-connect",
  "attributes": {
    "oidc.ciba.grant.enabled": "false",
    "client.secret.creation.time": "1732804243",
    "backchannel.logout.session.required": "true",
    "oauth2.device.authorization.grant.enabled": "false",
    "backchannel.logout.revoke.offline.tokens": "false"
  },
  "authenticationFlowBindingOverrides": {},
  "fullScopeAllowed": true,
  "nodeReRegistrationTimeout": -1,
  "protocolMappers": [
    {
      "name": "Client Host",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientHost",
        "id.token.claim": "true",
        "introspection.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientHost",
        "jsonType.label": "String"
      }
    },
    {
      "name": "Client ID",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "client_id",
        "id.token.claim": "true",
        "introspection.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "client_id",
        "jsonType.label": "String"
      }
    },
    {
      "name": "Client IP Address",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientAddress",
        "id.token.claim": "true",
        "introspection.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientAddress",
        "jsonType.label": "String"
      }
    }
  ],
  "defaultClientScopes": [
    "web-origins",
    "acr",
    "address",
    "profile",
    "roles",
    "offline_access",
    "organization",
    "harbor",
    "groups",
    "microprofile-jwt",
    "basic",
    "email"
  ],
  "optionalClientScopes": [
    "phone"
  ],
  "access": {
    "view": true,
    "configure": true,
    "manage": true
  }
}

Firefox error 400 :

'oauth2: "unauthorized_client" "Invalid client or Invalid client credentials"'

url:

https://harbor.local/c/oidc/callback?state=VtwYOjAIc3UOoMys0dc27bvwu9d73j09&session_state=fab50f9b-d4af-4757-a1cf-2c24f92636b0&iss=https%3A%2F%2Fkeycloak.local%2Frealms%2Fproduction&code=foobarbeer

Test with curl(I modify keycloak client, parameter Use refresh tokens for this test):

curl -X POST \
  https://keycloak.local/realms/production/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=foobarbeer" \
  -d "redirect_uri=https://harbor.local/c/oidc/callback" \
  -d "client_id=harbor" \
  -d "client_secret=foobarbeer"

Payload result:

{
    "access_token": "foobarbeer",
    "expires_in": 300,
    "refresh_expires_in": 0,
    "token_type": "Bearer",
    "id_token": "foobarbeer",
    "not-before-policy": 0,
    "session_state": "fab50f9b-d4af-4757-a1cf-2c24f92636b0",
    "scope": "openid address profile email microprofile-jwt groups organization"
}

access_token decrypted:

{
  "exp": 1732807056,
  "iat": 1732806756,
  "auth_time": 1732806690,
  "jti": "fooobarbeer",
  "iss": "https://keycloak.local/realms/production",
  "aud": [
    "realm-management",
    "broker",
    "account"
  ],
  "sub": "foobarberr",
  "typ": "Bearer",
  "azp": "harbor",
  "sid": "fooooooo-d4af-4757-a1cf-2c24f92636b0",
  "acr": "1",
  "allowed-origins": [
    "https://harbor.local"
  ],
  "realm_access": {
    "roles": [
      "default-roles-production"
    ]
  },
  "resource_access": {
    "realm-management": {
      "roles": [
        "view-identity-providers",
        "view-realm",
        "manage-identity-providers",
        "impersonation",
        "realm-admin",
        "create-client",
        "manage-users",
        "query-realms",
        "view-authorization",
        "query-clients",
        "query-users",
        "manage-events",
        "manage-realm",
        "view-events",
        "view-users",
        "view-clients",
        "manage-authorization",
        "manage-clients",
        "query-groups"
      ]
    },
    "broker": {
      "roles": [
        "read-token"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "view-applications",
        "view-consent",
        "view-groups",
        "manage-account-links",
        "manage-consent",
        "delete-account",
        "view-profile"
      ]
    }
  },
  "scope": "openid address profile email microprofile-jwt groups organization",
  "group_membership": [
    "admin",
    "architects"
  ],
  "upn": "marcos_roberto",
  "email_verified": false,
  "address": {},
  "name": "Marcos Roberto",
  "groups": [
    "default-roles-production",
    "default-roles-production",
    "default-roles-production"
  ],
  "preferred_username": "marcos_roberto",
  "given_name": "Marcos",
  "family_name": "Roberto"
}

harbor-core logs:

harbor-core-f7bcf4cb7-6vj7p core 2024-11-28T14:59:21Z [DEBUG] [/server/middleware/artifactinfo/artifact_info.go:55]: In artifact info middleware, url: /c/oidc/callback?state=J7LMWgW0NzZyoCz5BYwovOTZmCBH79t7&session_state=87ef2719-8876-4fa2-9993-906964fd6ce3&iss=https%3A%2F%2Fkeycloak.local%2Frealms%2Fproduction&code=foobarbeer
harbor-core-f7bcf4cb7-6vj7p core 2024-11-28T14:59:21Z [DEBUG] [/server/middleware/security/unauthorized.go:28][requestID="a93fa8bb010492c8d07ecf59309292a2"]: an unauthorized security context generated for request GET /c/oidc/callback
harbor-core-f7bcf4cb7-6vj7p core 2024-11-28T14:59:21Z [ERROR] [/core/controllers/oidc.go:118]: Failed to exchange token, error: oauth2: "unauthorized_client" "Invalid client or Invalid client credentials"
harbor-core-f7bcf4cb7-6vj7p core 2024-11-28T14:59:21Z [DEBUG] [/lib/http/error.go:62]: {"errors":[{"code":"BAD_REQUEST","message":"oauth2: \"unauthorized_client\" \"Invalid client or Invalid client credentials\""}]}

keycloak logs:

2024-11-28 14:59:21,746 WARN  [org.keycloak.events] (executor-thread-11) type="CODE_TO_TOKEN_ERROR", realmId="f3e2fad5-4b31-4689-a860-9d20847dd772", realmName="production", clientId="harbor", userId="null", ipAddress="192.168.4.240", error="invalid_client_credentials", grant_type="authorization_code"
2024-11-28 14:59:21,779 WARN  [org.keycloak.events] (executor-thread-10) type="CODE_TO_TOKEN_ERROR", realmId="f3e2fad5-4b31-4689-a860-9d20847dd772", realmName="production", clientId="harbor", userId="null", ipAddress="192.168.4.240", error="invalid_client_credentials", grant_type="authorization_code"

I've tried everything, but I can't get OIDC to work on my Harbor. I use Keycloak with all other apps like ArgoCD, Vault, Grafana, etc., but it doesn't work with Harbor.

@MinerYang MinerYang transferred this issue from goharbor/harbor-helm Dec 2, 2024
@reasonerjt reasonerjt self-assigned this Dec 2, 2024
@reasonerjt
Copy link
Contributor

reasonerjt commented Dec 2, 2024

@marcossilvestrini
I think the error message is clear
Invalid client or Invalid client credentials
Please double-check the client ID and client secret is correct.

I've tried everything, but I can't get OIDC to work on my Harbor. I use Keycloak with all other apps like ArgoCD, Vault, Grafana, etc., but it doesn't work with Harbor.

This is likely b/c they are using different clients and you misconfigured in Harbor.

@reasonerjt reasonerjt added the more-info-needed The issue author need to provide more details and context to the issue label Dec 2, 2024
@marcossilvestrini
Copy link
Author

marcossilvestrini commented Dec 3, 2024

@reasonerjt
Obviously I got client id and secret... unnecessary comment given all the context I went through. As for the "Invalid client or Invalid client credentials" message, you're wrong if you think it's "Clear"...it's as generic as the available TEST OIDC SERVER (I believe it doesn't validate anything credentials of oidc client). You should have observed the logs I sent...it has a lot of interesting things that could help us discover...alias with the same client id and secret I can negotiate the token through curl. If you don't want to help ok, now avoid unnecessary comments.

By the way... the oidc server test is successful... does this validate as credentials?

image

Client id and secret validate with curl:

curl -X POST \                                                                                                                                                           
  https://keycloak.local/realms/production/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=foo" \
  -d "redirect_uri=https://harbor.local/c/oidc/callback" \
  -d "client_id=harbor" \
  -d "client_secret=foo"

Result:

{"access_token":"foobar","expires_in":300,"refresh_expires_in":0,"token_type":"Bearer","id_token":"foo","not-before-policy":0,"session_state":"0b1b1db7-243f-46cd-ac80-8f2bca7780ff","scope":"openid address profile email microprofile-jwt groups organization"}                                                                                                                                          

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/oidc more-info-needed The issue author need to provide more details and context to the issue
Projects
None yet
Development

No branches or pull requests

2 participants