I might have become clippy this time (#449)

* clippiness

* it is really handy that we have tests

* it is still really handy that we have tests
This commit is contained in:
James Hodgkinson 2021-05-22 14:48:08 +10:00 committed by GitHub
parent 35c1de4c45
commit ca446ddca5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 34 additions and 34 deletions

View file

@ -13,19 +13,18 @@ will override even if applicable. They should only be created by system access p
because we have certain requirements to deny certain changes.
Access profiles are stored as entries and are dynamically loaded into a structure that is
more efficent for use at runtime. Schema and it's transactions are a similar implementation.
more efficent for use at runtime. Schema and its transactions are a similar implementation.
Search Requirements
-------------------
A search access profile, must be able to limit the content of a search request and it's
scoping.
A search access profile must be able to limit:
A search access profile, must be able to limit the returned set of data from the objects
visible.
1. the content of a search request and its scoping.
2. the returned set of data from the objects visible.
An example is that user Alice should only be able to search for objects where the class
is person, and where they are a memberOf "visible" group. Alice should only be able to
is person and the object is a memberOf "visible" group. Alice should only be able to
see those users displayNames (not their legalName for example), and their public email.
Worded a bit differently. You need permission over the scope of entries, you need to be able
@ -142,7 +141,7 @@ An example is that user Alice should only be able to delete objects where the me
Create Requirements
-------------------
A create profile defines a filtering limit on what content can be created and it's requirements.
A create profile defines a filtering limit on what content can be created and its requirements.
A create profile defines a limit on what attributes can be created in addition to the filtering
requirements.
@ -152,7 +151,7 @@ only name the group - they can not add members to the group.
A content requirement could be something such as the value an attribute can contain must conform to a
regex, IE, you can create a group of any name, except where the name contains "admin" somewhere
in it's name. Arguable, this is partially possible with filtering.
in its name. Arguable, this is partially possible with filtering.
For example, we want to be able to limit the classes that someone *could* create on something
because classes often are used as a security type.
@ -329,7 +328,7 @@ user is collected. These then are added to the users requested search as:
In this manner, the search security is easily applied, as if the targets to conform to one of the
required search profile filters, the outer And condition is nullified and no results returned.
Once complete, in the translation of the entry -> proto_entry, each access control and it's allowed
Once complete, in the translation of the entry -> proto_entry, each access control and its allowed
set of attrs has to be checked to determine what of that entry can be displayed. Consider there are
three entries, A, B, C. An ACI that allows read of "name" on A, B exists, and a read of "mail" on
B, C. The correct behaviour is then:
@ -395,7 +394,7 @@ filter_no_index to the entry to entry. If all of this passes, the create is allo
A key point, is that there is no union of create aci's - the WHOLE aci must pass, not parts of
multiple. This means if a control say "allows creating group with member" and "allows creating
user with name", creating a gorup with name is not allowed - despite your ability to create
an entry with "name" it's classes don't match. This way, the admin of the service can define
an entry with "name", its classes don't match. This way, the admin of the service can define
create controls with really specific intent to how they'll be used, without risk of two
controls causing un-intended effects (users that are also groups, or allowing values that
were not intended).

View file

@ -46,14 +46,15 @@ Rate Limiting is the process of delaying authentication responses to slow the nu
against an account to deter attackers. This is often used to prevent attackers from bruteforcing
passwords at a high rate.
The best defence again these attacks is MFA. Due to the design of Kanidm, the second factor
(ie the webauthn token or the otp) is always checked *before* the password, meaning that the
attacker is unable to attack the password *unless* they also have the corresponding MFA token.
The best defence again these attacks is Multi-factor authentication (MFA). Due to the design of Kanidm,
the second factor (ie the webauthn token or the OTP) is always checked *before* the password,
meaning that the attacker is unable to attack the password *unless* they also have
the corresponding MFA token.
However, not all accounts will have MFA enabled, which means that defences are still required to
prevent these attacks for password-only accounts. Accounts protected with TOTP must also be rate
limited according to NIST sp800 63b. Webauthn does *not* require ratelimiting as a single factor
or multi factor device.
limited according to [NIST SP800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html).
Webauthn does *not* require rate-limiting as a single factor or multi factor device.
As an account can only have a single proceeding authentication session at a time, this provides
serialisation and rate limiting per account of the service. However, as Kanidm will in the future
@ -78,7 +79,7 @@ For accounts with password-only:
* If the attempts continue, the account is hard locked and signalled to an external system that this has occured.
The value of X should be less than 100, so that the NIST guidelines can be met. This is beacuse when there are
many replicas, each replica maintains it's own locking state, so "eventually" as each replica is attempted to be
many replicas, each replica maintains its own locking state, so "eventually" as each replica is attempted to be
bruteforced, then they will all eventually soft lock the account. In larger environments, we require
external signalling to coordinate the locking of the account.
@ -101,7 +102,7 @@ It must be possible to expire an account so it no longer operates (IE temporary
accounts that can only operate after a known point in time (Student enrollments and their course
commencment date).
This expiry must exist at the account level, but also on issued token/api password levels. This allows revocation of
This expiry must exist at the account level, but also on issued token/API password levels. This allows revocation of
individual tokens, but also the expiry of the account and all tokens as a whole. This expiry may be
undone, allowing the credentials to become valid once again.
@ -111,7 +112,7 @@ are stored on the server in unix epoch to account for timezones and geographic d
* Interaction with already issued tokens.
* it prevents them from working?
Must prevent creation of radius auth tokens
Must prevent creation of RADIUS auth tokens
Must prevent login via unix.

View file

@ -886,7 +886,7 @@ impl QueryServerWriteV1 {
"class".into(),
Value::new_class("person"),
)))
.filter_map(|v| v)
.flatten()
.collect();
let ml = ModifyList::new_list(mods);
@ -939,7 +939,7 @@ impl QueryServerWriteV1 {
.chain(iter::once(shell.map(|s| {
Modify::Present("loginshell".into(), Value::new_iutf8(s.as_str()))
})))
.filter_map(|v| v)
.flatten()
.collect();
let ml = ModifyList::new_list(mods);
@ -980,7 +980,7 @@ impl QueryServerWriteV1 {
.chain(iter::once(gx.gidnumber.map(|n| {
Modify::Present("gidnumber".into(), Value::new_uint32(n))
})))
.filter_map(|v| v)
.flatten()
.collect();
let ml = ModifyList::new_list(mods);

View file

@ -1005,7 +1005,7 @@ pub async fn auth(mut req: tide::Request<AppState>) -> tide::Result {
Ok(ProtoAuthState::Denied(reason))
}
}
.map(|state| AuthResponse { state, sessionid })
.map(|state| AuthResponse { sessionid, state })
}
Err(e) => Err(e),
};

