Задача поставлена, теперь как бы ее так реализовать с использованием того-же NegotiateStream но уже поверх remoting. Сперва наперво должно прийти понимание, что наш NegotiateStream будет работать только с некоторыми стримами: NetworkStream или PipeStream. FileStream, MemoryStream не годятся категорически. Можно еще нагородить что-то свое, но это довольно долго. Сперва напишем интерфейс общения клиента и сервера.
Пусть он будет такой:
public interface IAuthenticationNTLM : IDisposable { Stream Stream { get; } void BeginOperation(); object EndOperation(); }
А протокол по этому интерфейсу пусть будет такой: клиент берет Stream и создает свою копию NegotiateStream затем вызывает BeginOperation и AuthenticateAsClient для своего NegotiateStream а в конце EndOperation и получает объект к которому он так стремился.
using (var negotiateStream = new NegotiateStream(new WriteCopyStream(ntlmAuthentication.Stream))) { ntlmAuthentication.BeginOperation(); negotiateStream.AuthenticateAsClient(credential, "", ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Delegation); obj = ntlmAuthentication.EndOperation(); }
Обратите внимание на некий WriteCopyStream - это класс прокладка, задача которой иззолировать клиентские врутненние классы NegotiateStream от попыток remoting передать их на сторону сервера, что приводит к гарантированному exception.
private sealed class WriteCopyStream : Stream { private readonly Stream myStream; public WriteCopyStream([NotNull] Stream stream) { if (stream == null) throw new ArgumentNullException("stream"); myStream = stream; } public override bool CanRead { get { return myStream.CanRead; } } public override bool CanSeek { get { return myStream.CanSeek; } } public override bool CanWrite { get { return myStream.CanWrite; } } public override long Length { get { return myStream.Length; } } public override long Position { get { return myStream.Position; } set { myStream.Position = value; } } public override void Flush() { myStream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { return myStream.Seek(offset, origin); } public override void SetLength(long value) { myStream.SetLength(value); } public override int Read(byte[] buffer, int offset, int count) { return myStream.Read(buffer, offset, count); } public override void Write(byte[] buffer, int offset, int count) { myStream.Write((byte[]) buffer.Clone(), offset, count); } }
С следующей части расскажу о том как устроен сервер...
No comments:
Post a Comment