From d33c3eceedc0f4e1186fa7e060a425671972494d Mon Sep 17 00:00:00 2001 From: Tom Elliott Date: Mon, 17 Aug 2026 14:57:06 -0500 Subject: [PATCH] Declare clientId a string, not a foreign key An OpenID Connect client id is a string the provider chooses -- "fog-web", or a GUID on Entra -- but it ends in "id", and FOGController::save() read any key ending in "id" as an integer foreign key. clientId is required, so the mismatch did not degrade anything: it made creating a provider impossible, reported as Required database field is empty: clientId about a field the admin had filled in, surfacing in the UI as the generic "Add provider failed!". No OIDC provider could be created at all, which also means no provider group, and so the Role and User Group provider-group tabs from #10 had nothing to associate. fogproject#1153 stops the base class inferring a column's type from its name and lets the model say so instead. This declares it. The gate lives in the existing provider-safety test because this belongs with the other silent ways a provider row can be wrong: dropping the declaration does not make providers slightly worse, it switches provider creation off entirely. Requires fogproject#1153; inert without it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_017aBSWrDArXHTpKWkkN27LR --- oidc/class/oidc.class.php | 14 ++++++++++++++ tests/oidc-provider-safety.test.php | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/oidc/class/oidc.class.php b/oidc/class/oidc.class.php index 12fa2af..ef34e4d 100644 --- a/oidc/class/oidc.class.php +++ b/oidc/class/oidc.class.php @@ -101,6 +101,20 @@ class OIDC extends FOGController 'issuer', 'clientId' ]; + /** + * clientId ends in "id" without being a foreign key. + * + * FOGController::save() reads a key ending in "id" as an integer id + * unless the model says otherwise. A client id is a string the provider + * chooses -- "fog-web", or a GUID on Entra -- so without this every + * create failed with "Required database field is empty: clientId" about + * a field that was filled in. Needs fogproject#1153. + * + * @var array + */ + protected $databaseFieldsNotInt = [ + 'clientId' + ]; /** * Validate before storing. * diff --git a/tests/oidc-provider-safety.test.php b/tests/oidc-provider-safety.test.php index 5b2b803..ebfe37c 100644 --- a/tests/oidc-provider-safety.test.php +++ b/tests/oidc-provider-safety.test.php @@ -297,6 +297,29 @@ function () { ); } +/* + * clientId must stay declared as a string. + * + * FOGController::save() reads any key ending in "id" as an integer foreign + * key unless the model opts out, and clientId is required -- so dropping the + * opt-out does not degrade anything, it makes creating a provider impossible, + * reported as "Required database field is empty: clientId" about a field the + * admin filled in. That is a whole feature off, so it is pinned here rather + * than left to be rediscovered. Needs fogproject#1153. + */ +$declared = []; +if (property_exists('OIDC', 'databaseFieldsNotInt')) { + $notInt = new \ReflectionProperty('OIDC', 'databaseFieldsNotInt'); + $notInt->setAccessible(true); + $declared = array_map('strtolower', (array)$notInt->getValue(new OIDC())); +} +if (!in_array('clientid', $declared, true)) { + fail( + 'OIDC does not declare clientId in $databaseFieldsNotInt, so ' + . 'save() will reject every provider whose client id is not a number' + ); +} + if (count($fails) > 0) { fwrite(STDERR, 'FAIL: ' . count($fails) . " problem(s):\n"); foreach ($fails as $f) {