Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #70 from himmelblau-idm/dmulder/c_libmsal
Browse files Browse the repository at this point in the history
Add FFI for libmsal and BrokerClientApplication
  • Loading branch information
dmulder authored Jun 3, 2024
2 parents 25d1453 + 6fe530a commit 0312ad6
Show file tree
Hide file tree
Showing 10 changed files with 2,347 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repository = "https://github.com/himmelblau-idm/msal"
[lib]
name = "msal"
path = "src/lib.rs"
crate-type = ["rlib", "cdylib"]

[features]
default = ["broker"]
Expand All @@ -35,3 +36,8 @@ kanidm-hsm-crypto = { version = "^0.2.0", optional = true }
regex = "^1.10.3"
zeroize = { version = "^1.7.0", features = ["zeroize_derive"] }
scraper = "0.19.0"
tokio = { version = "1.37.0", features = ["full"] }
tracing-subscriber = "0.3.18"

[build-dependencies]
cbindgen = "0.26.0"
32 changes: 32 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Unix Azure Entra ID implementation
Copyright (C) David Mulder <[email protected]> 2024
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use std::env;
use std::path::PathBuf;

fn main() {
let profile = env::var("PROFILE").unwrap();
let out_path = match profile.as_str() {
"release" => PathBuf::from("target/release"),
_ => PathBuf::from("target/debug"),
};
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

cbindgen::generate(crate_dir)
.expect("Couldn't write bindings!")
.write_to_file(out_path.join("include/msal.h"));
}
2 changes: 2 additions & 0 deletions cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language = "C"
include_guard = "MSAL_H"
1 change: 1 addition & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a.out
6 changes: 6 additions & 0 deletions example/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
all:
cargo build
gcc -g msal_example.c -I../target/debug/include -L../target/debug -lmsal

