solo-io / gloo-portal-issues

Public tracker for issues related to Gloo Portal
https://docs.solo.io/gloo-portal/latest/
1 stars 3 forks source link

Possible bug not displaying API usages when using OIDC for authentication #179

Closed day0ops closed 2 years ago

day0ops commented 2 years ago

Describe the bug Customer ran into this strange behaviour of not showing the API usages (on portal) when using OIDC as the auth mechanism. We double checked basic auth which seemed fine.

Logs didn't show any issues.

Posting the config,

Groups,

spec:
  accessLevel:
    apis:
      - environments:
          names:
            - mock-sms-api
            - external-sit
        products: {}
        usagePlans:
          - premium-sms
          - trial
          - enterprise-sms
    portals:
      - name: external-portal
        namespace: gloo-portal
  displayName: external-users-group
  oidcGroup:
    groupNames:
      - external-users-group

Portal,

apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
kind: Portal
metadata:
  creationTimestamp: '2022-07-03T17:31:53Z'
  generation: 58
  managedFields:
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:spec':
          'f:oidcAuth':
            .: {}
            'f:clientId': {}
            'f:clientSecret':
              .: {}
              'f:key': {}
              'f:name': {}
              'f:namespace': {}
            'f:groupClaimKey': {}
            'f:issuer': {}
      manager: Mozilla
      operation: Update
      time: '2022-07-03T17:49:27Z'
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:status':
          .: {}
          'f:observedGeneration': {}
          'f:publishedEnvironments': {}
          'f:state': {}
      manager: gloo-portal-controller
      operation: Update
      time: '2022-07-03T17:59:52Z'
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:spec':
          'f:banner':
            .: {}
            'f:configMap':
              .: {}
              'f:key': {}
              'f:name': {}
              'f:namespace': {}
          'f:favicon':
            .: {}
            'f:configMap':
              .: {}
              'f:key': {}
              'f:name': {}
              'f:namespace': {}
          'f:portalUrlPrefix': {}
          'f:staticPages': {}
          'f:description': {}
          'f:customStyling':
            .: {}
            'f:backgroundColor': {}
            'f:defaultTextColor': {}
            'f:primaryColor': {}
            'f:secondaryColor': {}
          .: {}
          'f:allApisPublicViewable': {}
          'f:pageExtensions':
            .: {}
            'f:key-2':
              .: {}
              'f:customHtml':
                .: {}
                'f:inlineString': {}
          'f:displayName': {}
          'f:primaryLogo':
            .: {}
            'f:configMap':
              .: {}
              'f:key': {}
              'f:name': {}
              'f:namespace': {}
          'f:publishedEnvironments': {}
          'f:domains': {}
          'f:enableIngress': {}
      manager: adminserver
      operation: Update
      time: '2022-07-05T04:51:09Z'
  name: external-portal
  namespace: gloo-portal
  resourceVersion: '22939020'
  uid: 44f70d61-bfe1-4f51-a199-32d7f873e972
