Ons het 'n gevaarlike verstek afgeskakel sonder om 'n enkele ry te migreer
Net betyds voorsiening (just-in-time provisioning) is die kenmerk wat onderneming se enkelaanmelding soos towerkrag laat voel. 'n Nuwe werknemer meld aan deur sy maatskappy se identiteitsverskaffer, daar bestaan nog geen rekening vir hom in jou toepassing nie, en een word ter plekke uit die bewering geskep. Niemand dien 'n kaartjie in nie, niemand word genooi nie, die persoon werk net.
Dit is ook, gelees uit die ander rigting, 'n kenmerk wat enigiemand wat daardie identiteitsverskaffer beheer toelaat om rekeninge in jou kliënt se huurgebied te skep deur te beweer dat 'n persoon bestaan. Dit is reg wanneer die verbinding streng tot een maatskappy se gids beperk is en elke mens daarin toegang behoort te hê. Dit is minder reg wanneer die verbinding 'n gedeelde gids is, of 'n kontrakteurhuurgebied, of een van daardie uitgestrekte federasies waar die groep mense vir wie die identiteitsverskaffer bereid is om in te staan veel groter is as die groep mense wat jou kliënt bedoel het om in te laat.
Ons s'n was standaard aan. Nie omdat iemand besluit het dit moet nie, wat die deel is wat die moeite werd is om by stil te staan. Dit was standaard aan omdat toe die veld bygevoeg is, die boolean wat dit uitgedruk het DisableJitProvisioning genoem is, en 'n onbepaalde boolean is false, en false het beteken "moenie deaktiveer nie". Die veiligste lees van 'n verstek wat niemand gekies het nie, is dat dit 'n ongeluk is, en hierdie een het as gedrag ingeburger geraak.
Om presies te wees oor die blootstelling, want dit was nooit so erg soos "enigiemand kan enigiemand skep" nie: twee hekke het reeds voor voorsiening geloop. 'n Verbinding kan 'n lys van toegelate e-posdomeine dra, en 'n bewering buite hulle word verwerp. 'n Verbinding kan 'n uitnodigingskenmerk vereis, en 'n ongenooide gebruiker word verwerp. Die werklike risiko van standaard aan was 'n verbinding waarin nie een van daardie twee opgestel is nie, wat presies die vorm is van 'n verbinding wat iemand vinnig opgestel het om enkelaanmelding aan die gang te kry.
Om die verstek om te draai is een woord. Om dit veilig om te draai is nie.
Die verandering wat almal hulle verbeel is om die veld te hernoem na JitProvisioningEnabled en dit standaard false te laat wees. Nuwe verbindings is standaard veilig, klaar.
Behalwe dat daardie veld gestoor word, en daar is verbindings in berging wat geskryf is voordat dit bestaan het. Hulle rye het glad nie die kolom nie. Wat met hulle gebeur, hang heeltemal af van watter rigting die boolean wys, want 'n ontbrekende kolom deserialiseer in altwee gevalle na false. Onder die ou negatiewe naam beteken ontbrekend "nie gedeaktiveer nie" en voorsiening gaan voort. Onder 'n nuwe positiewe naam beteken ontbrekend "nie geaktiveer nie" en voorsiening stop.
So 'n reguit hernoeming skakel stilweg net betyds voorsiening af vir elke verbinding wat 'n kliënt opgestel het toe dit aan was. Hulle het niks gekies nie, hulle is nie vertel nie, en die eerste wat hulle daarvan hoor is 'n werknemer wat nie kan aanmeld nie, op watter uur dit ook al gebeur. Dit is nie 'n sekuriteitsverbetering nie, dit is 'n onderbreking wat deur ontplooiing afgelewer word.
Die voor die hand liggende antwoord is 'n terugvulling (backfill): loop deur elke gestoorde verbinding, skryf die kolom uitdruklik, draai dan die verstek om. Dit werk, maar dit is 'n migrasie wat jy moet skryf, toets, teen elke huurder se berging laat loop, en seker maak oral voltooi is voordat die kode wat daarvan afhang uitgestuur word. Vir 'n boolean.
Die dubbele ontkenning
Ons het nie die migrasie geskryf nie. Die gestoorde kolom behou vir altyd sy ou negatiewe betekenis, en die model kry 'n positiewe eienskap voor dit:
public bool JitProvisioningEnabled { get; set; }
public bool DisableJitProvisioning
{
get => !JitProvisioningEnabled;
set => JitProvisioningEnabled = !value;
}
Die positiewe eienskap is die werklike een, met werklike berging daaragter, en dit is standaard false, wat die nuwe veilige verstek is. Die negatiewe naam is nou 'n berekende alias wat in altwee rigtings omkeer.
Volg 'n ou ry deur. Die kolom ontbreek, so dit lees as false, so die steller vir DisableJitProvisioning loop met false, so JitProvisioningEnabled word true. Die verbinding hou aan voorsien, presies soos sy eienaar dit opgestel het, en niks is gemigreer nie. Volg 'n nuwe verbinding deur. Niemand stel enige van die twee eienskappe nie, JitProvisioningEnabled bly by sy verstek van false, en die verbinding verwerp onbekende gebruikers totdat iemand kies om in te teken.
Albei gedrae kom uit dieselfde kode sonder enige vertakking, sonder enige weergawe-vlag, en sonder dat enige data aangeraak is. Die gestoorde bis het nooit van betekenis verander nie. Net die veld waarin dit beland het, en die omkering gebeur in 'n eienskap-steller wat by elke laai loop.
Wat dit gekos het
Dit is nie verniet nie, en die rekening arriveer by die API grens. Albei eienskappe is publiek, so albei word geserialiseer, en 'n kliënt wat 'n verbinding lees, iets verander, en dit terugskryf stuur nou twee eienskappe wat dieselfde ding beskryf. Deserialisering pas hulle toe in die volgorde waarin hulle in die vrag verskyn, so die laaste een wen. Stel die positiewe eienskap op true terwyl jy 'n verouderde negatiewe een laat bly in die voorwerp wat jy gaan haal het, en jou verandering word stilweg ongedaan gemaak deur 'n veld waarvan jy nie gedink het jy dit stuur nie.
Ons het dit ontdek op die manier waarop mens hierdie dinge ontdek, in 'n toets wat die vlag aangeskakel het en toe beweer het dit was aan. Die reël wat daaruit gekom het, is om albei vorme uitdruklik te stel by enige lees-wysig-skryf, wat ons eie end-tot-end-toets nou doen met 'n opmerking wat verduidelik waarom. As jy hierdie truuk aanneem, begroot daarvoor. 'n Tweerigting-alias koop vir jou 'n gratis migrasie en hef vir jou 'n dubbelsinnigheid op die draad.
Die fout wat die omdraai blootgelê het
Hier is die deel wat verder as booleans veralgemeen. Terwyl ons die verandering gemaak het, het ons ontdek dat die admin-eindpunt vir die skep van 'n OIDC-verbinding hierdie vlag nog nooit hoegenaamd gestel het nie. Nie verkeerd nie, nie op die verkeerde waarde nie. Dit het dit bloot nooit toegeken nie, en die versoekvoorwerp het geen veld gehad om dit aan toe te ken nie.
Dit was onsigbaar solank die verstek die waarde was wat almal wou hê. Elke verbinding het voorsienend uitgekom, wat is wat die kode wat vergeet het om dit te bedraad in elk geval sou opgelewer het, so daar was niks om op te let nie en geen toets wat kon misluk nie. Die oomblik toe die verstek omgedraai het, het daardie selfde gaping geword "elke nuutgeskepte OIDC-verbinding het voorsiening af en geen manier om dit aan te skakel nie", wat glad nie 'n subtiele fout is nie.
'n Verstek is die waarde van elke kodepad wat vergeet het om die veld te stel. Solank die verstek gerieflik is, is daardie paaie nie te onderskei van dié wat dit doelbewus stel nie. Om 'n verstek te verander, verander nie net nuwe gedrag nie, dit ontwikkel die foto: alles wat stilweg op die verstek gesteun het, word gelyktydig sigbaar, en sommige daarvan is stukkend.
Die merkblokkie wat nie beweeg het nie
Die laaste plek waar 'n verstek wegkruip, is die gebruikerskoppelvlak. Ons portaal het 'n merkblokkie gehad wat gelui het "Deaktiveer JIT-voorsiening", standaard ongemerk. Dit lui nou "Aktiveer JIT-voorsiening", en dit is steeds standaard ongemerk. Dieselfde element in dieselfde posisie met dieselfde aanvanklike toestand, en die teenoorgestelde betekenis.
Dit is 'n werklik gevaarlike soort verandering, so die lysaansig het 'n kenteken gekry. Enige verbinding wat nie ingeteken is nie, is nou gemerk, sodat die toestand sigbaar is sonder om enigiets oop te maak, eerder as om afgelei te word uit 'n ongemerkte blokkie wat vroeër die ander ding beteken het.
En wanneer 'n verbinding met voorsiening af 'n bewering vir iemand onbekend ontvang, word die gebruiker nie op 'n stapelspoor gedump nie. Hulle gaan terug na die toepassing waarvandaan hulle gekom het met 'n fout wat sê dat die rekening nie gevind is nie en dat hulle hul administrateur moet kontak, wat die ware en uitvoerbare weergawe is van wat pas gebeur het.
Verstekke is API oppervlak, geërf deur vier groepe
Verstekke is API oppervlak. Hulle word geërf deur gestoorde rye wat die veld voorafgaan, deur konfigurasielêers wat dit weglaat, deur kodepaaie wat dit nooit stel nie, en deur gebruikerskoppelvlak-kontroles waarvan die ongemerkte toestand hulle enkodeer. Voordat jy een verskuif, tel daardie vier groepe op en besluit, vir elkeen, of dit die nuwe verstek moet volg of die ou gedrag moet behou. Gewoonlik is die antwoord anders vir elkeen, en dit is die ontwerpwerk.
En as jy vind dat jy op die punt is om 'n datamigrasie te skryf om 'n boolean te skuif, kyk eers of die betekenis op sy plek kan bly terwyl die naam en die verstek voor dit skuif. Berging is die duur plek om van plan te verander. 'n Eienskap-steller is die goedkoop een.
As jy eerder wil hê jou identiteitsverskaffer moet met die versigtige verstekke reeds gekies uitgestuur word, laat Authagonal elke enkelaanmelding-verbinding kies om in te teken vir voorsiening, en sê vir jou reguit watter dit gedoen het.