Skip to content

Commit

Permalink
Implement Hello Pin changes via PAM
Browse files Browse the repository at this point in the history
This implements Pin changes via pam (a user will
call the terminal `passwd` command). This will
require more interaction than a typical call to
`passwd`, since we need to authenticate to Entra
Id to register the new Pin. This extra
authentication step forces the token to have an
ngcmfa amr.

Signed-off-by: David Mulder <[email protected]>
  • Loading branch information
dmulder committed Dec 10, 2024
1 parent 0eece87 commit d1e073c
Show file tree
Hide file tree
Showing 18 changed files with 518 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,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.4.2" }
libhimmelblau = { version = "0.4.4" }
clap = { version = "^4.5", features = ["derive", "env"] }
clap_complete = "^4.4.1"
reqwest = { version = "^0.12.2", features = ["json"] }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ sudo zypper ref && sudo zypper in himmelblau nss-himmelblau pam-himmelblau

The following packages are required on openSUSE to build and test this package.

sudo zypper in make cargo git gcc sqlite3-devel libopenssl-3-devel pam-devel libcap-devel libtalloc-devel libtevent-devel libldb-devel libdhash-devel krb5-devel pcre2-devel libclang13 autoconf make automake gettext-tools clang dbus-1-devel utf8proc-devel
sudo zypper in make cargo git gcc sqlite3-devel libopenssl-3-devel pam-devel libcap-devel libtalloc-devel libtevent-devel libldb-devel libdhash-devel krb5-devel pcre2-devel libclang13 autoconf make automake gettext-tools clang dbus-1-devel utf8proc-devel gobject-introspection-devel cairo-devel gdk-pixbuf-devel libsoup-devel pango-devel atk-devel gtk3-devel webkit2gtk3-devel


Or on Debian based systems:
Expand Down
11 changes: 9 additions & 2 deletions images/rpm/Dockerfile.fedora41
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ RUN dnf -y update && \
gettext \
sqlite-devel \
utf8proc-devel \
cargo && \
cargo \
gobject-introspection-devel \
cairo-devel \
libsoup-devel \
pango-devel \
atk-devel \
gtk3-devel \
webkit2gtk3-devel && \
dnf clean all

# Set environment for Rust
Expand All @@ -37,4 +44,4 @@ WORKDIR /himmelblau
RUN cargo install cargo-generate-rpm

# Build the project and create the RPM package
CMD cargo clean && cargo build --release && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
CMD cargo clean && cargo build --release --features interactive && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
11 changes: 9 additions & 2 deletions images/rpm/Dockerfile.rawhide
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ RUN dnf -y update && \
gettext \
sqlite-devel \
utf8proc-devel \
cargo && \
cargo \
gobject-introspection-devel \
cairo-devel \
libsoup-devel \
pango-devel \
atk-devel \
gtk3-devel \
webkit2gtk3-devel && \
dnf clean all

# Set environment for Rust
Expand All @@ -37,4 +44,4 @@ WORKDIR /himmelblau
RUN cargo install cargo-generate-rpm

# Build the project and create the RPM package
CMD cargo clean && cargo build --release && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
CMD cargo clean && cargo build --release --features interactive && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
10 changes: 9 additions & 1 deletion images/rpm/Dockerfile.rocky9
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ RUN yum update -y && yum install -y \
gettext \
sqlite-devel \
utf8proc-devel \
gobject-introspection-devel \
cairo-devel \
gdk-pixbuf-devel \
libsoup-devel \
pango-devel \
atk-devel \
gtk3-devel \
webkit2gtk3-devel \
&& yum clean all

# Install Rust (latest stable)
Expand All @@ -45,4 +53,4 @@ WORKDIR /himmelblau
RUN cargo install cargo-generate-rpm

# Build the project and create the .deb package
CMD cargo clean && cargo build --release && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
CMD cargo clean && cargo build --release --features interactive && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
10 changes: 9 additions & 1 deletion images/rpm/Dockerfile.tumbleweed
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ RUN zypper --non-interactive refresh && zypper --non-interactive update && \
sqlite3-devel \
utf8proc-devel \
cargo \
gobject-introspection-devel \
cairo-devel \
gdk-pixbuf-devel \
libsoup-devel \
pango-devel \
atk-devel \
gtk3-devel \
webkit2gtk3-devel \
&& zypper clean --all

# Set environment for Rust
Expand All @@ -38,4 +46,4 @@ WORKDIR /himmelblau
RUN cargo install cargo-generate-rpm

