code wiki / _hdl_build / nx_authz_session_gate.nx

nx_authz_session_gate.nx source

↩ module page · 165 lines · 8992 B

1// nx_authz_session_gate.nx -- proves the FULL per-request authorization chain a daemon runs, end-to-end and 2// sovereign: a real no-cookie OPAQUE session token (X-Nishi-Session) -> nx_sa_validate_handle (authn -> the 3// user's HANDLE) -> authz_level_of (handle -> permission LEVEL) -> authz_level_allow (LEVEL vs the gallery 4// policy) -> the NSFW section is served ONLY to a private-level user. Uses REAL Modern Auth (register + login 5// for genuine 152B tokens) + the gallery policy (/ ->0 public, /gallery/private/ ->2 NSFW). This is exactly 6// what nx_media_server will call per request. license_tier: ORIGINAL 7import "nx_site_auth.nx" 8import "nx_authz.nx" 9import "hub/nx_modern_auth_flow.nx" 10import "nx_base64.nx" 11import "nx_syscalls.nx" 12 13func sg_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 14func sg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 15func sg_row(name: *u8, ok: i64) -> i64 { if ok == 1 { sg_w(" PASS " as *u8) } if ok != 1 { sg_w(" FAIL " as *u8) } sg_w(name); sg_w("\n" as *u8); return ok } 16func sg_trunc(p: *u8) -> i64 { let fd: i64 = sys_openat_wr(p, 0x180); if fd >= 0 { sys_close(fd) } return 0 } 17func sg_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o + i] = s[i]; i = i + 1 } return o + i } 18func sg_catn(d: *u8, o: i64, s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { d[o + i] = s[i]; i = i + 1 } return o + n } 19func sg_streq_n(a: *u8, an: i64, b: *u8) -> i64 { 20 if an != sg_len(b) { return 0 } 21 var i: i64 = 0 22 while i < an { if (a[i] as i64) != (b[i] as i64) { return 0 } i = i + 1 } 23 return 1 24} 25 26// build "GET <path> HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: <b64tok>\r\n\r\n" into req; return length 27func sg_req(req: *u8, path: *u8, b64: *u8, b64n: i64) -> i64 { 28 var o: i64 = sg_cat(req, 0, "GET " as *u8) 29 o = sg_cat(req, o, path) 30 o = sg_cat(req, o, " HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 31 o = sg_catn(req, o, b64, b64n) 32 o = sg_cat(req, o, "\r\n\r\n" as *u8) 33 return o 34} 35 36// the per-request chain: validate session -> handle -> level -> authz. returns 1 ALLOW, 0 authz-DENY, -1 auth-FAIL. 37func sg_decide(ctx: *NxAuthContext, req: *u8, rl: i64, now_s: i64, hbuf: *u8, hn: *i64, uh: *i64, uhl: *i64, ul: *i64, un: i64, pp: *i64, pl: *i64, pv: *i64, np: i64, path: *u8) -> i64 { 38 let rc: i64 = nx_sa_validate_handle(ctx, req, rl, now_s, hbuf, 64, hn) 39 if rc != NX_MAUTH_OK { return 0 - 1 } 40 let lv: i64 = authz_level_of(hbuf, hn[0], uh, uhl, ul, un) 41 return authz_level_allow(lv, pp, pl, pv, np, path, sg_len(path)) 42} 43 44func main() -> i64 { 45 sg_w("authz-session chain gate: OPAQUE token -> handle -> level -> NSFW decision (end-to-end)\n" as *u8) 46 sg_trunc("/tmp/nx_azs_keys.log" as *u8) 47 sg_trunc("/tmp/nx_azs_store.log" as *u8) 48 49 let oprf: *u8 = sys_mmap(32) 50 let akp: *u8 = sys_mmap(32) 51 let akb: *u8 = sys_mmap(33) 52 let edp: *u8 = sys_mmap(32) 53 let edb: *u8 = sys_mmap(32) 54 if nx_uas_server_keys_load_or_init("/tmp/nx_azs_keys.log" as *u8, oprf, akp, akb, edp, edb) != NX_UAS_OK { sg_w("KEYS FAIL\n" as *u8); sys_exit(1) } 55 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 56 let store_p: *u8 = "/tmp/nx_azs_store.log" as *u8 57 let realm_p: *u8 = "nishifamily" as *u8 58 if nx_auth_context_init(ctx, realm_p, 11, realm_p, 11, store_p as i64, oprf, edp, edb, 900, 8192, 1, 1, 5, 1) != NX_MAUTH_OK { sg_w("CTX FAIL\n" as *u8); sys_exit(1) } 59 let mn: *u8 = sys_mmap(512) 60 let mnn: *i64 = sys_mmap(8) as *i64 61 if nx_modern_auth_register(ctx, "carol" as *u8, 5, "carol-secret-passphrase" as *u8, 23, mn, 512, mnn) != NX_MAUTH_OK { sg_w("REG carol FAIL\n" as *u8); sys_exit(1) } 62 if nx_modern_auth_register(ctx, "bob" as *u8, 3, "bob-secret-passphrase" as *u8, 21, mn, 512, mnn) != NX_MAUTH_OK { sg_w("REG bob FAIL\n" as *u8); sys_exit(1) } 63 64 let raw: *u8 = sys_mmap(NX_MAUTH_SESSION_TOKEN_BYTES) 65 let rawn: *i64 = sys_mmap(8) as *i64 66 let carol_b64: *u8 = sys_mmap(512) 67 rawn[0] = 0 68 if nx_modern_auth_login(ctx, "carol" as *u8, 5, "carol-secret-passphrase" as *u8, 23, raw, NX_MAUTH_SESSION_TOKEN_BYTES, rawn) != NX_MAUTH_OK { sg_w("LOGIN carol FAIL\n" as *u8); sys_exit(1) } 69 let carol_b64n: i64 = b64_encode(raw, NX_MAUTH_SESSION_TOKEN_BYTES, carol_b64) 70 let bob_b64: *u8 = sys_mmap(512) 71 rawn[0] = 0 72 if nx_modern_auth_login(ctx, "bob" as *u8, 3, "bob-secret-passphrase" as *u8, 21, raw, NX_MAUTH_SESSION_TOKEN_BYTES, rawn) != NX_MAUTH_OK { sg_w("LOGIN bob FAIL\n" as *u8); sys_exit(1) } 73 let bob_b64n: i64 = b64_encode(raw, NX_MAUTH_SESSION_TOKEN_BYTES, bob_b64) 74 75 // the session token carries the user-id-HASH (not the plaintext handle), so the level table is keyed by hash 76 let carol_hash: *u8 = sys_mmap(32) 77 nx_ncs_derive_user_id_hash(realm_p, 11, "carol" as *u8, 5, carol_hash) 78 let bob_hash: *u8 = sys_mmap(32) 79 nx_ncs_derive_user_id_hash(realm_p, 11, "bob" as *u8, 3, bob_hash) 80 81 let pp: *i64 = sys_mmap(8*8) as *i64 82 let pl: *i64 = sys_mmap(8*8) as *i64 83 let pv: *i64 = sys_mmap(8*8) as *i64 84 pp[0] = "/" as *u8 as i64 85 pl[0] = 1 86 pv[0] = 0 87 pp[1] = "/gallery/private/" as *u8 as i64 88 pl[1] = sg_len("/gallery/private/" as *u8) 89 pv[1] = 2 90 let np: i64 = 2 91 let uh: *i64 = sys_mmap(8*8) as *i64 92 let uhl: *i64 = sys_mmap(8*8) as *i64 93 let ul: *i64 = sys_mmap(8*8) as *i64 94 uh[0] = carol_hash as i64 95 uhl[0] = 32 96 ul[0] = 2 97 uh[1] = bob_hash as i64 98 uhl[1] = 32 99 ul[1] = 1 100 let un: i64 = 2 101 102 let req: *u8 = sys_mmap(4096) 103 let hbuf: *u8 = sys_mmap(64) 104 let hn: *i64 = sys_mmap(8) as *i64 105 let now_s: i64 = sys_now_realtime_sec() 106 var pass: i64 = 0 107 108 // T1: carol (private) -> NSFW ALLOW 109 let rl1: i64 = sg_req(req, "/gallery/private/p1" as *u8, carol_b64, carol_b64n) 110 let d1: i64 = sg_decide(ctx, req, rl1, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8) 111 var t1: i64 = 0 112 if d1 == 1 { t1 = 1 } 113 pass = pass + sg_row("T1 carol session -> level 2 -> NSFW ALLOWED" as *u8, t1) 114 115 // T2: bob (family) -> auth OK but NSFW DENY (decide == 0) 116 let rl2: i64 = sg_req(req, "/gallery/private/p1" as *u8, bob_b64, bob_b64n) 117 let d2: i64 = sg_decide(ctx, req, rl2, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8) 118 var t2: i64 = 0 119 if d2 == 0 { t2 = 1 } 120 pass = pass + sg_row("T2 bob session -> level 1 -> NSFW DENIED (not shared by all)" as *u8, t2) 121 122 // T3: NO session header -> auth FAIL (decide == -1) 123 let rl3: i64 = sg_cat(req, 0, "GET /gallery/private/p1 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 124 let d3: i64 = sg_decide(ctx, req, rl3, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8) 125 var t3: i64 = 0 126 if d3 == (0 - 1) { t3 = 1 } 127 pass = pass + sg_row("T3 no X-Nishi-Session -> auth DENY (no token, no access)" as *u8, t3) 128 129 // T4: tampered token -> auth FAIL 130 let bad: *u8 = sys_mmap(512) 131 var bi: i64 = 0 132 while bi < carol_b64n { bad[bi] = carol_b64[bi]; bi = bi + 1 } 133 if (bad[0] as i64) == 65 { bad[0] = 66 as u8 } 134 if (bad[0] as i64) != 66 { bad[0] = 65 as u8 } 135 let rl4: i64 = sg_req(req, "/gallery/private/p1" as *u8, bad, carol_b64n) 136 let d4: i64 = sg_decide(ctx, req, rl4, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8) 137 var t4: i64 = 0 138 if d4 == (0 - 1) { t4 = 1 } 139 pass = pass + sg_row("T4 tampered token -> auth DENY (forged rejected)" as *u8, t4) 140 141 // T5: the session's user-id-hash resolves to carol's level (the chain keys on the stable hash, not plaintext) 142 let rl5: i64 = sg_req(req, "/gallery/x" as *u8, carol_b64, carol_b64n) 143 let rc5: i64 = nx_sa_validate_handle(ctx, req, rl5, now_s, hbuf, 64, hn) 144 var t5: i64 = 0 145 if rc5 == NX_MAUTH_OK { if authz_level_of(hbuf, hn[0], uh, uhl, ul, un) == 2 { t5 = 1 } } 146 pass = pass + sg_row("T5 session user-id-hash resolves to carol's level (2)" as *u8, t5) 147 148 // T6: the rest is exposed -- bob can view a public gallery item (decide == 1) 149 let rl6: i64 = sg_req(req, "/gallery/sunset.jpg" as *u8, bob_b64, bob_b64n) 150 let d6: i64 = sg_decide(ctx, req, rl6, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/sunset.jpg" as *u8) 151 var t6: i64 = 0 152 if d6 == 1 { t6 = 1 } 153 pass = pass + sg_row("T6 public gallery item allowed (the rest is exposed)" as *u8, t6) 154 155 if pass == 6 { 156 let line: *u8 = "CMSGATE row=nx_authz_session session-to-level-to-nsfw-chain rows=6 pass=6 verdict=PASS\n" as *u8 157 let gf: i64 = sys_openat_append("knowledge/status/cms_gate.log" as *u8, 0x1a4) 158 if gf >= 0 { sys_write(gf, line, sg_len(line)); sys_close(gf) } 159 sg_w("AUTHZ-SESSION GATE GREEN 6/6 (OPAQUE token -> handle -> level -> NSFW gate, end-to-end)\n" as *u8) 160 sys_exit(0) 161 } 162 sg_w("AUTHZ-SESSION GATE RED\n" as *u8) 163 sys_exit(1) 164 return 1 165}