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

WW-5350 Refactor SecurityMemberAccess #780

Merged
merged 6 commits into from
Nov 12, 2023
Merged

WW-5350 Refactor SecurityMemberAccess #780

merged 6 commits into from
Nov 12, 2023

Conversation

kusalk
Copy link
Member

@kusalk kusalk commented Nov 5, 2023

WW-5350

See comments.

I didn't deprecate methods for which I've changed the signature as from what I can tell SecurityMemberAccess is not considered public API (no reasonable situation in which a Struts applications would need to override or instantiate the class themselves, nor is it a defined extensible bean) (WW-5343 aims to make it a configurable bean and thus public API).

final int memberModifiers = member.getModifiers();
final Class<?> memberClass = member.getDeclaringClass();
// target can be null in case of accessing static fields, since OGNL 3.2.8
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
Copy link
Member Author

Choose a reason for hiding this comment

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

Wanted to be a bit more deliberate about how we handle the arguments in case OGNL behaviour changes

}

if (disallowProxyMemberAccess && ProxyUtil.isProxyMember(member, target)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Extract this into its own protected method for consistency

LOG.warn("Access to non-public [{}] is blocked!", member);
return false;
}

if (!checkStaticFieldAccess(member, memberModifiers)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed redundant argument

return false;
}

if (!checkPublicMemberAccess(memberModifiers)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Tried to standardise around just passing the object and/or member to these protected methods

/**
* @return {@code true} if member access is allowed
*/
protected boolean checkExclusionList(Object target, Member member) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Extracted all the exclusion list checks into this method

return false;
}

if (disallowDefaultPackageAccess) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Extracted this into its own method

LOG.warn("Access to static field [{}] is blocked!", member);
return false;
}

// it needs to be before calling #checkStaticMethodAccess()
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 essentially an exemption to checkStaticMethodAccess so I moved it within that method - we shouldn't be relying on method call order here

&& isStatic(member)
&& member instanceof Method
&& member.getName().equals("values")
&& ((Method) member).getParameterCount() == 0;
Copy link
Member Author

Choose a reason for hiding this comment

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

Closed a minor hole where another static values method could also be exempted

return allowStaticFieldAccess;
} else {
protected boolean checkStaticFieldAccess(Member member) {
if (allowStaticFieldAccess) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Bypass computation if static field access is permitted

throw new IllegalArgumentException("Target does not match member!");
if (target != null) {
// Special case: Target is a Class object but not Class.class
if (Class.class.equals(target.getClass()) && !Class.class.equals(target)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Validate and throw exceptions if arguments are not what we expect as the following logic depends on these assumptions to be accurate

Copy link
Member

@lukaszlenart lukaszlenart left a comment

Choose a reason for hiding this comment

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

I'm good, thanks for all the changes! And as you said SecurityMemberAccess shouldn't be used by users directly so maybe marking it final would be a good idea?

@kusalk
Copy link
Member Author

kusalk commented Nov 12, 2023

@lukaszlenart I'm going to make it extensible as part of WW-5343 so that applications can add even stronger checks if they so desire - so will leave it not final

@kusalk kusalk merged commit 9d6fe74 into master Nov 12, 2023
6 of 7 checks passed
@kusalk kusalk deleted the WW-5350-allowlist branch November 12, 2023 08:56
Copy link

sonarcloud bot commented Nov 12, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

76.2% 76.2% Coverage
0.0% 0.0% Duplication

idea Catch issues before they fail your Quality Gate with our IDE extension sonarlint SonarLint

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants