Skip to content

Commit

Permalink
Merge pull request #286 from himmelblau-idm/dmulder/krb5
Browse files Browse the repository at this point in the history
Add Kerberos CCache support
  • Loading branch information
dmulder authored Nov 11, 2024
2 parents f91aa91 + b848064 commit d0aff37
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ tracing-subscriber = "^0.3.17"
tracing = "^0.1.37"
himmelblau_unix_common = { path = "src/common" }
kanidm_unix_common = { path = "src/glue" }
libhimmelblau = { version = "0.3.6" }
libhimmelblau = { version = "0.3.8" }
clap = { version = "^4.5", features = ["derive", "env"] }
clap_complete = "^4.4.1"
reqwest = { version = "^0.12.2", features = ["json"] }
Expand Down
3 changes: 1 addition & 2 deletions platform/debian/himmelblaud-tasks.service
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ ExecStart=/usr/sbin/himmelblaud_tasks
CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH
# SystemCallFilter=@aio @basic-io @chown @file-system @io-event @network-io @sync
ProtectSystem=strict
ReadWritePaths=/home /var/run/himmelblaud
ReadWritePaths=/home /var/run/himmelblaud /tmp /etc/krb5.conf.d
RestrictAddressFamilies=AF_UNIX
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=true
ProtectHostname=true
Expand Down
3 changes: 1 addition & 2 deletions platform/opensuse/himmelblaud-tasks.service
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ ExecStart=/usr/sbin/himmelblaud_tasks
CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH
# SystemCallFilter=@aio @basic-io @chown @file-system @io-event @network-io @sync
ProtectSystem=strict
ReadWritePaths=/home /var/run/himmelblaud
ReadWritePaths=/home /var/run/himmelblaud /tmp /etc/krb5.conf.d
RestrictAddressFamilies=AF_UNIX
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=true
ProtectHostname=true
Expand Down
1 change: 1 addition & 0 deletions src/common/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ pub const BROKER_APP_ID: &str = "29d9ed98-a469-4536-ade2-f981bc1d605e";
pub const BROKER_CLIENT_IDENT: &str = "38aa3b87-a06d-4817-b275-7a316988d93b";
pub const CN_NAME_MAPPING: bool = true;
pub const DEFAULT_HELLO_PIN_MIN_LEN: usize = 6;
pub const DEFAULT_CCACHE_DIR: &str = "/tmp/krb5cc_";
60 changes: 60 additions & 0 deletions src/common/src/idprovider/himmelblau.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,33 @@ impl IdProvider for HimmelblauMultiProvider {
}
}

async fn unix_user_ccaches(
&self,
id: &Id,
old_token: Option<&UserToken>,
tpm: &mut tpm::BoxedDynTpm,
machine_key: &tpm::MachineKey,
) -> (Vec<u8>, Vec<u8>) {
let account_id = match old_token {
Some(token) => token.spn.clone(),
None => id.to_string().clone(),
};
match split_username(&account_id) {
Some((_sam, domain)) => {
let providers = self.providers.read().await;
match providers.get(domain) {
Some(provider) => {
provider
.unix_user_ccaches(id, old_token, tpm, machine_key)
.await
}
None => (vec![], vec![]),
}
}
None => (vec![], vec![]),
}
}

async fn unix_user_prt_cookie(
&self,
id: &Id,
Expand Down Expand Up @@ -490,6 +517,39 @@ impl IdProvider for HimmelblauProvider {
})
}

async fn unix_user_ccaches(
&self,
id: &Id,
old_token: Option<&UserToken>,
tpm: &mut tpm::BoxedDynTpm,
machine_key: &tpm::MachineKey,
) -> (Vec<u8>, Vec<u8>) {
let account_id = match old_token {
Some(token) => token.spn.clone(),
None => id.to_string().clone(),
};
let prt = match self.refresh_cache.refresh_token(&account_id).await {
Ok(prt) => prt,
Err(e) => {
error!("Failed fetching PRT for Kerberos CCache: {:?}", e);
return (vec![], vec![]);
}
};
let cloud_ccache = self
.client
.write()
.await
.fetch_cloud_ccache(&prt, tpm, machine_key)
.unwrap_or(vec![]);
let ad_ccache = self
.client
.write()
.await
.fetch_ad_ccache(&prt, tpm, machine_key)
.unwrap_or(vec![]);
(cloud_ccache, ad_ccache)
}

async fn unix_user_prt_cookie(
&self,
id: &Id,
Expand Down
8 changes: 8 additions & 0 deletions src/common/src/idprovider/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ pub trait IdProvider {
_machine_key: &tpm::MachineKey,
) -> Result<UnixUserToken, IdpError>;

async fn unix_user_ccaches(
&self,
_id: &Id,
_old_token: Option<&UserToken>,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
) -> (Vec<u8>, Vec<u8>);

async fn unix_user_prt_cookie(
&self,
_id: &Id,
Expand Down
27 changes: 27 additions & 0 deletions src/common/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

// use async_trait::async_trait;
use hashbrown::HashSet;
use libc::uid_t;
use std::collections::BTreeSet;
use std::fmt::Display;
use std::num::NonZeroUsize;
Expand Down Expand Up @@ -647,6 +648,32 @@ where
}
}

pub async fn get_user_ccaches(&self, account_id: Id) -> Option<(uid_t, Vec<u8>, Vec<u8>)> {
let token = match self.get_usertoken(account_id.clone()).await {
Ok(Some(token)) => token,
_ => {
error!("Failed to fetch unix user token during access token request!");
return None;
}
};

let mut hsm_lock = self.hsm.lock().await;

let (cloud_ccache, ad_ccache) = self
.client
.unix_user_ccaches(
&account_id,
Some(&token),
hsm_lock.deref_mut(),
&self.machine_key,
)
.await;

drop(hsm_lock);

Some((token.gidnumber, cloud_ccache, ad_ccache))
}

