New pips, second try - #18
Conversation
Adding X509ExtractorPIP and PolicyNamesPIP with corresponding *IniConfigurationParser classes and *Test classes. PolicyNamesPIP makes use of a sub package policynamespip for a caching the info files. This solves argus-authz#15.
Add new PIPs including default config to pepd.ini
junit framework is deprecated in favour of junit tests indicated with @test etc. This requires a newer version of junit.
Add two new policy files which combine the standard IGTF policies, in order to simplify Argus PAP policy matching: WLCG VOs can be matched using policy-aspen-birch-cedar-dogwood while other VOs need to combine with policy-aspen-birch-cedar.
Before trying to get the modification time, test whether the file actually exists.
Introduce intermediate class UpdatingPolicyNamesCache that takes care of the updating of the PolicyNamesCache (formerly PolicyNamesPIPCache). The PIP itself now does not need to keep track of that. Remove the unused and non-trivial possibility of updating the trust dir for a running PIP.
Implement proper read/write locks to prevent memory corruption.
andreaceccanti
left a comment
There was a problem hiding this comment.
Hi Mischa,
I've reviewed the code more deeply (see comments).
In general things look good, but there are things that should be fixed to align it better to Java recommendations for code and other stuff.
The main comment about the updatingCache is about delegating the update responsibility to a background thread. If you don't want to implement that I can do it.
Thanks!
| <!-- .info files --> | ||
| <fileSet> | ||
| <directory>src/main/infofiles</directory> | ||
| <outputDirectory>/etc/grid-security/certificates</outputDirectory> |
There was a problem hiding this comment.
I don't like very much the idea that the info files end up in /etc/grid-security/certificates, and that
Argus owns stuff in that directory.
Are these files argus specific? If so, they could live in /etc/argus. If not, they shouldn't be packaged in Argus.
There was a problem hiding this comment.
they are indeed Argus specific, in that they don't (and will not) come from IGTF, but they do have the status of policy .info files in the same way as the policy-igtf-classic.info. Having them in /etc/argus will not work therefore, since they would not be found. The reason for having them in the first place, is to prevent us from needing separate permit lines for each individual policy (e.g. classic, mics, slcs and iota) but instead making a single entry with e.g. policy-aspen-birch-cedar-dogwood.
What we could do is put the file itself in /etc/argus/... and make a symlink into the /etc/grid-security/certificates directory.
There was a problem hiding this comment.
Since these files are fully argus-specific, then it's up to the PIP to look them up in whatever directory we choose, or am I missing something? I would go for something into /etc/argus/, but also /etc/grid-security/argus/ would be fine for me (following an approach similar to /etc/grid-security/vomsdir).
There was a problem hiding this comment.
I've discussed with DavidG and we could try to push them via the EGI policy packages (such as ca-policy-egi-core-1.79-1.noarch.rpm), which are specific to EGI, and actually also produced by David with an EGI hat instead of IGTF hat. The point is that the PIP looks in the 'trustDir' (i.e. normally /etc/grid-security/certificates) for all the info files, and hence that's also where these files should end up, either as file or as symlink. Any other directory does not make sense since they are the same sort of file from the PIP perspective. They are (reasonably) normal info files, only not IGTF.
There was a problem hiding this comment.
The point is that the PIP looks in the 'trustDir' (i.e. normally /etc/grid-security/certificates) for all the info file
The point is: are these files meant to be used by other services? If not, they should be packaged in an argus-owned directory, and the PIP modified to look into this directory.
I think the fact that the policy files and certificates must live in the same dir is only a limitation of the current PIP policy lookup implementation, or there's more to it?
There was a problem hiding this comment.
First of all, they might be used by other services, in that sense they're not specific to Argus, hence the suggestion to ship them with the EGI policy packages. For most services they are probably not needed, Argus needs them due to the limitation that we can not make logical OR statements in a permit rule, something along the lines of
rule permit {
vo="atlas"
{ ca-policy-names="policy-igtf-classic" OR
ca-policy-names="policy-igtf-mics" OR
ca-policy-names="policy-igtf-slcs" OR
ca-policy-names="policy-igtf-iota"
}
}
Furthermore, info files have always been in the same directory as the pem files, that includes policy info files such as policy-igtf-classic.info but also the info files for the CAs themselves.
There was a problem hiding this comment.
Ok, so it seems we have an agreement that these files should be packaged outside of the Argus PEPD, in a different package, provided by EGI, so please remove them from the assembly file.
There was a problem hiding this comment.
done. Same thing for the src/main/assembly/standalone.xml
| throws PIPProcessingException | ||
| { | ||
| long t0=System.nanoTime(); | ||
| boolean pipprocessed=false; |
There was a problem hiding this comment.
Java favours camelCase, so this should be pipProcessed.
| { | ||
| long t0=System.nanoTime(); | ||
| boolean pipprocessed=false; | ||
| String issuerdn=null; |
There was a problem hiding this comment.
issuerdn -> issuerDn
| for (Attribute attr: attributes) { | ||
| if (ATTR_X509_ISSUER.equals(attr.getId())) { | ||
| // Take first value (it should be singlevalued) | ||
| Object tmp = attr.getValues().iterator().next(); |
There was a problem hiding this comment.
tmp is a bad name, probably x509IssuerAttr is a better alternative
| } | ||
|
|
||
| // Look for the issuerdn in the .info files | ||
| String[] policynames=new String[0]; |
There was a problem hiding this comment.
policynames -> policyNames
| read.lock(); | ||
| try { | ||
| // Protect against empty cache | ||
| if (cache == null) { |
There was a problem hiding this comment.
Is there really a case when the cache can be null?
There was a problem hiding this comment.
Probably not, perhaps this should be an assertion instead, but in any case I don't like NPEs...
There was a problem hiding this comment.
if you don't like NPEs, you should use an Optional for the cache.
I would drop this, since there's really no chance, if the code is written properly, that the cache is null.
| // First check (with appropriate read lock) whether we need to do | ||
| // anything. If so, create a new cache. | ||
| read.lock(); | ||
| try { |
There was a problem hiding this comment.
I would drop this in favour of a separate thread that just takes the write lock according to a specified period
There was a problem hiding this comment.
I agree with the separate thread, but the write lock would also block use of the old cache which is still valid... It's not really an issue, since updating the set won't take that long, but still...
There was a problem hiding this comment.
That wouldn't be a problem
| // out-of-date (i.e. hasn't been updated in the mean time by another | ||
| // thread | ||
| if (newCache==null) | ||
| // This probably never happens: exception will have been thrown |
There was a problem hiding this comment.
We should drop the code if it never happens
There was a problem hiding this comment.
It probably never happens, but as C programmer I really don't like NPEs.
| // This probably never happens: exception will have been thrown | ||
| log.warn("New cache is null, continuing to use old one"); | ||
| else if (cache.getLifeTime() < update_interval) | ||
| log.info("Other thread appears to have already updated cache"); |
There was a problem hiding this comment.
this can also go away if you use the background updater thread
| String message= e.getMessage(); | ||
| log.debug("EXPECTED: " + message); | ||
| log.debug("GOT ("+message.indexOf(element)+"): " + element); | ||
| assertTrue("PIPProcessingException message does not contain: " + element, message.indexOf(element) >= 0); |
There was a problem hiding this comment.
instead of these general assertTrue/assertFalse, which produce ugly output difficoult to understand, people use the hamcrest matchers library and the assertThat method, which makes the test and output more readable
There was a problem hiding this comment.
Could I ask you to rewrite those? I've mostly copied from how things are currently done in the other PIPs. I agree fully that it's ugly, but then we should change it in all.
There was a problem hiding this comment.
I agree we should have consistency, but my objective here is to ensure that new code that enters to the codebase satisfies certain requirements. So please try the migration to hamcrest, and if you have questions/doubts I will be happy to help
There was a problem hiding this comment.
I've replaced it in a way similar to https://github.com/italiangrid/voms-api-java/blob/master/src/test/java/org/italiangrid/voms/test/TestVOMSESLineParser.java#L70-L73
so using assertThat with a CoreMatcher. I had to update the junit dependency to 4.11 to get it working.
Is this what you had in mind?
Fixing comments from argus-authz#18 - camelCase - use slf4j placeholders - use String.format() - use {} in all blocks - rethrow exceptions (in certain cases) - log some exceptions before throwing them. - use TimeUnit to convert hours to millisecs - rename some vars for clarity
Fixed one more block missing braces
Make Logger for each PIP private static final.
Use assertThat and a hamcrest matcher instead of a not so readable assertTrue for testing the message of a exception. assertThat needs a slightly newer junit.
The two meta policy info files policy-aspen-birch-cedar-dogwood.info and policy-aspen-birch-cedar.info will be packaged in an external package.
Hi Andrea,
hereby a new pull request.