# Build the project and create the RPM package
CMD cargo clean && cargo build --release && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
CMD cargo clean && cargo build --release --features interactive && strip -s target/release/*.so && strip -s target/release/aad-tool && strip -s target/release/himmelblaud && strip -s target/release/himmelblaud_tasks && strip -s target/release/broker && cargo generate-rpm -p src/daemon && cargo generate-rpm -p src/nss && cargo generate-rpm -p src/pam && cargo generate-rpm -p src/sshd-config && cargo generate-rpm -p src/sso
9 changes: 9 additions & 0 deletions images/ubuntu/Dockerfile.22.04
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ RUN apt-get update && apt-get install -y \
cargo \
libsqlite3-dev \
libutf8proc-dev \
libgirepository1.0-dev \
libcairo2-dev \
libgdk-pixbuf2.0-dev \
libsoup-3.0-dev \
libpango1.0-dev \
libatk1.0-dev \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
libjavascriptcoregtk-4.1-dev \
&& rm -rf /var/lib/apt/lists/*

# Install Rust (latest stable)
Expand Down
8 changes: 8 additions & 0 deletions images/ubuntu/Dockerfile.24.04
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ RUN apt-get update && apt-get install -y \
cargo \
libsqlite3-dev \
libutf8proc-dev \
libgirepository1.0-dev \
libcairo2-dev \
libgdk-pixbuf2.0-dev \
libsoup-3.0-dev \
libpango1.0-dev \
libatk1.0-dev \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
&& rm -rf /var/lib/apt/lists/*

# Install Rust (latest stable)
Expand Down
80 changes: 80 additions & 0 deletions src/common/src/idprovider/himmelblau.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,38 @@ impl IdProvider for HimmelblauMultiProvider {
}
}

async fn change_auth_token<D: KeyStoreTxn + Send>(
&self,
account_id: &str,
token: &UnixUserToken,
new_tok: &str,
keystore: &mut D,
tpm: &mut tpm::BoxedDynTpm,
machine_key: &tpm::MachineKey,
) -> Result<bool, IdpError> {
match split_username(account_id) {
Some((_sam, domain)) => {
let providers = self.providers.read().await;
match providers.get(domain) {
Some(provider) => {
provider
.change_auth_token(
account_id,
token,
new_tok,
keystore,
tpm,
machine_key,
)
.await
}
None => Err(IdpError::NotFound),
}
}
None => Err(IdpError::NotFound),
}
}

async fn unix_user_get(
&self,
id: &Id,
Expand Down Expand Up @@ -575,6 +607,54 @@ impl IdProvider for HimmelblauProvider {
})
}

async fn change_auth_token<D: KeyStoreTxn + Send>(
&self,
account_id: &str,
token: &UnixUserToken,
new_tok: &str,
keystore: &mut D,
tpm: &mut tpm::BoxedDynTpm,
machine_key: &tpm::MachineKey,
) -> Result<bool, IdpError> {
let hello_tag = self.fetch_hello_key_tag(account_id);

// Ensure the user is setting the token for the account it has authenticated to
if account_id.to_string().to_lowercase()
!= token
.spn()
.map_err(|e| {
error!("Failed checking the spn on the user token: {:?}", e);
IdpError::BadRequest
})?
.to_lowercase()
{
error!("A hello key may only be set by the authenticated user!");
return Err(IdpError::BadRequest);
}

// Set the hello pin
let hello_key = match self
.client
.write()
.await
.provision_hello_for_business_key(token, tpm, machine_key, new_tok)
.await
{
Ok(hello_key) => hello_key,
Err(e) => {
error!("Failed to provision hello key: {:?}", e);
return Ok(false);
}
};
keystore
.insert_tagged_hsm_key(&hello_tag, &hello_key)
.map_err(|e| {
error!("Failed to provision hello key: {:?}", e);
IdpError::Tpm
})?;
Ok(true)
}

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

async fn change_auth_token<D: KeyStoreTxn + Send>(
&self,
_account_id: &str,
_token: &UnixUserToken,
_new_tok: &str,
_keystore: &mut D,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
) -> Result<bool, IdpError>;

async fn unix_user_online_auth_init<D: KeyStoreTxn + Send>(
&self,
_account_id: &str,
Expand Down
29 changes: 29 additions & 0 deletions src/common/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,35 @@ where
}
}

pub async fn change_auth_token(
&self,
account_id: &str,
token: &UnixUserToken,
new_tok: &str,
) -> Result<bool, ()> {
let mut hsm_lock = self.hsm.lock().await;
let mut dbtxn = self.db.write().await;

let res = self
.client
.change_auth_token(
account_id,
token,
new_tok,
&mut dbtxn,
hsm_lock.deref_mut(),
&self.machine_key,
)
.await;

drop(hsm_lock);
dbtxn.commit().map_err(|_| ())?;

res.map_err(|e| {
debug!("change_auth_token error -> {:?}", e);
})
}

pub async fn get_usertoken(&self, account_id: Id) -> Result<Option<UserToken>, ()> {
debug!("get_usertoken");
// get the item from the cache
Expand Down
4 changes: 4 additions & 0 deletions src/common/src/unix_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pub enum ClientRequest {
PamAuthenticateStep(PamAuthRequest),
PamAccountAllowed(String),
PamAccountBeginSession(String),
PamChangeAuthToken(String, String, String, String),
InvalidateCache,
ClearCache,
Status,
Expand All @@ -95,6 +96,9 @@ impl ClientRequest {
format!("PamAccountAllowed({})", id)
}
ClientRequest::PamAccountBeginSession(_) => "PamAccountBeginSession".to_string(),
ClientRequest::PamChangeAuthToken(id, _, _, _) => {
format!("PamChangeAuthToken({}, ...)", id)
}
ClientRequest::InvalidateCache => "InvalidateCache".to_string(),
ClientRequest::ClearCache => "ClearCache".to_string(),
ClientRequest::Status => "Status".to_string(),
Expand Down
1 change: 1 addition & 0 deletions src/daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ kanidm_lib_file_permissions.workspace = true
identity_dbus_broker.workspace = true
base64.workspace = true
async-trait = "0.1.83"
libhimmelblau.workspace = true

[package.metadata.deb]
name = "himmelblau"
Expand Down
20 changes: 20 additions & 0 deletions src/daemon/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use std::time::Duration;
use bytes::{BufMut, BytesMut};
use clap::{Arg, ArgAction, Command};
use futures::{SinkExt, StreamExt};
use himmelblau::{ClientInfo, IdToken, UserToken as UnixUserToken};
use himmelblau_unix_common::config::HimmelblauConfig;
use himmelblau_unix_common::constants::DEFAULT_CONFIG_PATH;
use himmelblau_unix_common::db::{Cache, CacheTxn, Db};
Expand Down Expand Up @@ -549,6 +550,25 @@ async fn handle_client(
_ => ClientResponse::Error,
}
}
ClientRequest::PamChangeAuthToken(account_id, access_token, refresh_token, new_pin) => {
debug!("sm_chauthtok req");
let token = UnixUserToken {
token_type: "Bearer".to_string(),
scope: None,
expires_in: 0,
ext_expires_in: 0,
access_token: Some(access_token),
refresh_token,
id_token: IdToken::default(),
client_info: ClientInfo::default(),
prt: None,
};
cachelayer
.change_auth_token(&account_id, &token, &new_pin)
.await
.map(|_| ClientResponse::Ok)
.unwrap_or(ClientResponse::Error)
}
ClientRequest::InvalidateCache => {
debug!("invalidate cache");
cachelayer
Expand Down
6 changes: 6 additions & 0 deletions src/pam/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ repository.workspace = true
name = "pam_himmelblau"
crate-type = [ "cdylib" ]

[features]
interactive = ["libhimmelblau/interactive"]

[dependencies]
libc = { workspace = true }
kanidm_unix_common = { workspace = true }
tracing-subscriber = { workspace = true }
tracing = { workspace = true }
himmelblau_unix_common.workspace = true
tokio.workspace = true
libhimmelblau.workspace = true

[build-dependencies]
pkg-config.workspace = true
Expand All @@ -34,6 +39,7 @@ assets = [
["../../platform/debian/apparmor.unix-chkpwd.local", "etc/apparmor.d/local/unix-chkpwd", "644"],
]
maintainer-scripts = "../../platform/debian/scripts"
features = ["interactive"]

[package.metadata.generate-rpm]
name = "pam-himmelblau"
Expand Down
3 changes: 3 additions & 0 deletions src/pam/src/pam/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub const _PAM_DELETE_CRED: PamFlag = 0x0004;
pub const _PAM_REINITIALIZE_CRED: PamFlag = 0x0008;
pub const _PAM_REFRESH_CRED: PamFlag = 0x0010;
pub const _PAM_CHANGE_EXPIRED_AUTHTOK: PamFlag = 0x0020;
// see /usr/include/security/pam_modules.h
pub const PAM_PRELIM_CHECK: PamFlag = 0x4000;
pub const PAM_UPDATE_AUTHTOK: PamFlag = 0x2000;

// The Linux-PAM item types
// see /usr/include/security/_pam_types.h
Expand Down
Loading

0 comments on commit d1e073c

Please sign in to comment.