run:
LD_LIBRARY_PATH=../target/debug ./a.out
328 changes: 328 additions & 0 deletions example/msal_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
/*
Unix Azure Entra ID implementation
Copyright (C) David Mulder <[email protected]> 2024
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <msal.h>
#include <string.h>
#include <unistd.h>

void strip_newline(char *str) {
int len = strlen(str);
if (str[len-1] == '\n') {
str[len-1] = '\0';
}
}

int main() {
BoxedDynTpm *tpm = NULL;
BrokerClientApplication *client = NULL;
LoadableMachineKey *loadable_machine_key = NULL;
MachineKey *machine_key = NULL;
EnrollAttrs *attrs = NULL;
MFAAuthContinue *flow = NULL;
UserToken *token = NULL;
UserToken *token0 = NULL;
LoadableMsOapxbcRsaKey *transport_key = NULL;
LoadableIdentityKey *cert_key = NULL;
LoadableIdentityKey *hello_key = NULL;
MSAL_ERROR err;
char* auth_value = NULL;
char *domain = NULL;
size_t len;
char *username = NULL;
char *password = NULL;
char *msg = NULL;
char *mfa_method = NULL;
char *device_id = NULL;
char *refresh_token = NULL;
char *access_token = NULL;
char *spn = NULL;
char *uuid = NULL;
bool mfa = false;
bool user_exists;

err = set_global_tracing_level(TRACE);
if (err != SUCCESS) {
printf("Failed setting the tracing level\n");
goto OUT;
}

err = tpm_init(NULL, &tpm);
if (err != SUCCESS) {
printf("Failed to initialize tpm!\n");
goto OUT;
}
auth_value_generate(&auth_value);
printf("auth_value: %s\n", auth_value);

err = tpm_machine_key_create(tpm, auth_value, &loadable_machine_key);
if (err != SUCCESS) {
printf("Failed to create loadable machine key!\n");
goto OUT;
}

err = tpm_machine_key_load(tpm,
auth_value,
loadable_machine_key,
&machine_key);
if (err != SUCCESS) {
printf("Failed to load machine key!\n");
goto OUT;
}

err = broker_init(NULL, NULL, NULL, &client);
if (err != SUCCESS) {
printf("Failed to initialize the broker!\n");
goto OUT;
}

printf("Please enter your EntraID username: ");
getline(&username, &len, stdin);
strip_newline(username);

domain = strchr(username, '@');
if (domain != NULL) {
domain++;
} else {
printf("Failed to find the domain name from the user upn!\n");
goto OUT;
}

err = broker_check_user_exists(client, username, &user_exists);
if (err != SUCCESS) {
printf("Failed to check if the user exists!\n");
goto OUT;
}
if (user_exists) {
printf("User %s exists!\n", username);
} else {
printf("User %s does not exist!\n", username);
goto OUT;
}

password = getpass("Password: ");

err = broker_initiate_acquire_token_by_mfa_flow_for_device_enrollment(client,
username,
password,
&flow);
if (err != SUCCESS) {
printf("Failed to initiate an mfa token acquire!\n");
goto OUT;
}

err = mfa_auth_continue_msg(flow, &msg);
if (err != SUCCESS) {
printf("Failed to fetch MFA auth message!\n");
goto OUT;
}
printf("%s", msg);
fflush(stdout);

err = mfa_auth_continue_mfa_method(flow, &mfa_method);
if (err != SUCCESS) {
printf("Failed to fetch MFA method!\n");
goto OUT;
}
if (strcmp(mfa_method, "PhoneAppOTP") == 0
|| strcmp(mfa_method, "OneWaySMS") == 0
|| strcmp(mfa_method, "ConsolidatedTelephony") == 0) {
char *otp = getpass("");
err = broker_acquire_token_by_mfa_flow(client,
username,
otp,
0,
flow,
&token);
if (err != SUCCESS) {
printf("Failed to authenticate with otp!\n");
goto OUT;
}
} else {
printf("\n");
int polling_interval = mfa_auth_continue_polling_interval(flow);
int max_poll_attempts = mfa_auth_continue_max_poll_attempts(flow);
for (int i = 0; i < max_poll_attempts; i++) {
err = broker_acquire_token_by_mfa_flow(client,
username,
NULL,
i,
flow,
&token);
if (err == MFA_POLL_CONTINUE) {
sleep(polling_interval/1000);
} else if (err == SUCCESS) {
break;
} else {
printf("Failed to authenticate when polling!\n");
goto OUT;
}
}
}
printf("Authentication was successful!\n");

err = enroll_attrs_init(domain,
"msal_example_c",
NULL,
0,
NULL,
&attrs);
if (err != SUCCESS) {
printf("Failed to create enrollment attributes!\n");
goto OUT;
}

err = broker_enroll_device(client,
token,
attrs,
tpm,
machine_key,
&transport_key,
&cert_key,
&device_id);
if (err != SUCCESS) {
printf("Failed to enroll the device!\n");
goto OUT;
}
printf("Enrolled with device id: %s\n", device_id);

printf("Obtain PRT from enrollment refresh token\n");
err = user_token_refresh_token(token, &refresh_token);
if (err != SUCCESS) {
printf("Failed fetching refresh token\n");
goto OUT;
}
err = broker_acquire_token_by_refresh_token(client,
refresh_token,
NULL,
0,
NULL,
tpm,
machine_key,
&token0);
if (err != SUCCESS) {
printf("Failed to acquire token by refresh token\n");
goto OUT;
}

err = user_token_access_token(token0, &access_token);
if (err != SUCCESS) {
printf("Failed fetching access token\n");
goto OUT;
}
err = user_token_spn(token0, &spn);
if (err != SUCCESS) {
printf("Failed fetching token spn\n");
goto OUT;
}
err = user_token_uuid(token0, &uuid);
if (err != SUCCESS) {
printf("Failed fetching token uuid\n");
goto OUT;
}
err = user_token_amr_mfa(token0, &mfa);
if (err != SUCCESS) {
printf("Failed fetching token amr_mfa\n");
goto OUT;
}
printf("access_token: %s, spn: %s, uuid: %s, mfa?: %d\n",
access_token,
spn,
uuid,
mfa);

printf("Provision hello key");
err = broker_provision_hello_for_business_key(client,
token,
tpm,
machine_key,
"123456",
&hello_key);
if (err != SUCCESS) {
printf("Failed to provision a hello key!\n");
goto OUT;
}

printf("Acquire token via hello key\n");

user_token_free(token0);
err = broker_acquire_token_by_hello_for_business_key(client,
username,
hello_key,
NULL,
0,
NULL,
tpm,
machine_key,
"123456",
&token0);
if (err != SUCCESS) {
printf("Failed to aquire a token using the provisioned hello key!\n");
goto OUT;
}

string_free(access_token);
err = user_token_access_token(token0, &access_token);
if (err != SUCCESS) {
printf("Failed fetching access token\n");
goto OUT;
}
string_free(spn);
err = user_token_spn(token0, &spn);
if (err != SUCCESS) {
printf("Failed fetching token spn\n");
goto OUT;
}
string_free(uuid);
err = user_token_uuid(token0, &uuid);
if (err != SUCCESS) {
printf("Failed fetching token uuid\n");
goto OUT;
}
err = user_token_amr_mfa(token0, &mfa);
if (err != SUCCESS) {
printf("Failed fetching token amr_mfa\n");
goto OUT;
}
printf("access_token: %s, spn: %s, uuid: %s, mfa?: %d\n",
access_token,
spn,
uuid,
mfa);

OUT:
user_token_free(token);
user_token_free(token0);
mfa_auth_continue_free(flow);
string_free(auth_value);
loadable_machine_key_free(loadable_machine_key);
machine_key_free(machine_key);
broker_free(client);
tpm_free(tpm);
free(username);
string_free(msg);
string_free(mfa_method);
string_free(device_id);
loadable_ms_oapxbc_rsa_key_free(transport_key);
loadable_identity_key_free(cert_key);
loadable_identity_key_free(hello_key);
string_free(refresh_token);
string_free(access_token);
string_free(spn);
string_free(uuid);
}
Loading

0 comments on commit 0312ad6

Please sign in to comment.