Does Phoenix platform support Windows authentication?

Our web applications are currently in C #, running on Windows and IIS. We rely heavily on the Windows authentication scheme that is included in this environment. With Windows authentication turned on, we can determine the identity of the connected user and authorize on which screens and functions that they can use.

If I configure the Phoenix web application, will it be possible to determine the identity of the connected user based on their current Windows login? If there is no easy to use replacement for Windows authentication?

+4
source share
1 answer

I just did it on the weekend. Yes it is possible. You must use the HttpPlatformHandler add- on for IIS in order for it to work. The HttpPlatformHandler has a configuration parameter forwardWindowsAuthTokenthat you can use to forward the Windows user token for the authenticated user from IIS to your Phoenix application, which runs as a child process. You must use NIF to process the token and obtain the Windows username or SID. As you noted in the docs, you need to call CloseHandle to issue a Windows user token for each request.

( , . Elixir . , -, .)

, , ( Logger ):

defmodule MyApp.WindowsAuthentication do
  import Plug.Conn

  require Logger

  @on_load :load_nifs

  def load_nifs do
    if match? {:win32, _}, :os.type do
      :erlang.load_nif("./priv/windows_authentication", 0)
    else
      :ok
    end
  end

  def init(options), do: options

  def call(conn, _options) do
    if match? {:win32, _}, :os.type do
      case get_req_header(conn, "x-iis-windowsauthtoken") do
        [token_handle_string] ->
          # token_handle_string is a hex string
          token_handle = String.to_integer(token_handle_string, 16)
          case do_get_windows_username(token_handle) do
            {:ok, {domain_name, username}} ->
              conn = assign(conn, :windows_user, {domain_name, username})
            error ->
              Logger.error IO.inspect(error)
          end

          do_close_handle(token_handle)
        [] ->
          Logger.debug "X-IIS-WindowsAuthToken was not present"
      end
    end

    conn
  end

  def do_get_windows_username(_token_handle) do
    raise "do_get_windows_username/1 is only available on Windows"
  end

  def do_close_handle(_handle) do
    raise "do_close_handle/1 is only available on Windows"
  end
end

C NIF :

#include <Windows.h>
#include <erl_nif.h>

static const char* error_atom = "error";
static const char* invalid_token_handle_atom = "invalid_token_handle";
static const char* ok_atom = "ok";
static const char* win32_error_atom = "win32_error";

#define MAX_NAME 256

static HANDLE get_user_token(ErlNifEnv *env, ERL_NIF_TERM token) {
  HANDLE token_handle;

  if (!enif_get_ulong(env, token, (unsigned long *)&token_handle)) {
    return NULL;
  }

  return token_handle;
}

static ERL_NIF_TERM make_win32_error_tuple(ErlNifEnv* env, DWORD error_code) {
  return enif_make_tuple2(
    env,
    enif_make_atom(env, error_atom),
    enif_make_ulong(env, error_code)
  );
}

static ERL_NIF_TERM make_invalid_token_handle_error(ErlNifEnv* env) {
  return enif_make_tuple2(
    env,
    enif_make_atom(env, error_atom),
    enif_make_atom(env, invalid_token_handle_atom)
  );
}

static ERL_NIF_TERM do_get_windows_username(ErlNifEnv* env, int argc, ERL_NIF_TERM argv[]) {
  HANDLE token_handle;
  DWORD token_user_length;
  PTOKEN_USER token_user;
  DWORD last_error;
  WCHAR username[MAX_NAME];
  DWORD username_length = MAX_NAME;
  WCHAR domain_name[MAX_NAME];
  DWORD domain_name_length = MAX_NAME;
  size_t converted_chars;
  char converted_username[MAX_NAME * 2];
  char converted_domain_name[MAX_NAME * 2];
  errno_t err;
  BOOL succeeded;
  SID_NAME_USE sid_name_use;

  token_handle = get_user_token(env, argv[0]);
  if (!token_handle) {
    return make_invalid_token_handle_error(env);
  }

  if (!GetTokenInformation(token_handle, TokenUser, NULL, 0, &token_user_length)) {
    last_error = GetLastError();
    if (ERROR_INSUFFICIENT_BUFFER != last_error) {
      return make_win32_error_tuple(env, last_error);
    }
  }

  token_user = (PTOKEN_USER)malloc(token_user_length);
  if (!GetTokenInformation(token_handle, TokenUser, token_user, token_user_length, &token_user_length)) {
    free(token_user);
    return make_win32_error_tuple(env, GetLastError());
  }

  succeeded = LookupAccountSidW(
    NULL,
    token_user->User.Sid,
    username,
    &username_length,
    domain_name,
    &domain_name_length,
    &sid_name_use);
  if (!succeeded) {
    free(token_user);
    return make_win32_error_tuple(env, GetLastError());
  }

  err = wcstombs_s(&converted_chars, converted_username, 512, username, username_length);
  err = wcstombs_s(&converted_chars, converted_domain_name, 512, domain_name, domain_name_length);

  free(token_user);
  return enif_make_tuple2(
    env,
    enif_make_atom(env, ok_atom),
    enif_make_tuple2(
      env,
      enif_make_string(env, converted_domain_name, ERL_NIF_LATIN1),
      enif_make_string(env, converted_username, ERL_NIF_LATIN1)
    )
  );
}

static ERL_NIF_TERM do_close_handle(ErlNifEnv* env, int argc, ERL_NIF_TERM argv[]) {
  HANDLE token_handle;

  token_handle = get_user_token(env, argv[0]);
  if (!token_handle) {
    return make_invalid_token_handle_error(env);
  }

  if (!CloseHandle(token_handle)) {
    return make_win32_error_tuple(env, GetLastError());
  }

  return enif_make_atom(env, ok_atom);
}

static ErlNifFunc nif_functions[] = {
  { "do_close_handle", 1, do_close_handle },
  { "do_get_windows_username", 1, do_get_windows_username }
};

ERL_NIF_INIT(
  Elixir.MyApp.WindowsAuthentication,
  nif_functions,
  NULL,
  NULL,
  NULL,
  NULL
)

C 64- Visual Studio ++ ( x64 VS). VS2017. DLL priv .

cl /LD /I "C:\Program Files\erl-8.2\erts-8.2\include" /DDEBUG windows_authentication.c advapi32.lib

, web/router.ex:

pipeline :browser do
  plug :accepts, ["html"]
  plug MyApp.WindowsAuthentication
  plug :fetch_session
  plug :fetch_flash
  plug :protect_from_forgery
  plug :put_secure_browser_headers
end

, conn.assigns.windows_user {domain_name, username}, Windows .

. , erl.exe IIS. , . .

, , hex.pm, /, , Windows Phoenix.

+1

Source: https://habr.com/ru/post/1610448/


All Articles