nagaboinaramgopal opened a new pull request, #14205:
URL: https://github.com/apache/cloudstack/pull/14205

   ### Description
   
   The OAuth2 plugin resolves a login to a `UserOAuth2Authenticator` through a 
fixed
   provider-name to Spring-bean map. Each OIDC vendor is its own bean
   (`GoogleOAuth2Provider`, `GithubOAuth2Provider`, `KeycloakOAuth2Provider`) 
running the
   same authorization-code flow with no vendor-specific logic in it. Two 
consequences:
   adding an IdP means shipping a new class, and because `provider` is 
simultaneously the
   display name and the routing key, a domain can register exactly one 
`keycloak`.
   
   This PR decouples the two by adding a `type` column to `oauth_provider`:
   
   * `OAuth2AuthManagerImpl.getUserOAuth2AuthenticationProvider` looks the name 
up in the
     bean map first, as before, and only on a miss falls back to the 
registration's `type`.
     `provider` becomes an admin-chosen label; `type` selects the 
implementation. One bean
     can serve any number of registrations under arbitrary names.
   * `getUserOAuth2AuthenticationProvider`, `verifyUser` and 
`verifySecretCodeAndFetchEmail`
     now carry the registration name, so a shared bean knows which row it is 
acting for.
   * Existing `google`/`github`/`keycloak` rows have a null `type` and continue 
to dispatch
     by name, on the same code path as today.
   
   `GenericOIDCOAuth2Provider` is registered under `type=oidc` and configured 
with the issuer
   URL alone. It reads `token_endpoint` and `jwks_uri` from the issuer's
   `.well-known/openid-configuration` (cached; the document's `issuer` must 
match the
   configured value), and validates the `id_token` before trusting any claim in 
it: signature
   against the JWKS key named by the token `kid`, then issuer, audience and 
expiry, via CXF's
   `JwsJwtCompactConsumer` / `JwkUtils` / `JwtUtils`. That is 
`cxf-rt-rs-security-jose`,
   already on the plugin classpath, so no new dependency.
   
   Unlike the vendor providers, it holds no token in an instance field. The 
code is exchanged
   per call, and a code verified through `verifyOAuthCodeAndGetUser` is cached 
for 60s and
   consumed once, so the `oauthlogin` that immediately follows does not 
re-present it to the
   IdP.
   
   **API / response fix:** `ListOAuthProvidersCmd` and `UpdateOAuthProviderCmd` 
derived the
   response `enabled` flag from `authenticatorPluginNames.contains(provider)`, a
   name-to-bean check, which reported every generically-named registration as 
disabled. Both
   now also accept a registration whose `type` resolves to a plugin.
   
   `type` is settable on register but not on update: changing it would swap the
   implementation under an existing row.
   
   **Schema:** adds `type` and `issuer_url` to `oauth_provider` in the 4.23.0.0 
to 24.0.0
   upgrade file.
   
   **UI:** `Login.vue` renders a button per registered `oidc` provider (in 
addition to the
   existing google/github/keycloak buttons), labelled "Sign in with <label>". 
Clicking it
   reads the issuer's `authorization_endpoint` from discovery and starts the
   authorization-code flow. As with the keycloak provider, the registered 
`redirecturi` must
   carry `verifyOauth` (for example `https://<ui-host>/client?verifyOauth`) so 
the callback
   lands on the verify handler.
   
   Fixes: #9609
   
   ### Types of changes
   
   - [ ] Breaking change (fix or feature that would cause existing 
functionality to change)
   - [x] New feature (non-breaking change which adds functionality)
   - [ ] Bug fix (non-breaking change which fixes an issue)
   - [ ] Enhancement (improves an existing feature and functionality)
   - [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
   - [ ] Build/CI
   - [ ] Test (unit or integration test code)
   
   ### Feature/Enhancement Scale or Bug Severity
   
   #### Feature/Enhancement Scale
   
   - [x] Major
   - [ ] Minor
   
   ### Screenshots (if appropriate):
   
   ### How Has This Been Tested?
   
   **Unit tests** - oauth2 module, 103 tests green.
   
   * `GenericOIDCOAuth2ProviderTest` (27 tests) generates an RSA keypair, 
publishes the
     matching JWKS, and asserts that a genuinely signed token is accepted while 
these are
     rejected: a token with altered claims, one signed by a different key, one 
naming a `kid`
     absent from the JWKS, and issuer / audience / expiry mismatches. Also 
covers discovery
     document validation (issuer mismatch) and that a verified code is redeemed 
exactly once.
   * `OAuth2AuthManagerImplTest` covers the `type` fallback, an unknown `type` 
rejected at
     register time, and a real bean name winning without a DB lookup.
   * Vendor provider tests updated for the name-carrying signatures.
   * `DatabaseUpgradeCheckerTest` green with the new schema file.
   
   **Integration** - KVM advanced zone against Keycloak 25. Registered an 
`oidc` provider
   pointing at a Keycloak realm and logged a real user in through the Keycloak 
form:
   `verifyOAuthCodeAndGetUser` validates the RS256 signature against the realm 
JWKS and
   returns the email, `oauthlogin` with the same code issues the session, and
   `listOauthProviders` reports the generically-named provider as enabled.
   
   #### How did you try to break this feature and the system with this change?
   
   * A login presenting a valid, correctly signed token but claiming a 
different CloudStack
     user's email - rejected, no session.
   * Replay of an already-consumed code - rejected, no session.
   * A bogus/garbage code - rejected, no session.
   * After each of the above, a fresh correct login still succeeds.
   * Existing `google`/`github`/`keycloak` registrations are untouched and 
still log in
     (name-based dispatch, null `type`).
   * Discovery document whose `issuer` does not match the configured issuer URL 
- rejected.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to