Skip to content
academia.sh

Lesson 17 / 21

Single Sign-On

Measuring federation along the axis of the assertion: 15 of 18 applications bound to a single provider and 1562 user connections resting on 90 items, the revocation window determined not by the assertion's 5-minute lifetime but by the application's local session reaching 72 hours, and key rotation producing a manual item and an outage in 5 applications.

Published Updated

In this lesson

  • Derives the number of applications and user connections bound to a single identity provider
  • Measures the assertion's lifetime and the time revocation takes effect as separate numbers
  • Calculates signing-key rotation in terms of manual items and outages
Contents

The previous lesson measured the access decision at network entry: 80 devices, 1348 connection points, a single service. A user who has entered the network, though, connects to dozens of applications throughout the day and is not expected to authenticate separately at each one. Single sign-on meets that need: the user authenticates once, the result of that authentication is carried to applications as an assertion, and each application verifies the assertion on its own.

The assertion’s production, signature and issuer verification, audience and time window, and the conversion from attribute to role were measured in the Authentication and Authorization course; they are not repeated here. What this lesson measures is enterprise scale: how many applications are bound to a single provider, how many applications fall if the root breaks, how long the assertion lives, and how long it takes for closing an account to take effect in which application.

One Root, Fifteen Applications

EI11: in single sign-on, the application does not authenticate the user itself; it accepts an assertion signed by the identity provider. The provider’s signing key is the shared trust root of every application bound to it. EI12: the assertion’s lifetime and the application’s own session lifetime are separate numbers; the second one determines how long revocation takes to take effect. EI13: rotating the root key is free in an application that pulls the key itself; in an application where the key is loaded manually or pinned into configuration, it is a manual item and an outage.

EI11 is enterprise identity’s single biggest gain. The user keeps one password, account closing happens in one place, and multi-factor authentication is applied at one point. The same design shows the course’s measure at its sharpest: the source of the gain and the source of the fragility are the same item.

Eighteen Applications

The inventory below is a model: the applications of a fictional regional measurement network organization. There is no real organization, no real provider, and no real key.

// sso/apps.mjs — the applications of a fictional regional measurement network organization and
// how they bind to the central identity provider (model): no real organization, no real
// provider, and no real key. No randomness.

// EI11: in single sign-on, the application does not authenticate the user itself; it accepts
// an assertion signed by the identity provider. The provider's signing key is the shared
// trust root of every application bound to it.
// Columns: mode = federated (entered only through the provider), mixed (federated and local
// account together), local (not bound to the provider); assertionMin = the assertion's
// validity period, minutes; sessionHour = how long the application holds its own session;
// key = how the signing key reaches the application (pool: pulled from the key set; manual:
// loaded by hand; pinned: fingerprint pinned into configuration).
export const APP = `
  billing                federated   142   5    8    pool
  work-order             federated   118   5   12    pool
  meter-archive          federated    64   5    4    pool
  report-portal          federated   173   5    8    pool
  field-mobile-endpoint  federated   140   5   72    manual
  asset-inventory        federated    47   5    8    pool
  hr-portal              federated   206   2    2    pool
  expense-approval       federated    88   5    8    pinned
  document-archive       federated   151   5   24    pool
  training-portal        federated    96  10   24    manual
  procurement-portal     mixed        39   5    8    manual
  maintenance-plan       mixed        55   5   12    pool
  call-center            mixed       104   5    4    pinned
  ticketing-system       federated    77   5    8    pool
  data-dashboard         federated    62   5    2    pool
  firmware-server        local        11   0    0    none
  backup-console         local         7   0    0    none
  legacy-scada-console   local         9   0    0    none`
  .trim().split("\n").map((r) => {
    const p = r.trim().split(/\s+/);
    return { name: p[0], mode: p[1], users: +p[2], assertionMin: +p[3], sessionHour: +p[4], key: p[5] };
  });

// EI12: the assertion's lifetime and the application's own session lifetime are separate
// numbers; the second one determines how long revocation takes to take effect.
// EI13: rotating the root key is free in an application that pulls the key itself; in one
// that is loaded manually or pinned, it is a manual item and an outage.
export const CHAIN = ["signing key", "key distribution point", "audience record",
  "attribute mapping", "time window", "local session record"];
export const federated = (u) => u.mode !== "local";
// sso/tally.mjs — how many applications are bound to a single provider, how many applications fall
// if the root breaks, what the assertion's lifetime is, how many hours revocation takes to take effect, and what key rotation costs.
import { APP, CHAIN, federated } from "./apps.mjs";

const print = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const sum = (f, s = APP) => s.reduce((a, x) => a + f(x), 0);
const bound = APP.filter(federated);
const local = APP.filter((u) => !federated(u));

console.log(`${APP.length} applications, ${bound.length} of them bound to a single provider, ` +
  `${sum((u) => u.users, bound)} user connections, chain ${CHAIN.length} items`);
