EventStore / EventStoreDB-Client-Java

Official Asynchronous Java 8+ Client Library for EventStoreDB 20.6+
https://eventstore.com
Apache License 2.0
63 stars 20 forks source link

Getting io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access Denied #67

Closed dhirajkumar94 closed 3 years ago

dhirajkumar94 commented 3 years ago

Hi,

I am trying to create a listener using a persistent subscription client but getting error "PERMISSION_DENIED: Access Denied" even though I am getting stream events using a regular client.

The following code is not working and I am getting "Access Denied":

EventStoreDBClientSettings settings = EventStoreDBClientSettings.builder()
                .addHost(new Endpoint(config.getHost(), config.getPort()))
                .defaultCredentials(config.getUsername(), config.getPassword())
                .tls(config.isTls())
                .buildConnectionSettings();

EventStoreDBPersistentSubscriptionsClient persistentClient = EventStoreDBPersistentSubscriptionsClient.create(settings);

PersistentSubscriptionSettings settings = PersistentSubscriptionSettings.builder().resolveLinks(true)
                    .enableExtraStatistics()
                    .enableLinkResolution()
                    .maxRetryCount(100)
                    .build();

SubscribePersistentSubscriptionOptions options = SubscribePersistentSubscriptionOptions.get()
                    .authenticated(new UserCredentials(config.getUsername(), config.getPassword()))
                    .setBufferSize(100);
persistentClient.create(streamName, group, settings).get();
persistentClient.subscribe(streamName, group, options, listener).get();

The following code is working and I can fetch the events:

EventStoreDBClientSettings settings = EventStoreDBClientSettings.builder()
                .addHost(new Endpoint(config.getHost(), config.getPort()))
                .defaultCredentials(config.getUsername(), config.getPassword())
                .tls(config.isTls())
                .buildConnectionSettings();

EventStoreDBClient client = EventStoreDBClient.create(settings);

client.appendToStream(streamName, event);

List<ResolvedEvent> resolvedEvents =
                client.readStream(streamName, count, ReadStreamOptions.get().fromStart()).get().getEvents();

I am even able to create a persistent subscription by calling eventstore api endpoint: /subscriptions/{stream}/{subscription_name}

Response

{
  "correlationId": "6ea780d1-a7b8-4823-bb03-887649309474",
  "reason": "",
  "result": "Success",
  "msgTypeId": 42
}

And I can also read a stream via a Persistent Subscription (but only able to see eventType, data is missing): /subscriptions/{stream}/{subscription}/{count}?embed={embed}

Response:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Messages for 'test007/ptest999'</title>
    <id>https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999</id>
    <updated>2021-03-20T14:10:17.9787972Z</updated>
    <author>
        <name>EventStore</name>
    </author>
    <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/ack?ids=4933c2bf-ad96-49e7-9c62-41293ab58512,b2a709aa-cb95-4b06-bb31-0e3af868042a,95f702f8-d275-460a-a110-f33bb5625321" rel="ackAll" />
    <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/nack?ids=4933c2bf-ad96-49e7-9c62-41293ab58512,b2a709aa-cb95-4b06-bb31-0e3af868042a,95f702f8-d275-460a-a110-f33bb5625321" rel="nackAll" />
    <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/10" rel="previous" />
    <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999" rel="self" />
    <entry>
        <title>2@test007</title>
        <id>https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/2</id>
        <updated>2021-03-20T14:10:17.9787972Z</updated>
        <author>
            <name>EventStore</name>
        </author>
        <summary>testeventtype699</summary>
        <retryCount>5</retryCount>
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/2" rel="edit" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/2" rel="alternate" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/ack/95f702f8-d275-460a-a110-f33bb5625321" rel="ack" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/nack/95f702f8-d275-460a-a110-f33bb5625321" rel="nack" />
    </entry>
    <entry>
        <title>1@test007</title>
        <id>https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/1</id>
        <updated>2021-03-20T13:40:14.0542984Z</updated>
        <author>
            <name>EventStore</name>
        </author>
        <summary>testeventtype799</summary>
        <retryCount>5</retryCount>
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/1" rel="edit" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/1" rel="alternate" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/ack/b2a709aa-cb95-4b06-bb31-0e3af868042a" rel="ack" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/nack/b2a709aa-cb95-4b06-bb31-0e3af868042a" rel="nack" />
    </entry>
    <entry>
        <title>0@test007</title>
        <id>https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/0</id>
        <updated>2021-03-20T13:17:05.2185514Z</updated>
        <author>
            <name>EventStore</name>
        </author>
        <summary>testeventtype999</summary>
        <retryCount>5</retryCount>
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/0" rel="edit" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/streams/test007/0" rel="alternate" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/ack/4933c2bf-ad96-49e7-9c62-41293ab58512" rel="ack" />
        <link href="https://c045hrqrh41idocvl080-1.mesdb.eventstore.cloud:2113/subscriptions/test007/ptest999/nack/4933c2bf-ad96-49e7-9c62-41293ab58512" rel="nack" />
    </entry>
