Class ::nsmcp::FileCredentials (public)
::nx::Class ::nsmcp::FileCredentials
Defined in /usr/local/ns/tcl/nsmcp/credentials.tcl
- Testcases:
- No testcase defined.
Source code: :property authenticator:required :property section:required :property store:required :variable mutex :method init {} { set :mutex [ns_mutex create "nsmcp:credentials:[ns_info server]:[self]"] } :method names {} { set names [ns_config ${:section} credentials {}] if {[llength $names] != [llength [lsort -unique $names]]} { error "duplicate credential names" } foreach name $names { if {![regexp {^[A-Za-z0-9][A-Za-z0-9_.-]*$} $name]} { error "invalid symbolic credential name" } } return $names } :method prepare {name} { set section ${:section}/credential/$name set path [ns_config $section tokenFile {}] if {[file pathtype $path] ne "absolute" || ![file isfile $path] || ![file readable $path]} { error "credential $name requires a readable absolute tokenFile" } set principal [ns_config $section principal $name] set permissions [ns_config $section permissions {}] if {$principal eq ""} { error "credential $name requires a principal" } llength $permissions set expires [ns_config $section expires 0] if {![string is wideinteger -strict $expires] || ($expires != 0 && $expires <= [clock seconds])} { error "credential $name has an invalid or expired expiry" } set f [open $path rb] try { set raw [read $f 4097] } finally { close $f } if {[string length $raw] > 4096} { error "credential $name has an oversized token file" } set token [string trim $raw "\r\n"] if {[string length $token] < 32 || [string length $token] > 4096 || ![regexp {^[A-Za-z0-9._~+/-]+=*$} $token]} { error "credential $name has an invalid token file" } set digest [ns_crypto::md string -digest sha256 -- $token] return [dict create token $token digest $digest tokenFile $path principal $principal permissions $permissions targets [list [ns_info server]] expires $expires] } :method publish {name prepared} { ${:authenticator} grant [dict get $prepared token] [dict get $prepared principal] [dict get $prepared permissions] [dict get $prepared targets] [dict get $prepared expires] dict unset prepared token nsv_set ${:store} $name $prepared return $prepared } :public method loadAll {} { # # Load all configured credential files as one validated update. # # Stage every credential under the mutex before changing active # authenticator bindings. # # @return Credential metadata without bearer-token contents. # ns_mutex lock ${:mutex} try { # Validate every file/policy before changing any existing binding. set staged {} set digests {} foreach name [:names] { set prepared [:prepare $name] set digest [dict get $prepared digest] if {[dict exists $digests $digest]} { error "configured credentials must use distinct tokens" } dict set digests $digest $name dict set staged $name $prepared } foreach name [nsv_array names ${:store}] { ${:authenticator} revoke [dict get [nsv_get ${:store} $name] digest] nsv_unset ${:store} $name } dict for {name prepared} $staged { :publish $name $prepared } return [:describeUnlocked] } finally { ns_mutex unlock ${:mutex} } } :public method load {name} { # # Reload one configured credential file. # # Validate and install the selected credential while serializing updates # with the instance mutex. # # @param name Name of the configured or registered item to resolve. # # @return The loaded credential's metadata dictionary. # ns_mutex lock ${:mutex} try { if {$name ni [:names]} { error "unknown configured credential name" } set prepared [:prepare $name] foreach other [nsv_array names ${:store}] { if {$other ne $name && [dict get [nsv_get ${:store} $other] digest] eq [dict get $prepared digest]} { error "configured credentials must use distinct tokens" } } set previous {} if {[nsv_exists ${:store} $name]} { set previous [dict get [nsv_get ${:store} $name] digest] } set metadata [:publish $name $prepared] if {$previous ne "" && $previous ne [dict get $prepared digest]} { ${:authenticator} revoke $previous } return $metadata } finally { ns_mutex unlock ${:mutex} } } :public method revoke {name} { # # Revoke the active binding for a loaded credential. # # Resolve the configured name to its stored digest and revoke that # authenticator entry under the mutex. # # @param name Name of the configured or registered item to resolve. # # @return The authenticator's revocation result; unknown credentials raise # an error. # ns_mutex lock ${:mutex} try { if {![nsv_exists ${:store} $name]} { error "unknown loaded credential name" } ${:authenticator} revoke [dict get [nsv_get ${:store} $name] digest] } finally { ns_mutex unlock ${:mutex} } } :method describeUnlocked {} { set result {} foreach name [lsort [nsv_array names ${:store}]] { set metadata [nsv_get ${:store} $name] set current [${:authenticator} credentialInfo [dict get $metadata digest]] set status revoked if {$current ne ""} { set status active if {[dict get $current expires] != 0 && [dict get $current expires] <= [clock seconds]} { set status expired } } dict set metadata status $status dict set result $name $metadata } return $result } :public method describe {} { # # Describe loaded credential bindings without revealing tokens. # # Read the credential metadata under the instance mutex. # # @return The credential metadata returned by the unlocked descriptor # helper. # ns_mutex lock ${:mutex} try { return [:describeUnlocked] } finally { ns_mutex unlock ${:mutex} } }XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)