Skip to content

Commit 81c041d

Browse files
authored
clean up "test-privileged", "test-unprivileged" users (#1087)
1 parent ca46034 commit 81c041d

File tree

22 files changed

+372
-313
lines changed

22 files changed

+372
-313
lines changed

nexus/examples/config.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ session_absolute_timeout_minutes = 480
1515
# List of authentication schemes to support.
1616
#
1717
# This is not fleshed out yet and the only reason to change it now is for
18-
# working on authentication or authorization. Neither is really implemented
19-
# yet.
18+
# working on authentication or authorization.
2019
[authn]
2120
# TODO(https://github.com/oxidecomputer/omicron/issues/372): Remove "spoof".
2221
schemes_external = ["spoof", "session_cookie"]

nexus/src/authn/external/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ mod test {
191191
user_builtin_id: "1c91bab2-4841-669f-cc32-de80da5bbf39"
192192
.parse()
193193
.unwrap(),
194-
silo_id: *crate::db::fixed_data::silo::SILO_ID,
195194
};
196195
let grunt1 = Box::new(GruntScheme {
197196
name: name1,
@@ -208,7 +207,6 @@ mod test {
208207
user_builtin_id: "799684af-533a-cb66-b5ac-ab55a791d5ef"
209208
.parse()
210209
.unwrap(),
211-
silo_id: *crate::db::fixed_data::silo::SILO_ID,
212210
};
213211
let grunt2 = Box::new(GruntScheme {
214212
name: name2,

nexus/src/authn/external/session_cookie.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,8 @@ where
107107
}
108108
};
109109

110-
// TODO-security Once we have real SiloUsers and we can have
111-
// "test-privileged" and "test-unprivileged" be Silo Users, this should
112-
// be changed accordingly. Until then, the integration tests attempt to
113-
// use this scheme with "test-privileged", which requires that we
114-
// interpret these as BuiltinUsers.
115-
let actor = Actor::UserBuiltin {
116-
user_builtin_id: session.silo_user_id(),
110+
let actor = Actor::SiloUser {
111+
silo_user_id: session.silo_user_id(),
117112
silo_id: session.silo_id(),
118113
};
119114

nexus/src/authn/external/spoof.rs

Lines changed: 30 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,8 @@ use uuid::Uuid;
3737
// _authentication_ information. Similarly, the "Unauthorized" HTTP response
3838
// code usually describes an _authentication_ error.)
3939
//
40-
// The above example treats the specified user as a silo user. It's also
41-
// possible to use this mechanism to specify a built-in user. In that case, the
42-
// bearer token format looks like this:
43-
//
44-
// Authorization: Bearer oxide-spoof-builtin-<uuid>
45-
//
46-
// Either way, this mechanism trusts (without verification) that the client is
47-
// whoever they say they are. That's true of any bearer token, but this one is
40+
// This mechanism trusts (without verification) that the client is whoever
41+
// they say they are. That's true of any bearer token, but this one is
4842
// particularly dangerous because the tokens are long-lived and not secret.
4943

5044
pub const SPOOF_SCHEME_NAME: authn::SchemeName = authn::SchemeName("spoof");
@@ -63,16 +57,13 @@ lazy_static! {
6357
/// Actor (id) used for the special "bad credentials" error
6458
static ref SPOOF_RESERVED_BAD_CREDS_ACTOR: Actor = Actor::UserBuiltin {
6559
user_builtin_id: "22222222-2222-2222-2222-222222222222".parse().unwrap(),
66-
silo_id: *crate::db::fixed_data::silo::SILO_ID,
6760
};
6861
/// Complete HTTP header value to trigger the "bad actor" error
6962
pub static ref SPOOF_HEADER_BAD_ACTOR: Authorization<Bearer> =
70-
make_header_value_str(ActorType::Builtin, SPOOF_RESERVED_BAD_ACTOR)
71-
.unwrap();
63+
make_header_value_str(SPOOF_RESERVED_BAD_ACTOR).unwrap();
7264
/// Complete HTTP header value to trigger the "bad creds" error
7365
pub static ref SPOOF_HEADER_BAD_CREDS: Authorization<Bearer> =
74-
make_header_value_str(ActorType::Builtin, SPOOF_RESERVED_BAD_CREDS)
75-
.unwrap();
66+
make_header_value_str(SPOOF_RESERVED_BAD_CREDS).unwrap();
7667
}
7768

7869
/// Implements a (test-only) authentication scheme where the client simply
@@ -102,36 +93,19 @@ where
10293
}
10394
}
10495

105-
/// Specifies whether the spoof header explicitly specifies a built-in user or a
106-
/// normal (silo) user
107-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
108-
pub enum ActorType {
109-
Builtin,
110-
Silo,
111-
}
112-
11396
fn authn_spoof(raw_value: Option<&Authorization<Bearer>>) -> SchemeResult {
11497
let token = match raw_value {
11598
None => return SchemeResult::NotRequested,
11699
Some(bearer) => bearer.token(),
117100
};
118101

119-
let str_value = match token.strip_prefix(SPOOF_PREFIX) {
120-
None => {
121-
// This is some other kind of bearer token. Maybe another scheme
122-
// knows how to deal with it.
123-
return SchemeResult::NotRequested;
124-
}
125-
Some(s) => s,
126-
};
127-
128-
let (actor_kind, str_value) = {
129-
match str_value.strip_prefix("builtin-") {
130-
Some(s) => (ActorType::Builtin, s),
131-
None => (ActorType::Silo, str_value),
132-
}
133-
};
102+
if !token.starts_with(SPOOF_PREFIX) {
103+
// This is some other kind of bearer token. Maybe another scheme knows
104+
// how to deal with it.
105+
return SchemeResult::NotRequested;
106+
}
134107

108+
let str_value = &token[SPOOF_PREFIX.len()..];
135109
if str_value == SPOOF_RESERVED_BAD_ACTOR {
136110
return SchemeResult::Failed(Reason::UnknownActor {
137111
actor: str_value.to_owned(),
@@ -146,16 +120,10 @@ fn authn_spoof(raw_value: Option<&Authorization<Bearer>>) -> SchemeResult {
146120
}
147121

148122
match Uuid::parse_str(str_value).context("parsing header value as UUID") {
149-
Ok(actor_id) => {
123+
Ok(silo_user_id) => {
124+
// TODO This should really look up the silo for the given Silo User.
150125
let silo_id = *crate::db::fixed_data::silo::SILO_ID;
151-
let actor = match actor_kind {
152-
ActorType::Builtin => {
153-
Actor::UserBuiltin { user_builtin_id: actor_id, silo_id }
154-
}
155-
ActorType::Silo => {
156-
Actor::SiloUser { silo_user_id: actor_id, silo_id }
157-
}
158-
};
126+
let actor = Actor::SiloUser { silo_id, silo_user_id };
159127
SchemeResult::Authenticated(Details { actor })
160128
}
161129
Err(source) => SchemeResult::Failed(Reason::BadFormat { source }),
@@ -164,8 +132,8 @@ fn authn_spoof(raw_value: Option<&Authorization<Bearer>>) -> SchemeResult {
164132

165133
/// Returns a value of the `Authorization` header for this actor that will be
166134
/// accepted using this scheme
167-
pub fn make_header_value(kind: ActorType, id: Uuid) -> Authorization<Bearer> {
168-
make_header_value_str(kind, &id.to_string()).unwrap()
135+
pub fn make_header_value(id: Uuid) -> Authorization<Bearer> {
136+
make_header_value_str(&id.to_string()).unwrap()
169137
}
170138

171139
/// Returns a value of the `Authorization` header with `str` in the place where
@@ -176,14 +144,9 @@ pub fn make_header_value(kind: ActorType, id: Uuid) -> Authorization<Bearer> {
176144
/// this returns a typed value and so cannot be used to make various kinds of
177145
/// invalid headers.
178146
fn make_header_value_str(
179-
kind: ActorType,
180147
s: &str,
181148
) -> Result<Authorization<Bearer>, anyhow::Error> {
182-
let suffix = match kind {
183-
ActorType::Builtin => format!("builtin-{}", s),
184-
ActorType::Silo => String::from(s),
185-
};
186-
Authorization::bearer(&format!("{}{}", SPOOF_PREFIX, suffix))
149+
Authorization::bearer(&format!("{}{}", SPOOF_PREFIX, s))
187150
.context("not a valid HTTP header value")
188151
}
189152

@@ -209,8 +172,6 @@ mod test {
209172
use super::make_header_value;
210173
use super::make_header_value_raw;
211174
use super::make_header_value_str;
212-
use super::ActorType;
213-
use crate::db;
214175
use headers::authorization::Bearer;
215176
use headers::authorization::Credentials;
216177
use headers::Authorization;
@@ -221,18 +182,12 @@ mod test {
221182
fn test_make_header_value() {
222183
let test_uuid_str = "37b56e4f-8c60-453b-a37e-99be6efe8a89";
223184
let test_uuid = test_uuid_str.parse::<Uuid>().unwrap();
224-
let header_value = make_header_value(ActorType::Builtin, test_uuid);
185+
let header_value = make_header_value(test_uuid);
225186
// Other formats are valid here (e.g., changes in case or spacing).
226187
// However, a black-box test that accounted for those would be at least
227188
// as complicated as `make_header_value()` itself and wouldn't be so
228189
// convincing in demonstrating that that function does what we think it
229190
// does.
230-
assert_eq!(
231-
header_value.0.encode().to_str().unwrap(),
232-
"Bearer oxide-spoof-builtin-37b56e4f-8c60-453b-a37e-99be6efe8a89"
233-
);
234-
235-
let header_value = make_header_value(ActorType::Silo, test_uuid);
236191
assert_eq!(
237192
header_value.0.encode().to_str().unwrap(),
238193
"Bearer oxide-spoof-37b56e4f-8c60-453b-a37e-99be6efe8a89"
@@ -245,7 +200,7 @@ mod test {
245200
let test_uuid = test_uuid_str.parse::<Uuid>().unwrap();
246201
assert_eq!(
247202
make_header_value_raw(test_uuid_str.as_bytes()).unwrap(),
248-
make_header_value(ActorType::Silo, test_uuid).0.encode(),
203+
make_header_value(test_uuid).0.encode(),
249204
);
250205

251206
assert_eq!(
@@ -272,29 +227,18 @@ mod test {
272227
fn test_spoof_header_valid() {
273228
let test_uuid_str = "37b56e4f-8c60-453b-a37e-99be6efe8a89";
274229
let test_uuid = test_uuid_str.parse::<Uuid>().unwrap();
230+
let test_header = make_header_value(test_uuid);
275231

276-
// Success casees: the client provided a valid uuid in the header.
277-
for actor_type in [ActorType::Builtin, ActorType::Silo] {
278-
let test_header = make_header_value(actor_type, test_uuid);
279-
let success_case = authn_spoof(Some(&test_header));
280-
match success_case {
281-
SchemeResult::Authenticated(details) => {
282-
assert_eq!(details.actor.actor_id(), test_uuid);
283-
let found_type = details.actor.actor_type();
284-
match found_type {
285-
db::model::IdentityType::UserBuiltin => {
286-
assert_eq!(actor_type, ActorType::Builtin);
287-
}
288-
db::model::IdentityType::SiloUser => {
289-
assert_eq!(actor_type, ActorType::Silo);
290-
}
291-
}
292-
}
293-
result => {
294-
panic!("unexpectedly failed authentication: {:?}", result);
295-
}
296-
};
297-
}
232+
// Success case: the client provided a valid uuid in the header.
233+
let success_case = authn_spoof(Some(&test_header));
234+
match success_case {
235+
SchemeResult::Authenticated(details) => {
236+
assert_eq!(details.actor.actor_id(), test_uuid);
237+
}
238+
_ => {
239+
assert!(false);
240+
}
241+
};
298242
}
299243

300244
#[test]
@@ -335,8 +279,7 @@ mod test {
335279
];
336280

337281
for input in &bad_inputs {
338-
let test_header =
339-
make_header_value_str(ActorType::Builtin, input).unwrap();
282+
let test_header = make_header_value_str(input).unwrap();
340283
let result = authn_spoof(Some(&test_header));
341284
if let SchemeResult::Failed(error) = result {
342285
assert!(error.to_string().starts_with(

0 commit comments

Comments
 (0)