Задача поставлена, теперь как бы ее так реализовать с использованием того-же 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