Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
389   975   146   38.9
236   560   0.4   10
10     15.5  
1    
 
 
  ShibPermisRBAC       Line # 118 389 146 36.2% 0.36220473
 
No Tests
 
1   
2    /*
3    * Copyright (c) 2006, University of Kent
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are met:
8    *
9    * Redistributions of source code must retain the above copyright notice, this
10    * list of conditions and the following disclaimer.
11    *
12    * Redistributions in binary form must reproduce the above copyright notice,
13    * this list of conditions and the following disclaimer in the documentation
14    * and/or other materials provided with the distribution.
15    *
16    * 1. Neither the name of the University of Kent nor the names of its
17    * contributors may be used to endorse or promote products derived from this
18    * software without specific prior written permission.
19    *
20    * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21    * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23    * PURPOSE ARE DISCLAIMED.
24    *
25    * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32    * POSSIBILITY OF SUCH DAMAGE.
33    *
34    * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE
35    * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS
36    * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS
37    * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH
38    * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH
39    * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY
40    * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE
41    * SERIOUS FAULTS, IN THIS SOFTWARE.
42    *
43    * 5. This license is governed, except to the extent that local laws
44    * necessarily apply, by the laws of England and Wales.
45    *
46    */
47   
48    package issrg.shibboleth;
49    import issrg.ac.AttributeCertificate;
50    import issrg.aef.SamplePKI;
51    import issrg.pba.ParsedToken;
52    import issrg.pba.PbaException;
53    import issrg.pba.Subject;
54    import issrg.pba.rbac.BadURLException;
55    import issrg.pba.rbac.CustomisePERMIS;
56    import issrg.pba.rbac.LDAPDNPrincipal;
57    import issrg.pba.rbac.PermisAction;
58    import issrg.pba.rbac.PermisRBAC;
59    import issrg.pba.rbac.PermisTarget;
60    import issrg.pba.rbac.PolicyFinder;
61    import issrg.pba.rbac.SignatureVerifier;
62    import issrg.pba.rbac.URLHandler;
63    import issrg.pba.rbac.URLPrincipal;
64    import issrg.pba.rbac.policies.TargetOutOfDomainException;
65    import issrg.pba.rbac.x509.RepositoryACPolicyFinder;
66    import issrg.pba.repository.UserEntry;
67    import issrg.simplePERMIS.SimplePERMISPolicyFinder;
68   
69    import java.io.BufferedReader;
70    import java.io.FileInputStream;
71    import java.io.FileNotFoundException;
72    import java.io.IOException;
73    import java.io.InputStreamReader;
74    import java.security.Principal;
75    import java.util.Hashtable;
76    import java.util.Vector;
77   
78    import javax.naming.directory.Attributes;
79   
80    import org.apache.log4j.BasicConfigurator;
81    import org.apache.log4j.FileAppender;
82    import org.apache.log4j.Level;
83    import org.apache.log4j.Logger;
84    import org.apache.log4j.PatternLayout;
85   
86   
87    /**
88    * ShibPermisRBAC can be used in connection with
89    * Shibboleth. mod_permis Apache module collects the attributes that are made
90    * available by Shibboleth, then it uses PERMIS to make access control
91    * decisions.
92    *
93    * <p>This class uses the standard PermisRBAC, but uses
94    * ShibbolethAuthTokenParser to parse Shibboleth attributes and push them into
95    * getCreds method of PERMIS RBAC. The Role Assignment Policy should specify
96    * what IdPs can assign what attributes to the whole world, since the identity
97    * of the holder of the attributes is not known (is assumed "the whole world",
98    * noted as a null LDAP DN).
99    *
100    * <p>Shibboleth attributes are encoded by mod_permis as Shibboleth URLs, the
101    * format of which is described in ShibbolethPrincipal. The attributes are
102    * parsed to extract the attribute type (which must match one of the role types
103    * defined in PERMIS Policy - the OID is insignificant in this case), the
104    * attribute value, and the scope of the attribute is used as the issuer
105    * identifier. The only exception is that if the attribute is called
106    * attributeCertificateAttribute;binary, it is not decoded, but is pushed as
107    * is into PermisRBAC getCreds method and the usual X.509 AC parsing semantics
108    * apply.
109    *
110    * <p>This class maintains a hashtable of PermisRBAC objects referenced by the
111    * OID of the policy. This way it is possible to serve multiple policies in
112    * different circumstances, yet load and initialise them all once.
113    *
114    * @authors A.Otenko, W.Xu, Z.Q.Wu
115    *
116    * @see ShibbolethPrincipal
117    */
 
