/**
   * Create new authenticator configuration
   *
   * @param rep JSON describing new authenticator configuration
   * @deprecated Use {@link #newExecutionConfig(String, AuthenticatorConfigRepresentation)} instead
   */
  @Path("config")
  @POST
  @NoCache
  public Response createAuthenticatorConfig(AuthenticatorConfigRepresentation rep) {
    auth.requireManage();

    AuthenticatorConfigModel config =
        realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep));
    adminEvent
        .operation(OperationType.CREATE)
        .resourcePath(uriInfo, config.getId())
        .representation(rep)
        .success();
    return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
  }
 @Override
 public void buildPage(FormContext context, LoginFormsProvider form) {
   AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig();
   if (captchaConfig == null
       || captchaConfig.getConfig() == null
       || captchaConfig.getConfig().get(SITE_KEY) == null
       || captchaConfig.getConfig().get(SITE_SECRET) == null) {
     form.addError(new FormMessage(null, Messages.RECAPTCHA_NOT_CONFIGURED));
     return;
   }
   String siteKey = captchaConfig.getConfig().get(SITE_KEY);
   form.setAttribute("recaptchaRequired", true);
   form.setAttribute("recaptchaSiteKey", siteKey);
   form.addScript("https://www.google.com/recaptcha/api.js");
 }
  /**
   * Update authenticator configuration
   *
   * @param id Configuration id
   * @param rep JSON describing new state of authenticator configuration
   */
  @Path("config/{id}")
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @NoCache
  public void updateAuthenticatorConfig(
      @PathParam("id") String id, AuthenticatorConfigRepresentation rep) {
    auth.requireManage();

    AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id);
    if (exists == null) {
      throw new NotFoundException("Could not find authenticator config");
    }
    exists.setAlias(rep.getAlias());
    exists.setConfig(rep.getConfig());
    realm.updateAuthenticatorConfig(exists);
    adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
  }
  /**
   * Update execution with new configuration
   *
   * @param execution Execution id
   * @param json JSON with new configuration
   * @return
   */
  @Path("/executions/{executionId}/config")
  @POST
  @NoCache
  @Consumes(MediaType.APPLICATION_JSON)
  public Response newExecutionConfig(
      @PathParam("executionId") String execution, AuthenticatorConfigRepresentation json) {
    auth.requireManage();

    AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
    if (model == null) {
      session.getTransaction().setRollbackOnly();
      throw new NotFoundException("Illegal execution");
    }
    AuthenticatorConfigModel config = RepresentationToModel.toModel(json);
    config = realm.addAuthenticatorConfig(config);
    model.setAuthenticatorConfig(config.getId());
    realm.updateAuthenticatorExecution(model);

    json.setId(config.getId());
    adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(json).success();
    return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
  }
  @Override
  public void validate(ValidationContext context) {
    MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
    List<FormMessage> errors = new ArrayList<>();
    boolean success = false;
    context.getEvent().detail(Details.REGISTER_METHOD, "form");

    String captcha = formData.getFirst(G_RECAPTCHA_RESPONSE);
    if (!Validation.isBlank(captcha)) {
      AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig();
      String secret = captchaConfig.getConfig().get(SITE_SECRET);

      success = validateRecaptcha(context, success, captcha, secret);
    }
    if (success) {
      context.success();
    } else {
      errors.add(new FormMessage(null, Messages.RECAPTCHA_FAILED));
      formData.remove(G_RECAPTCHA_RESPONSE);
      context.getEvent().error(Errors.INVALID_REGISTRATION);
      context.validationError(formData, errors);
      return;
    }
  }
  @Override
  protected void authenticateImpl(
      AuthenticationFlowContext context,
      SerializedBrokeredIdentityContext serializedCtx,
      BrokeredIdentityContext brokerContext) {

    KeycloakSession session = context.getSession();
    RealmModel realm = context.getRealm();

    if (context.getClientSession().getNote(EXISTING_USER_INFO) != null) {
      context.attempted();
      return;
    }

    ExistingUserInfo duplication = checkExistingUser(context, serializedCtx, brokerContext);

    if (duplication == null) {
      logger.debugf(
          "No duplication detected. Creating account for user '%s' and linking with identity provider '%s' .",
          brokerContext.getModelUsername(), brokerContext.getIdpConfig().getAlias());

      UserModel federatedUser = session.users().addUser(realm, brokerContext.getModelUsername());
      federatedUser.setEnabled(true);
      federatedUser.setEmail(brokerContext.getEmail());
      federatedUser.setFirstName(brokerContext.getFirstName());
      federatedUser.setLastName(brokerContext.getLastName());

      for (Map.Entry<String, List<String>> attr : serializedCtx.getAttributes().entrySet()) {
        federatedUser.setAttribute(attr.getKey(), attr.getValue());
      }

      AuthenticatorConfigModel config = context.getAuthenticatorConfig();
      if (config != null
          && Boolean.parseBoolean(
              config
                  .getConfig()
                  .get(
                      IdpCreateUserIfUniqueAuthenticatorFactory
                          .REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION))) {
        logger.debugf("User '%s' required to update password", federatedUser.getUsername());
        federatedUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
      }

      // TODO: Event

      context.setUser(federatedUser);
      context.getClientSession().setNote(BROKER_REGISTERED_NEW_USER, "true");
      context.success();
    } else {
      logger.debugf(
          "Duplication detected. There is already existing user with %s '%s' .",
          duplication.getDuplicateAttributeName(), duplication.getDuplicateAttributeValue());

      // Set duplicated user, so next authenticators can deal with it
      context.getClientSession().setNote(EXISTING_USER_INFO, duplication.serialize());

      Response challengeResponse =
          context
              .form()
              .setError(
                  Messages.FEDERATED_IDENTITY_EXISTS,
                  duplication.getDuplicateAttributeName(),
                  duplication.getDuplicateAttributeValue())
              .createErrorPage();
      context.challenge(challengeResponse);
    }
  }
  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);
      }
    }
  }