jfrog / charts

JFrog official Helm Charts
https://jfrog.com/integration/helm-repository/
Apache License 2.0
249 stars 436 forks source link

login with oauth error - Binding token to existing user #1856

Closed husira closed 5 months ago

husira commented 5 months ago

Potential Bug Report

We deploy and operate an artifactory-pro instance for our customer (release 7.55.14) on a Kubernetes Cluster. For the Artifactory-pro we use the following statefulset.yaml and system.yaml (see files at the bottom).

In our Datacenter we have a new Kubernetes Platform so we need to migrate the whole Kubernetes Cluster to another platform. We migrate the whole PersistentVolume data from Artifactory and the Postgresql Database from the existing to a new Kubernetes Cluster.

This works perfectly and all the data could be migrated without any problems except one: The customer is using an OIDC OAuth provider which is configured in Artifactory:

image

After the cluster migration, all existing users with the realm "oauth" receive the following error after login with the OIDC provider:

image
login with oauth error - Binding token to existing user: 'xyz' (xyz@email.com) is allowed only through the user profile page

Artifactory-Log:

artifactory-0 artifactory 2024-01-29T12:22:08.101Z [jfrt ] [ERROR] [1383d3ed43a0b232] [o.a.a.s.o.OAuthHandlerImpl:202] [http-nio-8081-exec-8] - Error handling OAuth2 login: Binding token to existing user: 'xyz' (xyz@email.com) is allowed only through the user profile page

The user already exists in Artifactory:

image

If we remove the user from the Admin page (/ui/admin/management/users), the login via OIDC works again because the user is re-created automatically and the binding to the OAuth provider is done initially. But we can't remove all existing users with realm "oauth", because there is a large number of users and they have different groups & permissions.

With exact the same configuration on the existing cluster, the user is able to login using the same OAuth SSO provider. From our perspective this looks like a bug or deadlock, because regarding the Artifactory docs only the user itself could link his account via profile page to an existing OAuth provider: https://jfrog.com/help/r/jfrog-platform-administration-documentation/binding-existing-user-accounts But anyway the user should already be linked to this existing OAuth provider, because we copied all the data.

We have also looked through the Postgresql database, to check if the binding can be renewed somewhere via DB. However, we can't find anything. Actually an Admin account should have the possibility to bind existing users to existing OAuth Providers. Unfortunately we haven't even found an according REST API.

Thank you for your help.


Is this a BUG REPORT or FEATURE REQUEST? (choose one): Bug Report

Version of Helm and Kubernetes: Helm v3.13.1 and Kubernetes v1.24

Which chart: 107.55.14 (7.55.14). Also tested with 107.71.5 (7.71.5) with the same result.

Which product license (Enterprise/Pro/oss): Pro

JFrog support reference (if already raised with support team):

What happened: login with oauth error - Binding token to existing user

What you expected to happen: Login with OAuth Provider should work as expected

How to reproduce it (as minimally and precisely as possible): see description above

Anything else we need to know:

system.yaml

router:
  serviceRegistry:
    insecure: false
shared:
  logging:
    consoleLog:
      enabled: false
  extraJavaOpts: >
    -Dartifactory.graceful.shutdown.max.request.duration.millis=0
    -Dartifactory.access.client.max.connections=50
    -Djavax.net.ssl.trustStore=/opt/jfrog/artifactory/app/third-party/java/lib/security/cacerts_custom
  database:
    type: "postgresql"
    driver: "org.postgresql.Driver"
artifactory:
  database:
    maxOpenConnections: 80
  tomcat:
    maintenanceConnector:
      port: 8091
    connector:
      maxThreads: 200
      sendReasonPhrase: false
      extraConfig: acceptCount="100"
frontend:
  session:
    timeMinutes: "30"
access:
  database:
    maxOpenConnections: 80
  tomcat:
    connector:
      maxThreads: 50
      sendReasonPhrase: false
      extraConfig: acceptCount="100"
metadata:
  database:
    maxOpenConnections: 80
jfconnect:
  enabled: true

statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations:
    konvert.kumorilabs.io/chart: https://charts.jfrog.io,artifactory
    konvert.kumorilabs.io/generated-by: konvert
  labels:
    app: artifactory
    chart: artifactory-107.55.14
    component: artifactory
    heritage: Helm
    release: artifactory
  name: artifactory