console.log(`items bound to the root ${bound.length * CHAIN.length}, ` +
  `applications not bound to the root ${local.length} (${sum((u) => u.users, local)} accounts)`);

const A = [-10, 10, 10, 13, 19];
console.log("\n1. by binding mode");
print(A, "mode", "apps", "users", "root breaks", "assertion min avg");
for (const k of ["federated", "mixed", "local"]) {
  const s = APP.filter((u) => u.mode === k);
  const dk = s.filter((u) => u.assertionMin > 0);
  print(A, k, s.length, sum((u) => u.users, s), k === "local" ? 0 : s.length,
    dk.length ? (sum((u) => u.assertionMin, dk) / dk.length).toFixed(1) : "-");
}

const B = [-16, 10, 11, 21, 17];
console.log("\n2. revocation window: how long access lasts after an account is disabled");
print(B, "window", "apps", "users", "assertion min left", "session hr left");
for (const [name, lo, hi] of [["0-4 hr", 0, 4], ["5-12 hr", 5, 12],
  ["13-24 hr", 13, 24], ["25+ hr", 25, 999]]) {
  const s = bound.filter((u) => u.sessionHour >= lo && u.sessionHour <= hi);
  print(B, name, s.length, sum((u) => u.users, s), sum((u) => u.assertionMin, s),
    sum((u) => u.sessionHour, s));
}
const longest = bound.reduce((a, u) => (u.sessionHour > a.sessionHour ? u : a));
console.log(`longest window ${longest.sessionHour} hr (${longest.name}), ` +
  `assertion lifetime ${longest.assertionMin} minutes; ratio ${(longest.sessionHour * 60 / longest.assertionMin)}x`);

const C = [-8, 10, 11, 13, 13];
console.log("\n3. what rotating the signing key costs");
print(C, "key", "apps", "users", "manual item", "outage apps");
for (const a of ["pool", "manual", "pinned"]) {
  const s = bound.filter((u) => u.key === a);
  print(C, a, s.length, sum((u) => u.users, s), a === "pool" ? 0 : s.length,
    a === "pool" ? 0 : s.length);
}

const D = [-26, 8, 10, 22];
console.log("\n4. items that fall if the root breaks");
print(D, "item", "count", "fallen", "renewal");
const manual = bound.filter((u) => u.key !== "pool").length;
for (const s of [
  ["provider-bound apps", bound.length, bound.length, "trusted again"],
  ["user connections", sum((u) => u.users, bound), sum((u) => u.users, bound), "re-login"],
  ["signing key", 1, 1, "1 item produced"],
  ["manually carried key", manual, manual, `${manual} apps manually`],
  ["apps with local accounts", local.length, 0, "unaffected"],
]) print(D, ...s);
18 applications, 15 of them bound to a single provider, 1562 user connections, chain 6 items
items bound to the root 90, applications not bound to the root 3 (27 accounts)

1. by binding mode
mode            apps     users  root breaks  assertion min avg
federated         12      1364           12                5.2
mixed              3       198            3                5.0
local              3        27            0                  -

2. revocation window: how long access lasts after an account is disabled
window                apps      users   assertion min left  session hr left
0-4 hr                   4        436                   17               12
5-12 hr                  8        739                   40               72
13-24 hr                 2        247                   15               48
25+ hr                   1        140                    5               72
longest window 72 hr (field-mobile-endpoint), assertion lifetime 5 minutes; ratio 864x

3. what rotating the signing key costs
key           apps      users  manual item  outage apps
pool            10       1095            0            0
manual           3        275            3            3
pinned           2        192            2            2

4. items that fall if the root breaks
item                         count    fallen               renewal
provider-bound apps             15        15         trusted again
user connections              1562      1562              re-login
signing key                      1         1       1 item produced
manually carried key             5         5       5 apps manually
apps with local accounts         3         0            unaffected

The numbers are of the measurement class; their inputs are EI11–EI13 and the application inventory.

How Many Applications Are Bound to a Single Root

The header lines give the scope: 15 of 18 applications are bound to a single provider, 1562 user connections pass through that bond, and when six items are counted per application, a total of 90 items must be correct at the same time. The remaining three applications are not bound to the provider and keep 27 accounts on their own list.

The first table separates the modes. Twelve applications are entered only through the provider, three accept both the provider and their own local account. Mixed mode is put in place as an outage measure — when the provider goes down, 198 users can enter with a local account. The same item works in the opposite direction too: when a person is closed out at the provider, their local account in those three applications does not close. Mixed mode raises availability and lowers revocation; both come from the same row.

Local mode is the same pattern seen in the first lesson, in a different shape. Three applications are independent of the root and zero fall if the root breaks; against that, closing the 27 accounts happens through no central operation at all. Staying outside the root is not protection — it is adding a separate point of failure. These three applications’ 27 accounts appear in no central report in the organization’s identity inventory and have to be remembered by hand when the closing list is prepared; when they are not remembered, the number of accounts left behind is 27, and that number reads on no dashboard.

The Chain’s Six Items