</feed>

Full Stacktrace:

java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access Denied
    at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
    at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999)
    at com.incred.eventstore.util.EventStoreUtil.consume(EventStoreUtil.java:86)
    at com.incred.eventstore.listeners.Subscription.<init>(Subscription.java:21)
    at com.incred.eventstore.listeners.impl.TestListener.subscribe(TestListener.java:22)
    at com.incred.eventstore.runners.ConsumerRunner.onApplicationEvent(ConsumerRunner.java:38)
    at com.incred.eventstore.runners.ConsumerRunner.onApplicationEvent(ConsumerRunner.java:19)
    at io.micronaut.context.DefaultBeanContext.notifyEventListeners(DefaultBeanContext.java:1307)
    at io.micronaut.context.DefaultBeanContext.publishEvent(DefaultBeanContext.java:1292)
    at io.micronaut.http.server.netty.NettyHttpServer.fireStartupEvents(NettyHttpServer.java:498)
    at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:341)
    at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:110)
    at io.micronaut.runtime.Micronaut.lambda$start$2(Micronaut.java:70)
    at io.micronaut.runtime.Micronaut$$Lambda$706/0000000000000000.accept(Unknown Source)
    at java.base/java.util.Optional.ifPresent(Optional.java:183)
    at io.micronaut.runtime.Micronaut.start(Micronaut.java:68)
    at io.micronaut.runtime.Micronaut.run(Micronaut.java:299)
    at io.micronaut.runtime.Micronaut.run(Micronaut.java:285)
    at com.incred.eventstore.Application.main(Application.java:19)
Caused by: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access Denied
    at io.grpc.StatusRuntimeException.fillInStackTrace(StatusRuntimeException.java:68)
    at io.grpc.StatusRuntimeException.<init>(StatusRuntimeException.java:58)
    at io.grpc.StatusRuntimeException.<init>(StatusRuntimeException.java:50)
    at io.grpc.Status.asRuntimeException(Status.java:533)
    at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:478)
    at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java:464)
    at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:428)
    at io.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:461)
    at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:617)
    at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:803)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:782)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

I'm using the following dependency:

<dependency>
            <groupId>com.eventstore</groupId>
            <artifactId>db-client-java</artifactId>
            <version>0.7</version>
</dependency>
dhirajkumar94 commented 3 years ago

@YoEight could you please help

YoEight commented 3 years ago

Did you try with the latest version of the client (version 1.0.0)?

When that exception happens, is it when you create the persistent subscription or when you try to subscribe to it?

I also going to ask questions you didn't answer in a previous issue similar to this one:

When you try to create your persistent subscription, do you see a line in the server log resembling something like this:

Failed authorization check for {identity} in {duration} with {evaluationResult} ?

Did you change the default ACLs in your cluster?

When creating a persistent subscription, the authenticated user needs to also have read access on the target stream.

huyhoangepay commented 3 years ago

We're seeing the same issue.
The server logs:

Apr 22 08:52:01 event-store-cqrs bash[13640]: [13640, 9,08:52:01.777,WRN] Failed authorization check for "(anonymous)" in 00:23:07.2419626 with "subscriptions : process p: {streamId : $ce-customer#0} Deny : Policy : Legacy 1 12/31/9999 23:59:59 +00:00 : match:authenticated:Deny, $"

The issue is that we did pass the admin username/password when creating the client.
I tried the same API for the C# client, which works without problems.
Seems like a Java client bug

huyhoangepay commented 3 years ago

Ok I actually found the bug. In the DBClient (non-persistent) there's a step to authenticate the default credential if none is specified in the options:
https://github.com/EventStore/EventStoreDB-Client-Java/blob/f8f86592c485169de1fe3e22b9bde2e2c592193c/db-client-java/src/main/java/com/eventstore/dbclient/EventStoreDBClient.java#L91

That step doesn't exist in the EventStoreDBPersistentSubscriptionsClient class.
I can fix it with

var options = CreatePersistentSubscriptionOptions.get().settings(settings);
options.authenticated(new UserCredentials("my-user", "my-password"));

But the client should automatically add credentials if it already takes the default credential settings.
I think this was not detected in the unit tests because the unit tests only tested non-secure connections.

dhirajkumar94 commented 3 years ago

@huyhoangepay CreatePersistentSubscriptionOptions doesn't accept PersistentSubscriptionListener as an parameter. I am using SubscribePersistentSubscriptionOptions to create a persistence subscription but getting the error message "UNAVAILABLE: Network closed for unknown reason"

YoEight commented 3 years ago

A patch is now available on master.

YoEight commented 3 years ago

Thanks @huyhoangepay and @dhirajkumar94 for your investigations!

YoEight commented 3 years ago

The patch is available on the latest snapshot version of the client if you are interested: https://github.com/EventStore/EventStoreDB-Client-Java/issues/68#issuecomment-827502978

jselamy commented 3 years ago

I will check it out shortly