Check services in legacy security providers - #1197
Conversation
376f20b to
ca852dd
Compare
540ae55 to
d9b23db
Compare
9280b3d to
b08544a
Compare
|
I moved the mock provider in the |
Legacy security providers do not use the more modern getService() and putService() methods, but rather other more map based methods. Further checks are added to restrict through RestrictedSecurity the registration and retrieval of services through legacy providers. Tests are, also, added to verify these checks. Signed-off-by: Kostas Tsiounis <kostas.tsiounis@ibm.com>
b08544a to
76ec020
Compare
08b7050 to
d66c1ce
Compare
9ecf603 to
83447a7
Compare
| Set<Map.Entry<Object, Object>> entrySet = entrySet(); | ||
| Collection<Object> valuesToReturn = new ArrayList<>(entrySet.size()); | ||
| for (Map.Entry<Object, Object> entry : entrySet) { | ||
| if (checkRestrictedSecurityKey(entry.getKey())) { | ||
| // We're in restricted security mode which allows this service | ||
| // or provider info, so add it to list of values to be returned. | ||
| valuesToReturn.add(entry.getValue()); | ||
| } | ||
| } | ||
| return Collections.unmodifiableCollection(valuesToReturn); |
There was a problem hiding this comment.
The set should have already been filtered by entrySet(); this only needs to collect the values:
return entrySet().stream().map(entry -> entry.getValue()).toList();There was a problem hiding this comment.
Changed to suggestion mostly. I changed the last part to be collect(Collectors.toUnmodifiableList()) instead of toList() since that's what the method is supposed to return.
|
|
||
| import java.security.Provider; | ||
|
|
||
| public class LegacyProvider extends Provider { |
There was a problem hiding this comment.
test/lib/jdk/test/lib/LegacyProvider.java:33: warning: [serial] serializable class LegacyProvider has no definition of serialVersionUID
public class LegacyProvider extends Provider {
^
There was a problem hiding this comment.
I didn't see any of the other helper classes have anything to imitate. How do you think I should handle this? Just assign 1L since it won't be actually serialized?
There was a problem hiding this comment.
You can pick a UID at random; eclipse suggested this:
private static final long serialVersionUID = 5997431841873045817L;f9860c3 to
95bc3c1
Compare
| import java.util.function.BiConsumer; | ||
| import java.util.function.BiFunction; | ||
| import java.util.function.Function; | ||
| import java.util.stream.Collectors; |
There was a problem hiding this comment.
Please move this after line 48 (which is out of place, but from upstream).
| checkInitialized(); | ||
|
|
||
| if (RestrictedSecurity.isEnabled()) { | ||
| return entrySet().stream().map(entry -> entry.getValue()).collect(Collectors.toUnmodifiableList()); |
There was a problem hiding this comment.
Please use the toList() convenience method (which promises an unmodifiable list):
return entrySet().stream().map(entry -> entry.getValue()).toList();| } | ||
| return super.get(key); |
There was a problem hiding this comment.
Please add a blank line between lines 671 and 672, like other updated methods.
| private Object implPut(Object key, Object value) { | ||
| if (!checkLegacy(key)) return null; | ||
|
|
||
| if (!canRestrictedSecurityServiceBeRegistered(key)) { |
There was a problem hiding this comment.
Please explain the rules regarding which of isRestrictedSecurityServiceAllowed() and canRestrictedSecurityServiceBeRegistered() should be used. implCompute() uses the former, while implPut(), implReplace() and implReplaceAll() use the latter. This doesn't appear to be consistent.
There was a problem hiding this comment.
The idea is that when doing put() or replace() you already know the value to be inserted, so you are not actually retrieving any information and should thus be allowed to be used from any place of your code (i.e., canRestrictedSecurityServiceBeRegistered()). But with compute() and all of its variants, one can use it to just retrieve an existing value, which should only be allowed from the specific class defined in the constraint (i.e., isRestrictedSecurityServiceAllowed()).
What I just noticed though is that merge() does a thing very similar to compute(), so I might have to switch that to behave like it.
There was a problem hiding this comment.
I don't think the result is consistent yet; examples include:
keys()andkeySet()may yield a different elements than the keys inentrySet()forEach()exposes entries that would not be included inentrySet()merge()andput()allow storing entries that would not be permitted viacompute*()
There was a problem hiding this comment.
I don't think the result is consistent yet; examples include:
keys()andkeySet()may yield a different elements than the keys inentrySet()forEach()exposes entries that would not be included inentrySet()merge()andput()allow storing entries that would not be permitted viacompute*()
Regarding each of the points:
- The whole idea is to restrict getting services that potentially should not be allowed in a specific setting. Getting the keys doesn't give you access to any such services, thus the decision to not restrict
keys()andkeySet(). I could restrict that too, I just think it might be defeating the purpose. I would also need to add a debug path for cases where we want to see what is available through the provider. - I actually missed that. I will update
forEach(). - Like I mentioned before, I will update
merge()to matchcompute(), but I think there should be a difference between them andput(), because we need to allow users to register from wherever but only retrieve from explicitly specified classes. I know that I'm hindering the functionality ofcompute()andmerge()that could be used to just update/register new values, unless I manually check whether the supplied BiFunction is a tautology (i.e., just returns the same value) and it's just used to get a value. Do you think that would make sense to do?
There was a problem hiding this comment.
The whole idea is to restrict getting services that potentially should not be allowed in a specific setting
Perhaps I'm missing something. How does restricting access to keys or values affect access to services offered by a given provider?
There was a problem hiding this comment.
Perhaps I'm missing something. How does restricting access to keys or values affect access to services offered by a given provider?
This whole change was inspired by a use case of someone using a legacy Kafka provider, where services were inserted using put() and then retrieved using get() and subsequently being initialized through reflection. In these cases RestrictedSecurity wasn't able to enforce constraints from the loaded profile. Of course, we couldn't just check these two methods.
As far as keys() goes, my initial thought process was that it could not possibly affect the aforementioned scenario. I will, however, restrict it too for consistency reasons.
There was a problem hiding this comment.
If one has access to a service to be able to insert it via put() it's too late to prevent distribution of that service to others.
It's not clear that it's possible to completely restrict access to services by participants that employ reflection. The most direct route might be to reflect Properties.map and operate directly on that object, bypassing anything we might do the implementation of Provider.
How much effort should we expend on this when it can always be circumvented?
|
|
||
| private boolean canRestrictedSecurityServiceBeRegistered(Object key) { | ||
| Service service = createServiceFromKey(key); | ||
| return ((service == null) || RestrictedSecurity.canServiceBeRegistered(service)); |
There was a problem hiding this comment.
Please remove the outermost parentheses, here and on line 1078.
| * | ||
| * =========================================================================== | ||
| */ | ||
|
|
|
|
||
| import java.security.Provider; | ||
|
|
||
| public class LegacyProvider extends Provider { |
There was a problem hiding this comment.
You can pick a UID at random; eclipse suggested this:
private static final long serialVersionUID = 5997431841873045817L;| * the RestrictedSecurity mode. | ||
| */ | ||
| public class LegacyProvider extends Provider { | ||
| public LegacyProvider() { |
There was a problem hiding this comment.
This triggers "this-escape" warnings; making the class final addresses that.
|
How does this, and |
Legacy security providers do not use the more modern getService() and putService() methods, but rather other more map based methods.
Further checks are added to restrict through RestrictedSecurity the registration and retrieval of services through legacy providers.
Tests are, also, added to verify these checks.
Signed-off-by: Kostas Tsiounis kostas.tsiounis@ibm.com