Commit 1e6e90e6 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

feat: enhance Keycloak and Federation Manager integration with new scope handling for callbacks

parent a4b16075
Loading
Loading
Loading
Loading
+1 −1
Changes for README.md: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ Keycloak (`charts/keycloak`) runs as a platform service in `oop`, backed by the
| Realm | Used by | Clients |
|---|---|---|
| `oop` | Portal users, app providers, OEG | `oop-portal` (confidential, Auth Code + PKCE), `oeg` (audience only) |
| `federation` | FM, partner OPs (ADR-0042) | `originating-op-1`, `originating-op-2` (client credentials, scope `fed-mgmt`) |
| `federation` | FM, partner OPs (ADR-0042) | `originating-op-1`, `originating-op-2` (client credentials, scope `fed-mgmt`; `fed-mgmt-notif` optional, for callbacks) |

- Realm roles in `oop` (ADR-0048): `app-provider` (developers; given to every new user, including
  self-registered ones), `operator` (runs the platform) and `platform-admin` (manages users). None
+16 −1
Changes for oop-platform-chart/charts/keycloak/README.md: 16 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -149,6 +149,14 @@ The source of this model is ADR-0048.
Roles say **what** someone may do. They do not say **whose data** they may see; that is the
organization's job ([section 9](#9-organizations-and-tenants)).

### CAMARA scopes