View file

@ -194,7 +194,7 @@ impl SchemaAttribute {
SyntaxType::Credential => v.is_credential(),
SyntaxType::RadiusUtf8String => v.is_radius_string(),
SyntaxType::SshKey => v.is_sshkey(),
SyntaxType::ServicePrincipalName => v.is_spn(),
SyntaxType::SecurityPrincipalName => v.is_spn(),
SyntaxType::UINT32 => v.is_uint32(),
SyntaxType::Cid => v.is_cid(),
SyntaxType::NsUniqueId => v.is_nsuniqueid(),
@ -338,7 +338,7 @@ impl SchemaAttribute {
}
})
}),
SyntaxType::ServicePrincipalName => ava.iter().fold(Ok(()), |acc, v| {
SyntaxType::SecurityPrincipalName => ava.iter().fold(Ok(()), |acc, v| {
acc.and_then(|_| {
if v.is_spn() {
Ok(())
@ -708,13 +708,13 @@ impl<'a> SchemaWriteTransaction<'a> {
name: AttrString::from("spn"),
uuid: *UUID_SCHEMA_ATTR_SPN,
description: String::from(
"The service principle name of an object, unique across all domain trusts",
"The Security Principal Name of an object, unique across all domain trusts",
),
multivalue: false,
unique: true,
phantom: false,
index: vec![IndexType::Equality],
syntax: SyntaxType::ServicePrincipalName,
syntax: SyntaxType::SecurityPrincipalName,
},
);
self.attributes.insert(
@ -1085,7 +1085,7 @@ impl<'a> SchemaWriteTransaction<'a> {
unique: false,
phantom: true,
index: vec![],
syntax: SyntaxType::ServicePrincipalName,
syntax: SyntaxType::SecurityPrincipalName,
},
);
self.attributes.insert(

View file

@ -530,7 +530,7 @@ pub trait QueryServerTransaction<'a> {
SyntaxType::Credential => Err(OperationError::InvalidAttribute("Credentials can not be supplied through modification - please use the IDM api".to_string())),
SyntaxType::RadiusUtf8String => Err(OperationError::InvalidAttribute("Radius secrets can not be supplied through modification - please use the IDM api".to_string())),
SyntaxType::SshKey => Err(OperationError::InvalidAttribute("SSH public keys can not be supplied through modification - please use the IDM api".to_string())),
SyntaxType::ServicePrincipalName => Err(OperationError::InvalidAttribute("SPNs are generated and not able to be set.".to_string())),
SyntaxType::SecurityPrincipalName => Err(OperationError::InvalidAttribute("SPNs are generated and not able to be set.".to_string())),
SyntaxType::UINT32 => Value::new_uint32_str(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid uint32 syntax".to_string())),
SyntaxType::Cid => Err(OperationError::InvalidAttribute("CIDs are generated and not able to be set.".to_string())),
@ -612,7 +612,7 @@ pub trait QueryServerTransaction<'a> {
SyntaxType::Credential => Ok(PartialValue::new_credential_tag(value)),
SyntaxType::RadiusUtf8String => Ok(PartialValue::new_radius_string()),
SyntaxType::SshKey => Ok(PartialValue::new_sshkey_tag_s(value)),
SyntaxType::ServicePrincipalName => {
SyntaxType::SecurityPrincipalName => {
PartialValue::new_spn_s(value).ok_or_else(|| {
OperationError::InvalidAttribute("Invalid spn syntax".to_string())
})

View file

@ -123,7 +123,7 @@ pub enum SyntaxType {
Credential,
RadiusUtf8String,
SshKey,
ServicePrincipalName,
SecurityPrincipalName,
UINT32,
Cid,
NsUniqueId,
@ -148,7 +148,7 @@ impl TryFrom<&str> for SyntaxType {
"CREDENTIAL" => Ok(SyntaxType::Credential),
"RADIUS_UTF8STRING" => Ok(SyntaxType::RadiusUtf8String),
"SSHKEY" => Ok(SyntaxType::SshKey),
"SERVICE_PRINCIPLE_NAME" => Ok(SyntaxType::ServicePrincipalName),
"SECURITY_PRINCIPAL_NAME" => Ok(SyntaxType::SecurityPrincipalName),
"UINT32" => Ok(SyntaxType::UINT32),
"CID" => Ok(SyntaxType::Cid),
"NSUNIQUEID" => Ok(SyntaxType::NsUniqueId),
@ -174,7 +174,7 @@ impl TryFrom<usize> for SyntaxType {
8 => Ok(SyntaxType::Credential),
9 => Ok(SyntaxType::RadiusUtf8String),
10 => Ok(SyntaxType::SshKey),
11 => Ok(SyntaxType::ServicePrincipalName),
11 => Ok(SyntaxType::SecurityPrincipalName),
12 => Ok(SyntaxType::UINT32),
13 => Ok(SyntaxType::Cid),
14 => Ok(SyntaxType::Utf8StringIname),
@ -199,7 +199,7 @@ impl SyntaxType {
SyntaxType::Credential => 8,
SyntaxType::RadiusUtf8String => 9,
SyntaxType::SshKey => 10,
SyntaxType::ServicePrincipalName => 11,
SyntaxType::SecurityPrincipalName => 11,
SyntaxType::UINT32 => 12,
SyntaxType::Cid => 13,
SyntaxType::Utf8StringIname => 14,
@ -227,7 +227,7 @@ impl fmt::Display for SyntaxType {
SyntaxType::Credential => "CREDENTIAL",
SyntaxType::RadiusUtf8String => "RADIUS_UTF8STRING",
SyntaxType::SshKey => "SSHKEY",
SyntaxType::ServicePrincipalName => "SERVICE_PRINCIPLE_NAME",
SyntaxType::SecurityPrincipalName => "SECURITY_PRINCIPAL_NAME",
SyntaxType::UINT32 => "UINT32",
SyntaxType::Cid => "CID",
SyntaxType::NsUniqueId => "NSUNIQUEID",