Skip to content

Commit 5a97b59

Browse files
authored
Merge pull request #31 from docker/add-user-identity
Add user identity in Owin context - merging with authority :)
2 parents 27bfa36 + 9668568 commit 5a97b59

File tree

5 files changed

+54
-5
lines changed

5 files changed

+54
-5
lines changed

src/HttpOverStream.NamedPipe/NamedPipeDialer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.IO;
33
using System.IO.Pipes;
44
using System.Net.Http;
5+
using System.Security.Principal;
56
using System.Threading;
67
using System.Threading.Tasks;
78

@@ -13,6 +14,7 @@ public class NamedPipeDialer : IDial
1314
private readonly string _serverName;
1415
private readonly PipeOptions _pipeOptions;
1516
private readonly int _timeoutMs;
17+
private readonly TokenImpersonationLevel _impersonationLevel;
1618

1719
public NamedPipeDialer(string pipeName)
1820
: this(pipeName, ".", PipeOptions.Asynchronous, 0)
@@ -24,17 +26,18 @@ public NamedPipeDialer(string pipeName, int timeoutMs)
2426
{
2527
}
2628

27-
public NamedPipeDialer(string pipeName, string serverName, PipeOptions pipeOptions, int timeoutMs)
29+
public NamedPipeDialer(string pipeName, string serverName, PipeOptions pipeOptions, int timeoutMs, TokenImpersonationLevel impersonationLevel = TokenImpersonationLevel.Identification)
2830
{
2931
_pipeName = pipeName;
3032
_serverName = serverName;
3133
_pipeOptions = pipeOptions;
3234
_timeoutMs = timeoutMs;
35+
_impersonationLevel = impersonationLevel;
3336
}
3437

3538
public async ValueTask<Stream> DialAsync(HttpRequestMessage request, CancellationToken cancellationToken)
3639
{
37-
var pipeStream = new NamedPipeClientStream(_serverName, _pipeName, PipeDirection.InOut, _pipeOptions);
40+
var pipeStream = new NamedPipeClientStream(_serverName, _pipeName, PipeDirection.InOut, _pipeOptions, _impersonationLevel);
3841
await pipeStream.ConnectAsync(_timeoutMs, cancellationToken).ConfigureAwait(false);
3942
if (cancellationToken.CanBeCanceled)
4043
{

src/HttpOverStream.NamedPipe/NamedPipeHttpClientBuilder.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Net.Http;
3+
using System.Security.Principal;
34
using HttpOverStream.Client;
45
using HttpOverStream.Logging;
56

@@ -13,6 +14,7 @@ public class NamedPipeHttpClientBuilder
1314
private TimeSpan? _perRequestTimeout;
1415
private Version _httpVersion;
1516
private TimeSpan? _namedPipeConnectionTimeout;
17+
private TokenImpersonationLevel _impersonationLevel = TokenImpersonationLevel.Identification;
1618

1719
public NamedPipeHttpClientBuilder(string pipeName)
1820
{
@@ -49,11 +51,21 @@ public NamedPipeHttpClientBuilder WithNamedPipeConnectionTimeout(TimeSpan timeSp
4951
return this;
5052
}
5153

54+
public NamedPipeHttpClientBuilder WithImpersonationLevel(TokenImpersonationLevel impersonationLevel)
55+
{
56+
_impersonationLevel = impersonationLevel;
57+
return this;
58+
}
59+
5260
public HttpClient Build()
5361
{
54-
var dialer = _namedPipeConnectionTimeout == null
55-
? new NamedPipeDialer(_pipeName)
56-
: new NamedPipeDialer(_pipeName, (int)_namedPipeConnectionTimeout.Value.TotalMilliseconds);
62+
var connectionTimeout = 0;
63+
if (_namedPipeConnectionTimeout.HasValue)
64+
{
65+
connectionTimeout = (int)_namedPipeConnectionTimeout.Value.TotalMilliseconds;
66+
}
67+
68+
var dialer = new NamedPipeDialer(_pipeName, ".", System.IO.Pipes.PipeOptions.Asynchronous, connectionTimeout, _impersonationLevel);
5769

5870
var innerHandler = new DialMessageHandler(dialer, _logger, _httpVersion);
5971
HttpClient httpClient;

src/HttpOverStream.NamedPipe/NamedPipeListener.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.IO;
55
using System.IO.Pipes;
66
using System.Linq;
7+
using System.Security.Principal;
78
using System.Threading;
89
using System.Threading.Tasks;
910
using HttpOverStream.Logging;
@@ -188,6 +189,31 @@ private async Task DisposeWhenCancelled(IDisposable disposable, string threadNam
188189
_logger.LogError($"Exception disposing dummy {threadName} stream: {e}");
189190
}
190191
}
192+
193+
public IPrincipal GetTransportIdentity(Stream connection)
194+
{
195+
var serverStream = connection as NamedPipeServerStream;
196+
if (serverStream == null)
197+
{
198+
throw new InvalidOperationException("connection should be a NamedPipeServerStream");
199+
}
200+
201+
WindowsPrincipal principal = null;
202+
try
203+
{
204+
serverStream.RunAsClient(() =>
205+
{
206+
principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
207+
});
208+
}
209+
catch
210+
{
211+
// this can fail if client explicitly connected with ImpersonationLevel.None.
212+
// default is ImpersonationLevel.Identify which runs fine.
213+
}
214+
215+
return principal;
216+
}
191217
}
192218

193219
internal static class CancellationTokenExtensions

src/HttpOverStream.Server.Owin/CustomListenerHost.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ private async void OnAccept(Stream stream)
5353

5454
_logger.WriteVerbose("Server: reading message..");
5555
await PopulateRequestAsync(stream, owinContext.Request, CancellationToken.None).ConfigureAwait(false);
56+
57+
// some transports (shuch as Named Pipes) may require the server to read some data before being able to get the
58+
// client identity. So we get the client identity after reading the request headers
59+
var transportIdentity = _listener.GetTransportIdentity(stream);
60+
owinContext.Request.User = transportIdentity;
61+
5662
_logger.WriteVerbose("Server: finished reading message");
5763
Func<Task> sendHeadersAsync = async () =>
5864
{

src/HttpOverStream/IListen.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Security.Principal;
34
using System.Threading;
45
using System.Threading.Tasks;
56

@@ -9,5 +10,6 @@ public interface IListen
910
{
1011
Task StartAsync(Action<Stream> onConnection, CancellationToken cancellationToken);
1112
Task StopAsync(CancellationToken cancellationToken);
13+
IPrincipal GetTransportIdentity(Stream connection);
1214
}
1315
}

0 commit comments

Comments
 (0)