windows_native_keyring_store/
lib.rs

1/*!
2
3# Windows native credential store for the keyring crate
4
5This module implements a credential store for the keyring crate that uses the
6Windows Credential Manager as its back end.
7
8## Usage
9
10To make this store the default for creation of keyring entries, execute this code:
11```
12keyring_core::set_default_store(windows_native_keyring_store::Store::new().unwrap())
13```
14
15## Mapping service and user values to credentials
16
17Each entry in keyring is mapped to a _generic credential_ in the Windows Credential Manager.
18The identifier for each credential in Windows is a `target_name` string.  If an entry is created with
19an explicit `target` modifier, that value is used as the `target_name`.
20Otherwise, a `target_name` string is generated by concatenating a prefix string, the `user`,
21a delimiter string, the `service`, and a suffix string.  The prefix, delimiter, and suffix strings
22are part of the store configuration.  Their default values are: empty strings for the prefix and suffix,
23and a '.' for the delimiter.
24
25Note that service and user strings, by default, can contain the delimiter
26string, so it is possible for entries with different service and user strings to
27map to the same description (and thus the same credential in the store). If you
28are worried about this, you can avoid it by configuring your store to forbid the
29delimiter string in the service string.
30
31## Persistence Type
32
33Each generic credential can have one of three persistence types, defined
34precisely in the Windows API
35[here](https://learn.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw),
36and represented in this API by the [CredPersist] enumeration values
37[Session](CredPersist::Session), [Local](CredPersist::Local), and
38[Enterprise](CredPersist::Enterprise).
39
40By default, created credentials have [Enterprise](CredPersist::Enterprise) persistence,
41but you can specify a desired persistence by using the `persistence` modifier at entry
42creation time with a (case-insensitive) value of `Session`, `Local`, or `Enterprise`. Note
43that this type will only be applied when the credential's secret is written; it does not
44control the persistence of an existing credential in the store whose value is read via the entry.
45
46The persistence of an existing credential can be read and updated via its `persistence` attribute.
47Note that updating this attribute on an existing credential does `not` update the remembered
48persistence in the entry used to access that credential. Thus, setting the secret in a credential
49always changes its persistence to match that specified when the entry was created.
50
51## Attributes
52
53In addition to the `persistence` attribute mentioned in the last section,
54there are three string attributes that are held on each generic credential:
55`target_alias`, `username`, and `comment`. The `username` attribute will be set
56from the `user` specifier whenever an entry is written.
57All four attributes on existing credentials can be read and set using the
58[get_attributes](keyring_core::Entry::get_attributes) and
59[update_attributes](keyring_core::Entry::update_attributes) methods.
60
61## Search
62
63This credential store module supports searching for existing credentials.
64You can (optionally) specify a regular-expression pattern to be matched against each
65credential's `target_name`. If you don't specify a pattern, all existing
66generic credentials are returned.
67
68The entries returned from search are all wrappers, of course, but if the
69wrapped credential *can* be specified by the store being searched, then
70the return entry will also be a specifier. But recall that each store can
71have its own conventions for delimiters used when forming the `target_name`.
72Thus, a search in one store may return a wrapper/specifier for an existing credential
73but that same search in another store may return a wrapper that is *not* a specifier.
74
75## Warnings
76
77Tests show that operating on the same entry from different threads
78does not reliably sequence the operations in the same order they
79are initiated. (For example, setting a password on one thread and
80then immediately spawning another to get the password may return a
81`NoEntry` error on the spawned thread.) So be careful not to
82access the same entry on multiple threads simultaneously.
83
84Tests show that changing a credential's persistence type
85immediately before reading it may cause the read to fail,
86especially if the credential manager is busy on multiple
87threads.
88
89 */
90
91pub mod cred;
92pub use cred::CredPersist;
93pub mod store;
94pub use store::Store;
95#[cfg(test)]
96mod tests;
97mod utils;