spec:
  replicas: 1
  selector:
    matchLabels:
      app: artifactory
      release: artifactory
      role: artifactory
  serviceName: artifactory
  template:
    metadata:
      annotations:
        checksum/access-config: 3215dfe6a3a807e6d5807cf25849dbe138ac0b7b834d44b7d144274143ea532c
        checksum/binarystore: 7ba07805046fdc20760566efc52cde5153feb9ac43c0ddeac25ae8d1dba3dc0d
        checksum/database-secrets: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
        checksum/systemyaml: 52169284926a9bc247d14443144fb79aa7416b0df7e3242e23fda8d5c7763944
      labels:
        app: artifactory
        chart: artifactory-107.55.14
        component: artifactory
        heritage: Helm
        release: artifactory
        role: artifactory
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: artifactory
                  release: artifactory
              topologyKey: kubernetes.io/hostname
            weight: 100
      containers:
      - command:
        - /bin/bash
        - -c
        - |
          set -e; if [ -d /artifactory_extra_conf ] && [ -d /artifactory_bootstrap ]; then

            echo "Copying bootstrap config from /artifactory_extra_conf to /artifactory_bootstrap";
            cp -Lrfv /artifactory_extra_conf/ /artifactory_bootstrap/;
          fi; exec /entrypoint-artifactory.sh
        env:
        - name: JF_SHARED_DATABASE_USERNAME
          valueFrom:
            secretKeyRef:
              key: username
              name: artifactory.artifactory-postgres.credentials
        - name: JF_SHARED_DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              key: password
              name: artifactory.artifactory-postgres.credentials
        - name: JF_SHARED_DATABASE_URL
          valueFrom:
            secretKeyRef:
              key: db-url
              name: artifactory
        - name: JVM_MINIMUM_MEMORY
          value: 3072m
        - name: JVM_MAXIMUM_MEMORY
          value: 3072m
        - name: JVM_RESERVED_CODE_CACHE_SIZE
          value: 1524m
        - name: JVM_SUPPORT_RECOMMENDED_ARGS
          value: -Duser.timezone=Europe/Zurich -Djavax.net.ssl.trustStore=/opt/jfrog/artifactory/app/third-party/java/lib/security/cacerts_custom
            -Djavax.net.ssl.trustStorePassword=changeit -Dhttp.proxyHost=proxy.proxy.com
            -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy.proxy.com
            -Dhttps.proxyPort=8080 -Dhttp.nonProxyHosts="localhost|*.svc|*.svc.cluster.local"
        - name: SKIP_WAIT_FOR_EXTERNAL_DB
          value: "true"
        image: releases-docker.jfrog.io/jfrog/artifactory-pro:7.55.14
        imagePullPolicy: IfNotPresent
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - curl -s -k --fail --max-time 5 http://localhost:8091/artifactory/api/v1/system/liveness
          failureThreshold: 5
          initialDelaySeconds: 0
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        name: artifactory
        ports:
        - containerPort: 8082
          name: http
        - containerPort: 8081
          name: http-internal
        resources:
          limits:
            cpu: "2"
            memory: 6Gi
          requests:
            cpu: 500m
            memory: 5Gi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - NET_RAW
          runAsNonRoot: true
        startupProbe:
          exec:
            command:
            - sh
            - -c
            - curl -s -k --fail --max-time 5 http://localhost:8091/artifactory/api/v1/system/readiness
          failureThreshold: 90
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 5
        volumeMounts:
        - mountPath: /var/opt/jfrog/artifactory
          name: artifactory-volume
        - mountPath: /opt/jfrog/artifactory/app/third-party/java/lib/security/cacerts_custom
          name: java-keystore-cacert
          readOnly: true
          subPath: cacerts_custom
        - mountPath: /tmp/etc/artifactory/binarystore.xml
          name: binarystore-xml
          subPath: binarystore.xml
        - mountPath: /artifactory_bootstrap/artifactory.cluster.license
          name: artifactory-license
          subPath: license
        - mountPath: /artifactory_bootstrap/info/installer-info.json
          name: installer-info
          subPath: installer-info.json
      initContainers:
      - command:
        - bash
        - -c
        - rm -fv /var/opt/jfrog/artifactory/etc/db.properties
        image: releases-docker.jfrog.io/ubi9/ubi-minimal:9.1.0.1760
        imagePullPolicy: IfNotPresent
        name: delete-db-properties
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: 10m
            memory: 50Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - NET_RAW
          runAsNonRoot: true
        volumeMounts:
        - mountPath: /var/opt/jfrog/artifactory
          name: artifactory-volume
      - command:
        - bash
        - -c
        - rm -rfv /var/opt/jfrog/artifactory/lost+found /var/opt/jfrog/artifactory/data/.lock
        image: releases-docker.jfrog.io/ubi9/ubi-minimal:9.1.0.1760
        imagePullPolicy: IfNotPresent
        name: remove-lost-found
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: 10m
            memory: 50Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - NET_RAW
          runAsNonRoot: true
        volumeMounts:
        - mountPath: /var/opt/jfrog/artifactory
          name: artifactory-volume
      - command:
        - bash
        - -c
        - |
          echo "Preparing /var/opt/jfrog/artifactory/etc/access/bootstrap.creds"; mkdir -p /var/opt/jfrog/artifactory/etc/access; cp -Lrf /tmp/access/bootstrap.creds /var/opt/jfrog/artifactory/etc/access/bootstrap.creds; chmod 600 /var/opt/jfrog/artifactory/etc/access/bootstrap.creds;
        image: releases-docker.jfrog.io/ubi9/ubi-minimal:9.1.0.1760
        imagePullPolicy: IfNotPresent
        name: access-bootstrap-creds
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: 10m
            memory: 50Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - NET_RAW
          runAsNonRoot: true
        volumeMounts:
        - mountPath: /var/opt/jfrog/artifactory
          name: artifactory-volume
        - mountPath: /tmp/access/bootstrap.creds
          name: access-bootstrap-creds
          subPath: admin-password
      - command:
        - /bin/bash
        - -c
        - |
          if [[ -e "/var/opt/jfrog/artifactory/etc/filebeat.yaml" ]]; then chmod 644 /var/opt/jfrog/artifactory/etc/filebeat.yaml; fi; echo "Copy system.yaml to /var/opt/jfrog/artifactory/etc"; mkdir -p /var/opt/jfrog/artifactory/etc; mkdir -p /var/opt/jfrog/artifactory/etc/access/keys/trusted; cp -fv /tmp/etc/system.yaml /var/opt/jfrog/artifactory/etc/system.yaml; echo "Remove /var/opt/jfrog/artifactory/lost+found folder if exists"; rm -rfv /var/opt/jfrog/artifactory/lost+found; echo "Copy binarystore.xml file"; mkdir -p /var/opt/jfrog/artifactory/etc/artifactory; cp -fv /tmp/etc/artifactory/binarystore.xml /var/opt/jfrog/artifactory/etc/artifactory/binarystore.xml; echo "Copy access.config.patch.yml to /var/opt/jfrog/artifactory/etc/access"; mkdir -p /var/opt/jfrog/artifactory/etc/access; cp -fv /tmp/etc/access.config.patch.yml /var/opt/jfrog/artifactory/etc/access/access.config.patch.yml; echo "Copy joinKey to /var/opt/jfrog/artifactory/bootstrap/access/etc/security"; mkdir -p /var/opt/jfrog/artifactory/bootstrap/access/etc/security; echo -n ${ARTIFACTORY_JOIN_KEY} > /var/opt/jfrog/artifactory/bootstrap/access/etc/security/join.key; echo "Copy masterKey to /var/opt/jfrog/artifactory/etc/security"; mkdir -p /var/opt/jfrog/artifactory/etc/security; echo -n ${ARTIFACTORY_MASTER_KEY} > /var/opt/jfrog/artifactory/etc/security/master.key;
        env:
        - name: ARTIFACTORY_JOIN_KEY
          valueFrom:
            secretKeyRef:
              key: join-key
              name: artifactory
        - name: ARTIFACTORY_MASTER_KEY
          valueFrom:
            secretKeyRef:
              key: master-key
              name: artifactory
        image: releases-docker.jfrog.io/ubi9/ubi-minimal:9.1.0.1760
        name: copy-system-configurations
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: 10m
            memory: 50Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - NET_RAW
          runAsNonRoot: true
        volumeMounts:
        - mountPath: /var/opt/jfrog/artifactory
          name: artifactory-volume
        - mountPath: /tmp/etc/system.yaml
          name: systemyaml
          subPath: system.yaml
        - mountPath: /tmp/etc/artifactory/binarystore.xml
          name: binarystore-xml
          subPath: binarystore.xml
        - mountPath: /tmp/etc/access.config.patch.yml
          name: access-config
          subPath: access.config.patch.yml
      securityContext:
        fsGroup: 1030
        runAsUser: 1030
      serviceAccountName: artifactory
      terminationGracePeriodSeconds: 40
      volumes:
      - configMap:
          name: java-keystore-cacert
        name: java-keystore-cacert
      - name: artifactory-volume
        persistentVolumeClaim:
          claimName: artifactory-volume-artifactory
      - name: artifactory-license
        secret:
          secretName: artifactory
      - name: access-bootstrap-creds
        secret:
          secretName: artifactory
      - configMap:
          name: artifactory-installer-info
        name: installer-info
      - name: systemyaml
        secret:
          secretName: artifactory-systemyaml-bgkhtt98kc
      - name: access-config
        secret:
          secretName: artifactory-access-config-2h79g65gch
      - name: binarystore-xml
        secret:
          secretName: artifactory-binarystore-d55tk5f2fk
  updateStrategy:
    type: RollingUpdate
gitta-jfrog commented 5 months ago

Hello @husira The issue described is related to the Artifactory application, and it's not related to the JFrog Helm Charts (which are maintained under this GitHub repository)

According to my knowledge, it is a known limitation. However, it should not happen when both source and target instances have the same OAuth configuration (hint: check out the access_users_custom_data for a specific user and verify the PropKEY starting with 'authinfo.' has the same key as the OAuth configuration)

I'll suggest reaching out JFrog Support or JFrog Community Support for further investigation.