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