Виджет JavaScript с доверительной аутентификацией в активном каталоге - PullRequest
2 голосов
/ 30 сентября 2011

Я строю новый проект, и у меня есть некоторые споры о том, как его нужно развивать.Основная задача заключается в разработке потребляемого виджета JavaScript, который другие внутренние разработчики могут встроить в свои веб-приложения.Хитрость заключается в том, что потребитель должен иметь возможность сообщить мне, какой пользователь AD в данный момент зарегистрирован на своей странице ... и затем мне нужно верить, что переданное имя пользователя исходит от потребителя и не было подделано из внешних источников..

Общее решение должно иметь ОЧЕНЬ простую настройку на стороне потребителя, не требующую изменений скомпилированного кода.Кроме того, он должен быть функциональным как в приложениях ASP.net, так и в приложениях PHP (поэтому я решил использовать JavaScript).

В целом это похоже на решение Oauth ... за исключением того, что доверие между доменами может быть внутреннимтак как я уже знаю, что каждый пользователь в компании доверяет домену хоста.

Я начал гасить его и застрял.Моя идея заключалась в том, что я бы в основном разместил файл JavaScript, который клиентский хост мог бы встроить в свою страницу.Во время цикла загрузки страницы они могли запустить мой виджет JavaScript и передать его в виде простого текстового имени пользователя (все, что мне действительно нужно).Каким-то образом я бы установил безопасное доверие между веб-страницей хоста клиента и моим виджетом, чтобы сторонние разработчики не могли встроить мой виджет в ложную веб-страницу и отправлять команды действий под пользователем, отличным от его собственного.

Надеюсь, это имеет смысл для кого-то.

1 Ответ

1 голос
/ 04 ноября 2011

Я так и не нашел ответ, так сказать, но я выбрал метод:

Итак, я выбрал шаблон, в котором я пишу свой виджет JavaScript и HTML, используя предложенную jQuery UI Widget Factory . Это позволяет моему потребителю реализовать виджет, используя простой синтаксис, такой как:

<script src="widget.js"></script>
$('#someElement').myWidget({ encryptionUrl: handlerPath }); 

Теперь вы заметили, что как часть моего виджета я прошу потребителя передать "handlerPath". «Обработчик» - это просто контроллер Microsoft MVC, который отвечает за получение авторизованного пользователя и шифрование вызова.

Итак, обработчик в моем приложении выглядит примерно так ...

[Authorize]
public JsonpResult GetToken(string body, string title, string sender)
{
    Packet token = new Packet();
    try
    {
       // Get the widget host's public cert
       string publicKey = "some.ssl.key.name.here";
       // Get the consumer host's private cert
       string privateKey = "this.consumers.ssl.key.name.here";

       // Build a simple message object containing secure details
       // Specifically, the Body will have action items (in JSON) from my widget
       // The User will be generated from the consumer's backend, thus secure 
       Message message = new Message(){
        Body = body,
        Title = title,
        User = System.Web.HttpContext.Current.User.Identity.Name,
        EncryptionServerIP = Request.UserHostAddress,
        Sender = new Uri(sender),
        EncryptionTime = DateTime.Now
       };

       PacketEncryption encryption = new PacketEncryption();
       // This class just wraps basic encryption and signing methods
       token = encryption.EncryptAndSign(message, publicKey, privateKey);
       token.Trust = "thisConsumerTrustName";
    }
       catch (Exception exception)
    {
       throw;
    }

   return this.Jsonp(token);
}

Теперь у меня есть зашифрованный «токен», который был зашифрован с использованием открытого ключа хоста виджета и подписан с использованием личного ключа потребителя виджета. Этот «токен» передается обратно в виджет через JSONP с сервера-потребителя.

Мой виджет затем отправляет этот «токен» (все еще как JSONP) на свой хост-сервер. Сервер размещения виджетов имеет расшифровывающую логику, которая выглядит примерно так:

public Message DecryptAndVerify(Packet packet, string requestIP)
{
    if (packet == null) throw new ArgumentNullException("packet");
    if (requestIP == null) throw new ArgumentNullException("requestIP");

    Message message = new Message();

    try
    {
        // Decrypt using the widget host's private key
        RSAEncryption decrypto = new RSAEncryption("MyPrivateKey");
        // Verify the signature using the "trust's" public key
        // This is important because like you'll notice, I get the trust name
        // from the encrypted packet. I then maintain a "trust store" mapping 
        // in my web.config, or SQL server
        RSAEncryption verifyo = new RSAEncryption(GetPublicKeyFromTrust(packet.Trust));

        string decryptedJson = decrypto.DecryptString(packet.EncryptedData);

        // Verify the signature
        if (!verifyo.Verify(decryptedJson, packet.Signature))
        {
        Exception ex = new Exception("Secure packet was not verified. Tamper evident");
        throw ex;
        }

        // If the message is encrypted correctly, turn it into a message object
        message = decryptedJson.FromJson<Message>();

        // Verify the ip
        if (message.EncryptionServerIP != requestIP)
        {
        Exception ex = new Exception("Request IP does not match encryption IP. Tamper evident");
        throw ex;
        }

        // Verify the time
        if ((DateTime.Now - message.EncryptionTime).Seconds > 30)
        {
        Exception ex = new Exception("Secure packet is too old");
        throw ex;
        }

    }
    catch (Exception ex)
        {
            throw ex;
        }
    return message;
}

Идея состоит в том, что виджет JavaScript определяет безопасные действия, которые хочет выполнить конечный пользователь. Затем он перезванивает своему хосту (используя путь обработчика, предоставленный потребителем) и запрашивает зашифрованный токен. Этот токен содержит IP-адрес абонента, временную метку, текущее имя пользователя AD и набор действий, которые необходимо выполнить. Как только виджет получает токен, он передает его на свой хост-сервер, после чего сервер проверяет, является ли он

  • Подписано и зашифровано надлежащим образом в соответствии с предопределенными довериями
  • Не старше 30 секунд
  • С того же IP-адреса, что и первоначальный запрос к серверу потребителя

После того, как я определю, что эти проверки являются действительными, я могу воздействовать на действия пользователя, создавая идентификатор WindowsPrincipal из строкового имени пользователя следующим образом:

WindowsPrincipal pFoo = new WindowsPrincipal(new WindowsIdentity("username"));
bool test = pFoo.IsInRole("some role");

Все сказано и сделано, я установил доверенный запрос от потребителя виджета, и мне больше не нужно запрашивать аутентификацию.

Надеюсь, это поможет вам. Он работает в моей внутренней среде в течение месяца для обеспечения качества и пока работает отлично.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...