-
Notifications
You must be signed in to change notification settings - Fork 395
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
[ISSUE-1206] improvement: Use the real user for audit information #1258
Conversation
Blocked by #1257 |
@@ -13,4 +13,6 @@ public interface AuthConstants { | |||
String AUTHORIZATION_BASIC_HEADER = "Basic "; | |||
|
|||
String ANONYMOUS_USER = "anonymous"; | |||
|
|||
String AuthenticatedPrincipalAttributeName = AuthConstants.class.getName() + "-principal"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you capitalize the first letter, also why don't you use the upper-case for this static variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
private String currentUser; | ||
|
||
private static final ThreadLocal<PrincipalContext> context = new ThreadLocal<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it safe to use thread local variable? I'm afraid if we change some code, we will not get the correct variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if we don't remove the thread local variable in time, we will get the wrong user if this thread is reused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the meantime, is it better to use "InheritableThreadLocal"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we use a thread pool, InheritableThreadLocal
can't also guarantee that we get the correct user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if we don't remove the thread local variable in time, we will get the wrong user if this thread is reused.
Now, we use try finally to guarantee the correctness. It's a regular way to solve the similar case.
@@ -52,7 +53,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha | |||
authData = headerData.nextElement().getBytes(StandardCharsets.UTF_8); | |||
} | |||
if (authenticator.isDataFromToken()) { | |||
authenticator.authenticateToken(authData); | |||
Principal principal = authenticator.authenticateToken(authData); | |||
request.setAttribute(AuthConstants.AuthenticatedPrincipalAttributeName, principal); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a common way to get user name from attribute?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pulsar uses this way. I don't find other implements. Some systems will put the user formation into the session. But we don't have session manager in our Jetty server. It may bring some cost to add a session manager in our Jetty server. So I choose to use to put the user to the attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -80,7 +81,7 @@ public Response createTable( | |||
@PathParam("catalog") String catalog, | |||
@PathParam("schema") String schema, | |||
TableCreateRequest request) { | |||
try { | |||
try (PrincipalContext context = Utils.createUserPrincipalContext(httpRequest)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you would wrap this for all the operations later on, not just create and alter operations. For example, if you want to support proxy user for hive catalog operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
import javax.security.auth.Subject; | ||
|
||
@SuppressWarnings("removal") | ||
public class PrincipalUtils { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refer to the doAs and getCurrentUser from Hadoop UserInformation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This api will be removed in the future. But JDK doesn't provide alternative solution. Hadoop will encounter the similar situation. I add the anotation to avoid the failure of compile.
Please let me know when it is ready to review again. |
I have addressed all the comments. It's ready to review again. |
@@ -13,4 +13,6 @@ public interface AuthConstants { | |||
String AUTHORIZATION_BASIC_HEADER = "Basic "; | |||
|
|||
String ANONYMOUS_USER = "anonymous"; | |||
|
|||
String AUTHENTICATED_PRINCIPAL_ATTRIBUTE_NAME = AuthConstants.class.getName() + "-principal"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of using AuthConstants.class.getName()
as an attribute name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer to the style of Pulsar. I have added the comment.
Throwable cause = pae.getCause(); | ||
if (!(cause instanceof Exception)) { | ||
throw new RuntimeException( | ||
"PrivilegedActionException with no " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which exception will be thrown here, the exception message is not easy to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use Guava's Throwables
to simplify the code here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
executorService.submit( | ||
() -> | ||
Assertions.assertEquals( | ||
"testThreadPool", PrincipalUtils.getCurrentPrincipal().getName())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this may not be correct if the thread is cached and reused? You can only make sure to get correct principal when you doAs
in the lambda function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doAs doesn't use InherittedThreadLocal. The implement is referring to the UserGroupInformation. It get the principal from stack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My fault. Removed.
All comments are addressed.
|
What changes were proposed in this pull request?
Use the real user for audit information.
Use a PrincipalContext to pass the value of user without interface modification referring to the design of Spark's TaskContext
Why are the changes needed?
Fix: #1206
Does this PR introduce any user-facing change?
No.
How was this patch tested?
Add UT.