Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
67   318   23   9.57
40   111   0.43   7
7     4.14  
1    
 
 
  LDAPRepository       Line # 112 67 23 40.4% 0.40350878
 
No Tests
 
1    /*
2    * Copyright (c) 2000-2005, University of Salford
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *
8    * Redistributions of source code must retain the above copyright notice, this
9    * list of conditions and the following disclaimer.
10    *
11    * Redistributions in binary form must reproduce the above copyright notice,
12    * this list of conditions and the following disclaimer in the documentation
13    * and/or other materials provided with the distribution.
14    *
15    * Neither the name of the University of Salford nor the names of its
16    * contributors may be used to endorse or promote products derived from this
17    * software without specific prior written permission.
18    *
19    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22    * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29    * POSSIBILITY OF SUCH DAMAGE.
30    */
31    /*
32    * Copyright (c) 2006, University of Kent
33    * All rights reserved.
34    *
35    * Redistribution and use in source and binary forms, with or without
36    * modification, are permitted provided that the following conditions are met:
37    *
38    * Redistributions of source code must retain the above copyright notice, this
39    * list of conditions and the following disclaimer.
40    *
41    * Redistributions in binary form must reproduce the above copyright notice,
42    * this list of conditions and the following disclaimer in the documentation
43    * and/or other materials provided with the distribution.
44    *
45    * 1. Neither the name of the University of Kent nor the names of its
46    * contributors may be used to endorse or promote products derived from this
47    * software without specific prior written permission.
48    *
49    * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
50    * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
51    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52    * PURPOSE ARE DISCLAIMED.
53    *
54    * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
55    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61    * POSSIBILITY OF SUCH DAMAGE.
62    *
63    * 4. YOU AGREE THAT THE EXCLUSIctx.getAttributes(dnONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE
64    * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS
65    * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS
66    * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH
67    * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH
68    * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY
69    * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE
70    * SERIOUS FAULTS, IN THIS SOFTWARE.
71    *
72    * 5. This license is governed, except to the extent that local laws
73    * necessarily apply, by the laws of England and Wales.
74    */
75   
76    package issrg.utils.repository;
77   
78    import issrg.utils.ToRawCredential;
79    import javax.naming.directory.DirContext;
80    import javax.naming.directory.Attributes;
81    import javax.naming.NamingException;
82    import javax.naming.NamingEnumeration;
83    import javax.naming.NameParser;
84    import javax.naming.Name;
85    import java.security.Principal;
86    import java.util.Vector;
87   
88    import issrg.pba.rbac.CustomisePERMIS;
89   
90    import org.apache.log4j.*;// added for logging
91    /**
92    * This class is the implementation of the Attribute Repository for LDAP.
93    * It can be built out of an array of DirContext. Each of these contexts
94    * constitutes a root for LDAP searches. Each DirContext is obtained by
95    * establishing an LDAP connection with the directory concerned.
96    *
97    * <p>The object can be used for retrieving similar information from multiple
98    * directories simultaneously. For example, it is useful when retrieving X.509
99    * Attribute Certificates for PMI entities that possess ACs issued by different
100    * issuers (therefore, stored in different directories available to these
101    * issuers).
102    *
103    * <p>The object uses MultiRepository to create multiple threads, and acts as
104    * a proxy object for backwards compatibility (earlier versions of this object
105    * had a constructor with an array of DirContext). It is better to use
106    * MultiRepository for multi-root clusters of LDAP repositories to be more
107    * efficient.
108    *
109    * @author A Otenko
110    * @version 0.2
111    */
 
