source: java/net/deterlab/abac/CredentialFactory.java @ 120b7d8

abac0-leakabac0-meitvf-new-xml
Last change on this file since 120b7d8 was c1736fe, checked in by Ted Faber <faber@…>, 12 years ago

Nicer class structure for GENI credentials

  • Property mode set to 100644
File size: 8.1 KB
Line 
1package net.deterlab.abac;
2
3import java.io.*;
4import java.util.*;
5import java.lang.reflect.*;
6
7
8/**
9 * A class for parsing and generating Credentials inside a Context.  All
10 * credential parsing should use a credential factory inside a context uses a
11 * CredentialFactory.
12 * @author <a href="http://abac.deterlab.net">ISI ABAC team</a>
13 * @version 1.4
14 */
15public class CredentialFactory implements Cloneable {
16    protected List<CredentialFactorySpecialization> spec;
17
18    /**
19     * The xmlparsing routines helpfully close input streams when they
20     * successfully parse a document from one.  It's possible for a correctly
21     * parsed XML document to need to be reparsed by later specialization, for
22     * example because the XML was fine, but it was the wrong type of
23     * credential.  This makes the close operation a NOOP.
24     */
25    static protected class UnclosableBufferedInputStream extends 
26        BufferedInputStream {
27            public UnclosableBufferedInputStream(InputStream is) {
28                super(is);
29            }
30            public UnclosableBufferedInputStream(InputStream is, int s) {
31                super(is, s);
32            }
33
34            public void close() throws IOException { }
35    };
36    /** The classes understood by the default CredentialFactory (in order) */
37    static public String[] defNames = new String[] {
38        "net.deterlab.abac.GENICredentialv1_1",
39        "net.deterlab.abac.GENICredentialv1_0",
40        "net.deterlab.abac.X509Credential",
41        "net.deterlab.abac.GENIPrivCredential",
42    };
43
44    /** Maximum credential size that can be rewound for reparsing */
45    public static final int maxSize = 50 * 1024;
46
47    /**
48     * Create a Credential Factory that parses the default type(s)
49     * @throws ABACException if the object cannot be created
50     */
51    public CredentialFactory() throws ABACException {
52        spec = new ArrayList<CredentialFactorySpecialization>();
53        for ( String name: defNames) 
54            registerClass(name);
55    }
56
57    /**
58     * Create a Credential Factory that parses the given type(s).  Each String
59     * should be the binary name for a class that exports a static
60     * getCredentialParser method that returns a CredentialParser for the
61     * class.
62     * @param names a Collection of Strings naming the classes to parse
63     * @throws ABACException if the object cannot be created
64     */
65    public CredentialFactory(Collection<String> names) throws ABACException {
66        spec = new ArrayList<CredentialFactorySpecialization>();
67        for (String n : names ) 
68            registerClass(n);
69    }
70
71    /**
72     * Create a Credential Factory that parses the given type(s).  Each String
73     * should be the binary name for a class that exports a static
74     * getCredentialParser method that returns a CredentialParser for the
75     * class.
76     * @param names an Array of Strings naming the classes to parse
77     * @throws ABACException if the object cannot be created
78     */
79    public CredentialFactory(String[] names) throws ABACException {
80        spec = new ArrayList<CredentialFactorySpecialization>();
81        for (String n : names ) 
82            registerClass(n);
83    }
84
85    /**
86     * Create a Credential Factory that is a clone of the given
87     * CredentialFactory.
88     * @param cf the CredentialFactory to copy
89     * @throws ABACException if the object cannot be created
90     */
91    public CredentialFactory(CredentialFactory cf) throws ABACException {
92        this();
93
94        spec = new ArrayList<CredentialFactorySpecialization>();
95
96        for ( int i = 0; i < spec.size(); i++) 
97            spec.add(cf.spec.get(i));
98    }
99
100    /**
101     * Make a copy of this CredentialFactory
102     * @return a CredentialFactory, a copy of this one
103     */
104    public Object clone() throws CloneNotSupportedException {
105        CredentialFactory cf = null;
106        try {
107            cf = new CredentialFactory(this);
108        }
109        catch (ABACException ae) {
110            return null;
111        }
112        return cf;
113    }
114
115
116    /**
117     * Parse an input stream using each possible credential format and the
118     * available identities for validation.  Return the credentials found or
119     * throw an ABACException with the problem.  It wraps the input stream in a
120     * BufferedInputStream in order to retry is a parser fails.  Credentials
121     * larger than maxSize will nor be able to be reparsed.
122     * @param is an InputStream to parse
123     * @param ids a Collection of Identities for validation
124     * @return an Array of Credentials parsed
125     * @throws CertInvalidException if the stream is unparsable
126     * @throws MissingIssuerException if none of the Identities can validate the
127     * @throws BadSignatureException if the signature check fails
128     */
129    public Credential[] parseCredential(InputStream is, 
130            Collection<Identity> ids) throws ABACException {
131        Credential[] rv = null;
132        ABACException err = null;
133        UnclosableBufferedInputStream bs = 
134            new UnclosableBufferedInputStream(is, maxSize);
135
136        bs.mark(maxSize);
137        for (CredentialFactorySpecialization c : spec ) {
138            try {
139                rv = c.parseCredential(bs, ids);
140                break;
141            }
142            catch (ABACException e ) {
143                err = e;
144                rv = null;
145            }
146            try {
147                if (spec.size() > 1) bs.reset(); 
148            }
149            catch (IOException ie) { 
150                break;
151            }
152        }
153
154        if ( rv != null ) 
155            return rv;
156        else 
157            throw (err != null) ? err :
158                new ABACException("null exception and failed construction??");
159    }
160
161
162    /**
163     * Parse a File using each possible credential format and the
164     * available identities for validation.  Return the credentials found or
165     * throw an ABACException with the problem.  Calls the InputStream version
166     * internally.
167     * @param f a File to parse
168     * @param ids a Collection of Identities for validation
169     * @return an Array of Credentials parsed
170     * @throws CertInvalidException if the stream is unparsable
171     * @throws MissingIssuerException if none of the Identities can validate the
172     * @throws BadSignatureException if the signature check fails
173     */
174    public Credential[] parseCredential(File f, 
175            Collection<Identity> ids) throws ABACException {
176        try {
177            return parseCredential(new FileInputStream(f), ids);
178        }
179        catch (FileNotFoundException e) {
180            throw new CertInvalidException(e.getMessage(), e);
181        }
182    }
183    /**
184     * Parse a file named fn using each possible credential format and the
185     * available identities for validation.  Return the credentials found or
186     * throw an ABACException with the problem.  Calls the InputStream version
187     * internally.
188     * @param fn a String holding the filename to parse
189     * @param ids a Collection of Identities for validation
190     * @return an Array of Credentials parsed
191     * @throws CertInvalidException if the stream is unparsable
192     * @throws MissingIssuerException if none of the Identities can validate the
193     * @throws BadSignatureException if the signature check fails
194     */
195    public Credential[] parseCredential(String fn, 
196            Collection<Identity> ids) throws ABACException {
197        return parseCredential(new File(fn), ids);
198    }
199
200    /**
201     * Return a credential from the first class registered in
202     * the factory.
203     * @param head a Role, the head of the encoded ABAC statement
204     * @param tail a Role, the tail of the decoded ABAC statement
205     * @return a Credential encoding that ABAC statement
206     */
207    public Credential generateCredential(Role head, Role tail) {
208        if (spec.isEmpty()) return null;
209        return spec.get(0).generateCredential(head, tail);
210    }
211
212    /**
213     * Add the named class to the list of usable specializations.  The class
214     * passed in must have a static getCredentialFactorySpecialization() method
215     * that returns a CredentialFactorySpecialization to use.
216     * @param name a String containing the binary name of the class to register
217     * @throws ABACException if there is a problem.  The cause field of this
218     * exception is set to the classloading exception, if any.
219     */
220    public void registerClass(String name)
221        throws ABACException {
222        CredentialFactorySpecialization cs = null;
223
224        try {
225            /* <?> doesn't guarantee much, but shuts the compiler up */
226            Class<?> c =  Class.forName(name);
227            Method m = c.getMethod("getCredentialFactorySpecialization");
228
229            cs = (CredentialFactorySpecialization) m.invoke(null);
230        }
231        catch (Exception e) {
232            throw new ABACException("Could not register credential type" + 
233                    e.getMessage(), e);
234        }
235
236        spec.add(cs);
237    }
238}
Note: See TracBrowser for help on using the repository browser.