Portal tokens also carry one scope per CAMARA operation (QoD, Edge Application Management,
Location Retrieval), named as in each API's OpenAPI `security` block. The list lives in
[`files/camara-scopes.yaml`](files/camara-scopes.yaml): add an entry there when OEG gains an
operation. On an existing installation, also create the scope in the admin console and add it to
`oop-portal` as **Default** ([Change realm settings after install](#change-realm-settings-after-install)).

### Clients

| Client | Kind | Used by | What it does |
@@ -201,6 +209,13 @@ unless Keycloak's public URL is `http://localhost[:port]` or `http://127.0.0.1[:
- Each partner client can only use **client credentials** (machine to machine). No browser, no password.
- Every token carries the scope **`fed-mgmt`** (the name the GSMA OPG.04 API contract requires) and
  the audience **`federation-manager`**, which Federation Manager checks.
- Partners sending us a **callback** (federation status, instance status, zone updates) ask for
  **`fed-mgmt-notif`** too (`scope=fed-mgmt-notif` in the token request). It is an *optional*
  scope, so only tokens that request it carry it: a normal API token is not a callback token.
  Both names come from `global.federation.scopes`.
  On an installation older than this scope, add it by hand: realm `federation` → **Client scopes**
  → **Create client scope** (name `fed-mgmt-notif`, protocol OpenID Connect), then on each partner
  client → **Client scopes** → **Add client scope** → `fed-mgmt-notif` as **Optional**.
- Each partner has its **own** secret, generated into `keycloak-credentials` as
  `federation-<client id>-secret`. We give it to that partner over a secure channel. One partner's
  secret never works for another partner.
@@ -474,7 +489,7 @@ Use the same ID for everyone in the same organization: it is compared exactly.
   create the client in the admin console (realm `federation` → **Clients** → **Create client**):
   - Client ID: the same ID; **Client authentication** on; only **Service accounts roles** ticked.
   - **Credentials** tab: paste the secret from `keycloak-credentials`.
   - **Client scopes** tab: add `fed-mgmt` as **Default**.
   - **Client scopes** tab: add `fed-mgmt` as **Default** and `fed-mgmt-notif` as **Optional**.
   - **Client scopes** → `<client id>-dedicated` → **Add mapper** → **By configuration** → **Audience**:
     *Included Custom Audience* `federation-manager`, *Add to access token* on.
3. Send the client ID and secret to the partner over a secure channel, together with our token URL:
+35 −0
Changes for oop-platform-chart/charts/keycloak/files/camara-scopes.yaml: 35 added lines, 0 removed lines.
Original line number Diff line number Diff line
# CAMARA operation scopes of realm `oop`, one per operation across QoD, Edge Application
# Management and Location Retrieval. Names match each API's OpenAPI `security` block.
# Every scope here is created in the realm and issued on portal tokens.
- name: "edge-application-management:apps:read"
  description: "List/view applications"
- name: "edge-application-management:apps:write"
  description: "Register applications"
- name: "edge-application-management:apps:delete"
  description: "Delete applications"
- name: "edge-application-management:instances:read"
  description: "List/view app instances"
- name: "edge-application-management:instances:write"
  description: "Create app instances"
- name: "edge-application-management:instances:delete"
  description: "Delete app instances"
- name: "edge-application-management:deployments:read"
  description: "List/view app deployments"
- name: "edge-application-management:deployments:write"
  description: "Create app deployments"
- name: "edge-application-management:deployments:update"
  description: "Update app deployments"
- name: "edge-application-management:deployments:delete"
  description: "Delete app deployments"
- name: "edge-application-management:clusters:read"
  description: "List clusters"
- name: "edge-application-management:edge-cloud-zones:read"
  description: "List edge cloud zones"
- name: "qod-sessions-read"
  description: "Retrieval of QoS sessions"
- name: "qod-sessions-write"
  description: "Creation and update of QoS sessions"
- name: "qod-sessions-delete"
  description: "Deletion of QoS sessions"
- name: "location-retrieval:read"
  description: "Retrieve a device's location"
+14 −0
Changes for oop-platform-chart/charts/keycloak/templates/_helpers.tpl: 14 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -100,6 +100,20 @@ Audience added to partner tokens in the `federation` realm; Federation Manager r
{{- .Values.realms.federation.audience | default (dig "federation" "audience" "federation-manager" (.Values.global | default dict)) -}}
{{- end }}

{{/*
OPG.04 scope names in the `federation` realm, from global.federation.scopes: `api` for normal
E/WBI calls (default scope of every partner client), `notif` for callbacks (optional scope, so
only tokens that request it carry it). The federation-manager chart should read the same globals.
Usage: include "keycloak.federationScope" (list $ "api")
*/}}
{{- define "keycloak.federationScope" -}}
{{- $ctx := index . 0 -}}
{{- $key := index . 1 -}}
{{- $defaults := dict "api" "fed-mgmt" "notif" "fed-mgmt-notif" -}}
{{- dig "federation" "scopes" $key (index $defaults $key) ($ctx.Values.global | default dict) -}}
{{- end }}


{{/*
Keycloak's public URL (KC_HOSTNAME, and so the `iss` of every token): `hostname` if set,
else <scheme>://<public host>:<NodePort> (the Service port for other Service types).
+17 −48
Changes for oop-platform-chart/charts/keycloak/templates/realms-configmap.yaml: 17 added lines, 48 removed lines.
Original line number Diff line number Diff line
@@ -78,49 +78,19 @@ data:
        ]
      },
      {{- /*
      One CAMARA scope per operation across QoD, Edge Application Management and Location
      Retrieval (matches each API's OpenAPI `security` block exactly -- see the *-api.yaml
      files under src/open_exposure_gateway/api/camara/). Attached below as default scopes
      on the `portal` client alongside Keycloak's own built-ins, so every token already
      carries them the same way `organization` and the realm role already do -- no separate
      consent step, since it's the same developer logging into their own account, not a
      third party requesting delegated access.
      Attached below as default scopes on the `portal` client alongside Keycloak's own
      built-ins, so every token already carries them the same way `organization` and the
      realm role already do -- no separate consent step, since it's the same developer
      logging into their own account, not a third party requesting delegated access.
      */ -}}
      {{- $camaraScopeNames := list
        "edge-application-management:apps:read"
        "edge-application-management:apps:write"
        "edge-application-management:apps:delete"
        "edge-application-management:instances:read"
        "edge-application-management:instances:write"
        "edge-application-management:instances:delete"
        "edge-application-management:deployments:read"
        "edge-application-management:deployments:write"
        "edge-application-management:deployments:update"
        "edge-application-management:deployments:delete"
        "edge-application-management:clusters:read"
        "edge-application-management:edge-cloud-zones:read"
        "qod-sessions-read"
        "qod-sessions-write"
        "qod-sessions-delete"
        "location-retrieval:read"
      }}
      {{- $camaraScopes := $.Files.Get "files/camara-scopes.yaml" | fromYamlArray }}
      {{- $camaraScopeNames := list }}
      "clientScopes": [
        { "name": "edge-application-management:apps:read", "protocol": "openid-connect", "description": "List/view applications" },
        { "name": "edge-application-management:apps:write", "protocol": "openid-connect", "description": "Register applications" },
        { "name": "edge-application-management:apps:delete", "protocol": "openid-connect", "description": "Delete applications" },
        { "name": "edge-application-management:instances:read", "protocol": "openid-connect", "description": "List/view app instances" },
        { "name": "edge-application-management:instances:write", "protocol": "openid-connect", "description": "Create app instances" },
        { "name": "edge-application-management:instances:delete", "protocol": "openid-connect", "description": "Delete app instances" },
        { "name": "edge-application-management:deployments:read", "protocol": "openid-connect", "description": "List/view app deployments" },
        { "name": "edge-application-management:deployments:write", "protocol": "openid-connect", "description": "Create app deployments" },
        { "name": "edge-application-management:deployments:update", "protocol": "openid-connect", "description": "Update app deployments" },
        { "name": "edge-application-management:deployments:delete", "protocol": "openid-connect", "description": "Delete app deployments" },
        { "name": "edge-application-management:clusters:read", "protocol": "openid-connect", "description": "List clusters" },
        { "name": "edge-application-management:edge-cloud-zones:read", "protocol": "openid-connect", "description": "List edge cloud zones" },
        { "name": "qod-sessions-read", "protocol": "openid-connect", "description": "Retrieval of QoS sessions" },
        { "name": "qod-sessions-write", "protocol": "openid-connect", "description": "Creation and update of QoS sessions" },
        { "name": "qod-sessions-delete", "protocol": "openid-connect", "description": "Deletion of QoS sessions" },
        { "name": "location-retrieval:read", "protocol": "openid-connect", "description": "Retrieve a device's location" }
        {{- range $i, $sc := $camaraScopes }}
        {{- $camaraScopeNames = append $camaraScopeNames $sc.name }}
        {{- if $i }},{{ end }}
        { "name": {{ $sc.name | toJson }}, "protocol": "openid-connect", "description": {{ $sc.description | toJson }} }
        {{- end }}
      ],
      "clients": [
        {
@@ -261,15 +231,13 @@ data:
    {
      "realm": "federation",
      "enabled": true,
      {{- $apiScope := include "keycloak.federationScope" (list $ "api") }}
      {{- $notifScope := include "keycloak.federationScope" (list $ "notif") }}
      "clientScopes": [
        {
          "name": {{ .clientScope.name | toJson }},
          "protocol": "openid-connect",
          "description": {{ .clientScope.description | toJson }}
        }
        { "name": {{ $apiScope | toJson }}, "protocol": "openid-connect", "description": "OPG.04 E/WBI API calls" },
        { "name": {{ $notifScope | toJson }}, "protocol": "openid-connect", "description": "OPG.04 E/WBI callbacks" }
      ],
      "clients": [
        {{- $scope := .clientScope.name }}
        {{- $audience := include "keycloak.federationAudience" $ }}
        {{- range $i, $c := (include "keycloak.federationClients" $ | fromJsonArray) }}
        {{- if $i }},{{ end }}
@@ -284,7 +252,8 @@ data:
          "implicitFlowEnabled": false,
          "directAccessGrantsEnabled": false,
          "serviceAccountsEnabled": true,
          "defaultClientScopes": [ {{ $scope | toJson }} ],
          "defaultClientScopes": [ {{ $apiScope | toJson }} ],
          "optionalClientScopes": [ {{ $notifScope | toJson }} ],
          "protocolMappers": [
            {{- include "keycloak.audienceMapper" (dict "name" "audience-federation-manager" "custom" $audience) | nindent 12 }}
          ]
Loading