/** Get authenticator provider's configuration description */
  @Path("config-description/{providerId}")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  @NoCache
  public AuthenticatorConfigInfoRepresentation getAuthenticatorConfigDescription(
      @PathParam("providerId") String providerId) {
    auth.requireView();

    ConfigurableAuthenticatorFactory factory =
        CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId);
    if (factory == null) {
      throw new NotFoundException("Could not find authenticator provider");
    }
    AuthenticatorConfigInfoRepresentation rep = new AuthenticatorConfigInfoRepresentation();
    rep.setProviderId(providerId);
    rep.setName(factory.getDisplayType());
    rep.setHelpText(factory.getHelpText());
    rep.setProperties(new LinkedList<ConfigPropertyRepresentation>());
    List<ProviderConfigProperty> configProperties = factory.getConfigProperties();
    for (ProviderConfigProperty prop : configProperties) {
      ConfigPropertyRepresentation propRep = getConfigPropertyRep(prop);
      rep.getProperties().add(propRep);
    }
    return rep;
  }
  /** Get configuration descriptions for all clients */
  @Path("per-client-config-description")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  @NoCache
  public Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription() {
    auth.requireAny();

    List<ProviderFactory> factories =
        session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);

    Map<String, List<ConfigPropertyRepresentation>> toReturn = new HashMap<>();
    for (ProviderFactory clientAuthenticatorFactory : factories) {
      String providerId = clientAuthenticatorFactory.getId();
      ConfigurableAuthenticatorFactory factory =
          CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId);
      ClientAuthenticatorFactory clientAuthFactory = (ClientAuthenticatorFactory) factory;
      List<ProviderConfigProperty> perClientConfigProps =
          clientAuthFactory.getConfigPropertiesPerClient();
      List<ConfigPropertyRepresentation> result = new LinkedList<>();
      for (ProviderConfigProperty prop : perClientConfigProps) {
        ConfigPropertyRepresentation propRep = getConfigPropertyRep(prop);
        result.add(propRep);
      }

      toReturn.put(providerId, result);
    }

    return toReturn;
  }
  public void recurseExecutions(
      AuthenticationFlowModel flow,
      List<AuthenticationExecutionInfoRepresentation> result,
      int level) {
    int index = 0;
    List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutions(flow.getId());
    for (AuthenticationExecutionModel execution : executions) {
      AuthenticationExecutionInfoRepresentation rep =
          new AuthenticationExecutionInfoRepresentation();
      rep.setLevel(level);
      rep.setIndex(index++);
      rep.setRequirementChoices(new LinkedList<String>());
      if (execution.isAuthenticatorFlow()) {
        AuthenticationFlowModel flowRef = realm.getAuthenticationFlowById(execution.getFlowId());
        if (AuthenticationFlow.BASIC_FLOW.equals(flowRef.getProviderId())) {
          rep.getRequirementChoices()
              .add(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name());
          rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.REQUIRED.name());
          rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.DISABLED.name());
        } else if (AuthenticationFlow.FORM_FLOW.equals(flowRef.getProviderId())) {
          rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.REQUIRED.name());
          rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.DISABLED.name());
          rep.setProviderId(execution.getAuthenticator());
          rep.setAuthenticationConfig(execution.getAuthenticatorConfig());
        } else if (AuthenticationFlow.CLIENT_FLOW.equals(flowRef.getProviderId())) {
          rep.getRequirementChoices()
              .add(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name());
          rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.REQUIRED.name());
          rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.DISABLED.name());
        }
        rep.setDisplayName(flowRef.getAlias());
        rep.setConfigurable(false);
        rep.setId(execution.getId());
        rep.setAuthenticationFlow(execution.isAuthenticatorFlow());
        rep.setRequirement(execution.getRequirement().name());
        rep.setFlowId(execution.getFlowId());
        result.add(rep);
        AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId());
        recurseExecutions(subFlow, result, level + 1);
      } else {
        String providerId = execution.getAuthenticator();
        ConfigurableAuthenticatorFactory factory =
            CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId);
        rep.setDisplayName(factory.getDisplayType());
        rep.setConfigurable(factory.isConfigurable());
        for (AuthenticationExecutionModel.Requirement choice : factory.getRequirementChoices()) {
          rep.getRequirementChoices().add(choice.name());
        }
        rep.setId(execution.getId());

        if (factory.isConfigurable()) {
          AuthenticatorConfigModel authenticatorConfig =
              realm.getAuthenticatorConfigById(execution.getAuthenticatorConfig());

          if (authenticatorConfig != null) {
            rep.setAlias(authenticatorConfig.getAlias());
          }
        }

        rep.setRequirement(execution.getRequirement().name());
        rep.setProviderId(execution.getAuthenticator());
        rep.setAuthenticationConfig(execution.getAuthenticatorConfig());
        result.add(rep);
      }
    }
  }