spec:
  oidcAuth:
    clientId: external-portal
    clientSecret:
      key: client_secret
      name: external-portal-oidc-secret
      namespace: gloo-portal
    groupClaimKey: group
    issuer: >-
      https://keycloak/auth/realms/portal
  allApisPublicViewable: true
  pageExtensions:
    key-2:
      customHtml:
        inlineString: >-
          <script>
            // 1. Create the button
          var button = document.createElement("BUTTON");
          button.type = "button";
          button.innerHTML = "Register";
          // 2. Append somewhere
          var body =
          document.getElementsByClassName("main-button-container")[0];
          var style = body.style.cssText;
          button.setAttribute('style', 'background-color: rgb(201,33,46);margin:
          5px;');
          button.setAttribute('class', 'ant-btn main-button');
          body.appendChild(button);
          // 3. Add event handler
          button.addEventListener ("click", function() {
            window.location.replace("https://keycloak/auth/realms/portal/protocol/openid-connect/auth?client_id=external-portal&redirect_uri=https%3A%2F%2Fexternal-portal.apps%2Fcallback&response_type=code&scope=openid+profile+email&state=oauth2state");
          });
          var htitle =
          document.getElementsByClassName("home-page-portal-title")[0];
          htitle.setAttribute('style', 'color: #F9F9F9;');
          </script>
  banner:
    configMap:
      key: banner-img
      name: gloo-portal-external-portal-banner-img
      namespace: gloo-portal
  displayName: Org Developer Portal
  primaryLogo:
    configMap:
      key: primary-logo
      name: gloo-portal-external-portal-primary-logo
      namespace: gloo-portal
  publishedEnvironments:
    - name: external-sit
      namespace: gloo-portal
    - name: mock-sms-api
      namespace: gloo-portal
  domains:
    - external-portal.apps
  enableIngress: false
  favicon:
    configMap:
      key: favicon
      name: gloo-portal-external-portal-favicon
      namespace: gloo-portal
  portalUrlPrefix: 'https://external-portal.apps/'
  staticPages:
    - content:
        configMap:
          key: how-to-use-this-portal
          name: gloo-portal-external-portal-how-to-use-this-portal
          namespace: gloo-portal
      displayOnHomepage: true
      name: how-to-use-this-portal
      navigationLinkName: Learn to use this portal
      path: /how-to-use-the-portal
  description: Sample description
  customStyling:
    backgroundColor: '#F9F9F9'
    defaultTextColor: '#35393B'
    primaryColor: '#C9212E'
    secondaryColor: '#253E58'
status:
  observedGeneration: 58
  publishedEnvironments:
    - apiProducts:
        - name: bulk-sms
          namespace: gloo-portal
        - name: text-to-voice-call-bulk
          namespace: gloo-portal
      name: external-sit
      namespace: gloo-portal
    - apiProducts:
        - name: org-bill-pay
          namespace: gloo-portal
        - name: org-recharge
          namespace: gloo-portal
        - name: bulk-sms
          namespace: gloo-portal
        - name: text-to-voice-call-bulk
          namespace: gloo-portal
      name: mock-sms-api
      namespace: gloo-portal
  state: Succeeded

Environment,

apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
kind: Environment
metadata:
  creationTimestamp: '2022-07-03T16:53:42Z'
  generation: 21
  managedFields:
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:spec':
          'f:domains': {}
      manager: Mozilla
      operation: Update
      time: '2022-07-04T12:50:27Z'
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:status':
          .: {}
          'f:apiProducts': {}
          'f:modifiedDate': {}
          'f:observedGeneration': {}
          'f:publishedPortals': {}
          'f:state': {}
      manager: gloo-portal-controller
      operation: Update
      time: '2022-07-05T03:51:47Z'
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:spec':
          .: {}
          'f:apiProducts': {}
          'f:basePath': {}
          'f:displayInfo':
            .: {}
            'f:displayName': {}
          'f:gatewayConfig': {}
          'f:parameters':
            .: {}
            'f:usagePlans':
              .: {}
              'f:enterprise-sms':
                .: {}
                'f:authPolicy':
                  .: {}
                  'f:apiKey': {}
                'f:displayName': {}
                'f:rateLimit':
                  .: {}
                  'f:requestsPerUnit': {}
                  'f:unit': {}
              'f:premium-sms':
                .: {}
                'f:authPolicy':
                  .: {}
                  'f:apiKey': {}
                'f:displayName': {}
                'f:rateLimit':
                  .: {}
                  'f:requestsPerUnit': {}
                  'f:unit': {}
              'f:trial':
                .: {}
                'f:authPolicy':
                  .: {}
                  'f:apiKey': {}
                'f:displayName': {}
                'f:rateLimit':
                  .: {}
                  'f:requestsPerUnit': {}
                  'f:unit': {}
      manager: adminserver
      operation: Update
      time: '2022-07-05T04:40:40Z'
  name: external-sit
  namespace: gloo-portal
  resourceVersion: '22939012'
  uid: 30ac7282-363a-4901-8f65-732398aaf1df
spec:
  apiProducts:
    - names:
        - bulk-sms
        - text-to-voice-call-bulk
      usagePlans:
        - premium-sms
        - enterprise-sms
        - trial
      versions: {}
  basePath: /
  displayInfo:
    displayName: Production
  domains:
    - external-gateway.apps
  gatewayConfig: {}
  parameters:
    usagePlans:
      enterprise-sms:
        authPolicy:
          apiKey: {}
        displayName: >-
          Enterprise | INR 1 per 10 API calls | Maximum of 100000 API calls per
          day
        rateLimit:
          requestsPerUnit: 100000
          unit: DAY
      premium-sms:
        authPolicy:
          apiKey: {}
        displayName: Premium | INR 1 per API Call | Maximum of 10000 API calls per day
        rateLimit:
          requestsPerUnit: 10000
          unit: DAY
      trial:
        authPolicy:
          apiKey: {}
        displayName: Trial | Free | 3 Api calls per hour
        rateLimit:
          requestsPerUnit: 3
          unit: HOUR
status:
  apiProducts:
    - name: bulk-sms
      namespace: gloo-portal
      usagePlans:
        - premium-sms
        - enterprise-sms
        - trial
      versions:
        1.0.0:
          apiType: OPEN_API
          routes:
            - method: POST
              operationId: gloo-portal.sendbulksms
              path: /messaging/v1/example
              route:
                backends:
                  - upstream:
                      name: default-bulk-sms-8080
                      namespace: gloo-system
              summary: Send sms
    - name: text-to-voice-call-bulk
      namespace: gloo-portal
      usagePlans:
        - premium-sms
        - enterprise-sms
        - trial
      versions:
        1.0.0:
          apiType: OPEN_API
          routes:
            - method: POST
              operationId: >-
                text-to-voice-call-bulk.gloo-portal
              path: /voice/v1/text-to-voicecall/bulk
              route:
                backends:
                  - upstream:
                      name: default-text-to-voice-8080
                      namespace: gloo-system
  modifiedDate: '2022-07-08T06:14:50.174083540Z'
  observedGeneration: 21
  publishedPortals:
    - apiProducts:
        - name: bulk-sms
          namespace: gloo-portal
        - name: text-to-voice-call-bulk
          namespace: gloo-portal
      domains:
        - external-portal.apps
      name: external-portal
      namespace: gloo-portal
  state: Succeeded

APIProduct,

apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
kind: APIProduct
metadata:
  creationTimestamp: '2022-07-03T16:55:40Z'
  generation: 6
  managedFields:
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:spec':
          .: {}
          'f:displayInfo':
            .: {}
            'f:contact':
              .: {}
              'f:email': {}
              'f:name': {}
              'f:url': {}
            'f:description': {}
            'f:image':
              .: {}
              'f:configMap':
                .: {}
                'f:key': {}
                'f:name': {}
                'f:namespace': {}
            'f:license': {}
            'f:title': {}
          'f:versions': {}
      manager: adminserver
      operation: Update
      time: '2022-07-04T04:52:01Z'
    - apiVersion: [portal.gloo.solo.io/v1beta1](http://portal.gloo.solo.io/v1beta1)
      fieldsType: FieldsV1
      fieldsV1:
        'f:status':
          .: {}
          'f:modifiedDate': {}
          'f:observedGeneration': {}
          'f:state': {}
          'f:versionInfo':
            .: {}
            'f:1.0.0':
              .: {}
              'f:apiRoutes': {}
              'f:apiType': {}
              'f:numberOfEndpoints': {}
      manager: gloo-portal-controller
      operation: Update
      time: '2022-07-06T09:53:56Z'
  name: bulk-sms
  namespace: gloo-portal
  resourceVersion: '22938990'
  uid: beef5e90-5cd3-43c4-a82a-b12e56da80e8
spec:
  displayInfo:
    contact:
      email: 
      name: Support
      url: 'https://example.com/'
    description: >-
      Sample description
    image:
      configMap:
        key: image
        name: gloo-portal-bulk-sms-image
        namespace: gloo-portal
    license: {}
    title: Org Bulk SMS
  versions:
    - apis:
        - apiDoc:
            name: org-messaging
            namespace: gloo-portal
          openApi:
            operations:
              - gatewayConfig:
                  route:
                    routeRef:
                      name: bulk-sms
                      namespace: gloo-system
                id: sendbulksms
      name: 1.0.0
      tags:
        IQ: {}
        sms: {}
status:
  modifiedDate: '2022-07-08T06:14:49.911258208Z'
  observedGeneration: 6
  state: Succeeded
  versionInfo:
    1.0.0:
      apiRoutes:
        - method: POST
          operationId: bulk-sms.gloo-portal
          path: /messaging/v1/example
          route:
            backends:
              - upstream:
                  name: default-bulk-sms-8080
                  namespace: gloo-system
          summary: Send sms
      apiType: OPEN_API
      numberOfEndpoints: 1

To Reproduce Steps to reproduce the behavior:

  1. Typical setup of OIDC with keycloak performing user group mapping

Expected behavior API usages should have been shown when logged in

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

day0ops commented 2 years ago

I couldnt reproduce this myself. Tried both 1.2.4 and 1.2.5. And nothing screamed at me looking at this config

day0ops commented 2 years ago

They also mentioned that if the Environment is created in Caps its being accepted but not able to create API keys. Trying to gather more information on this

bewebi commented 2 years ago

I've attempted to reproduce and done static code analysis

My conclusion is basically that the logic looks good and it seems possible/likely that the user they’re logging in with isn’t actually a member of the group and that since AllApisPublicViewable is true on their Portal they can still see the Product(s) listed but because they’re not authorized to interact with them they see no Plans One way to test if that was the issue would be to set AllApisPublicViewable to false and see if the Product(s) are visible at all

Here is what the page looks like under different circumstances:

Authenticated user is a member of a group that has access to "Petstore Product":

Screen Shot 2022-07-15 at 5 05 41 PM

Authenticated user is not a member of a group that has access to "Petstore Product" and Portal has AllApisPublicViewable set to true:

Screen Shot 2022-07-15 at 5 08 45 PM

Authenticated user is not a member of a group that has access to "Petstore Product" and Portal has AllApisPublicViewable set to false:

Screen Shot 2022-07-15 at 5 10 12 PM

Note that the UI does not seem to reflect a login for a user that cannot view any Products. In the above screenshot I am logged in even though that is not reflected in the UI. It is still possible to view the above view by manually navigating to /keys. This likely constitutes a separate bug.

We should try to determine if the customer is authenticating with users that have access to the Product(s) in question and proceed from there.

bewebi commented 2 years ago

The root cause of the issue was that Keycload was prepending a / to the group name, causing authenticated users not to have access to APIs as described above.

The customer is able to resolve the issue without code change, presumably by adding the / to the groupNames entry in the Group CR.

While this issue can be closed, it may be worthwhile to document this behavior of Keycloak or otherwise improve our documentation to highlight the distinction between authenticating to the Portal and having access to APIs.