Class: Clickwrap::Policy
- Inherits:
-
Object
- Object
- Clickwrap::Policy
- Defined in:
- lib/clickwrap/policy.rb
Overview
A compiled, frozen policy: what the server will present and what it will accept back.
The browser may answer a policy. It may never choose one. Policy key, revision, document versions, validity, subject binding, retention, and request-evidence fields are all resolved server-side and rechecked at submit, because every one of them is a security decision and a form field is not a safe place to keep one.
A policy's revision is the digest of its compiled snapshot. Publishing
freezes that snapshot in the database the first time the policy is
presented or captured, so a receipt written today still explains itself
after the Ruby source has moved on. The digest covers declared structure and
copy; host lambdas (subject fingerprints, protected-outcome recorders) are
recorded as present rather than serialized, since their bodies cannot be
canonicalized. That boundary is stated in the receipt rather than papered
over.
Instance Attribute Summary collapse
-
#authority_rule ⇒ Object
readonly
Returns the value of attribute authority_rule.
-
#capture_channels ⇒ Object
readonly
Returns the value of attribute capture_channels.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#locales ⇒ Object
readonly
Returns the value of attribute locales.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#persist_presentations_because ⇒ Object
readonly
Returns the value of attribute persist_presentations_because.
-
#persist_presentations_for ⇒ Object
readonly
Returns the value of attribute persist_presentations_for.
-
#request_evidence ⇒ Object
readonly
Returns the value of attribute request_evidence.
-
#retention_class_key ⇒ Object
readonly
Returns the value of attribute retention_class_key.
-
#revision ⇒ Object
readonly
Returns the value of attribute revision.
-
#snapshot ⇒ Object
readonly
Returns the value of attribute snapshot.
-
#statements ⇒ Object
readonly
Returns the value of attribute statements.
-
#tenant_scope ⇒ Object
readonly
Returns the value of attribute tenant_scope.
Instance Method Summary collapse
- #authorization_statements ⇒ Object
- #consent_statements ⇒ Object
- #document_keys ⇒ Object
-
#initialize(key:, statements:, retention_class_key: nil, request_evidence: nil, persist_presentations_for: nil, persist_presentations_because: nil, capture_channels: nil, locales: nil, tenant_scope: "optional", authority_rule: nil, options: {}) ⇒ Policy
constructor
A new instance of Policy.
- #kinds ⇒ Object
- #one_time_statements ⇒ Object
- #optional_statements ⇒ Object
-
#permits_acting_for? ⇒ Boolean
Delegation, guardianship, service-account action, and impersonation are rejected unless the policy opts in and the host authority adapter agrees.
- #permits_acting_for_party?(represented_party) ⇒ Boolean
- #permits_capture_channel?(channel) ⇒ Boolean
-
#permits_exemptions? ⇒ Boolean
Whether a system exemption may stand in for a human action under this policy.
- #permits_locale?(locale) ⇒ Boolean
- #persist_presentations? ⇒ Boolean
- #protected_outcome_statement ⇒ Object
- #protected_outcome_statements ⇒ Object
- #records_protected_outcome? ⇒ Boolean
- #required_statements ⇒ Object
- #statement(statement_key) ⇒ Object
- #statement!(statement_key) ⇒ Object
- #subject_bound? ⇒ Boolean
-
#tenant_from_controller(candidate) ⇒ Object
Resolves ambient controller context according to this policy.
- #tenant_not_applicable? ⇒ Boolean
- #tenant_optional? ⇒ Boolean
- #tenant_required? ⇒ Boolean
- #to_s ⇒ Object
-
#validate_tenant!(tenant) ⇒ Object
Direct service callers own their arguments, so an incompatible explicit value is rejected instead of silently rewritten.
Constructor Details
#initialize(key:, statements:, retention_class_key: nil, request_evidence: nil, persist_presentations_for: nil, persist_presentations_because: nil, capture_channels: nil, locales: nil, tenant_scope: "optional", authority_rule: nil, options: {}) ⇒ Policy
Returns a new instance of Policy.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/clickwrap/policy.rb', line 26 def initialize(key:, statements:, retention_class_key: nil, request_evidence: nil, persist_presentations_for: nil, persist_presentations_because: nil, capture_channels: nil, locales: nil, tenant_scope: "optional", authority_rule: nil, options: {}) @key = key.to_s @statements = statements.freeze @retention_class_key = retention_class_key&.to_s @request_evidence = request_evidence || RequestEvidencePolicy.new(policy_key: @key) @persist_presentations_for = persist_presentations_for @persist_presentations_because = persist_presentations_because @capture_channels = (capture_channels || Vocabulary::CAPTURE_CHANNELS).map(&:to_s).freeze @locales = locales&.map(&:to_s)&.freeze @tenant_scope = tenant_scope.to_s @authority_rule = @options = .freeze validate! @snapshot = build_snapshot.freeze @revision = Digest.digest_canonical(@snapshot).freeze freeze end |
Instance Attribute Details
#authority_rule ⇒ Object (readonly)
Returns the value of attribute authority_rule.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def @authority_rule end |
#capture_channels ⇒ Object (readonly)
Returns the value of attribute capture_channels.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def capture_channels @capture_channels end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def key @key end |
#locales ⇒ Object (readonly)
Returns the value of attribute locales.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def locales @locales end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def @options end |
#persist_presentations_because ⇒ Object (readonly)
Returns the value of attribute persist_presentations_because.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def persist_presentations_because @persist_presentations_because end |
#persist_presentations_for ⇒ Object (readonly)
Returns the value of attribute persist_presentations_for.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def persist_presentations_for @persist_presentations_for end |
#request_evidence ⇒ Object (readonly)
Returns the value of attribute request_evidence.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def request_evidence @request_evidence end |
#retention_class_key ⇒ Object (readonly)
Returns the value of attribute retention_class_key.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def retention_class_key @retention_class_key end |
#revision ⇒ Object (readonly)
Returns the value of attribute revision.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def revision @revision end |
#snapshot ⇒ Object (readonly)
Returns the value of attribute snapshot.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def snapshot @snapshot end |
#statements ⇒ Object (readonly)
Returns the value of attribute statements.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def statements @statements end |
#tenant_scope ⇒ Object (readonly)
Returns the value of attribute tenant_scope.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def tenant_scope @tenant_scope end |
Instance Method Details
#authorization_statements ⇒ Object
68 |
# File 'lib/clickwrap/policy.rb', line 68 def = statements.select { |statement| statement.kind == "authorization" } |
#consent_statements ⇒ Object
67 |
# File 'lib/clickwrap/policy.rb', line 67 def = statements.select { |statement| statement.kind == "consent" } |
#document_keys ⇒ Object
62 |
# File 'lib/clickwrap/policy.rb', line 62 def document_keys = statements.flat_map(&:document_keys).uniq |
#kinds ⇒ Object
63 |
# File 'lib/clickwrap/policy.rb', line 63 def kinds = statements.map(&:kind).uniq |
#one_time_statements ⇒ Object
65 |
# File 'lib/clickwrap/policy.rb', line 65 def one_time_statements = statements.select(&:one_time?) |
#optional_statements ⇒ Object
61 |
# File 'lib/clickwrap/policy.rb', line 61 def optional_statements = statements.select(&:optional?) |
#permits_acting_for? ⇒ Boolean
Delegation, guardianship, service-account action, and impersonation are rejected unless the policy opts in and the host authority adapter agrees. When permitted, the receipt keeps the authenticated principal, asserted actor, and represented party as separate facts; Clickwrap does not decide whether that authority is sufficient.
125 |
# File 'lib/clickwrap/policy.rb', line 125 def permits_acting_for? = .fetch(:permit_acting_for, false) == true |
#permits_acting_for_party?(represented_party) ⇒ Boolean
127 128 129 |
# File 'lib/clickwrap/policy.rb', line 127 def permits_acting_for_party?(represented_party) permits_acting_for? && &.permits?(represented_party) end |
#permits_capture_channel?(channel) ⇒ Boolean
81 |
# File 'lib/clickwrap/policy.rb', line 81 def permits_capture_channel?(channel) = capture_channels.include?(channel.to_s) |
#permits_exemptions? ⇒ Boolean
Whether a system exemption may stand in for a human action under this
policy. It is off unless the policy says otherwise, and an exemption never
satisfies agreed_to? or any other human-action predicate even when it
is permitted — it answers exempted_from? instead.
79 |
# File 'lib/clickwrap/policy.rb', line 79 def permits_exemptions? = .fetch(:permit_exemptions, false) == true |
#permits_locale?(locale) ⇒ Boolean
83 84 85 |
# File 'lib/clickwrap/policy.rb', line 83 def permits_locale?(locale) locales.nil? || locales.include?(locale.to_s) end |
#persist_presentations? ⇒ Boolean
73 |
# File 'lib/clickwrap/policy.rb', line 73 def persist_presentations? = !persist_presentations_for.nil? |
#protected_outcome_statement ⇒ Object
70 |
# File 'lib/clickwrap/policy.rb', line 70 def protected_outcome_statement = protected_outcome_statements.first |
#protected_outcome_statements ⇒ Object
69 |
# File 'lib/clickwrap/policy.rb', line 69 def protected_outcome_statements = statements.select(&:record_protected_outcome_with) |
#records_protected_outcome? ⇒ Boolean
71 |
# File 'lib/clickwrap/policy.rb', line 71 def records_protected_outcome? = protected_outcome_statement.present? |
#required_statements ⇒ Object
60 |
# File 'lib/clickwrap/policy.rb', line 60 def required_statements = statements.select(&:required?) |
#statement(statement_key) ⇒ Object
48 49 50 |
# File 'lib/clickwrap/policy.rb', line 48 def statement(statement_key) statements.find { |statement| statement.key == statement_key.to_s } end |
#statement!(statement_key) ⇒ Object
52 53 54 55 56 57 58 |
# File 'lib/clickwrap/policy.rb', line 52 def statement!(statement_key) statement(statement_key) || raise( UnknownStatementError, "Policy #{key} has no statement #{statement_key.inspect}. It declares: " \ "#{statements.map(&:key).join(", ")}." ) end |
#subject_bound? ⇒ Boolean
66 |
# File 'lib/clickwrap/policy.rb', line 66 def subject_bound? = statements.any?(&:subject_bound?) |
#tenant_from_controller(candidate) ⇒ Object
Resolves ambient controller context according to this policy. Personal evidence deliberately discards a current organization; tenant-required evidence fails before rendering if the host cannot supply one.
94 95 96 97 98 99 |
# File 'lib/clickwrap/policy.rb', line 94 def tenant_from_controller(candidate) return nil if tenant_not_applicable? validate_tenant!(candidate) candidate end |
#tenant_not_applicable? ⇒ Boolean
87 |
# File 'lib/clickwrap/policy.rb', line 87 def tenant_not_applicable? = tenant_scope == "not_applicable" |
#tenant_optional? ⇒ Boolean
89 |
# File 'lib/clickwrap/policy.rb', line 89 def tenant_optional? = tenant_scope == "optional" |
#tenant_required? ⇒ Boolean
88 |
# File 'lib/clickwrap/policy.rb', line 88 def tenant_required? = tenant_scope == "required" |
#to_s ⇒ Object
131 |
# File 'lib/clickwrap/policy.rb', line 131 def to_s = "Clickwrap policy #{key} (#{revision})" |
#validate_tenant!(tenant) ⇒ Object
Direct service callers own their arguments, so an incompatible explicit value is rejected instead of silently rewritten.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/clickwrap/policy.rb', line 103 def validate_tenant!(tenant) if tenant_not_applicable? && tenant.present? raise DefinitionError, "Policy #{key} says `tenant_is :not_applicable`, but this call supplied a tenant. " \ "Remove `tenant:`; personal evidence must not change identity when the actor joins " \ "or switches organizations." end if tenant_required? && tenant.nil? raise DefinitionError, "Policy #{key} says `tenant_is :required`, but this call supplied no tenant. Pass " \ "the server-resolved tenant to presentation, capture, and verification." end true end |