Key cutting log · 2026-10-28
75 sign-ins and 75 CAS answers run through SESAME on 2026-10-28: 149 passed, 1 tool error.
A real raw PHP app, served by php -S with no network, signed a browser in and out 75 times across every option SESAME has. Then the cas driver read 75 serviceValidate answers, good, bad and hostile, shaped like the ones Wayne State's CAS server sends. One answer it should have refused, it accepted. That is on this page too.
Ticket 1 · The tally
A hundred and fifty turns of the key
A round trip passes when every one of its seven requests ends where SESAME says it should. An answer passes when the driver returns the expected identity or the exact named failure. There is no "flagged" here: a wrong result from an auth library is a tool error.
- 149Passed75 of 75 round trips, 74 of 75 answers
- 0Flaggednot used for an auth library
- 1Tool errora wrong namespace read as a success; fix queued
- 0Not applicableevery unit fit
Round trips
75 round trips, one square each: 75 passed, 0 flagged, 0 tool errors, 0 not applicable.
CAS answers
75 CAS answers, one square each: 74 passed, 0 flagged, 1 tool errors, 0 not applicable.
One tag per unit, in run order. These units are synthetic on purpose: no real account, password or ticket was used, and nothing reached a Wayne State service.
Ticket 2 · Round trips
Seventy-five browsers, in and out
Each round trip is seven requests with a cookie jar: the protected page sends you to sign in, the login sends you to CAS, CAS sends you back with a ticket, the ticket is checked once and dropped from the address bar, the page knows you, the MFA check gives its reason, and logout clears you out.
| Option | Values | Trips |
|---|---|---|
| Driver | fake (in local, dev, development, test and testing) and cas | 11 + 64 |
| CAS protocol | 2.0 (/serviceValidate) and 3.0 (/p3/serviceValidate) | 32 each |
assume_mfa | off and on | 32 each |
authenticationDate | absent, an hour ago, ten hours ago, an hour in the future | 16 each |
renew | off and on, checked on the login redirect and on validation | 32 each |
| Logout return-to | a page on the app, and a foreign site | 32 each |
What the MFA check answered
What held
MFA was satisfied only when assume_mfa was on and CAS reported a sign-in within eight hours: 8 of 8. A sign-in ten hours old was TOO_OLD, a date in the future or no date at all was NO_AUTH_TIME, never a pass. All 32 foreign return-to addresses were replaced with the app's own URL. Every logout sent Cache-Control: no-store and Clear-Site-Data, and every next request was signed out.
Ticket 3 · CAS answers
Seventy-five answers from the server
Each answer went to CasDriver::login through a stub HTTP client, with the ticket in the request, exactly as the app hands it over.
| Kind | Cases | Right | Expected result |
|---|---|---|---|
| Valid success (2.0 and 3.0, attributes, CDATA, BOM, other prefix, non-ASCII, bad dates) | 35 | 35 | the user, attributes kept |
| CAS failure codes, with and without text, failure beside success | 18 | 18 | "CAS authentication failed: CODE" |
| DOCTYPE: an external entity attempt and an HTML login page | 2 | 2 | refused before parsing |
| Not XML at all | 4 | 4 | "not valid XML" |
| Neither success nor failure (empty, no namespace, wrong namespace, nested) | 4 | 3 | "neither a success nor a failure" |
| Success with an empty or missing user | 3 | 3 | "has no user" |
| HTTP 302, 404, 500, 503 from the server | 4 | 4 | "answered with HTTP N" |
| Malformed ticket (PT-, smuggled query, too long, lower case) | 5 | 5 | refused with no call to the server |
The one it got wrong
An answer whose cas: prefix was bound to a different namespace was read as a success. The parser matched the prefix, not the namespace it promises to check. Such an answer could only come from the CAS server SESAME is configured to trust, over HTTPS, so the risk is small, but the code says namespace and should mean it. The fix and a test for this exact answer are queued before the next tag.
Ticket 4 · Cut your own
Run it on your own app
Install SESAME, wire the raw PHP path, and walk through the door with the fake driver on your machine.
Install
composer require waynestate/sesameA sign-in page, raw PHP, local only
<?php
require __DIR__ . '/../vendor/autoload.php';
session_start();
// build Sesame with DriverFactory::make(Config::fromArray([...])) as in the README, then:
$user = sesame_login();Serve it on a free port
php -S localhost:18921 -t publicThe proof harness did exactly this inside php:8.4-cli with no network, swapping the CAS server for a stub client, and logged each unit as one line (tool commit, unit id, command, exit code, duration, outcome) in the stack's internal record.
Ticket 5 · Small print
What this does not prove
- No real CAS server was contacted and no real account was used. The answers are synthetic, shaped from the protocol and from what Wayne State's server returns; a live sign-in is proved on a test site, not here.
- It ran the raw PHP path. The Laravel path shares the same core and has its own tests, but these 75 round trips did not go through a Laravel app.
- The gateway driver (signed assertions from a front proxy) was not part of this run.
- Replay of a used ticket is the CAS server's job; the stub did not model it.
- One tool error stands until the namespace fix ships. This page will say 150 when it does.
No key under the mat. We checked 150 times.