112    public class LDAPRepository extends DefaultRepository{
113    private MultiRepository mr=null;
114    private DirContext ctx=null;
115   
116    private int status; // status of the Repository
117    private Throwable diagnosis; // the ultimate status: the stack frame in it, the error message to deliver, etc
118   
 
119  0 toggle protected LDAPRepository(){}
120   
121    static Logger logger = Logger.getLogger("issrg.utils.repository.LDAPRepository");
122   
123    /**
124    * This constructor builds the LDAPRepository with a number of roots.
125    *
126    * @param Contexts - An array of DirContexts to use as the roots of LDAP
127    * searches
128    */
 
129  0 toggle public LDAPRepository(DirContext [] Contexts) {
130   
131  0 LDAPRepository [] ldaps=new LDAPRepository[Contexts.length];
132  0 for (int i=0; i<ldaps.length; i++){
133  0 if (logger.isDebugEnabled()){
134  0 try {
135  0 logger.debug("Base DN = " + Contexts[i].getNameInNamespace()) ;
136    } catch (NamingException e) {
137    // TODO Auto-generated catch block
138  0 e.printStackTrace();
139    }}
140  0 ldaps[i]=new LDAPRepository(Contexts[i]);
141    }
142   
143  0 mr=new MultiRepository(ldaps);
144    }
145   
146    /**
147    * This creates an LDAPRepository with a single root context
148    *
149    * @param Context - A DirContext to be used as the root of LDAP searches
150    */
 
151  1 toggle public LDAPRepository(DirContext Context) {
152  1 ctx=Context;
153  1 if (logger.isDebugEnabled()){
154  0 try {
155  0 logger.debug("Base DN = " + ctx.getNameInNamespace());
156    } catch (NamingException e) {
157    // TODO Auto-generated catch block
158  0 e.printStackTrace();
159    }}
160    }
161   
162    /**
163    * This method gets the set of named attributes from the entry with the DN.
164    * It searches all ldap contexts simultaneously. If the DN and named attribute
165    * exist in more than one of the named contexts, then multiple attribute
166    * values will be returned.
167    *
168    * <p>Note that all attribute retrieval methods call this method, and they do
169    * not update the status or diagnosis set by this method, and they propagate
170    * the exceptions thrown by this method.
171    *
172    * <p>After calling the method the repository will be set into one of the
173    * states: FAILURE_STATUS, SUCCESS_STATUS or PARTIAL_SUCCESS_STATUS. Failure
174    * means there were no roots that succeeded. Success means that all of the
175    * roots succeeded (the entries were found and some or no attributes were
176    * retrieved). Partial success means that some of the roots failed, but some
177    * have succeeded, which may be in case some of the roots do not contain
178    * the required entry. The caller must find out himself what the cause is, and
179    * decide if the results are sufficiently successful.
180    *
181    * @param DN The distinguished name of the entry from which the attributes
182    * are requested
183    * @param AttributeNames The array of LDAP names for the attributes; can be
184    * null, if all available attributes and their values are to be retrieved
185    *
186    * @return the requested attributes; the Repository status reflects the status
187    * of retrieval, the diagnosis contains exceptions the underlying objects
188    * threw, if they failed
189    *
190    * @throws RepositoryException, if all of the repositories failed, in which
191    * case the
192    * embedded exception will be the Throwable returned by <code>getDiagnosis</code>
193    * method; FAILURE_STATUS will also be set
194    */
195   
 
196  3 toggle public Attributes getAttributes(java.security.Principal DN, String [] AttributeNames) throws RepositoryException{
197  3 if (logger.isDebugEnabled()){
198  0 logger.debug("retrieving attributes: " );
199   
200    //System.err.print("retrieving attributes: ");
201  0 for(int i=0; i<AttributeNames.length; i++)
202    {
203  0 if (i!=0) System.err.print(",");
204  0 logger.debug("Attribute type is " + AttributeNames[i]);}
205   
206    }
207  3 if (mr==null){
208  3 try{
209  3 diagnosis=null;
210  3 if (logger.isDebugEnabled()){
211   
212  0 String attrs="";
213   
214  0 for(int i=0; AttributeNames!=null && i<AttributeNames.length; i++){
215  0 if (i==0) {
216  0 attrs=AttributeNames[i];
217  0 } else {attrs+=", "+AttributeNames[i];}
218    }
219  0 logger.debug("getting ["+attrs+"] attributes for "+DN.getName()); //************
220  0 int i = 0;
221  0 Attributes f = ctx.getAttributes(dnWithoutBaseDN(ctx, DN.getName()), AttributeNames);
222  0 logger.debug(f.size() + " attributes were found");
223   
224    }
225  3 if (DN.getName().equals("")) logger.debug("warning : an empty DN ");
226  3 Attributes atts = ctx.getAttributes(dnWithoutBaseDN(ctx, DN.getName()), AttributeNames);
227  1 ToRawCredential toRaw = new ToRawCredential(atts,this.getClass().getName());
228  1 atts = toRaw.convert();
229  1 return (Attributes)atts.clone();
230    }catch(javax.naming.NameNotFoundException nnfe){
231  0 if (logger.isDebugEnabled())logger.debug(nnfe.getClass().getName()+" exception occured while retrieving attributes");//*************
232    //nnfe.printStackTrace(); //*************
233   
234  2 diagnosis=nnfe; // set this as a diagnosis, so partial success can be signalled
235  0 if (logger.isDebugEnabled())logger.debug("returning: null");
236  2 return null; // return null, i.e. no attributes were found
237    }catch(Throwable th){
238   
239  0 if (logger.isDebugEnabled())logger.debug(th.getClass().getName()+" exception occured while retrieving attributes");//*************
240    //th.printStackTrace(); //*************
241   
242  0 diagnosis=new RepositoryException("Failed to get attributes", th);
243  0 throw (RepositoryException)diagnosis;
244   
245    }finally{
246  3 status=diagnosis==null?SUCCESS_STATUS:FAILURE_STATUS;
247    }
248    } else {
249  0 if (logger.isDebugEnabled()) logger.debug("using MultiRepository to retrieve the attributes"); //************
250  0 Attributes atts = mr.getAttributes(DN, AttributeNames);
251  0 ToRawCredential toRaw = new ToRawCredential(atts,this.getClass().getName());
252  0 atts = toRaw.convert();
253  0 return (Attributes)atts.clone();
254    }
255    }
256   
257    /**
258    * This method returns the status of the repository. It is set when returning
259    * attributes.
260    *
261    * @return the integer value corresponding to the status
262    *
263    * @see getAttributes(java.security.Principal,String[])
264    */
 
265  0 toggle public int getStatus(){
266  0 return mr==null?status:mr.getStatus();
267    }
268   
269    /**
270    * This method returns the Throwable, representing the error, or null, if no
271    * error has been encountered (only if the repository is in SUCCESS_STATUS).
272    * The Throwable contains an error message and the stack trace of the error.
273    *
274    * @return Throwable object, representing the error, or null if there was no
275    * error during the last call
276    */
 
277  3 toggle public Throwable getDiagnosis(){
278  3 return mr==null?diagnosis:mr.getDiagnosis();
279    }
280   
281    /**
282    * This is a utility method that strips off the base DN from the DN, if it
283    * is present there. Sometimes the DN is relative to the root, sometimes it is
284    * an absolute DN and includes the DN of the root DirContext. It is important
285    * to stranslate the DN into the DN without the base DN for successful
286    * searches.
287    *
288    * @param root - the DirContext of the search root
289    * @param dn - a DN with or without the base DN (the DN of the search root)
290    *
291    * @return a LDAP DN relative to the base DN (the DN of the search root)
292    *
293    * @throws NamingException, if the DN is not a valid DN
294    */
 
295  3 toggle public static String dnWithoutBaseDN(DirContext root, String dn) throws NamingException {
296   
297  3 String baseDN = root.getNameInNamespace();
298  3 NameParser np = root.getNameParser("");
299  3 Name baseDNName = np.parse(baseDN);
300  3 Name dnName = np.parse(dn);
301   
302  3 if (!dnName.isEmpty()) {
303  2 Name dnWithoutBaseDN = dnName.getSuffix(baseDNName.size());
304    //System.out.println("DN w/o base DN: "+dnWithoutBaseDN);//****************
305   
306  2 if (dnName.startsWith(baseDNName)){
307    //System.out.println("DN starts with the Base DN");//*************
308  0 dnName = dnName.getSuffix(baseDNName.size());
309   
310    //System.out.println("We've got "+dnName.toString());//*************
311    }else{
312    // well... it should not come here!
313    }
314    }
315  3 logger.debug("DN name = <"+dnName.toString()+">");
316  3 return dnName.toString();
317    }
318    }