### Description

`TransportGrantAction` currently provides an `executeWithGrantAuthentication` method which sub-classes can leverage. Instead of requiring sub-classes to invoke this method directly, we instead can move it into the `doExecute` method of `TransportGrantAction`, and allow inheritors to specify their own handler for grant authentication, something along the lines of: 

```
class TransportGrantAction {

    final void doExecute(...) {
        // executeWithGrantAuthentication can furthermore be inlined as part of this refactor
        executeWithGrantAuthentication(request, ActionListener.wrap(
            authentication -> { doSomethingWithAuthentication(...) }
        ));
    }

    abstract doSomethingWithAuthentication(...);
}
```

This reduces boilerplate and establishes a clearer contract for sub-classes of `TransportGrantAction`.
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/TransportGrantAction.java
this.authenticationService = authenticationService;
        this.authorizationService = authorizationService;
        this.threadContext = threadContext;
    }
    protected void executeWithGrantAuthentication(GrantRequest grantRequest, ActionListener<Authentication> listener) {
        try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
            final AuthenticationToken authenticationToken = grantRequest.getGrant().getAuthenticationToken();
            assert authenticationToken != null : "authentication token must not be null";
            if (authenticationToken == null) {
                listener.onFailure(
                    new ElasticsearchSecurityException("the grant type [{}] is not supported", grantRequest.getGrant().getType())
                );
                return;
            }
            final String runAsUsername = grantRequest.getGrant().getRunAsUsername();
            final ActionListener<Authentication> authenticationListener = ActionListener.wrap(authentication -> {
                if (authentication.isRunAs()) {
                    final String effectiveUsername = authentication.getEffectiveSubject().getUser().principal();
                    if (runAsUsername != null && false == runAsUsername.equals(effectiveUsername)) {
                        
                        listener.onFailure(
                            new ElasticsearchStatusException("the provided grant credentials do not support run-as", RestStatus.BAD_REQUEST)
                        );
                    } else {
                        
                        
                        assert runAsUsername != null || "access_token".equals(grantRequest.getGrant().getType());
                        authorizationService.authorize(
                            authentication,
                            AuthenticateAction.NAME,