118    public class ShibPermisRBAC {
 
119  1 toggle static { // add ShibbolethURLHandler only once when the JVM starts
120  1 try {
121  1 CustomisePERMIS
122    .addURLHandler("issrg.shibboleth.ShibbolethURLHandler");
123    } catch (ClassNotFoundException cnfe) {
124  0 cnfe.printStackTrace(System.err);
125    }
126    }
127   
128    private static final issrg.utils.Version version = new issrg.utils.Version(
129    "issrg/shibboleth/version", "saam");
130   
131    public static final int OK = 0;
132   
133    public static final int DENY = 1;
134   
135    public static final int DECLINED = 2;
136   
137    public static final int debugLevel =0;
138   
139    private static String configFilename = "saam.cfg";
140   
141    private static String logFile = "logs/permis.log";
142   
143    private static String patternString = "%d{yyyy MMM dd HH:mm:ss} [%c] -%-5p- %m%n";
144   
145    private static boolean bPermisPull = false;
146   
147    private static String permisDebugFlag = "INFO";
148   
149    private ShibbolethAuthzTokenParser shibParser = new ShibbolethAuthzTokenParser();
150   
151    private String AC_attribute; // the name of the AC attribute to expect
152   
153    private PermisRBAC pbaApi = null;
154   
155    private static Hashtable hht = new Hashtable();
156   
157    private static Logger root =Logger.getRootLogger();
158    private static Logger logger = Logger
159    .getLogger("issrg.shibboleth.ShibPermisRBAC");
160   
161   
162    private boolean isXML = false;
163    private boolean crypto = false;
164    /**
165    * This constructor wraps a ShibPermisRBAC around a given instance of
166    * PermisRBAC. The constructor is made private so that ShibPermisRBACs
167    * are only constructed through the static method (that does the
168    * accounting of ShibPermisRBACs for policies with different OIDs).
169    *
170    * @param pbaApi - the PermisRBAC object to wrap around
171    *
172    * @see #getShibPermisRBAC
173    */
 
174  0 toggle private ShibPermisRBAC(PermisRBAC pbaApi) {
175  0 this.pbaApi = pbaApi;
176   
177    }
178   
179    /**
180    * The contructor of the class
181    *
182    * @param pconf
183    * the specified Permis configuration: {policy OID, SOA DN,
184    * Policy LDAP
185    * URL, AC Attribute, Root CA PKC file name, PKC attribute}
186    * @param pACLoS
187    * the locations where to pull ACs from in pull mode; can be
188    * null in push mode
189    */
 
190  2 toggle public ShibPermisRBAC(String[] pConf, String[] pACLoS) {
191   
192  2 try{
193  2 if (logger.isInfoEnabled()) {
194  1 logger.info("ShibPermisRBAC v" + version.getVersion());
195    }
196  2 String SOA = pConf[1]; // permis_szPoIss;
197  2 String oID = pConf[0]; // permis_szPoId;
198  2 String LDAP = pConf[2]; // permis_szPoLo
199  2 AC_attribute = pConf[3]; // permis_szACAttr;
200  2 byte[] pkc = loadPKC(pConf[4]); // permis_szRootCA);
201  2 String PKC_attribute = pConf[6]; // permis_szPKCAttr
202   
203  2 if (logger.isDebugEnabled()) {
204  0 logger.debug("Recieved Policy Details");
205  0 logger.debug("SOA : " + SOA);
206  0 logger.debug("OID : " + oID);
207  0 logger.debug("Policy Location : " + LDAP);
208  0 logger.debug("PKC certificate location: " + pConf[4]);
209  0 logger.debug("AC Attribute : " + AC_attribute);
210  0 logger.debug("PKC Attribute : " + PKC_attribute);
211    }
212   
213  2 if (LDAP.toLowerCase().startsWith("ldap://")){
214  0 if (SOA.intern() == "null"){
215  0 logger.error("In order to use LDAP the SOA must be set");
216   
217    }
218  0 if (oID.intern() == "null"){
219  0 logger.error("In order to use LDAP the OID must be set");
220    }
221    }
222   
223   
224  2 if (LDAP.toLowerCase().endsWith(".xml")) {
225  2 isXML = true;
226  0 if (logger.isDebugEnabled())logger.debug("XML policy is being used");
227    }else{
228  0 if (logger.isDebugEnabled())logger.debug("AC policy is being used");
229    }
230   
231   
232   
233  2 if (pkc != null){
234  0 if (logger.isDebugEnabled()){
235  0 logger.debug("A PKC certificate has been found so Cryptography will be used");
236    }
237  0 crypto = true;
238   
239    }else{
240  2 if (logger.isDebugEnabled()){
241  0 logger.debug("NO PKC certificate has been found so Cryptography will not be used");
242    }
243    }
244   
245  2 if (logger.isDebugEnabled()){
246  0 logger.debug("Checking for security classes");
247    }
248  2 Class pkcRepository = null;
249  2 Class defaultVerifier = null;
250  2 Class verifier = null;
251  2 try{
252  2 pkcRepository = Class.forName("issrg.security.PKCRepository");
253  2 defaultVerifier = Class.forName("issrg.security.DefaultVerifier");
254  2 verifier = Class.forName("issrg.security.Verifier");
255  2 if (logger.isDebugEnabled()){
256  0 logger.debug("Security Classes loaded");
257    }
258    }catch(ClassNotFoundException cnfe){
259  0 logger.warn(cnfe.getMessage()+" - could not find a security class");
260    }
261   
262  2 if (AC_attribute!=null) {
263  2 logger.debug("Setting AC attribute");
264  2 CustomisePERMIS.setAttributeCertificateAttribute(AC_attribute);
265   
266  2 logger.debug("AC attribute set");
267    }else{
268  0 logger.debug("No AC attribute was specified");
269    }
270  2 if (PKC_attribute!=null){
271  2 logger.debug("Setting PKC attribute");
272  2 CustomisePERMIS.setUserCertificateAttribute(PKC_attribute);
273  2 logger.debug("PKC attribute set");
274    }else{
275  0 logger.debug("No PKC attribute was specified");
276    }
277   
278  2 issrg.utils.repository.AttributeRepository r = null;
279  2 issrg.utils.repository.VirtualRepository vr = null;
280   
281  2 if (!bPermisPull || pACLoS == null){ pACLoS = new String[0];
282    // now pACLoS is not null,
283    // and pACLoS.length==0, if pull is not used
284  2 if (logger.isDebugEnabled()){
285  0 logger.debug("pACLoS length =" +pACLoS.length);//engineering
286   
287    }
288    }
289   
290  2 String LDAPS[] = new String[pACLoS.length ];
291   
292    // assume the strings without protocol are filenames
293   
294   
295   
296   
297  2 for (int i=0; i<pACLoS.length; ++i) {
298  0 LDAPS[i] = pACLoS[i];
299  0 if(logger.isDebugEnabled()){
300   
301  0 logger.debug("AC Location = "+LDAPS[i]);
302   
303   
304    }
305    }
306   
307    // and the rest of LDAPS are AC Locations, if any
308   
309  2 issrg.utils.repository.AttributeRepository [] reps = new issrg.utils.repository.AttributeRepository[LDAPS.length];
310   
311  2 for (int i=0; i<reps.length; i++){
312  0 try{
313  0 reps[i] = URLHandler.getRepositoryByURL(LDAPS[i]);
314   
315   
316  0 if(logger.isDebugEnabled())logger.debug("Repository "+ (i)+ " loaded");
317   
318   
319    }catch(BadURLException bue){
320   
321  0 if(logger.isEnabledFor(Level.ERROR))logger.error("Repository "+(i )+" failed: "+bue.getMessage());
322  0 if(logger.isEnabledFor(Level.ERROR))logger.error(bue.fillInStackTrace());
323   
324    }
325    }
326   
327   
328    // now all reps are Repositories, as initialised using URLs.
329    // Some of reps may be null, if they failed to initialise
330   
331  2 r = new issrg.utils.repository.MultiRepository(reps);
332   
333  2 SignatureVerifier sv = null;
334  0 if (logger.isDebugEnabled())logger.debug("Initalising Cryptography");
335  2 if (pkc!=null){
336  0 try{
337  0 if (verifier==null || defaultVerifier==null || (r!=null && pkcRepository==null)) throw new NoSuchMethodException("Security classes are missing");
338   
339  0 Object ds = defaultVerifier.newInstance();
340  0 defaultVerifier.getMethod("setRootCA", new Class[]{new byte[0].getClass()}).invoke(ds, new Object[]{pkc});
341   
342  0 if (logger.isDebugEnabled())logger.debug("Root CA set");
343  0 if (r!=null){
344  0 Object pRepository = pkcRepository.getConstructor(new Class[]{issrg.utils.repository.AttributeRepository.class}).newInstance(new Object[]{r});
345   
346  0 defaultVerifier.getMethod("setPKCRepository", new Class[]{pkcRepository}).invoke(ds, new Object[]{pRepository});
347  0 if (logger.isDebugEnabled())logger.debug("Cryptography Initalised");
348  0 } else if(logger.isEnabledFor(Level.WARN))logger.warn("No repositories could be used to retrieve PKCs");
349  0 sv = new SamplePKI();
350    }catch(NoSuchMethodException nsme){
351   
352  0 if(logger.isEnabledFor(Level.WARN))logger.warn("Failed to set up security: "+nsme.getMessage());
353    }
354    }else{
355    // this is pretty serious. have to notify irrespective of the
356    // debug level
357  2 if (logger.isDebugEnabled()){
358  0 logger.debug("No Root CA specified - assuming no signature verification");
359    }
360    }
361  2 PolicyFinder pf = null;
362  2 try{
363  2 if (isXML == true){
364  0 if (logger.isDebugEnabled())logger.debug("Creating a SimplePERMISPolicyFinder [" +LDAP +"]" );//engineering
365  2 pf = new SimplePERMISPolicyFinder(LDAP);
366   
367    }else{
368  0 if (logger.isDebugEnabled())logger.debug("Creating a RepositryACPolicyFinder");//engineering
369   
370  0 issrg.utils.repository.AttributeRepository policyrep = URLHandler.getRepositoryByURL(LDAP) ;
371   
372   
373  0 pf = new RepositoryACPolicyFinder(policyrep, oID,
374    new LDAPDNPrincipal(SOA), sv);
375   
376    }
377    }catch(Exception e){
378  0 logger.error("There was a problem creating the Policy Finder object");
379    }
380  2 issrg.pba.rbac.CustomisePERMIS.configureX509Flavour();
381   
382  2 int a = 0;
383  0 if (logger.isDebugEnabled())logger.debug("Creating the Decison Engine");
384   
385  2 pbaApi = new PermisRBAC(pf, r, null);
386  2 if (pbaApi != null){
387  0 if (logger.isDebugEnabled())logger.debug("Success the Decison Engine Has been created");
388    }else{
389  0 if (logger.isEnabledFor(Level.ERROR))logger.error("Creation of the Decision Engine Failed");
390    }
391  2 shibParser.setAuthTokenParsingRules(pf.getParsedPolicy().getAuthTokenParsingRules());
392    }catch (Throwable th){
393  0 if (logger.isEnabledFor(Level.ERROR)){
394  0 logger.error("Failed to initialise: " + th.getMessage());
395  0 logger.error(th.fillInStackTrace());
396    }
397    }
398   
399   
400    }
401    /**
402    * Get a ShibPermisRBAC object. If a ShibPermisRBAC object corresponding
403    * to
404    * oid already exists, return the object. Otherwise, create a new
405    * ShibPermisRBAC object.
406    *
407    * @param pconf
408    * the specified Permis configuration: {policy OID, SOA DN,
409    * URL of the Repository with the Policy,
410    * AC Attribute, Root CA PKC file name, PKC attribute}
411    *
412    * @return a ShibPermisRBAC object
413    */
 
414  9 toggle public static ShibPermisRBAC getShibPermisRBAC(String[] pConf,
415    String[] pACLoS) {
416  9 ShibPermisRBAC sprbac = (ShibPermisRBAC) hht.get(pConf[0]);
417   
418  9 if (sprbac == null) {
419  1 sprbac = new ShibPermisRBAC(pConf, pACLoS);
420  1 hht.put(pConf[0], sprbac);
421    }
422   
423  9 return sprbac;
424    }
425   
426    /**
427    * Get the pbaApi reference of the specified ShibPermisRBAC object
428    *
429    * @return a pbaApi reference
430    */
 
431  9 toggle public PermisRBAC getPbaApi() {
432  9 return pbaApi;
433    }
434   
435    /**
436    * This method performs Permis Authorisation and returns OK, DENY or
437    * DECLINED, depending on the decision.
438    *
439    * <p>The method finds a ShibPermisRBAC instance corresponding to the
440    * policy OID or constructs a new one, then invokes authorise method on
441    * it to get the authorisation decision.
442    *
443    * @param creds - the ACs or Shibboleth
444    * attributes; use null, if Pull mode should be used
445    * @param originURL - the
446    * URL of the Origin; the hostname from the URL will be appended to
447    * the
448    * unscoped attributes
449    * @param userDN - the user dn; normally is an empty string in
450    * Shibboleth-Apache integration, but can be a real DN (the "dn"
451    * attribute is provided by IdP or the DN of the authenticated user
452    * in integration scenarios without Shibboleth)
453    * @param action - the action
454    * of accessing the Permis protected resource; normally one of the
455    * HTTP actions: "GET", "PUT", "POST", etc
456    * @param targetDN - the URL of
457    * the target
458    * @param pConf - the specified Permis configuration.
459    *
460    * @return an integer to represent success (OK=0), failed (DENY=1) or
461    * not applicable (DECLINED=2); the latter is returned if the target
462    * is out of Target Domain
463    */
 
464  9 toggle public static int permisAuth(String[] creds, String originURL,
465    String userDN, String action, String targetDN, String[] pConf,
466    String[] pACLoS)
467    {
468   
469  9 try
470    {
471    // Don't load the configuration file
472    // loadConfiguration(configFilename);
473   
474    // Use the hardcoded default path for log file
475  9 PatternLayout layout = new PatternLayout(patternString);
476  9 FileAppender appender = new FileAppender(layout, logFile, true);
477  9 root.removeAllAppenders();
478  9 root.addAppender(appender);
479    }
480    catch (Exception ex)
481    {
482  0 BasicConfigurator.configure();
483    }
484  9 if (pConf[5]== null){
485  0 pConf[5] = "";
486    }
487  9 if (pConf[5] != "" )
488    {
489  9 permisDebugFlag = new String(pConf[5]).toUpperCase();
490  9 root.setLevel(Level.toLevel(permisDebugFlag));
491   
492    }else{
493  0 root.setLevel(Level.INFO);
494    }
495   
496  9 if (logger.isInfoEnabled())
497    {
498  0 logger.info("*** NEW DECISION REQUEST ***");
499  0 logger.info("originURL: " + originURL);
500  0 logger.info("userDN: " + userDN);
501  0 logger.info("action: " + action);
502  0 logger.info("targetDN: " + targetDN);
503    }
504   
505   
506   
507  9 if (creds == null){
508  0 bPermisPull = true;
509  0 if(logger.isDebugEnabled())logger.debug("Pull mode selected");}
510    else{
511  9 bPermisPull = false;
512  0 if(logger.isDebugEnabled())logger.debug("Push mode selected");
513    }
514  9 try {
515   
516   
517   
518  0 if(logger.isDebugEnabled())logger.debug("Pull mode: "+ bPermisPull);//engineering
519   
520  9 if (creds != null) {
521  0 if(logger.isDebugEnabled())logger.debug("Number of Creds recieved: " + creds.length );
522  9 if(logger.isDebugEnabled()){
523  0 for (int i = 0; i < creds.length && creds[i] != null; ++i) {
524  0 logger.debug("creds " + (i+1) + " is: " + creds[i]);
525    }
526    }
527    } else {
528  0 if(logger.isDebugEnabled())logger.debug("No creds were recieved");
529    }
530   
531  9 if (pACLoS != null) {
532   
533  0 if(logger.isDebugEnabled())logger.debug("Number of AC Locations recieved: "
534    + pACLoS.length );
535  0 if(logger.isDebugEnabled()){
536  0 for (int i = 0; i < pACLoS.length && pACLoS[i] != null; ++i) {
537   
538  0 logger.debug("AC Location" + (i + 1) + " is: " + pACLoS[i]);
539    }
540    }
541    } else {
542  0 if(logger.isDebugEnabled())logger.debug("No AC Locations were provided");
543    }
544   
545   
546  9 if (logger.isDebugEnabled()){
547  0 logger.debug("Creating Decision Engine");
548    }
549  9 return getShibPermisRBAC(pConf, pACLoS).authorise(creds, originURL,
550    userDN, action, targetDN, pConf, pACLoS, debugLevel);
551    } catch (TargetOutOfDomainException toode) {
552   
553  0 if(logger.isEnabledFor(Level.ERROR))logger.error("Target out of domain: " + toode.getMessage());
554  0 if(logger.isEnabledFor(Level.ERROR))logger.error("", toode.fillInStackTrace());
555  0 if (logger.isInfoEnabled())logger.error("Decision returned: DECLINED");
556  0 return DECLINED;
557    } catch (PbaException pe) {
558  0 if(logger.isEnabledFor(Level.ERROR))logger.error("Invalid input: " + pe.getMessage());
559  0 if(logger.isEnabledFor(Level.ERROR))logger.error("", pe.fillInStackTrace());
560  0 if (logger.isInfoEnabled())logger.error("Decision returned: DENY");
561  0 return DENY;
562   
563    } catch (Throwable th) {
564   
565  0 if(logger.isEnabledFor(Level.ERROR))logger.error("Run-time error: ");
566  0 if(logger.isEnabledFor(Level.ERROR))logger.error("", th.fillInStackTrace());
567  0 if (logger.isInfoEnabled())logger.error("Decision returned: DENY");
568  0 return DENY;
569    } finally {
570   
571  0 if(logger.isInfoEnabled())logger.info("*** DECISION REQUEST PROCESSED ***\r\n");
572    }
573    }
574   
575    /**
576    * This method performs Permis Authorisation and returns OK, DENY or
577    * DECLINED, depending on the decision.
578    *
579    * @param creds - the ACs or Shibboleth
580    * attributes; use null, if Pull mode should be used
581    * @param originURL - the
582    * URL of the Origin; the hostname from the URL will be appended to
583    * the
584    * unscoped attributes
585    * @param userDN - the user dn; normally is an empty string in
586    * Shibboleth-Apache integration, but can be a real DN (the "dn"
587    * attribute is provided by IdP or the DN of the authenticated user
588    * in integration scenarios without Shibboleth)
589    * @param action - the action
590    * of accessing the Permis protected resource; normally one of the
591    * HTTP actions: "GET", "PUT", "POST", etc
592    * @param targetDN - the URL of
593    * the target
594    * @param pConf - the specified Permis configuration.
595    *
596    * @return an integer to represent success (OK=0), failed (DENY=1) or
597    * not applicable (DECLINED=2); the latter is returned if the target
598    * is out of Target Domain
599    */
 
600  9 toggle public int authorise(String[] creds, String originURL, String userDN,
601    String action, String targetDN, String[] pConf, String[] pACLoS,
602    int debugLevel) throws PbaException,
603    issrg.utils.RFC2253ParsingException {
604  9 if (logger.isDebugEnabled()){
605  0 logger.debug("Authorise called - setting up the decison for the PDP");
606    }
607   
608  9 PermisTarget pt = null;
609  9 PermisRBAC rbac = getPbaApi();
610  9 Subject s;
611   
612  9 if (rbac == null){
613  0 if(logger.isEnabledFor(Level.WARN)){logger.warn("PermisRBAC failed to initialise");}
614  0 if(logger.isInfoEnabled()){logger.info("Authorisation decision : DENY");}
615  0 return DENY; // PermisRBAC may fail to initialise, in which case
616    } // ShibPermisRBAC object will exist,
617    // but its pbaApi will be null
618   
619  9 try {
620   
621  0 if(logger.isDebugEnabled()){logger.debug("Creating Permis Target");}
622  9 pt = new PermisTarget(targetDN); // see if it is a URL or a DN
623  0 if(logger.isDebugEnabled()){logger.debug("Permis Target Created");}
624    } catch (issrg.pba.rbac.BadURLException bue) {
625  0 if(logger.isEnabledFor(Level.WARN)){logger.warn("TargetDN is a bad URL");}
626  0 if(logger.isInfoEnabled()){logger.info("Authorisation decision : DECLINED");}
627  0 return DECLINED; // we are not dealing with DNs in Apache - only
628    // URLs should be allowed
629    }
630  0 if(logger.isDebugEnabled()){logger.debug("TargetDN: " + targetDN);}
631   
632  9 try {
633  9 originURL = new URLPrincipal(originURL).getHost(); // sometimes
634    // originURL is
635    // null - e.g.
636    // when no
637    // Shibboleth is
638    // installed,
639    // and push mode
640    // is operated;
641    // so the domain
642    // will read
643    // "null" in
644    // such cases -
645    // but, in fact,
646    // PUSH
647    // shouldn't be
648    // used in such
649    // cases!
650  0 if(logger.isDebugEnabled()){logger.debug("Origin is a URL: "+ originURL);}
651    } catch (issrg.pba.rbac.BadURLException bde) {
652  0 if(logger.isDebugEnabled()){logger.debug("Origin is not a URL: " + originURL);}
653    // do nothing - ignore the error; if the originURL is not a valid
654    // URL, just use the whole URI then
655    }
656   
657   
658   
659   
660  9 java.security.Principal userP = new LDAPDNPrincipal(userDN);
661   
662   
663   
664   
665  9 UserEntry user = new UserEntry(userP);
666  0 if(logger.isDebugEnabled())logger.debug("UserEntry:" + user.getDN().getName());//technical
667  9 Object[] normalisedCreds = null;
668   
669  9 if (creds == null) {
670   
671  0 if (logger.isDebugEnabled())
672    {
673  0 logger.debug("Going to PULL ACs");
674  0 logger.debug("Get Creds Called with the Parameters:");
675  0 logger.debug("Principal: "+ userP.getName());
676  0 logger.debug("Object[]: null");
677    }
678  0 s = rbac.getCreds(userP, (Object[]) null); // pull AC
679   
680    } else {
681  9 Vector newCreds = new Vector();
682  9 Vector attValue = new Vector();
683  20 for (int i = 0; i < creds.length; i++) {
684  11 int idx = creds[i].indexOf("=");
685  11 String prefix = "";
686   
687  11 if (idx >= 0) { // ...then this is a Shibboleth Attribute. Chop
688    // the 'shib:attributeType=' bit
689  11 prefix = creds[i].substring(0, idx + 1);
690  11 creds[i] = creds[i].substring(idx + 1);
691   
692    }
693   
694  11 boolean bAC = prefix.equals("shib:" + AC_attribute + "="); // check
695    // if
696    // this
697    // attribute
698    // is a
699    // attributeCertificateAttribute;binary
700    //if (logger.isDebugEnabled())logger.debug("bAC = " +bAC);
701  11 creds[i] = creds[i] + ";";
702   
703  11 int oldIdx = 0;
704  0 while ((idx = creds[i].indexOf(";", oldIdx)) >= 0) {
705  12 String value = creds[i].substring(oldIdx, idx);
706   
707  12 if (bAC) {
708  0 if (logger.isDebugEnabled())logger.debug("AC_Attribute found");
709  3 byte[] ac = org.apache.axis.encoding.Base64.decode(value);
710  3 newCreds.add(ac); // now add a byte array containing the AC to creds
711  3 attValue.add(AC_attribute);
712   
713    } else {
714  9 if (value.indexOf("@") < 0)
715  0 value = value + "@" + originURL; // this should
716    // happen only
717    // if it is not
718    // an AC
719   
720   
721  9 int attValint = prefix.indexOf(":");
722  9 int v = prefix.indexOf("=");
723  9 String attVal = prefix.substring(attValint +1, v);
724  9 attValue.add(attVal);
725   
726   
727  9 newCreds.add(shibParser.decode(prefix + value, user)); // add
728    // the
729    // value
730    // as a
731    // 'shib:attributeType='+value,
732    // set
733    // the
734    // Holder
735    // to
736    // be
737    // as
738    // specified
739    // to
740    // the
741    // method
742    // call
743    }
744  12 oldIdx = idx + 1;
745    }
746   
747    }
748   
749  9 normalisedCreds = newCreds.toArray();
750   
751  9 Object [] normalisedAtts = attValue.toArray();
752   
753   
754  0 if(logger.isDebugEnabled())logger.debug("Going to PUSH the following: ");
755  0 if(logger.isDebugEnabled())logger.debug("getCreds called with the following parameters:");
756  0 if(logger.isDebugEnabled())logger.debug("Subject DN:" + user.getEntryName().getName());
757  9 if(logger.isDebugEnabled()){
758  0 logger.debug("There are " + creds.length + " creds");
759  0 try{
760  0 for (int i = 0; i < normalisedCreds.length; i++){
761   
762  0 try{
763  0 ParsedToken debugtoken = (ParsedToken) normalisedCreds[i];
764  0 if (debugtoken.getCredentials().toString().equals("<role null: null (-oo; +oo)>")){
765  0 logger.debug("[attribute [" + normalisedAtts [i]+ "] has not been found in the PERMIS role hierarchy policy]");
766    }else{
767   
768  0 logger.debug("[" + normalisedCreds[i]+ "]" + debugtoken.getCredentials().toString());
769    }
770    }catch (java.lang.ClassCastException e){
771  0 byte[] ac = (byte []) normalisedCreds[i];
772  0 System.err.println(ac);
773  0 logger.debug("[attribute [attributeCertificateAttribute] will be parsed by the PERMIS CVS]" );
774    }
775   
776    }
777    }catch (ArrayIndexOutOfBoundsException e){
778   
779    }
780    }
781   
782    }
783   
784  9 s = rbac.getCreds(user.getEntryName(), normalisedCreds); // this will
785    // do all
786    // the
787    // methods:
788    // - if creds==null, PermisRBAC will Pull the ACs from LDAP
789    // - if creds!=null, PermisRBAC will use the given ACs/Attributes
790    // the actual format of Credentials is specified at construction time
791    // (see getShibPermisRBAC()) by registering an appropriate
792    // AuthTokenParser
793  9 String g = "";
794  9 String fred = s.exportCreds().toString();
795  9 try{
796  9 if (logger.isInfoEnabled()){
797  0 while (fred.indexOf("role") != -1){
798  0 int a = fred.indexOf("role");
799  0 fred = fred.substring(a);
800  0 a = fred.indexOf(" ");
801  0 a = fred.indexOf(' ',a+1);
802  0 a = fred.indexOf(' ',a+1);
803  0 g = g + fred.substring(5,a) + ", ";
804  0 fred = fred.substring(a);
805   
806    }
807  0 int a = g.lastIndexOf(",");
808  0 g = g.substring(0,a);
809  0 g = g + ")";
810    }
811    }catch(Exception e){
812   
813    }
814  0 if(logger.isInfoEnabled())logger.info("Get Creds has returned the following valid roles: (" + g);
815   
816  9 if(logger.isDebugEnabled()){
817  0 logger.debug("Get Creds has returned the following" +s.exportCreds());
818  0 logger.debug("Calling the PERMIS PDP for a decision");
819  0 logger.debug("Sending the following parameters to Decision: ");
820  0 logger.debug("Creds : " + s.exportCreds().toString() );
821  0 logger.debug("Action : " + action);
822  0 logger.debug("Target : " + pt.getName());
823    }
824  9 if (rbac.decision(s, new PermisAction(action), pt, null)) {
825  0 if(logger.isInfoEnabled())logger.info("Authorisation succeeded.");
826  7 return OK;
827    } else {
828  0 if(logger.isInfoEnabled())logger.info("Authorisation failed.");
829  2 return DENY;
830    }
831    }
832   
833    /**
834    * This is a utility method that loads an X.509 Attribute Certificate
835    * from a file and puts it in a VirtualRepository for later use.
836    *
837    * @param vr - the VirtualRepository to place the AC to
838    * @param filename - the name of the file with the AC inside
839    */
 
840  0 toggle public static void loadAC(issrg.utils.repository.VirtualRepository vr,
841    String filename) {
842  0 try {
843  0 if (filename == null){
844  0 if (logger.isEnabledFor(Level.WARN))logger.debug("AC location is null");
845    }else{
846  0 if (filename == ""){
847  0 if (logger.isEnabledFor(Level.WARN))logger.debug("AC location is null");
848    }else{
849  0 if (logger.isDebugEnabled())logger.debug("Loading AC located at : " + filename);
850  0 java.io.InputStream io = new java.io.FileInputStream(filename);
851  0 byte[] ac = new byte[io.available()];
852  0 io.read(ac);
853  0 issrg.ac.AttributeCertificate acd = issrg.ac.AttributeCertificate
854    .guessEncoding(ac);
855    // now put the ac into the entry with the name of the holder
856    // we are working with explicit Holder specification only: no BCIDs
857   
858  0 vr.populate(issrg.ac.Util.generalNamesToString(
859    acd.getACInfo().getHolder().getEntityName()).toUpperCase(),
860    CustomisePERMIS.getAttributeCertificateAttribute(), ac);
861  0 if (logger.isDebugEnabled())logger.debug("Success AC located at : " + filename + "has been loaded");
862    }
863    }
864   
865    } catch (Throwable th) {
866   
867  0 if (logger.isEnabledFor(Level.ERROR)){
868  0 logger.error("Failed to load AC from [" + filename + "]");
869  0 logger.error (th.fillInStackTrace());
870    }
871    }
872    }
873   
874    /**
875    * This method loads an X.509 Public Key Certificate and returns its
876    * byte array.
877    *
878    * @param filename
879    * the file name of certificate
880    */
 
881  2 toggle private static byte[] loadPKC(String filename) {
882  2 if (filename == null)
883  0 return null;
884  2 if (filename.intern() == "null")
885  0 return null;
886  2 if (filename.intern() == "")
887  2 return null;
888  0 try {
889  0 java.io.InputStream io = new java.io.FileInputStream(filename);
890  0 byte[] pkc = new byte[io.available()];
891   
892   
893  0 io.read(pkc);
894  0 new iaik.x509.X509Certificate(pkc); // try to decode the byte array
895    // - this will check that the
896    // byte array is in fact a X.509
897    // PKC
898  0 return pkc;
899    } catch (Throwable th) {
900  0 if (logger.isEnabledFor(Level.ERROR)){
901  0 logger.error("Failed to load PKC from [" + filename + "]");
902  0 logger.error(th.fillInStackTrace());
903    }
904  0 return null;
905    }
906   
907    }
908   
909    /**
910    * This method reads logger settings from configuration file
911    * @param filename
912    * the file name of configruation file
913    */
 
914  0 toggle private static void loadConfiguration(String filename) throws Exception
915    {
916  0 try
917    {
918  0 BufferedReader in;
919   
920  0 try
921    {
922  0 in = new BufferedReader(new InputStreamReader(
923    new FileInputStream("conf/" + filename)));
924    }
925    catch(FileNotFoundException fnfe1)
926    {
927  0 try
928    {
929  0 in = new BufferedReader(new InputStreamReader(
930    new FileInputStream("bin/" + filename)));
931    }
932    catch(FileNotFoundException fnfe2)
933    {
934  0 in = new BufferedReader(new InputStreamReader(
935    new FileInputStream(filename)));
936    }
937    }
938   
939  0 String line;
940  0 String key;
941  0 String value;
942  0 while ((line = in.readLine()) != null)
943    {
944  0 line = line.intern();
945  0 line = line.trim();
946  0 if (line == "")
947  0 continue;
948   
949  0 int i = line.indexOf(" ");
950  0 if (i < 0)
951  0 continue;
952   
953  0 key = line.substring(0, i).toLowerCase().trim().intern();
954  0 value = line.substring(i + 1).trim().intern();
955   
956  0 if (key.charAt(0) == '#')
957    {
958  0 continue;
959  0 } else if (key.compareToIgnoreCase("logFile") == 0)
960    {
961  0 logFile = value;
962    } else
963  0 continue;
964    }
965    }
966    // propagate the exceptions to the caller
967    catch (FileNotFoundException fnfe)
968    {
969  0 throw new FileNotFoundException("Config file not found" + filename);
970    } catch (IOException ioe)
971    {
972  0 throw new IOException("Error reading configuration file");
973    }
974    }
975    }