sreeise / graph-rs-sdk

Microsoft Graph API client writen in Rust
MIT License
100 stars 25 forks source link

WAM Integration - Brokers #431

Open sreeise opened 1 year ago

sreeise commented 1 year ago

Web Account Manager is a Windows 10+ component that is part of the OS. The web account manager enables the use of brokers as a way to do interactive authentication.

https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token-wam

Languages such as C# use Microsoft.Identity.Client.NativeInterop wich is really just using a C API underneath.

Its also not very clear what they are doing underneath in the C API and/or what is called the MSAL runtime that is needed for brokers because it is INTERNAL to Microsoft. Windows is still closed source despite Microsoft's new found commitment to open source. So this one may not be completley feasible.

The windows crate has web account manager, however, having tried to use this before there were issues that are known that may prevent its use. Research should be done to conclude whether the windows crate in Rust can be used to do this.

There is also the possiblity of using IntPtr and the dll method described in the above article. IntPtr I beleive is just a specifc sized int and i32 should work fine? Thats confusing but if not there are IntPtr types available to use from the Rust crate winapi or it may be possible that the windows crate has this as well.

Other references:

C++ example using WAM:

sreeise commented 1 year ago

The only way I know of to do this, since we can't use the runtime that MSAL uses, is to use XAML with Rust. You can see below that whatever MSAL runtime is using as a UI is not going to work with with Rust.

Create a windows uri:

fn w_uri(value: &str) -> Uri {
    Uri::CreateUri(&HSTRING::from(value)).unwrap()
}
use windows::core::HSTRING;
use windows::Security::Authentication::Web::{WebAuthenticationBroker, WebAuthenticationOptions};
use windows::Foundation::Uri;

  let options = WebAuthenticationOptions::None;

  // This is the authorization uri where you log in
  let uri = w_uri(url.as_str());

  // This is the redirect uri. This should be the uri you get from Azure Active Directory
  // and starts with msal
  let redirect_uri = w_uri("msal234253237-7f41-4432b-n434e-132942mn97://auth");

  let auth_operation =
      WebAuthenticationBroker::AuthenticateWithCallbackUriAsync(options, &uri, &redirect_uri).unwrap();

  let auth_status = auth_operation.Status()?;

  if auth_status != windows::Foundation::AsyncStatus::Completed {
      // Handle the error
      return Err(windows::core::Error::from_win32());
  }

  // Get the authentication result
  let auth_result = auth_operation.GetResults()?;
  println!("{:#?}", auth_result);

  // Get the access token from the authentication result
  let access_token = auth_result.ResponseData()?;
  println!("{:#?}", access_token);

results in:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: HRESULT(...), message: "There are no remote procedure calls active on this thread." }