Skip to content

Commit 082664f

Browse files
authored
store role assignments in the database (#520)
1 parent 640253d commit 082664f

21 files changed

+1524
-677
lines changed

common/src/sql/dbinit.sql

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,10 @@ CREATE INDEX ON omicron.public.console_session (
663663
/*******************************************************************/
664664

665665
/*
666-
* IAM
666+
* Identity and Access Management (IAM)
667+
*
668+
* **For more details and a worked example using the tables here, see the
669+
* documentation for the omicron_nexus crate, "authz" module.**
667670
*/
668671

669672
/*
@@ -757,6 +760,36 @@ CREATE TABLE omicron.public.role_builtin (
757760
PRIMARY KEY(resource_type, role_name)
758761
);
759762

763+
/*
764+
* Assignments between users, roles, and resources
765+
*
766+
* A built-in user has role on a resource if there's a record in this table that
767+
* points to that user, role, and resource.
768+
*
769+
* For more details and a worked example, see the omicron_nexus::authz
770+
* module-level documentation.
771+
*/
772+
773+
CREATE TABLE omicron.public.role_assignment_builtin (
774+
/* Composite foreign key into "role_builtin" table */
775+
resource_type STRING(63) NOT NULL,
776+
role_name STRING(63) NOT NULL,
777+
778+
/*
779+
* Foreign key into some other resource table. Which table? This is
780+
* identified implicitly by "resource_type" above.
781+
*/
782+
resource_id UUID NOT NULL,
783+
784+
/*
785+
* Foreign key into table of built-in users.
786+
*/
787+
user_builtin_id UUID NOT NULL,
788+
789+
/* The entire row is the primary key. */
790+
PRIMARY KEY(user_builtin_id, resource_type, resource_id, role_name)
791+
);
792+
760793
/*******************************************************************/
761794

762795
/*

nexus/src/authz/actor.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Oso integration for Actor types
6+
7+
use super::roles::RoleSet;
8+
use crate::authn;
9+
use omicron_common::api::external::ResourceType;
10+
use uuid::Uuid;
11+
12+
/// Represents [`authn::Context`] (which is either an authenticated or
13+
/// unauthenticated actor) for Polar
14+
#[derive(Clone, Debug)]
15+
pub struct AnyActor {
16+
authenticated: bool,
17+
actor_id: Option<Uuid>,
18+
roles: RoleSet,
19+
}
20+
21+
impl AnyActor {
22+
pub fn new(authn: &authn::Context, roles: RoleSet) -> Self {
23+
let actor = authn.actor();
24+
AnyActor {
25+
authenticated: actor.is_some(),
26+
actor_id: actor.map(|a| a.0),
27+
roles,
28+
}
29+
}
30+
}
31+
32+
impl oso::PolarClass for AnyActor {
33+
fn get_polar_class_builder() -> oso::ClassBuilder<Self> {
34+
oso::Class::builder()
35+
.add_attribute_getter("authenticated", |a: &AnyActor| {
36+
a.authenticated
37+
})
38+
.add_attribute_getter("authn_actor", |a: &AnyActor| {
39+
a.actor_id.map(|actor_id| AuthenticatedActor {
40+
actor_id,
41+
roles: a.roles.clone(),
42+
})
43+
})
44+
}
45+
}
46+
47+
/// Represents an authenticated [`authn::Context`] for Polar
48+
#[derive(Clone, Debug)]
49+
pub struct AuthenticatedActor {
50+
actor_id: Uuid,
51+
roles: RoleSet,
52+
}
53+
54+
impl AuthenticatedActor {
55+
/// Returns whether this actor has the given role for the given resource
56+
pub fn has_role_resource(
57+
&self,
58+
resource_type: ResourceType,
59+
resource_id: Uuid,
60+
role: &str,
61+
) -> bool {
62+
self.roles.has_role(resource_type, resource_id, role)
63+
}
64+
}
65+
66+
impl PartialEq for AuthenticatedActor {
67+
fn eq(&self, other: &Self) -> bool {
68+
self.actor_id == other.actor_id
69+
}
70+
}
71+
72+
impl Eq for AuthenticatedActor {}
73+
74+
impl oso::PolarClass for AuthenticatedActor {
75+
fn get_polar_class_builder() -> oso::ClassBuilder<Self> {
76+
oso::Class::builder().with_equality_check().add_constant(
77+
AuthenticatedActor {
78+
actor_id: authn::USER_DB_INIT.id,
79+
roles: RoleSet::new(),
80+
},
81+
"USER_DB_INIT",
82+
)
83+
}
84+
}

0 commit comments

Comments
 (0)