Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for pluggable Custom Presto Authenticators #24111

Merged
merged 2 commits into from
Jan 10, 2025

Conversation

imsayari404
Copy link
Contributor

@imsayari404 imsayari404 commented Nov 21, 2024

Description

A pluggable authenticator in Presto allows the authentication process to be customized based on specific use cases, such as integrating with different identity providers or token validation strategies.

Motivation and Context

Fixes #24052

Test Plan

Added Unit Tests

Contributor checklist

  • Please make sure your submission complies with our development, formatting, commit message, and attribution guidelines.
  • PR description addresses the issue accurately and concisely. If the change is non-trivial, a GitHub Issue is referenced.
  • Documented new properties (with its default value), SQL syntax, functions, or other functionality.
  • If release notes are required, they follow the release notes guidelines.
  • Adequate tests were added if applicable.
  • CI passed.

Release Notes

Please follow release notes guidelines and fill in the release notes below.

== RELEASE NOTES ==

Security Changes
* Add support for pluggable Custom Presto Authenticators :pr:`#24111`

@prestodb-ci prestodb-ci added the from:IBM PR from IBM label Nov 21, 2024
@prestodb-ci prestodb-ci requested review from a team and pramodsatya and removed request for a team November 21, 2024 10:39
Copy link
Contributor

@pramodsatya pramodsatya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @imsayari404, could you please add a test? Will the JwtAuthenticator and PasswordAuthenticator be refactored, as suggested in #24053 (review), in this PR?


import static java.util.Objects.requireNonNull;

public class PrestoAuthenticator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PrestoAuthenticator class does not need to be an interface because it serves as a concrete adapter between the Airlift Authenticator interface and the pluggable design provided by PrestoAuthenticator and PrestoAuthenticatorFactory SPI. Its role is to delegate authentication to the PrestoAuthenticatorManager.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pramodsatya I understand why you might be confused. We have an interface called PrestoAuthenticator in the presto-spi package with the same name.

@tdcmeehan Currently, we've followed the same naming convention as was done for the PasswordAuthenticator SPI. This could lead to confusion since we have an SPI with the same name as the PasswordAuthenticator class in the presto-main package. Do you think we should refactor the class names in presto-main to eliminate the confusion?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. How about CustomPrestoAuthenticator?

@tdcmeehan tdcmeehan self-assigned this Nov 21, 2024
Copy link
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the doc! A couple of rephrasing suggestions for conciseness.

Also - because this is a new page - you must add

develop/presto-authenticator

to https://github.com/prestodb/presto/blob/master/presto-docs/src/main/sphinx/develop.rst

so the new page will show up on the Developer Guide index page https://prestodb.io/docs/current/develop.html .

@imjalpreet imjalpreet force-pushed the custom_presto_authenticator branch 2 times, most recently from 5a9b144 to caefe42 Compare November 25, 2024 23:01
@imjalpreet
Copy link
Member

Will the JwtAuthenticator and PasswordAuthenticator be refactored, as suggested in #24053 (review), in this PR?

@pramodsatya There has been a slight change since my last comment on this issue. After discussions with @tdcmeehan, we introduced a new and more generic SPI that is independent of the current Authenticators. This SPI can be used to implement any type of custom authenticator, without being limited to just a custom implementation of JWT or Password Authenticators.

We decided to keep the current implementation of Password and JWT authenticators unchanged to avoid introducing a breaking change.

@imjalpreet imjalpreet marked this pull request as ready for review November 25, 2024 23:14
@imjalpreet imjalpreet requested review from elharo, a team and shrinidhijoshi as code owners November 25, 2024 23:14
@imjalpreet
Copy link
Member

@tdcmeehan can you please have a look whenever you get a chance? Thanks!

Copy link
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the revisions! The page content looks good to me.

However, because this is a new page in the Presto documentation, you must add

develop/presto-authenticator

to https://github.com/prestodb/presto/blob/master/presto-docs/src/main/sphinx/develop.rst

so the new page will show up on the Developer Guide index page in the Presto documentation.

