Подтвердить что ты не робот

Использование билетов Oauth через несколько сервисов?

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

4b9b3361

Ответ 1

Второе программное обеспечение сервера авторизации Catalana OAuth2 не предназначалось для этого сценария (главным образом потому, что его зависимость от машинного ключа для проверки токена).

Если вы хотите централизовать генерацию маркера, вам следует изучить сервер авторизации OAuth2, который был разработан для этого. Thinktecture AuthorizationServer - это сервер с открытым исходным кодом, который делает это: http://thinktecture.github.io/Thinktecture.AuthorizationServer/

Ответ 2

После разговора с Броком Алленом в комментариях к исходному сообщению я не могу гарантировать, что это хорошее/безопасное решение, но это код, который я использовал. (Примечание: версия этого кода доступна как пакет nuget.)

Я создал реализацию IDataProtector, которая использует AES:

internal class AesDataProtectorProvider : IDataProtector
{
    // Fields
    private byte[] key;

    // Constructors
    public AesDataProtectorProvider(string key)
    {
        using (var sha1 = new SHA256Managed())
        {
            this.key = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
        }
    }

    // IDataProtector Methods
    public byte[] Protect(byte[] data)
    {
        byte[] dataHash;
        using (var sha = new SHA256Managed())
        {
            dataHash = sha.ComputeHash(data);
        }

        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = this.key;
            aesAlg.GenerateIV();

            using (var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
            using (var msEncrypt = new MemoryStream())
            {
                msEncrypt.Write(aesAlg.IV, 0, 16);

                using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                using (var bwEncrypt = new BinaryWriter(csEncrypt))
                {
                    bwEncrypt.Write(dataHash);
                    bwEncrypt.Write(data.Length);
                    bwEncrypt.Write(data);
                }
                var protectedData = msEncrypt.ToArray();
                return protectedData;
            }
        }
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = this.key;

            using (var msDecrypt = new MemoryStream(protectedData))
            {
                byte[] iv = new byte[16];
                msDecrypt.Read(iv, 0, 16);

                aesAlg.IV = iv;

                using (var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
                using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                using (var brDecrypt = new BinaryReader(csDecrypt))
                {
                    var signature = brDecrypt.ReadBytes(32);
                    var len = brDecrypt.ReadInt32();
                    var data = brDecrypt.ReadBytes(len);

                    byte[] dataHash;
                    using (var sha = new SHA256Managed())
                    {
                        dataHash = sha.ComputeHash(data);
                    }

                    if (!dataHash.SequenceEqual(signature))
                        throw new SecurityException("Signature does not match the computed hash");

                    return data;
                }
            }
        }
    }
}

И затем использовал это в реализации ISecureDataFormat следующим образом:

public class SecureTokenFormatter : ISecureDataFormat<AuthenticationTicket>
{
    // Fields
    private TicketSerializer serializer;
    private IDataProtector protector;
    private ITextEncoder encoder;

    // Constructors
    public SecureTokenFormatter(string key)
    {
        this.serializer = new TicketSerializer();
        this.protector = new AesDataProtectorProvider(key);
        this.encoder = TextEncodings.Base64Url;
    }

    // ISecureDataFormat<AuthenticationTicket> Members
    public string Protect(AuthenticationTicket ticket)
    {
        var ticketData = this.serializer.Serialize(ticket);
        var protectedData = this.protector.Protect(ticketData);
        var protectedString = this.encoder.Encode(protectedData);
        return protectedString;
    }

    public AuthenticationTicket Unprotect(string text)
    {
        var protectedData = this.encoder.Decode(text);
        var ticketData = this.protector.Unprotect(protectedData);
        var ticket = this.serializer.Deserialize(ticketData);
        return ticket;
    }
}

Параметр "ключ" в конструкторе может быть установлен на одно и то же значение для нескольких служб, и все они смогут расшифровать ( "снять защиту" ) и использовать билет.

Ответ 3

Я знаю, что это старый вопрос, но у меня был аналогичный вариант использования. В соответствии с документами OWIN OAuth использует машинный ключ для защиты данных. Поскольку вы контролируете все экземпляры, я полагаю, что просто настройка машинного ключа в веб-конфигурации будет работать.

Ссылка: http://msdn.microsoft.com/en-us/library/microsoft.owin.security.oauth.oauthauthorizationserveroptions(v = vs. 113).aspx

Ответ 4

Вы можете использовать этот пакет nuget https://www.nuget.org/packages/Owin.Security.AesDataProtectorProvider/

Он содержит метод расширения для IAppBuilder, который позволяет вам настроить собственный ключ

appBuilder.UseAesDataProtectorProvider(key);