fix(iam): keep revocation core active when new flows are disabled
This commit is contained in:
@@ -15,7 +15,7 @@ $app->config->set(['default'=>'file','stores'=>['file'=>['type'=>'File','path'=>
|
||||
$app->config->set(['default'=>'fixture','connections'=>['fixture'=>['type'=>'sqlite','database'=>$file,'prefix'=>'','fields_strict'=>true]]], 'database');
|
||||
$manager = new think\DbManager(); $manager->setConfig($app->config->get('database')); $app->instance('think\Db', $manager);
|
||||
$app->config->set(['data_scope'=>['enabled'=>false], 'unique_identification'=>'fixture'], 'project');
|
||||
$app->config->set(['application_id'=>'zyt','portal_url'=>'https://iam.example.test','v2_enabled'=>true,'v2_introspection_token'=>str_repeat('c',32)], 'iam');
|
||||
$app->config->set(['application_id'=>'zyt','portal_url'=>'https://iam.example.test','v2_enabled'=>true,'v2_management_enabled'=>true,'v2_launch_enabled'=>true,'v2_introspection_token'=>str_repeat('c',32)], 'iam');
|
||||
try {
|
||||
foreach ([
|
||||
'CREATE TABLE admin (id INTEGER PRIMARY KEY,account TEXT,name TEXT,password TEXT,disable INTEGER,root INTEGER,multipoint_login INTEGER DEFAULT 1,delete_time INTEGER)',
|
||||
@@ -59,7 +59,7 @@ try {
|
||||
Db::name('admin')->where('id',1)->update(['disable'=>1]); denies(fn()=>IamV2Source::check($s1['session_id']),'ACCOUNT_DISABLED'); Db::name('admin')->where('id',1)->update(['disable'=>0]);
|
||||
Db::name('admin_session')->where('id',1)->update(['token'=>'rotated']); denies(fn()=>IamV2Source::check($s1['session_id']),'REAUTH_REQUIRED'); Db::name('admin_session')->where('id',1)->update(['token'=>'fixture-token-1']);
|
||||
IamV2Source::revokeSession($s1['session_id']); denies(fn()=>IamV2Source::check($s1['session_id']),'REAUTH_REQUIRED'); ok(IamV2Source::check($s2['session_id'])['revoked']===0,'revoking one browser preserves other independent session');
|
||||
$calls=[];$cfg=['v2_enabled'=>true,'api_url'=>'https://iam.example.test/api','public_url'=>'https://zyt.example.test','erp_url'=>'https://erp.example.test','v2_token'=>str_repeat('v',32),'v2_management_token'=>str_repeat('m',32),'application_id'=>'zyt'];
|
||||
$calls=[];$cfg=['v2_enabled'=>true,'v2_management_enabled'=>true,'v2_launch_enabled'=>true,'api_url'=>'https://iam.example.test/api','public_url'=>'https://zyt.example.test','erp_url'=>'https://erp.example.test','v2_token'=>str_repeat('v',32),'v2_management_token'=>str_repeat('m',32),'application_id'=>'zyt'];
|
||||
$client=new IamV2Client($cfg,function($method,$url,$headers,$body)use(&$calls){$calls[]=compact('method','url','headers','body');return ['status'=>200,'body'=>json_encode(['binding'=>null,'employee'=>null,'access'=>['allowed'=>false]])];});
|
||||
$service=new IamV2Manager($client);$service->binding(2);$service->binding(2);ok(count($calls)===1,'30 second read cache');
|
||||
Db::name('iam_v2_binding')->where('admin_id',2)->update(['checked_at'=>time()-31]);$service->binding(2);ok(count($calls)===2,'missed revocation compensation after 30 seconds');
|
||||
@@ -145,6 +145,7 @@ try {
|
||||
Db::name('system_role_menu')->insert(['role_id'=>7,'menu_id'=>7]);Db::name('admin_role')->insert(['admin_id'=>2,'role_id'=>7]);
|
||||
ok(IamV2Source::introspect($raceProof,'management','')['protectedAccount']===true,'protection recomputed at callback after target privilege change');
|
||||
denies(fn()=>IamV2Source::authorize($normalSession,'bind',[1],true,true),'PROTECTED_ACCOUNT_REVIEW_REQUIRED');
|
||||
ok(IamV2Source::liveStatus($normalSession['session_id'],1,'self_link')['protectedAccount']===true,'self-link callback reports live protection without requiring management capabilities');
|
||||
denies(fn()=>IamV2Source::liveStatus($normalSession['session_id'],1,'management',['1']),'PROTECTED_ACCOUNT_REVIEW_REQUIRED');
|
||||
Db::name('system_role_menu')->where('role_id',7)->delete();
|
||||
denies(fn()=>IamV2Source::liveStatus($normalSession['session_id'],1,'management',['2']),'FORBIDDEN');
|
||||
@@ -167,7 +168,16 @@ try {
|
||||
$oldGeneration=IamV2Source::enroll('old-generation-token','password',false);
|
||||
IamV2Source::revokeGeneration(4,1,'old-employee');
|
||||
ok((int) Db::name('admin_session')->where('id',4)->value('expire_time')<=time(),'old generation without newer holder expires actual business session row');
|
||||
$gateSession=IamV2Source::enroll('fixture-token-1','password',false);
|
||||
$pendingProof=IamV2Source::proof($gateSession,'management',[2],['iam:bind']);
|
||||
$gateConfig=$app->config->get('iam');$gateConfig['v2_management_enabled']=false;$gateConfig['v2_launch_enabled']=false;$app->config->set($gateConfig,'iam');
|
||||
ok(IamV2Source::liveStatus($gateSession['session_id'],1)['active'],'closing new-flow gates preserves live-session validation');
|
||||
denies(fn()=>IamV2Source::proof($gateSession,'launch',[1]),'FEATURE_DISABLED');
|
||||
denies(fn()=>IamV2Source::introspect($pendingProof,'management',''),'FEATURE_DISABLED');
|
||||
denies(fn()=>IamV2Source::liveStatus($gateSession['session_id'],1,'management',['2']),'FEATURE_DISABLED');
|
||||
Db::name('admin')->where('id',1)->update(['disable'=>1]);denies(fn()=>IamV2Source::liveStatus($gateSession['session_id'],1),'ACCOUNT_DISABLED');
|
||||
ok(!IamV2Client::feature('management',['v2_enabled'=>true]) && !IamV2Client::feature('launch',['v2_enabled'=>true]),'new-flow gates default closed independently of global core');
|
||||
$legacy=$cfg; unset($legacy['v2_token']); $legacy['application_token']=str_repeat('l',32); denies(fn()=>new IamV2Client($legacy),'SERVICE_UNAVAILABLE');
|
||||
denies(fn()=>IamV2Client::https('https://iam.example.test/path?override=1'),'INVALID_FIXED_URL');
|
||||
} finally { @unlink($file); if (is_dir($cachePath)) { foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cachePath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) { $path->isDir() ? rmdir($path->getPathname()) : unlink($path->getPathname()); } rmdir($cachePath); } }
|
||||
echo "PASS IamV2SourceTest: independent browser SID, legacy reauth, live DB, scope, protected accounts, single-use proof/intent, expiry, immutable authTime, disabled/rotated/revoked sessions, 30s compensation, signed event replay/digest/future/version, revoked tombstone, batch protected filtering/index mapping, selected-only execution, no local account mutation, credential-change revocation, central empty-tx/reconcile contract, first-link/session preservation, access restoration, protected single-review/ordinary denial/live target protection, separate credentials, durable events, historical mapping, generation-specific business expiry\n";
|
||||
echo "PASS IamV2SourceTest: independent browser SID, legacy reauth, live DB, scope, protected accounts, single-use proof/intent, expiry, immutable authTime, disabled/rotated/revoked sessions, 30s compensation, signed event replay/digest/future/version, revoked tombstone, batch protected filtering/index mapping, selected-only execution, no local account mutation, credential-change revocation, central empty-tx/reconcile contract, first-link/session preservation, access restoration, protected single-review/ordinary denial/live target protection, separate credentials, durable events, historical mapping, generation-specific business expiry, maintenance gates retain revocation core and live self-link protection\n";
|
||||
|
||||
Reference in New Issue
Block a user