throws AuthenticationException
{
try {
return authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(request);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HttpServletRequest is a little broad because it also returns the input stream of the actual request. In theory, someone could call that in a plugin. I think that should be a loud failure if that happens. Can you implement a subclass of HttpServletRequest, which wraps an inner HttpServletRequest, but throws if you attempt to use any method which modifies the request, or reads something which doesn't support repeatable reads (such as getInputStream)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've implemented the changes as suggested. I created a subclass of HttpServletRequest that wraps an inner HttpServletRequest and throws an exception if any method is called that modifies the request or accesses non-repeatable data like getInputStream. Let me know if there's anything else you'd like me to adjust.

@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch 2 times, most recently from 28a51c9 to 1ad5092 Compare December 13, 2024 08:20
Comment on lines 120 to 124
@Override
public String getPathTranslated()
{
return super.getPathTranslated();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary right? Just omit this and it will use the parent method.

import java.util.Enumeration;
import java.util.Map;

public class RestrictedHttpServletRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call it

Suggested change
public class RestrictedHttpServletRequest
public class ReadOnlyHttpServletRequest

throws AuthenticationException
{
try {
//wrapped the original HttpServletRequest in a RestrictedHttpServletRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this comment, it is self evident

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I'll remove the unnecessary comment and rename the file to CustomPrestoAuthenticator as suggested.


import static java.util.Objects.requireNonNull;

public class PrestoAuthenticator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. How about CustomPrestoAuthenticator?

Copy link
Contributor

@tdcmeehan tdcmeehan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please squash commits.

Comment on lines 66 to 226
public String getQueryString()
{
return super.getQueryString();
}

@Override
public String getRemoteUser()
{
return super.getRemoteUser();
}

@Override
public boolean isUserInRole(String role)
{
return super.isUserInRole(role);
}

@Override
public Principal getUserPrincipal()
{
return super.getUserPrincipal();
}

@Override
public String getRequestedSessionId()
{
return super.getRequestedSessionId();
}

@Override
public String getRequestURI()
{
return super.getRequestURI();
}

@Override
public StringBuffer getRequestURL()
{
return super.getRequestURL();
}

@Override
public String getServletPath()
{
return super.getServletPath();
}

@Override
public HttpSession getSession(boolean create)
{
return super.getSession(create);
}

@Override
public HttpSession getSession()
{
return super.getSession();
}

@Override
public String changeSessionId()
{
return super.changeSessionId();
}

@Override
public boolean isRequestedSessionIdValid()
{
return super.isRequestedSessionIdValid();
}

@Override
public boolean isRequestedSessionIdFromCookie()
{
return super.isRequestedSessionIdFromCookie();
}

@Override
public boolean isRequestedSessionIdFromURL()
{
return super.isRequestedSessionIdFromURL();
}

@Override
public boolean isRequestedSessionIdFromUrl()
{
return super.isRequestedSessionIdFromUrl();
}

@Override
public Map<String, String[]> getParameterMap()
{
return super.getParameterMap();
}

@Override
public String[] getParameterValues(String name)
{
return super.getParameterValues(name);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@Override
public String getAuthType()
{
return super.getAuthType();
}
@Override
public Cookie[] getCookies()
{
return super.getCookies();
}
@Override
public long getDateHeader(String name)
{
return super.getDateHeader(name);
}
@Override
public String getHeader(String name)
{
return super.getHeader(name);
}
@Override
public Enumeration<String> getHeaders(String name)
{
return super.getHeaders(name);
}
@Override
public Enumeration<String> getHeaderNames()
{
return super.getHeaderNames();
}
@Override
public int getIntHeader(String name)
{
return super.getIntHeader(name);
}
@Override
public String getMethod()
{
return super.getMethod();
}
@Override
public String getPathInfo()
{
return super.getPathInfo();
}
@Override
public String getContextPath()
{
return super.getContextPath();
}
@Override
public String getQueryString()
{
return super.getQueryString();
}
@Override
public String getRemoteUser()
{
return super.getRemoteUser();
}
@Override
public boolean isUserInRole(String role)
{
return super.isUserInRole(role);
}
@Override
public Principal getUserPrincipal()
{
return super.getUserPrincipal();
}
@Override
public String getRequestedSessionId()
{
return super.getRequestedSessionId();
}
@Override
public String getRequestURI()
{
return super.getRequestURI();
}
@Override
public StringBuffer getRequestURL()
{
return super.getRequestURL();
}
@Override
public String getServletPath()
{
return super.getServletPath();
}
@Override
public HttpSession getSession(boolean create)
{
return super.getSession(create);
}
@Override
public HttpSession getSession()
{
return super.getSession();
}
@Override
public String changeSessionId()
{
return super.changeSessionId();
}
@Override
public boolean isRequestedSessionIdValid()
{
return super.isRequestedSessionIdValid();
}
@Override
public boolean isRequestedSessionIdFromCookie()
{
return super.isRequestedSessionIdFromCookie();
}
@Override
public boolean isRequestedSessionIdFromURL()
{
return super.isRequestedSessionIdFromURL();
}
@Override
public boolean isRequestedSessionIdFromUrl()
{
return super.isRequestedSessionIdFromUrl();
}
@Override
public Map<String, String[]> getParameterMap()
{
return super.getParameterMap();
}
@Override
public String[] getParameterValues(String name)
{
return super.getParameterValues(name);
}

Just remove these, they will all use the parent's implementation if they are not specified.

@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch from c175051 to 44d8042 Compare December 14, 2024 05:38
ReadOnlyHttpServletRequest restrictedRequest = new ReadOnlyHttpServletRequest(request);
return authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(restrictedRequest);
}
catch (RuntimeException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this exception more specific?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just let it throw.

Comment on lines 44 to 45
ReadOnlyHttpServletRequest restrictedRequest = new ReadOnlyHttpServletRequest(request);
return authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(restrictedRequest);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ReadOnlyHttpServletRequest restrictedRequest = new ReadOnlyHttpServletRequest(request);
return authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(restrictedRequest);
authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(new ReadOnlyHttpServletRequest(request));

Comment on lines 46 to 51
public void setRequired()
{
required.set(true);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this flag, let's just pass in the SecurityConfig as a parameter to this class and @Inject it. And just check in the constructor if CUSTOM is one of the authentication types. Then we can make it immutable, private final boolean.

Finally, let's name it something else, like customAuthenticatorRequested.

@@ -53,6 +53,11 @@
<artifactId>jol-core</artifactId>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this could be problematic. I don't think it's a great idea to add the servlet API to the SPI. Instead, wondering if we can do something similar, like just authenticating the headers. That way, instead of the API surface being a ServletRequest, it could just be a map representing the headers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can undo this change since we are removing the dependency from HttpServletRequest in the new SPI.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can undo this change since we are removing the dependency from HttpServletRequest in the new SPI.

Copy link
Member

@imjalpreet imjalpreet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsayari404 thanks for the changes, I have taken another pass and added a few comments.

@@ -147,6 +151,8 @@ public PluginManager(
QueryPreparerProviderManager queryPreparerProviderManager,
AccessControlManager accessControlManager,
PasswordAuthenticatorManager passwordAuthenticatorManager,
SecurityConfig securityConfig,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this is not required, please remove this.

}

// Utility method to extract headers from HttpServletRequest
private Map<String, String> getHeadersMap(HttpServletRequest request)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we can move this method after all the public methods

// Utility method to extract headers from HttpServletRequest
private Map<String, String> getHeadersMap(HttpServletRequest request)
{
Map<String, String> headers = new HashMap<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some headers can be sent by clients as several headers each with a different value. So, we should update this to Map<String, List<String>>

Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use request.getHeaders(headerName) to get all the values.

return authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(headers);
}
catch (AccessDeniedException e) {
throw e;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: let's wrap this in AuthenticationException

Suggested change
throw e;
throw new AuthenticationException(e.getMessage());

Comment on lines 129 to 138
return (httpRequest) -> {
// TEST_HEADER will have value of the form PART1:PART2
String[] header = httpRequest.get(TEST_HEADER).split(":");

if (header[0].equals(this.validHeaderValue)) {
return new BasicPrincipal(header[1]);
}

throw new AccessDeniedException("Authentication Failed!");
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After making the headers map in SPI to Map<String, List<String>>, we can refactor this.

Suggested change
return (httpRequest) -> {
// TEST_HEADER will have value of the form PART1:PART2
String[] header = httpRequest.get(TEST_HEADER).split(":");
if (header[0].equals(this.validHeaderValue)) {
return new BasicPrincipal(header[1]);
}
throw new AccessDeniedException("Authentication Failed!");
};
return (headers) -> {
// TEST_HEADER will have value of the form PART1:PART2
String[] header = headers.get(TEST_HEADER).get(0).split(":");
if (header[0].equals(this.validHeaderValue)) {
return new BasicPrincipal(header[1]);
}
throw new AccessDeniedException("Authentication Failed!");
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove this class since this is unused

* @return the authenticated Principal
* @throws AccessDeniedException if not allowed
*/
Principal createAuthenticatedPrincipal(Map<String, String> headers);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the headers map to Map<String, List<String>>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this class as this is unused

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this as well

Copy link
Member

@imjalpreet imjalpreet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsayari404 thanks, mostly LGTM now, just a few minor comments.

@@ -75,6 +75,7 @@
</dependency>

<!-- Presto SPI -->

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty line can be removed

Comment on lines 65 to 76
Map<String, List<String>> headers = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
Enumeration<String> headerValues = request.getHeaders(headerName);
List<String> valuesList = new ArrayList<>();
while (headerValues.hasMoreElements()) {
valuesList.add(headerValues.nextElement());
}
headers.put(headerName, valuesList);
}
return headers;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can refactor this method and use Java Stream API

Suggested change
Map<String, List<String>> headers = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
Enumeration<String> headerValues = request.getHeaders(headerName);
List<String> valuesList = new ArrayList<>();
while (headerValues.hasMoreElements()) {
valuesList.add(headerValues.nextElement());
}
headers.put(headerName, valuesList);
}
return headers;
return Collections.list(request.getHeaderNames())
.stream()
.collect(Collectors.toMap(
headerName -> headerName,
headerName -> Collections.list(request.getHeaders(headerName))
));


private Map<String, List<String>> getHeadersMap(HttpServletRequest request)
{
Map<String, List<String>> headers = new HashMap<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the previous comment, please refactor this as well.

@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch from 19c5bca to 2c9848c Compare January 2, 2025 17:33
Copy link
Member

@imjalpreet imjalpreet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsayari404 thanks, changes LGTM, can we squash the commits into relevant commits?

@imjalpreet imjalpreet requested a review from tdcmeehan January 3, 2025 02:37
@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch 2 times, most recently from b1590a7 to 0220514 Compare January 3, 2025 05:59
imjalpreet
imjalpreet previously approved these changes Jan 3, 2025
Copy link
Member

@imjalpreet imjalpreet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍🏼

steveburnett
steveburnett previously approved these changes Jan 3, 2025
Copy link
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! (docs)

Pulled updated branch, new local doc build, looks good. Thanks!

@imsayari404
Copy link
Contributor Author

Hi @tdcmeehan ,
I’ve addressed all the requested changes in the PR, and it’s ready for another round of review. Could you please take a look when you get a chance? Let me know if there’s anything else that needs to be updated.

Copy link
Contributor

@tdcmeehan tdcmeehan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some nits, otherwise LGTM

ReadOnlyHttpServletRequest restrictedRequest = new ReadOnlyHttpServletRequest(request);
return authenticatorManager.getAuthenticator().createAuthenticatedPrincipal(restrictedRequest);
}
catch (RuntimeException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just let it throw.

{
return Collections.list(request.getHeaderNames())
.stream()
.collect(Collectors.toMap(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.collect(Collectors.toMap(
.collect(toImmutableMap(

// Utility method to extract headers from HttpServletRequest
private Map<String, List<String>> getHeadersMap(HttpServletRequest request)
{
return Collections.list(request.getHeaderNames())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return Collections.list(request.getHeaderNames())
return list(request.getHeaderNames())

.stream()
.collect(Collectors.toMap(
headerName -> headerName,
headerName -> Collections.list(request.getHeaders(headerName))));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
headerName -> Collections.list(request.getHeaders(headerName))));
headerName -> list(request.getHeaders(headerName))));

@imsayari404 imsayari404 dismissed stale reviews from steveburnett and imjalpreet via c873a49 January 9, 2025 07:05
@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch from 0220514 to c873a49 Compare January 9, 2025 07:05
Copy link
Member

@imjalpreet imjalpreet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor change, otherwise LGTM

public Principal authenticate(HttpServletRequest request)
throws AuthenticationException
{
// Extracting headers into a Map
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need to catch AccessDeniedException here and throw it as AuthenticationException, we cannot remove that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the catch clause for RuntimeException but we need to catch AccessDeniedException.

@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch from c873a49 to 415ef55 Compare January 9, 2025 09:50
@imsayari404 imsayari404 requested a review from imjalpreet January 9, 2025 09:53
imsayari404 and others added 2 commits January 9, 2025 16:01
Add TestingPrestoAuthenticatorFactory

Co-authored-by: Sayari Mukherjee <[email protected]>
@imsayari404 imsayari404 force-pushed the custom_presto_authenticator branch from 415ef55 to f6fe09f Compare January 9, 2025 10:37
Copy link
Member

@imjalpreet imjalpreet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsayari404 Thanks for the PR, LGTM!

@imjalpreet
Copy link
Member

@tdcmeehan This should be good for another review. Thank you.

@tdcmeehan tdcmeehan merged commit 9fbbc51 into prestodb:master Jan 10, 2025
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
from:IBM PR from IBM
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pluggable JWT Authenticator in Presto
6 participants