What
OneTimeUse is refused as of #42, on the grounds that honouring it means remembering which assertions have been spent and this SP keeps no such record. That is what SAML Core 2.5.1.5 asks of a party in that position, so it is correct, and it is also the whole of what #42 does about it.
Once #44 lands, the record exists. Its replay_dict already remembers every accepted assertion until it expires, which is exactly the state OneTimeUse demands. An assertion carrying the condition is still refused, including on a deployment that has the dict configured and is therefore able to satisfy it.
What it should do
Accept OneTimeUse when replay tracking is on, refuse it when it is off.
Concretely:
- carry the condition through the reader, as a flag on
saml_assertion_t and a field on the Lua table, rather than letting it fall into unknown_condition
- put it back on
is_known_condition in src/xml.c
- have
assertions_acceptable refuse an assertion carrying it while replay_dict is unset, and pass it otherwise, since the replay cache then enforces the single use for real
The message on the refusal should say the SP cannot satisfy the condition without replay tracking, so an operator reads it as something to configure rather than something to work around.
Why it is worth doing
An IdP sends OneTimeUse when the assertion is sensitive enough that it wants one shot at it. Refusing those outright turns a deployment that can honour the condition into one that cannot log in at all, which is the wrong answer for the deployment that went to the trouble of configuring the dict.
Notes
Raised by @jarvis9443 reviewing #42. The refusal is the conservative half of that review; this issue is the other half. Depends on #44.
What
OneTimeUseis refused as of #42, on the grounds that honouring it means remembering which assertions have been spent and this SP keeps no such record. That is what SAML Core 2.5.1.5 asks of a party in that position, so it is correct, and it is also the whole of what #42 does about it.Once #44 lands, the record exists. Its
replay_dictalready remembers every accepted assertion until it expires, which is exactly the stateOneTimeUsedemands. An assertion carrying the condition is still refused, including on a deployment that has the dict configured and is therefore able to satisfy it.What it should do
Accept
OneTimeUsewhen replay tracking is on, refuse it when it is off.Concretely:
saml_assertion_tand a field on the Lua table, rather than letting it fall intounknown_conditionis_known_conditioninsrc/xml.cassertions_acceptablerefuse an assertion carrying it whilereplay_dictis unset, and pass it otherwise, since the replay cache then enforces the single use for realThe message on the refusal should say the SP cannot satisfy the condition without replay tracking, so an operator reads it as something to configure rather than something to work around.
Why it is worth doing
An IdP sends
OneTimeUsewhen the assertion is sensitive enough that it wants one shot at it. Refusing those outright turns a deployment that can honour the condition into one that cannot log in at all, which is the wrong answer for the deployment that went to the trouble of configuring the dict.Notes
Raised by @jarvis9443 reviewing #42. The refusal is the conservative half of that review; this issue is the other half. Depends on #44.