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

Promote usage of Subjects in Authentication class #88494

Merged

Conversation

ywangd
Copy link
Member

@ywangd ywangd commented Jul 13, 2022

This PR is a follow-up of #86246 to further clean up the Authentication
class by:

  • Promote usage of the Subject class. The User field and a few other
    related fields are now removed from Authentication. Relevant methods
    have their implementation replaced by using Subjects and same
    behaviours are retained.
  • Remove the temporary internal RunAsUser class. Its essence is about
    wire serialisation which is now merged into Authentication itself.
  • Simplify serialisation of regular User object. All the complexities of
    handling inner user is now completely within the Authentication class
    itself.
  • Consolidate assertions in different places into a single method that
    is called in constructors. Also removed a few assertions because there
    is no RunAsUser class anymore and a User object is just a simple user.

Relates: #86246
Relates: #86544

Resolves: #80117

This PR is a follow-up of elastic#86246 to further clean up the Authentication
class by:
* Promoting usage of the Subject class. The User field and a few other
  related fields are now removed from Authentication. Relevant methods
  have their implementation replaced by using Subjects and same
  behaviours are retained.
* Removed the temporary internal RunAsUser class. It essence is about
  wire serialisation which is now merged into Authentication itself.
* Simplify serialisation of regular User object. All the complexities of
  handling inner user is now completely within the Authentication class
  itself.
* Cosnolidate assertions in different places into a single method that
  is called in constructors. Also removed a few assertions because there
  is no RunAsUser class anymore and a User object is just a simple user.

Relates: elastic#86246
Relates: elastic#86544
@ywangd ywangd added >refactoring :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) v8.4.0 labels Jul 13, 2022
@ywangd ywangd requested a review from tvernum July 13, 2022 04:39
@elasticmachine elasticmachine added the Team:Security Meta label for security team label Jul 13, 2022
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (Team:Security)

Comment on lines -68 to -69
// TODO(hub-cap) Clean this up after moving User over - This class can re-inherit its field AUTHENTICATION_KEY in AuthenticationField.
// That interface can be removed
Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know what this comment means. But I am pretty sure it no longer applies.

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 from when we split core and security into separate jars. The decision about which class went into each project (and which classes were split down the middle) was made almost entirely on pragmatic grounds rather than a principled design choice. In some cases we split things apart just to make it work (a day or so before feature freeze).

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the context. So the removal is safe enough.

Comment on lines +228 to +260
final Map<String, Object> newMetadata = maybeRewriteMetadataForApiKeyRoleDescriptors(olderVersion, this);

