Franck
Franck

Reputation: 39

Quarkus Mutiny context propagation and server sent events

I am trying to set up an SSE channel that filters events based on the identity of the client who subscribed. The SecurityIdentity received upon subscription however is not propagated at dispatch time, so channel.send call fail with an UnauthorizedException.

Here is what I have, as expected by the time the server calls channel.send(event) there is no SecurityIdentity to inject and assert ! _identity.isAnonymous(); (in fact the @Authenticated annotation is detected and causes the dispatch to fail).

How do I "save" the security identity of the subscribe REST call to use it later at dispatch time?

Thanks!

REST resource:

@GET
@Path("stream")
@Produces(MediaType.SERVER_SENT_EVENTS)
@RestStreamElementType(MediaType.APPLICATION_JSON)
public Multi<PassportEvent> stream(@QueryParam("order") Integer orderId) {
    return _passportService.stream(orderId);
}

Service:

@Inject
@Channel("passports")
Multi<PassportEvent> passportEvents;
    
@Inject
SecurityIdentity _identity;

@Authenticated
public Multi<PassportEvent> stream(Integer orderId)
{
    assert ! _identity.isAnonymous();

    return passportEvents
        .filter(event -> Objects.equals(event.tenantId, getTenantId())
            && (orderId == null || Objects.equals(orderId, event.orderId)));
}

Emitting service:

@Inject
@Channel("passports")
Emitter<PassportEvent> passportEvents;

// no security identity here
createPassport(...) {
    ...
    if (passportEvents.hasRequests()) {
       PassportEvent event = ...;
            passportEvents.send(event);
        }
    }
}

Upvotes: 0

Views: 97

Answers (1)

Franck
Franck

Reputation: 39

I solved this by having one emitter by identity (which is what I needed for my use case):

public Multi<PaymentEvent> stream(int personId)
    {
        return Multi.createFrom().emitter(e -> {
            _emitters.put(personId, new TenantEmitter<>(e, 
getTenantId()));
            e.onTermination(() ->
                _emitters.remove(personId));
        });
    }

    void dispatchEvent(PaymentEvent event)
    {
        TenantEmitter<PaymentEvent> emitter = _emitters.get(event.getPersondId());
        if (emitter != null && Objects.equals(emitter.getTenantId(), getTenantId())) {
            emitter.getEmitter().emit(event);
        }
    }

Upvotes: 1

Related Questions