protected void completeAuthentication(
      HttpServerExchange exchange,
      SecurityContext securityContext,
      SkeletonKeyToken token,
      String surrogate) {
    final SkeletonKeyPrincipal skeletonKeyPrincipal =
        new SkeletonKeyPrincipal(token.getPrincipal(), surrogate);
    Set<String> roles = null;
    if (config.isUseResourceRoleMappings()) {
      SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
      if (access != null) roles = access.getRoles();
    } else {
      SkeletonKeyToken.Access access = token.getRealmAccess();
      if (access != null) roles = access.getRoles();
    }
    if (roles == null) roles = Collections.emptySet();
    final Set<String> accountRoles = roles;
    Account account =
        new Account() {
          @Override
          public Principal getPrincipal() {
            return skeletonKeyPrincipal;
          }

          @Override
          public Set<String> getRoles() {
            return accountRoles;
          }
        };
    securityContext.authenticationComplete(account, "FORM");
  }
  @Override
  public AuthenticationMechanismOutcome authenticate(
      HttpServerExchange exchange, SecurityContext securityContext) {
    BearerTokenAuthenticator bearer = createBearerTokenAuthenticator();
    AuthenticationMechanismOutcome outcome = bearer.authenticate(exchange);
    if (outcome == AuthenticationMechanismOutcome.NOT_AUTHENTICATED) {
      exchange.putAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY, bearer.getChallenge());
      return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    } else if (outcome == AuthenticationMechanismOutcome.AUTHENTICATED) {
      final SkeletonKeyToken token = bearer.getToken();
      String surrogate = bearer.getSurrogate();
      SkeletonKeySession session =
          new SkeletonKeySession(bearer.getTokenString(), token, resourceMetadata);
      propagateBearer(exchange, session);
      completeAuthentication(exchange, securityContext, token, surrogate);
      return AuthenticationMechanismOutcome.AUTHENTICATED;
    } else if (config.isBearerOnly()) {
      exchange.putAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY, bearer.getChallenge());
      return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
    }

    OAuthAuthenticator oauth = createOAuthAuthenticator(exchange);
    outcome = oauth.authenticate();
    if (outcome == AuthenticationMechanismOutcome.NOT_AUTHENTICATED) {
      exchange.putAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY, oauth.getChallenge());
      return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    } else if (outcome == AuthenticationMechanismOutcome.NOT_ATTEMPTED) {
      exchange.putAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY, oauth.getChallenge());
      return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
    }
    SkeletonKeySession session =
        new SkeletonKeySession(oauth.getTokenString(), oauth.getToken(), resourceMetadata);
    propagateOauth(exchange, session);
    completeAuthentication(exchange, securityContext, oauth.getToken(), null);
    log.info("AUTHENTICATED");
    return AuthenticationMechanismOutcome.AUTHENTICATED;
  }
 protected BearerTokenAuthenticator createBearerTokenAuthenticator() {
   return new BearerTokenAuthenticator(resourceMetadata, config.isUseResourceRoleMappings());
 }