final Authentication newAuthentication;
if (isRunAs()) {
// The lookup user for run-as currently doesn't have authentication metadata associated with them because
// lookupUser only returns the User object. The lookup user for authorization delegation does have
// authentication metadata, but the realm does not expose this difference between authenticatingUser and
// delegateUser so effectively this is handled together with the authenticatingSubject not effectiveSubject.
newAuthentication = new Authentication(
new Subject(
effectiveSubject.getUser(),
maybeRewriteRealmRef(olderVersion, effectiveSubject.getRealm()),
olderVersion,
effectiveSubject.getMetadata()
),
new Subject(
authenticatingSubject.getUser(),
maybeRewriteRealmRef(olderVersion, authenticatingSubject.getRealm()),
olderVersion,
newMetadata
),
type
);
} else {
newAuthentication = new Authentication(
new Subject(
authenticatingSubject.getUser(),
maybeRewriteRealmRef(olderVersion, authenticatingSubject.getRealm()),
olderVersion,
newMetadata
),
type
);
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the only place that is more bloated after refactoring. In all other places, the change is a simplification.

);
this.authenticatingUser = Objects.requireNonNull(authenticatingUser);
}
public static class AuthenticationSerializationHelper {
Copy link
Member Author

Choose a reason for hiding this comment

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

This class now only deals with regular User object. It does not need to stay inside the Authentication class anymore. But I kept it here to avoid more changes. Besides the usages by Authentication, it is only used by GetUserResponse which should ever just read/write regular User objects.

this.user = AuthenticationSerializationHelper.readUserFrom(in);
this.authenticatedBy = new RealmRef(in);
// Read the user(s)
final User outerUser = AuthenticationSerializationHelper.doReadUserFrom(in);
Copy link
Contributor

Choose a reason for hiding this comment

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

The distinction between readUserFrom and doReadUserFrom isn't very clear from the names. Do we really need both? If so, can the names reflect their differences in some way?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah the name doReadUserFrom is bad. I changed it to readUserWithoutTrailingBoolean. It is still not great. But I am out of ideas. Also added a comment to readUserFrom to explain the difference.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't love it, but I suspect it needs a larger refactor to work around it.
We can leave it as is for now.

} else {
this.lookedUpBy = null;
lookedUpBy = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need an assert innerUser == null here? Should every inner user have a looked-up-by realm?

Ah, I see it down below. I think I'd prefer the two asserts are consistently placed - either on read from the stream or on construction of the Subject.

Copy link
Member Author

Choose a reason for hiding this comment

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

Do we need an assert innerUser == null here?

Unfortunately no. We use null lookedUpBy to indicate run-as failure (when the run-as user does not exists). In this case, we will have non-null innerUser but null lookedUpBy.

But the reverse is true, i.e. if innerUser is null, we should definitely have null lookedUpBy as well. That's why the other assertion is down below because it does not fit here.

That said, I pulled them together into a single statement and added an elaborative comment for it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Tweaked it a bit and made it simpler.

@@ -205,15 +206,16 @@ public RealmRef getSourceRealm() {
* the lifetime of the original request.
*/
public Version getVersion() {
return version;
return effectiveSubject.getVersion();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we deprecate this method? It doesn't feel like it makes sense to have a version on Authentication now

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes I deprecated it.

public Map<String, Object> getMetadata() {
return metadata;
return authenticatingSubject.getMetadata();
Copy link
Contributor

Choose a reason for hiding this comment

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

As above, should this be deprecated?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep as well.

@@ -243,34 +273,19 @@ public Authentication maybeRewriteForOlderVersion(Version olderVersion) {
*/
public Authentication runAs(User runAs, @Nullable RealmRef lookupRealmRef) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we document the circumstances under which lookupRealmRef is null ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added Javadoc for the arguments which covers this.

@ywangd ywangd requested a review from tvernum July 13, 2022 07:01
@ywangd ywangd added the auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) label Jul 14, 2022
@elasticsearchmachine elasticsearchmachine merged commit 8b0832d into elastic:master Jul 14, 2022
@ywangd ywangd deleted the better-hide-runasuser-class branch July 14, 2022 02:35
weizijun added a commit to weizijun/elasticsearch that referenced this pull request Jul 15, 2022
* upstream/master: (2974 commits)
  Reserved cluster state service (elastic#88527)
  Add transport action immutable state checks (elastic#88491)
  Remove suggest flag from index stats docs (elastic#85479)
  Polling cluster formation state for master-is-stable health indicator (elastic#88397)
  Add test execution guide in yamlRestTest asciidoc (elastic#88490)
  Add troubleshooting guide for corrupt repository (elastic#88391)
  [Transform] Finetune Schedule to be less noisy on retry and retry slower (elastic#88531)
  Updatable API keys - auto-update legacy RDs (elastic#88514)
  Fix typo in TransportForceMergeAction and TransportClearIndicesCacheA… (elastic#88064)
  Fixed NullPointerException on bulk request (elastic#88358)
  Avoid needless index metadata builders during reroute (elastic#88506)
  Set metadata on request in API key noop test (elastic#88507)
  Fix passing positional args to ES in Docker (elastic#88502)
  Improve description for task api detailed param (elastic#88493)
  Support cartesian shape with doc values (elastic#88487)
  Promote usage of Subjects in Authentication class (elastic#88494)
  Add CCx 2.0 feature flag (elastic#88451)
  Reword the watcher 'always' and 'never' condition docs (elastic#86105)
  Simplify azure discovery installation docs (elastic#88404)
  Breakup FIPS CI testing jobs
  ...

# Conflicts:
#	server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java
#	x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapper.java
ywangd added a commit to ywangd/elasticsearch that referenced this pull request Oct 24, 2022
This PR removes the deprecated Authentication#getMetadata method and
replaces its usages with #getAuthenticatingSubject#getMetadata.

Relates: elastic#88494
ywangd added a commit to ywangd/elasticsearch that referenced this pull request Oct 24, 2022
This PR removes the deprecated Authentication#getUser method and
replaces its usages with #getEffectiveSubject#getUser.

Relates: elastic#88494
ywangd added a commit that referenced this pull request Oct 25, 2022
This PR removes the deprecated Authentication#getMetadata method and
replaces its usages with #getAuthenticatingSubject#getMetadata.

Relates: #88494
ywangd added a commit that referenced this pull request Oct 25, 2022
This PR removes the deprecated Authentication#getUser method and
replaces its usages with #getEffectiveSubject#getUser.

Relates: #88494
ywangd added a commit to ywangd/elasticsearch that referenced this pull request Oct 25, 2022
This PR removes the deprecated Authentication#getAuthenticatedBy method
and replaces its usages with #getAuthenticatingSubject#getRealm

Relates: elastic#88494
ywangd added a commit that referenced this pull request Oct 25, 2022
This PR removes the deprecated Authentication#getAuthenticatedBy method
and replaces its usages with #getAuthenticatingSubject#getRealm

Relates: #88494
ywangd added a commit to ywangd/elasticsearch that referenced this pull request Oct 26, 2022
This PR removes the deprecated Authentication#getLookedUpBy method.
Its usages are replaced by either isRunAs or
getEffectiveSubject#getRealm or their combinations depending on the
actual context.

Relates: elastic#88494
ywangd added a commit that referenced this pull request Oct 26, 2022
This PR removes the deprecated Authentication#getLookedUpBy method.
Its usages are replaced by either isRunAs or
getEffectiveSubject#getRealm or their combination depending on the
actual context.

Relates: #88494
elasticsearchmachine pushed a commit that referenced this pull request Dec 11, 2022
This PR removes the deprecated Authentication#getSourceRealm method. Its
usage is mostly replaced by #getEffectiveSubject#getRealm except for
ApiKeyService#getCreatorRealmName and ApiKeyService#getCreatorRealmType
which has a special handling to return authenticatingSubject's realm
when run-as lookup fails. This is to maintain BWC since these
information is used in audit logs. Therefore, even it is technically
incorrect, we should not break it without careful planning.

Relates: #88494
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) >refactoring :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) Team:Security Meta label for security team v8.4.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Revisit and rationalise the Authentication class
4 participants