@@ -132,7 +132,7 @@ public void ensureDefinitionIsEnrichedAsPreDefinedFromConfiguration() {
132132 predefinedExtraFields -> predefinedExtraFields .add ("/definition" ),
133133 preDefinedExtraFieldsReadGrantObject -> preDefinedExtraFieldsReadGrantObject
134134 .set (JsonKey .of ("/definition" ), JsonArray .newBuilder ()
135- .add (0 )
135+ .add (KNOWN_ISSUER_FULL_SUBJECT )
136136 .build ()
137137 ),
138138 preDefinedFieldsObject -> preDefinedFieldsObject .set ("definition" , KNOWN_DEFINITION )
@@ -157,17 +157,17 @@ public void ensureDefinitionAndAdditionalNamespaceSpecificIsEnrichedAsPreDefined
157157 .add ("/attributes/public1" )
158158 .add ("/attributes/private" ),
159159 preDefinedExtraFieldsReadGrantObject -> preDefinedExtraFieldsReadGrantObject
160- .set (JsonKey .of ("/attributes/public1" ), JsonArray .newBuilder ()
161- .add (0 )
162- .add (1 )
160+ .set (JsonKey .of ("/definition" ), JsonArray .newBuilder ()
161+ .add (KNOWN_ISSUER_FULL_SUBJECT )
163162 .build ()
164163 )
165- .set (JsonKey .of ("/definition" ), JsonArray .newBuilder ()
166- .add (0 )
164+ .set (JsonKey .of ("/attributes/public1" ), JsonArray .newBuilder ()
165+ .add (KNOWN_ISSUER_FULL_SUBJECT )
166+ .add (KNOWN_ISSUER_RESTRICTED_SUBJECT )
167167 .build ()
168168 )
169169 .set (JsonKey .of ("/attributes/private" ), JsonArray .newBuilder ()
170- .add (0 )
170+ .add (KNOWN_ISSUER_FULL_SUBJECT )
171171 .build ()
172172 ),
173173 preDefinedFieldsObject -> preDefinedFieldsObject
@@ -269,17 +269,17 @@ public void ensureConditionBasedEnrichmentAsPreDefinedFromConfiguration() {
269269 .add ("/attributes/folder" ),
270270 preDefinedExtraFieldsReadGrantObject -> preDefinedExtraFieldsReadGrantObject
271271 .set (JsonKey .of ("/attributes/public1" ), JsonArray .newBuilder ()
272- .add (0 )
273- .add (1 )
272+ .add (KNOWN_ISSUER_FULL_SUBJECT )
273+ .add (KNOWN_ISSUER_RESTRICTED_SUBJECT )
274274 .build ()
275275 )
276276 .set (JsonKey .of ("/attributes/folder" ), JsonArray .newBuilder ()
277- .add (0 )
277+ .add (KNOWN_ISSUER_FULL_SUBJECT )
278278 .build ()
279279 )
280280 .set (JsonKey .of ("/attributes/folder/public" ), JsonArray .newBuilder ()
281- .add (2 )
282- .add (1 )
281+ .add (KNOWN_ISSUER_ANOTHER_SUBJECT )
282+ .add (KNOWN_ISSUER_RESTRICTED_SUBJECT )
283283 .build ()
284284 ),
285285 preDefinedFieldsObject -> preDefinedFieldsObject
@@ -289,6 +289,47 @@ public void ensureConditionBasedEnrichmentAsPreDefinedFromConfiguration() {
289289 );
290290 }
291291
292+ /**
293+ * Reproduces the production scenario: connection with {@code thing:/ READ} requesting
294+ * {@code attributes} as extraFields. Verifies that the read grant header contains string
295+ * subject IDs that {@code DittoCachingSignalEnrichmentFacade} can match against.
296+ */
297+ @ Test
298+ public void readGrantHeaderContainsStringSubjectIdsForRootReadPolicy () {
299+ // GIVEN: a policy with only thing:/ READ (like lora-downlink-processor in production)
300+ final PolicyEnforcerProvider fullAccessProvider = mock (PolicyEnforcerProvider .class );
301+ when (fullAccessProvider .getPolicyEnforcer (KNOWN_POLICY_ID ))
302+ .thenReturn (CompletableFuture .completedFuture (Optional .of (PolicyEnforcer .of (FULL_ACCESS_POLICY ))));
303+ final ThingEventEnricher sut = new ThingEventEnricher (fullAccessProvider , true );
304+ final var configs = getPreDefinedExtraFieldsConfigs (
305+ "namespaces = [\" org.eclipse.ditto.some\" ]\n " +
306+ "extra-fields = [\" attributes\" ]"
307+ );
308+
309+ // WHEN: enriched headers are calculated
310+ final CompletionStage <DittoHeaders > resultHeadersStage = calculateEnrichedSignalHeaders (sut , configs );
311+ final DittoHeaders headers = resultHeadersStage .toCompletableFuture ().join ();
312+
313+ // THEN: the read grant header must contain string subject IDs, not integer indices
314+ final String readGrantHeader = headers .get (
315+ DittoHeaderDefinition .PRE_DEFINED_EXTRA_FIELDS_READ_GRANT_OBJECT .getKey ());
316+ assertThat (readGrantHeader )
317+ .as ("read grant header should be present" )
318+ .isNotNull ();
319+ final JsonObject readGrant = JsonFactory .readFrom (readGrantHeader ).asObject ();
320+ // Verify it contains string subject IDs (e.g. "foo-issuer:full-subject"), not integers
321+ readGrant .forEach (field -> {
322+ final JsonArray subjects = field .getValue ().asArray ();
323+ subjects .forEach (value ->
324+ assertThat (value .isString ())
325+ .as ("read grant array values must be strings, not integers: %s" , value )
326+ .isTrue ()
327+ );
328+ });
329+ // Verify the specific subject is present for /attributes
330+ assertThat (readGrantHeader ).contains (KNOWN_ISSUER_FULL_SUBJECT );
331+ }
332+
292333 private List <PreDefinedExtraFieldsConfig > getPreDefinedExtraFieldsConfigs (final String ... configurations ) {
293334 return Arrays .stream (configurations )
294335 .map (configString ->
0 commit comments