pub async fn get_user_prt_cookie(&self, account_id: Id) -> Option<String> {
let token = match self.get_usertoken(account_id.clone()).await {
Ok(Some(token)) => token,
Expand Down
2 changes: 2 additions & 0 deletions src/common/src/unix_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use libc::uid_t;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
Expand Down Expand Up @@ -133,6 +134,7 @@ pub enum TaskRequest {
HomeDirectory(HomeDirectoryInfo),
LocalGroups(String),
LogonScript(String, String),
KerberosCCache(uid_t, Vec<u8>, Vec<u8>),
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
10 changes: 10 additions & 0 deletions src/config/krb5_himmelblau.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[libdefaults]
default_ccache_name = DIR:/tmp/krb5cc_%{uid}
[domain_realm]
.windows.net = KERBEROS.MICROSOFTONLINE.COM
.azure.net = KERBEROS.MICROSOFTONLINE.COM
[realm]
KERBEROS.MICROSOFTONLINE.COM = {
kdc = https://login.microsoftonline.com/common/kerberos
kpasswd_server = https://login.microsoftonline.com/common/kerberos
}
5 changes: 4 additions & 1 deletion src/daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ async-trait = "0.1.83"
name = "himmelblau"
maintainer = "David Mulder <[email protected]>"
depends = ["libssl3", "libsqlite3-0", "libutf8proc3"]
recommends = ["nss-himmelblau", "pam-himmelblau"]
recommends = ["nss-himmelblau", "pam-himmelblau", "krb5-user"]
assets = [
["../../platform/debian/himmelblau.conf.example", "etc/himmelblau/himmelblau.conf", "644"],
["../../src/config/krb5_himmelblau.conf", "etc/krb5.conf.d/", "644"],
["target/release/aad-tool", "usr/bin/", "755"],
["../../platform/debian/himmelblaud-tasks.service", "etc/systemd/system/", "644"],
["../../platform/debian/himmelblaud.service", "etc/systemd/system/", "644"],
Expand All @@ -70,6 +71,7 @@ name = "himmelblau"
maintainer = "David Mulder <[email protected]>"
assets = [
{ source = "../../src/config/himmelblau.conf.example", dest = "/etc/himmelblau/himmelblau.conf", mode = "644" },
{ source = "../../src/config/krb5_himmelblau.conf", dest = "/etc/krb5.conf.d/", mode = "644" },
{ source = "target/release/aad-tool", dest = "/usr/bin/", mode = "755" },
{ source = "../../platform/opensuse/himmelblaud-tasks.service", dest = "/usr/lib/systemd/system/", mode = "644" },
{ source = "../../platform/opensuse/himmelblaud.service", dest = "/usr/lib/systemd/system/", mode = "644" },
Expand All @@ -88,3 +90,4 @@ assets = [
[package.metadata.generate-rpm.recommends]
nss-himmelblau = "*"
pam-himmelblau = "*"
krb5 = "*"
74 changes: 59 additions & 15 deletions src/daemon/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,7 @@ async fn handle_client(
.map(|pam_auth_response| pam_auth_response.into())
.unwrap_or(ClientResponse::Error)
{
ClientResponse::PamAuthenticateStepResponse(resp) => {
macro_rules! ret {
() => {
ClientResponse::PamAuthenticateStepResponse(resp)
};
}
ClientResponse::PamAuthenticateStepResponse(mut resp) => {
match auth_session {
AuthSession::Success(account_id) => {
match resp {
Expand Down Expand Up @@ -381,30 +376,79 @@ async fn handle_client(
Ok(Ok(status)) => {
if status == 2 {
debug!("Authentication was explicitly denied by the logon script");
ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Denied)
} else {
ret!()
resp =
PamAuthResponse::Denied;
}
}
_ => {
error!("Execution of logon script failed");
ret!()
}
}
}
Err(e) => {
error!("Execution of logon script failed: {:?}", e);
ret!()
}
}
} else {
ret!()
}

// Initialize the user Kerberos ccache
if let Some((uid, cloud_ccache, ad_ccache)) =
cachelayer
.get_user_ccaches(Id::Name(
account_id.to_string(),
))
.await
{
let (tx, rx) = oneshot::channel();

match task_channel_tx
.send_timeout(
(
TaskRequest::KerberosCCache(
uid,
cloud_ccache,
ad_ccache,
),
tx,
),
Duration::from_millis(100),
)
.await
{
Ok(()) => {
// Now wait for the other end OR timeout.
match time::timeout_at(
time::Instant::now()
+ Duration::from_secs(60),
rx,
)
.await
{
Ok(Ok(status)) => {
if status != 0 {
error!("Kerberos credential cache load failed for {}: Status code: {}", account_id, status);
}
}
Ok(Err(e)) => {
error!("Kerberos credential cache load failed for {}: {:?}", account_id, e);
}
Err(e) => {
error!("Kerberos credential cache load failed for {}: {:?}", account_id, e);
}
}
}
Err(e) => {
error!("Kerberos credential cache load failed for {}: {:?}", account_id, e);
}
}
}

ClientResponse::PamAuthenticateStepResponse(resp)
}
_ => ret!(),
_ => ClientResponse::PamAuthenticateStepResponse(resp),
}
}
_ => ret!(),
_ => ClientResponse::PamAuthenticateStepResponse(resp),
}
}
other => other,
Expand Down
Loading

0 comments on commit d0aff37

Please sign in to comment.