Skip to content

Handle Null Group Attributes in /participants Endpoint to Prevent 500 Error

Bug in Release/1.3.0

There is an issue in the /participants endpoint that caused a 500 Internal Server Error when the endpoint attempted to process groups in Keycloak that lack required attributes

When making a GET request to /participants, the endpoint fetches all groups in Keycloak. If any group is missing required attributes (e.g., ATR_NAME, ATR_PUBLIC_KEY, or ATR_SD_HASH), a NullPointerException occurs in toParticipantExt, causing a server error. This can occur if groups are created directly in Keycloak and do not meet the expected structure.

Quick fix: on ParticipantDaoImpl file

  • Update the toParticipantExt method to safely handle missing attributes and returning null if a group is missing required fields.
private ParticipantMetaData toParticipantExt(GroupRepresentation groupRepo) {
    Map<String, List<String>> attributes = groupRepo.getAttributes();
    // Check for required attributes and log if any are missing
    if (attributes.get(ATR_NAME) == null || attributes.get(ATR_NAME).isEmpty() ||
        attributes.get(ATR_PUBLIC_KEY) == null || attributes.get(ATR_PUBLIC_KEY).isEmpty() ||
        attributes.get(ATR_SD_HASH) == null || attributes.get(ATR_SD_HASH).isEmpty()) {
        return null; 
    }
    return new ParticipantMetaData(groupRepo.getName(), attributes.get(ATR_NAME).get(0),
        attributes.get(ATR_PUBLIC_KEY).get(0), null, attributes.get(ATR_SD_HASH).get(0));
  }
  • Update the search method to filter out null results (representing incomplete or unknown groups), ensuring only valid ParticipantMetaData instances are counted and returned.
  public PaginatedResults<ParticipantMetaData> search(Integer offset, Integer limit) {
    GroupsResource instance = keycloak.realm(realm).groups();
    List<GroupRepresentation> groups = instance.groups(null, offset, limit, false);
    
    // Map groups to ParticipantMetaData, filter non-null values, and collect
    List<ParticipantMetaData> validParticipants = groups.stream()
        .map(this::toParticipantExt)
        .filter(Objects::nonNull)
        .collect(Collectors.toList());

    // Set total as the count of valid ParticipantMetaData instances
    long total = validParticipants.size();

    return new PaginatedResults<>(total, validParticipants);

  }