Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support authenticated gossip read request (DB-305) #253

Merged
merged 1 commit into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/EventStore.Client.Common/EventStoreCallOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ public static CallOptions CreateStreaming(EventStoreClientSettings settings,
Create(settings, deadline, userCredentials, cancellationToken);

// deadline falls back to connection DefaultDeadline
public static CallOptions CreateNonStreaming(EventStoreClientSettings settings,
CancellationToken cancellationToken) => Create(settings, settings.DefaultDeadline,
settings.DefaultCredentials, cancellationToken);

public static CallOptions CreateNonStreaming(EventStoreClientSettings settings, TimeSpan? deadline,
UserCredentials? userCredentials, CancellationToken cancellationToken) => Create(settings,
deadline ?? settings.DefaultDeadline, userCredentials, cancellationToken);
Expand All @@ -28,10 +32,10 @@ private static CallOptions Create(EventStoreClientSettings settings, TimeSpan? d
: bool.FalseString
}
},
credentials: (settings.DefaultCredentials ?? userCredentials) == null
credentials: (userCredentials ?? settings.DefaultCredentials) == null
? null
: CallCredentials.FromInterceptor(async (_, metadata) => {
var credentials = settings.DefaultCredentials ?? userCredentials;
var credentials = userCredentials ?? settings.DefaultCredentials;

var authorizationHeader = await settings.OperationOptions
.GetAuthenticationHeaderValue(credentials!, CancellationToken.None)
Expand Down
2 changes: 1 addition & 1 deletion src/EventStore.Client/ChannelSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public ChannelSelector(
ChannelCache channelCache) {
_inner = settings.ConnectivitySettings.IsSingleNode
? new SingleNodeChannelSelector(settings, channelCache)
: new GossipChannelSelector(settings, channelCache, new GrpcGossipClient());
: new GossipChannelSelector(settings, channelCache, new GrpcGossipClient(settings));
}

public Task<ChannelBase> SelectChannelAsync(CancellationToken cancellationToken) =>
Expand Down
14 changes: 10 additions & 4 deletions src/EventStore.Client/GrpcGossipClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@

namespace EventStore.Client {
internal class GrpcGossipClient : IGossipClient {
public async ValueTask<ClusterMessages.ClusterInfo> GetAsync(ChannelBase channel,
CancellationToken cancellationToken) {
var client = new Gossip.Gossip.GossipClient(channel);
private readonly EventStoreClientSettings _settings;

public GrpcGossipClient(EventStoreClientSettings settings) {
_settings = settings;
}

using var call = client.ReadAsync(new Empty(), cancellationToken: cancellationToken);
public async ValueTask<ClusterMessages.ClusterInfo> GetAsync(ChannelBase channel, CancellationToken ct) {
var client = new Gossip.Gossip.GossipClient(channel);
using var call = client.ReadAsync(
new Empty(),
EventStoreCallOptions.CreateNonStreaming(_settings, ct));
timothycoleman marked this conversation as resolved.
Show resolved Hide resolved
var result = await call.ResponseAsync.ConfigureAwait(false);

return new(result.Members.Select(x =>
Expand Down
78 changes: 78 additions & 0 deletions test/EventStore.Client.Operations.Tests/AuthenticationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;

namespace EventStore.Client {
public class AuthenticationTests : IClassFixture<AuthenticationTests.Fixture> {
private readonly Fixture _fixture;
private static readonly Dictionary<string, UserCredentials> _credentials =
new Dictionary<string, UserCredentials> {
{ nameof(TestCredentials.Root), TestCredentials.Root },
{ nameof(TestCredentials.TestUser1), TestCredentials.TestUser1 },
};

public AuthenticationTests(Fixture fixture) {
_fixture = fixture;
}

public static IEnumerable<object?[]> AuthenticationCases() {
var root = nameof(TestCredentials.Root);
var testUser = nameof(TestCredentials.TestUser1);

var shouldFail = false;
var shouldSucceed = true;

// no user credentials
yield return new object?[] {1, root, null, shouldSucceed};
yield return new object?[] {2, testUser, null, shouldFail};
yield return new object?[] {3, null, null, shouldFail};

// unprivileged user credentials
yield return new object?[] {4, root, testUser, shouldFail};
yield return new object?[] {5, testUser, testUser, shouldFail};
yield return new object?[] {6, null, testUser, shouldFail};

// root user credentials
yield return new object?[] {7, root, root, shouldSucceed};
yield return new object?[] {8, testUser, root, shouldSucceed};
yield return new object?[] {9, null, root, shouldSucceed};
}

[Theory, MemberData(nameof(AuthenticationCases))]
public async Task system_call_with_credentials_combination(int caseNr, string? defaultUser, string? user, bool succeeds) {

_fixture.Settings.DefaultCredentials = defaultUser != null ? _credentials[defaultUser] : null;
_fixture.Settings.ConnectionName = $"Authentication case #{caseNr} {defaultUser}";

await using var client = new EventStoreOperationsClient(_fixture.Settings);

var result = await Record.ExceptionAsync(() =>
client.SetNodePriorityAsync(1, userCredentials: user != null ? _credentials[user] : null));

if (succeeds) {
Assert.Null(result);
return;
}

Assert.NotNull(result);
}

public class Fixture : EventStoreClientFixture {
protected override async Task Given() {
var userManagementClient = new EventStoreUserManagementClient(Settings);
await userManagementClient.WarmUpAsync();

await userManagementClient.CreateUserWithRetry(
loginName: TestCredentials.TestUser1.Username!,
fullName: nameof(TestCredentials.TestUser1),
groups: Array.Empty<string>(),
password: TestCredentials.TestUser1.Password!,
userCredentials: TestCredentials.Root)
.WithTimeout(TimeSpan.FromMilliseconds(1000));
}

protected override Task When() => Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace EventStore.Client {
public abstract class EventStoreClientFixture : EventStoreClientFixtureBase {
public EventStoreOperationsClient Client { get; }
public EventStoreClient StreamsClient { get; }
public new EventStoreClientSettings Settings => base.Settings;

protected EventStoreClientFixture(EventStoreClientSettings? settings = null) : base(settings) {
protected EventStoreClientFixture(EventStoreClientSettings? settings = null, bool? runInMemory = null)
: base(settings, noDefaultCredentials: true, env: Env(runInMemory)) {

Client = new EventStoreOperationsClient(Settings);
StreamsClient = new EventStoreClient(Settings);
}

private static IDictionary<string, string>? Env(bool? runInMemory) {
if (runInMemory == null) {
return null;
}

return new Dictionary<string, string>() {
{ "EVENTSTORE_MEM_DB", runInMemory.Value.ToString() },
};
}

protected override async Task OnServerUpAsync() {
await StreamsClient.WarmUpAsync();
await Client.WarmUpAsync();
Expand Down
4 changes: 4 additions & 0 deletions test/EventStore.Client.Operations.Tests/scavenge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ await Assert.ThrowsAsync<AccessDeniedException>(() =>
}

public class Fixture : EventStoreClientFixture {
// always run scavenge against physical database
public Fixture () : base(runInMemory: false) {
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ public abstract class EventStoreClientFixture : EventStoreClientFixtureBase {
public EventStoreClient StreamsClient { get; }
public EventStoreUserManagementClient UserManagementClient { get; }

protected EventStoreClientFixture(EventStoreClientSettings? settings = null, bool skipPSWarmUp=false) : base(settings) {
protected EventStoreClientFixture(EventStoreClientSettings? settings = null, bool skipPSWarmUp=false, bool noDefaultCredentials=false)
: base(settings, noDefaultCredentials: noDefaultCredentials){

_skipPsWarmUp = skipPSWarmUp;

Client = new EventStorePersistentSubscriptionsClient(Settings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public Task throws_access_denied() =>
}).WithTimeout();

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() =>
Client.CreateToAllAsync(
"agroupname55",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public Task throws_access_denied() =>
}).WithTimeout();

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() =>
Client.CreateToAllAsync(
"agroupname55",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public create_without_permissions(Fixture fixture) {
private readonly Fixture _fixture;

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ await Assert.ThrowsAsync<AccessDeniedException>(
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ public async Task returns_result_with_normal_user_credentials() {
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override async Task Given() {
if (SupportsPSToAll.No) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task returns_result_with_normal_user_credentials() {
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(skipPSWarmUp: true) {
public Fixture () : base(skipPSWarmUp: true, noDefaultCredentials: true) {
}

protected override async Task Given() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ await Assert.ThrowsAsync<AccessDeniedException>(() =>
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true) {
}

protected override async Task Given() {
if (SupportsPSToAll.No) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ await Assert.ThrowsAsync<AccessDeniedException>(
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override async Task Given() {
await Client.CreateToAllAsync(Group, new PersistentSubscriptionSettings(),
userCredentials: TestCredentials.Root);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public Task throws_access_denied() =>
}).WithTimeout();

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() =>
Client.CreateToStreamAsync(
Stream,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public create_without_permissions(Fixture fixture) {
private readonly Fixture _fixture;

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ await Assert.ThrowsAsync<AccessDeniedException>(
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ public async Task returns_result_for_normal_user() {
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true) {
}

protected override Task Given() =>
Client.CreateToStreamAsync(
groupName: GroupName,
Expand Down Expand Up @@ -174,7 +177,7 @@ await Client.SubscribeToStreamAsync(
for (int i = 0; i < 15; i++) {
await StreamsClient.AppendToStreamAsync(StreamName, StreamState.Any, new [] {
new EventData(Uuid.NewUuid(), "test-event", ReadOnlyMemory<byte>.Empty)
});
}, userCredentials: TestCredentials.Root);
}

await tcs.Task;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public async Task returns_result_with_normal_user_credentials() {
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(skipPSWarmUp: true) {
public Fixture () : base(skipPSWarmUp: true, noDefaultCredentials: true) {
}

protected override async Task Given() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ await Assert.ThrowsAsync<AccessDeniedException>(() =>
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true) {
}

protected override Task Given() =>
Client.CreateToStreamAsync(
StreamName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ await Assert.ThrowsAsync<AccessDeniedException>(
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true){
}

protected override async Task Given() {
await StreamsClient.AppendToStreamAsync(Stream, StreamState.NoStream, CreateTestEvents());
await StreamsClient.AppendToStreamAsync(Stream, StreamState.NoStream, CreateTestEvents(),
userCredentials: TestCredentials.Root);
await Client.CreateToStreamAsync(Stream, Group, new PersistentSubscriptionSettings(),
userCredentials: TestCredentials.Root);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ await Assert.ThrowsAsync<AccessDeniedException>(async () =>
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true) {
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ public abstract class EventStoreClientFixture : EventStoreClientFixtureBase {
public EventStoreClient StreamsClient { get; }
public EventStoreProjectionManagementClient Client { get; }

protected EventStoreClientFixture(EventStoreClientSettings? settings = null) : base(settings,
new Dictionary<string, string> {
protected EventStoreClientFixture(EventStoreClientSettings? settings = null, bool noDefaultCredentials = false) :
base(settings, new Dictionary<string, string> {
["EVENTSTORE_RUN_PROJECTIONS"] = "ALL",
["EVENTSTORE_START_STANDARD_PROJECTIONS"] = "True"
}) {
}, noDefaultCredentials) {
Client = new EventStoreProjectionManagementClient(Settings);
UserManagementClient = new EventStoreUserManagementClient(Settings);
StreamsClient = new EventStoreClient(Settings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public async Task throws_when_given_no_credentials() {
}

public class Fixture : EventStoreClientFixture {
public Fixture () : base(noDefaultCredentials: true) {
}

protected override Task Given() => Task.CompletedTask;
protected override Task When() => Task.CompletedTask;
}
Expand Down
Loading
Loading