Only one of the six items counted per application is the key; the remaining five are records standing around the key that must hold true at the same time. The key distribution point says where the application gets its signing key from; if that address is unreachable, verification cannot happen. The audience record binds which application the assertion was produced for; when it is written wrong, an assertion produced for one application is accepted by another.

Attribute mapping translates the field names coming from the provider into the fields the application expects, and a wrong mapping sets up identity correctly but authorization wrong. The time window comes up here for the third time: the assertion’s five-minute lifetime is measured against both sides’ clocks, and when the clocks drift apart, a valid assertion is rejected. The sixth item is the application’s own session record, and the entire next section is about it.

For fifteen applications, a total of 90 items is the number of independent records the organization must keep correct in order to get a single person into a single application. Eighty-nine of these items are not cryptographic; only one, the key at the top of the list, is both cryptographic and the one forming the attack surface. The root is a single item, the root’s surroundings are eighty-nine items, and the entire operating burden is on the second number.

The Revocation Window

The second table is the center of this lesson. The assertion’s lifetime is five minutes in most applications, and that number is often read as “the bond with the identity provider refreshes every five minutes.” It is not. The assertion only carries the login; after the application accepts the login it opens its own session, and on every subsequent request it looks at that session, not the assertion.

That is why, when an account is disabled, the number that determines how long access takes to end is the application’s session lifetime, not the assertion’s. In four applications that period is under four hours and covers 436 users; in eight applications it is between five and twelve hours. The longest window is at the field mobile endpoint: 72 hours. In that same application the assertion’s lifetime is five minutes; the ratio between the two numbers is 864 times.

The number’s meaning is direct. A person who leaves the organization or whose account is suspended keeps working in that application for three more days despite their record being closed in the central repository, and no log shows this as an error. The federation’s revocation speed is the speed of the application holding the longest session lifetime; averages say nothing at this scale. At enterprise scale, the way to speed up revocation is not shortening the assertion — it is shortening applications’ session lifetimes or requiring regular re-authentication; both get written to the user as a few extra steps a day.

The Cost of Rotating the Key

The third table counts EI13. Ten applications pull the signing key themselves from the key set the provider publishes; when the provider adds a new key, nothing happens in these applications and the manual item is zero. In the remaining five applications the key is either loaded manually or its fingerprint is pinned into configuration; rotation produces one manual item and one outage in each of these five.

The number five covers 467 of the 1562 users. The rotation plan is built around these five applications: the new key is published, configuration is updated in five applications, and then the old key is removed. There is a window in the middle of these three steps, and if the old key is dropped before the window closes, login stops in five applications.

The number determines how often the organization renews the root. In a portfolio with zero manual items, key rotation is a routine operation; in a portfolio with five manual items, it requires a planned maintenance window and gets postponed. Root renewal frequency is not a property of the root — it is a property of the automation rate of the items bound to it.

If the Root Breaks

The fourth table counts the break. When the signing key is compromised, all 15 of the 15 applications bound to the provider and all 1562 user connections fall. The assertion states on its own which user it was produced for; the party who knows the key can produce a valid assertion for any user it wants, and doing so needs no password and no second factor. This is the application-layer counterpart of the pattern seen in the ticket-granting service’s key in the second lesson.

The renewal bill is surprisingly small: the produced key is a single item. The bill’s real item is getting the new key to 15 applications — automatic in ten, manual in five. At the moment of a breach, the five manual items are done immediately rather than waiting for a maintenance window, and an outage in those five applications is unavoidable.

The three local applications again fall zero. In a root breach this looks like an advantage, but in that same breach the organization’s first task is to re-authenticate 1562 connections, and the 27 accounts of those three applications stay outside that operation: they neither fall nor get renewed. Being outside central control is not being outside the incident. In the inventory made after the breach, these three applications never enter the list, and because they do not enter it, they are never reviewed again; an item left outside the root’s scope stays outside the root breach’s investigation too.

Summary

  • 15 of 18 applications are bound to a single identity provider; 1562 user connections rest on a chain of 90 items.
  • Mixed mode raises availability and lowers revocation: when the provider goes down 198 users can log in, while an account closed at the provider stays open in those applications.
  • The application’s session lifetime, not the assertion’s 5-minute lifetime, determines how long revocation takes to take effect; the longest window is 72 hours and the ratio between the two numbers is 864 times.
  • Rotating the signing key costs zero in 10 applications and one manual item plus one outage each in 5 applications; this ratio determines root renewal frequency.
  • When the root breaks, 15 applications and 1562 connections fall; the newly produced key is 1 item, but it is carried to 5 applications by hand.

Next Step

This lesson counted a single authentication carried to 15 applications; that single authentication itself still rests on a password. If the password is known, all 1562 connections open in a single step. That is why a second factor is added to enterprise login, and which path the added factor closes is a separate question: not every factor type closes the same paths, and none closes all of them. The next lesson measures factor types by the paths they close and counts how many bypass paths stay open.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close