source: libabac/abac.hh

Last change on this file was a39bdab, checked in by Ted Faber <faber@…>, 10 years ago

Differentially cleaner C++ STL invocation. Passes clang++.

  • Property mode set to 100644
File size: 22.7 KB
Line 
1#ifndef __ABAC_HH__
2#define __ABAC_HH__
3
4#include <cstdio>
5#include <stdexcept>
6#include <string>
7#include <vector>
8
9namespace ABAC {
10    extern "C" {
11        #include "abac.h"
12    }
13
14    class Attribute;
15    class ID;
16    class Role;
17    class Credential;
18
19/***
20ABAC::Context
21    An ABAC Context
22***/
23    class Context {
24        public:
25/***
26f  Context()
27     default constructor
28     (C:abac_context_new)
29f  Context(const Context &)
30     copy constructor, used for cloning the context
31     (C:abac_context_dup)
32f  ~Context()
33     default destructor
34     (C:abac_context_free)
35***/
36            Context() { m_ctx = abac_context_new(); }
37            Context(const Context &context) { m_ctx = abac_context_dup(context.m_ctx); }
38            ~Context() { abac_context_free(m_ctx); }
39
40/***
41f  int load_id_file(char *)
42     load identity certificate from an id file
43     (C:abac_context_load_id_file)
44f  int load_id_chunk(abac_chunk_t)
45     load id certificate from an chunk
46     (C:abac_context_load_id_chunk)
47f  int load_id_id(ID&)
48     load id certificate from an existing ID
49     (C:abac_context_load_id_id)
50f  int load_attribute_file(char *)
51     load attribute certificate from an id file.
52     (C:abac_context_load_attribute_file)
53f  int load_attribute_chunk(abac_chunk_t)
54     load attribute certificate from an chunk
55     (C:abac_context_load_attribute_chunk)
56f  returns :
57        ABAC_CERT_SUCCESS   successfully loaded
58        ABAC_CERT_INVALID   invalid certificate (or file not found)
59        ABAC_CERT_BAD_SIG   invalid signature
60***/
61            int load_id_file(char *filename) { return abac_context_load_id_file(m_ctx, filename); }
62            int load_id_chunk(abac_chunk_t cert) { return abac_context_load_id_chunk(m_ctx, cert); }
63            int load_id_id(ID& id); /* defined later in the class */
64            int load_attribute_file(char *filename) { return abac_context_load_attribute_file(m_ctx, filename); }
65            int load_attribute_chunk(abac_chunk_t cert) { return abac_context_load_attribute_chunk(m_ctx, cert); }
66
67/***
68f  std::vector<Credential> query(char *, char *, bool &)
69     run the query:
70        role <-?- principal
71     returns true/false in success
72     returns a proof upon success, partial proof on failure
73     (C:abac_context_query)
74     (C::abac_free_credentials_free)
75***/
76
77    /* abac query, returns a vector of credentials on success, NULL on fail */
78    std::vector<Credential> query(char *role, char *principal, bool &success);
79/***
80f  std::vector<Credential> credentials(bool &)
81     returns a vector of all the credentials loaded in the context
82     (C:abac_context_credentials)
83     (C::abac_context_credentials_free)
84***/
85    std::vector<Credential> credentials();
86/***
87f  void load_directory(char *)
88     load a directory full of certificates:
89f       first: ${path}/NAME_ID.{der,pem} as identity certificates
90               implicitly looking for ${path}/NAME_private.{der,pem} as
91               the private key file
92        last: ${path}/NAME_attr.xml as attribute certificates
93      (C:abac_context_load_directory)
94***/
95            void load_directory(char *path) { abac_context_load_directory(m_ctx, path); }
96
97/***
98f  void set_nickname(char *key, char *nick)
99     Set the nickname (value printed) for keyid.  The substitution is made
100     in Role::short_string(Context) and when bake(Context) is called on a new
101     attribute.
102     (C:abac_context_set_nickname)
103***/
104        void set_nickname(char *key, char *nick) {
105            abac_context_set_nickname(m_ctx, key, nick);
106        }
107        private:
108            abac_context_t *m_ctx;
109        friend class Role;
110        friend class ID;
111        friend class Attribute;
112    };
113
114/***
115ABAC::Role
116   A Role, most calls are rarely used outside the library
117***/
118    class Role {
119        public:
120/***
121f  Role()
122     default constructor, do not use, for swig only
123f  Role(abac_role_t*)
124     copy constructor, used for cloning an Role
125     (C:abac_role_dup)
126f  Role(char *)
127     instantiate a role from a string
128     (C:abac_role_from_string)
129f  Role(const Role &)
130     copy constructor, used for cloning an Role
131     (C:abac_role_dup)
132f  ~Role()
133     default destructor
134     (C:abac_role_free)
135***/
136            Role() : m_role(NULL) { } // do not use: here for swig
137            Role(abac_role_t *role) { m_role = abac_role_dup(role); }
138            Role(char *role_name) { m_role = abac_role_from_string(role_name); }
139            Role(const Role &role) { m_role = abac_role_dup(role.m_role); }
140            ~Role() { abac_role_free(m_role); }
141/***
142f  bool is_principal()
143     (C:abac_role_is_principal)
144f  bool is_role()
145     (C:abac_role_is_role)
146f  bool is_linking()
147     (C:abac_role_is_linking)
148     indicates the type of role encoded
149***/
150            bool is_principal() const { return abac_role_is_principal(m_role); }
151            bool is_role() const { return abac_role_is_role(m_role); }
152            bool is_linking() const { return abac_role_is_linking(m_role); }
153
154/***
155f  char* string()
156     string representation of the role
157     (C:abac_role_string)
158***/
159            char *string() const { return abac_role_string(m_role); }
160/***
161f  char* short_string()
162     string representation of the role
163     (C:abac_role_short_string)
164***/
165            char *short_string(Context& c) const { 
166                return abac_role_short_string(m_role, c.m_ctx);
167            }
168/***
169f  char* linked_role()
170     the linked role of a linking role
171     i.e., A.r1.r2, linked_role() returns A.r1
172     (C:abac_role_linked_role)
173f  char* role_name()
174     the role name of any role (the part after the last dot)
175     (C:abac_role_role_name)
176f  char* principal()
177     the principal part of any role
178     (C:abac_role_principal)
179***/
180            char *linked_role() const { return abac_role_linked_role(m_role); }
181            char *role_name() const { return abac_role_role_name(m_role); }
182            char *principal() const { return abac_role_principal(m_role); }
183
184        private:
185            abac_role_t *m_role;
186    };
187
188/***
189ABAC::Credential
190   This is never instantiated directly. These will only ever be
191   returned as a result of calls to Context::query or
192   Context::credentials.
193***/
194    class Credential {
195        public:
196/***
197f  Credential()
198     default constructor, do not use, for swig only
199f  Credential(abac_credential_t*)
200     copy constructor, used for cloning a credential
201     (C:abac_credential_head)
202     (C:abac_credential_tail)
203     (C:abac_credential_dup)
204f  Credential(const Credential&)
205     copy constructor, used for cloning a credential
206     (C:abac_credential_head)
207     (C:abac_credential_tail)
208     (C:abac_credential_dup)
209f  ~Credential()
210     default destructor
211     (C:abac_credential_free)
212***/
213            Credential() : m_cred(NULL) { } // do not use: here for swig
214            Credential(abac_credential_t *cred) :
215                m_head(abac_credential_head(cred)),
216                m_tail(abac_credential_tail(cred)),
217                m_cred(abac_credential_dup(cred))
218                    { }
219            Credential(const Credential &cred) :
220                m_head(cred.m_head),
221                m_tail(cred.m_tail),
222                m_cred(abac_credential_dup(cred.m_cred))
223                    { }
224            ~Credential() { abac_credential_free(m_cred); }
225/***
226f  Role &head()
227     returns the head of the credential
228f  Role &tail()
229     returns the tail of the credential
230***/
231            const Role &head() { return m_head; }
232            const Role &tail() { return m_tail; }
233/***
234f  abac_chunk_t attribute_cert()
235     returns the attribute certificate in chunk, suitable for
236     transmission over the network or storage in a file
237     (C:abac_credential_attribute_cert)
238f  abac_chunk_t issuer_cert()
239     returns the issuer certificate in chunk, again suitable for
240     network transmission or file storage
241     (C:abac_credential_issuer_cert)
242***/
243            abac_chunk_t attribute_cert() { return abac_credential_attribute_cert(m_cred); }
244            abac_chunk_t issuer_cert() { return abac_credential_issuer_cert(m_cred); }
245       
246        private:
247            abac_credential_t *m_cred;
248            Role m_head, m_tail;
249    };
250
251
252/***
253ABAC::ID
254   An ID holds a principal credential. It maybe imported from an existing
255   ID credential via external files, constructed from a streaming chunk,
256   or instantiated on the fly
257***/
258    class ID {
259        public:
260/***
261f  ID()
262     default constructor, do not use, for swig only
263f  ID(const ID &)
264     copy constructor, used for cloning an ID
265     (C:abac_id_dup)
266f  ~ID()
267     default destructor
268     (C:abac_id_free)
269***/
270            ID() : m_id(NULL) { } // do not use: required by swig
271            ID(const ID &id) { m_id = abac_id_dup(id.m_id); }
272            ~ID() { abac_id_free(m_id); }
273
274/***
275f  ID(char *)
276     load an ID certificate from a file, will throw an exception
277     if the certificate cannot be loaded
278     (C:abac_id_from_file)
279***/
280            ID(char *filename) : m_id(NULL) {
281                m_id = abac_id_from_file(filename);
282                if (m_id == NULL)
283                    throw std::invalid_argument("Could not load ID cert");
284            }
285
286/***
287f  ID_chunk(abac_chunk_t chunk)
288     create an ID certificate from an certificate chunk, will
289     throw an exception if the certificate cannot be loaded
290     (C:abac_id_from_chunk)
291***/
292            ID(abac_chunk_t chunk) : m_id(NULL) {
293                m_id = abac_id_from_chunk(chunk);
294                if (m_id == NULL)
295                    throw std::invalid_argument("Could not load ID certificate with a chunk");
296            }
297/***
298f  ID(char *,int)
299     generates a new ID(cert&key) with the supplied CN and validity period
300     - CN must be alphanumeric and begin with a letter
301     - validity must be at least one second
302     will throw an exception if either of the above is violated
303     (C:abac_id_generate)
304***/
305            ID(char *cn, int validity) : m_id(NULL) {
306                int ret = abac_id_generate(&m_id, cn, validity);
307                if (ret == ABAC_GENERATE_INVALID_CN)
308                    throw std::invalid_argument("CN must be alphanumeric and start with a letter");
309                if (ret == ABAC_GENERATE_INVALID_VALIDITY)
310                    throw std::invalid_argument("Validity must be > 0 days");
311            }
312/***
313f  void load_privkey(char *)
314     loads the private key associated with the ID credential,
315     will throw an exception if the key cannot be loaded
316     (C:abac_id_privkey_from_file)
317f  void load_privkey_chunk(abac_chunk_t)
318     loads the private key associated with the ID credential,
319     will throw an exception if the key cannot be loaded
320     (C:abac_id_privkey_from_chunk)
321f  int has_privkey()
322     check to see if there is a privkey in this ID
323     (C:abac_id_has_privkey)
324***/
325            void load_privkey(char *filename) {
326                int ret = abac_id_privkey_from_file(m_id, filename);
327                if (ret != ABAC_SUCCESS)
328                    throw std::invalid_argument("Could not load private key");
329            }
330            void load_privkey_chunk(abac_chunk_t chunk) {
331                int ret = abac_id_privkey_from_chunk(m_id, chunk);
332                if (ret != ABAC_SUCCESS)
333                    throw std::invalid_argument("Could not load private key with a chunk");
334            }
335            int has_privkey() {
336                int ret= abac_id_has_privkey(m_id);
337                return ret;
338            }
339/***
340f  char *keyid()
341     returns the SHA1 keyid of the id cert
342     (C:abac_id_keyid)
343f  char *cn()
344     returns the cn of the id cert
345     (C:abac_id_cn)
346f  char *cert_filename()
347     returns the default libabac filename for the cert.
348     value must be freed by caller.
349     (C:abac_id_cert_filename)
350***/
351            char *keyid() { return abac_id_keyid(m_id); }
352            char *cn() { return abac_id_cn(m_id); }
353            char *cert_filename() { return abac_id_cert_filename(m_id); }
354/***
355f  void write_cert(FILE *)
356     writes a PEM-encoded certificate to a file handle
357     (C:abac_id_write_cert)
358f  void write_cert(string &)
359     writes a PEM-encoded certificate to a file named in string
360f  void write_cert_file(const char *)
361     writes a PEM-encoded certificate to a file
362f  void write_cert_name(const char *)
363     writes a PEM-encoded certificate to a file
364     (added to support original libcreddy users)
365***/
366            void write_cert(FILE *out) { abac_id_write_cert(m_id, out); }
367            void write_cert(const std::string &name) {
368                FILE *out = fopen(name.c_str(), "a+");
369                if (out == NULL)
370                    throw std::invalid_argument("Could not open certificate file for writing");
371                write_cert(out);
372                fclose(out);
373            }
374            // Simplifies access from swig
375            void write_cert_file(const char *n) {
376                write_cert(std::string(n));
377            }
378            void write_cert_name(const char *n) {
379                write_cert(std::string(n));
380                fprintf(stderr,"ABAC::ID::write_cert_name is deprecated, please use ABAC::ID::write_cert_name\n");
381            }
382/***
383f  char *privkey_filename()
384     returns the default libabac filename for the private key.
385     value must be freed by caller.
386     (C:abac_id_privkey_filename)
387***/
388            char *privkey_filename() { return abac_id_privkey_filename(m_id); }
389/***
390f  void write_privkey(FILE *)
391     write the private key to a file handle
392     throws a std::logic_error if no private key is loaded
393     (C:abac_id_write_privkey)
394f  void write_privkey(string &)
395     writes a private key to file named in string
396f  void write_privkey_file(const char *)
397     writes a private key to a file
398f  void write_privkey_name(const char *)
399     writes a private key to a file
400     (added to support original libcreddy users)
401***/
402            void write_privkey(FILE *out) {
403                int ret = abac_id_write_privkey(m_id, out);
404                if (ret!=ABAC_SUCCESS) throw std::logic_error("No private key loaded");
405            }
406            void write_privkey(const std::string &name) {
407                FILE *out = fopen(name.c_str(), "a+");
408                if (out == NULL)
409                    throw std::invalid_argument("Could not open privkey file for writing");
410                write_privkey(out);
411                fclose(out);
412            }
413            // Simplifies access from swig
414            void write_privkey_file(const char *name) {
415                write_privkey(std::string(name));
416            }
417            void write_privkey_name(const char *name) {
418                write_privkey(std::string(name));
419                fprintf(stderr,"ABAC::ID::write_privkey_name is deprecated, please use ABAC::ID::write_privkey_file\n");
420            }
421/***
422f  abac_chunk_t cert_chunk()
423     returns a DER-encoded binary representation of the X.509 ID cert
424     associated with this ID.
425     can be passed to libabac's Context::load_id_chunk()
426     (C:abac_id_cert_chunk)
427f  abac_chunk_t privkey_chunk()
428     returns a PEM-encoded binary representation of the private key
429     associated with this ID.
430     (C:abac_id_privkey_chunk)
431***/
432            abac_chunk_t cert_chunk() { return abac_id_cert_chunk(m_id); }
433            abac_chunk_t privkey_chunk() { return abac_id_privkey_chunk(m_id); }
434
435            friend class Attribute;
436            friend class Context;
437
438        private:
439            abac_id_t *m_id;
440    };
441
442/***
443ABAC::Attribute
444   This is the attribute representation for the access policy rule
445       LHS <- RHS
446   The sequence of generation is to
447       first, instantiate the object, ie, LHS (head)
448       second, adding subject(s) to it, ie, RHS (tail)
449       and then baking it.
450   Only once it's baked can you access the X.509 cert.
451   Once it's been baked you can no longer add subjects to it
452***/
453    class Attribute {
454        public:
455/***
456f  Attribute()
457     default constructor, do not use, for swig only
458f  ~Attribute()
459     default destructor
460     (C:abac_attribute_free)
461***/
462            Attribute() : m_attr(NULL) { } // do not use: required by swig
463            ~Attribute() { abac_attribute_free(m_attr); }
464
465/***
466f  Attribute(ID&, char*,int)
467     constructor that creates an attribute policy to be signed by the issuer
468     with the given role with a specified validity period
469     An exception will be thrown if:
470       - the issuer has no private key
471       - the Head role is invalid
472       - the validity period is invalid (must be >= 0 second)
473       - The issuer is invalid
474     (C:abac_attribute_create)
475***/
476            Attribute(ID &issuer, char *role, int validity) : m_attr(NULL) {
477                int ret = abac_attribute_create(&m_attr, issuer.m_id, role, validity);
478                if (ret == ABAC_ATTRIBUTE_ISSUER_NOKEY)
479                    throw std::invalid_argument("Issuer has no private key");
480                if (ret == ABAC_ATTRIBUTE_INVALID_ROLE)
481                    throw std::invalid_argument("Role name must be alphanumeric");
482                if (ret == ABAC_ATTRIBUTE_INVALID_VALIDITY)
483                    throw std::invalid_argument("Validity must be > 0 days");
484                if (ret == ABAC_ATTRIBUTE_INVALID_ISSUER)
485                    throw std::invalid_argument("Issuer's validity expired");
486            }
487
488
489/***
490f  bool principal(char *keyid)
491     {keyid}
492     validate the principal and insert into the attribute
493     throw a std::logic_error if the cert's been baked and keyid bad
494     (C:abac_attribute_principal)
495f bool role(char *keyid, char *role)
496     {keyid.role}
497     validate the principal and role and insert into the attribute
498     throw a std::logic_error if the cert's been baked and keyid bad
499     (C:abac_attribute_role)
500f bool linking_role(char *keyid, char *role, char *linked)
501     {keyid.linked.role}
502     validate the role and linking role and insert into the attribute
503     throw a std::logic_error if the cert's been baked and keyid bad
504     (C:abac_attribute_linking_role)
505***/
506            bool principal(char *keyid) {
507                if (baked()) throw std::logic_error("Cert is already baked");
508                return abac_attribute_principal(m_attr, keyid);
509            }
510            bool role(char *keyid, char *role) {
511                if (baked()) throw std::logic_error("Cert is already baked");
512                return abac_attribute_role(m_attr, keyid, role);
513            }
514            bool linking_role(char *keyid, char *role, char *linked) {
515                if (baked()) throw std::logic_error("Cert is already baked");
516                return abac_attribute_linking_role(m_attr, keyid, role, linked);
517            }
518/***
519f  bool bake()
520     Generate the cert. Call this after you've added subjects to your cert.
521     This returns false if there are no subjects
522     This will throw an exception if the cert's already been baked.
523     (C:abac_attribute_bake)
524***/
525            bool bake() {
526                if (baked()) throw std::logic_error("Cert is already baked");
527                return abac_attribute_bake(m_attr);
528            }
529
530/***
531f  bool bake(Context c)
532     Generate the cert. Call this after you've added subjects to your cert.
533     This returns false if there are no subjects
534     This will throw an exception if the cert's already been baked.
535     This version annotated the baked credential with any mnemonic names in the
536     context.
537     (C:abac_attribute_bake_context)
538***/
539            bool bake(Context& c) {
540                if (baked()) throw std::logic_error("Cert is already baked");
541                return abac_attribute_bake_context(m_attr, c.m_ctx);
542            }
543
544/***
545f  bool baked()
546     returns true iff the certificate has been baked.
547     (C:abac_attribute_baked)
548***/
549            bool baked() { return abac_attribute_baked(m_attr); }
550
551/***
552f  set_output_format(char *fmt)
553     {fmt}
554     Set the attribute's output format.  Valid choices are GENIv1.0 and
555     GENIV1.1.  Default is GENIv1.1.
556***/
557            void set_output_format(char *fmt) {
558                abac_attribute_set_output_format(m_attr, fmt);
559            }
560
561/***
562f  get_output_format(char *fmt)
563     Get the attribute's output format.  Do not delete the string/
564***/
565            char *get_output_format() {
566                return abac_attribute_get_output_format(m_attr);
567            }
568
569/***
570f  void write(FILE *)
571     write an attribute certificate in XML to an open file handle
572     Throws an exception if the certificate isn't baked
573     (C:abac_attribute_write)
574f  void write(const string&)
575     write an attribute certificate in XML to file named in string
576f  void write_file(const char *)
577     write an attribute certificate in XML to file
578f  void write_name(const char *)
579     write an attribute certificate in XML to file
580     (added to support original libcreddy users)
581***/
582            void write(FILE *out) {
583                int ret = abac_attribute_write(m_attr, out);
584                if (ret!=ABAC_SUCCESS) throw std::logic_error("Cert is not baked");
585            }
586            void write(const std::string &name) {
587                FILE *out = fopen(name.c_str(), "w");
588                if (out == NULL)
589                    throw std::invalid_argument("Could not open certificate file for writing");
590                write(out);
591                fclose(out);
592            }
593            void write_file(const char *name) {
594                int ret = abac_attribute_write_file(m_attr, name);
595                if (ret!=ABAC_SUCCESS) throw std::logic_error("Cert is not baked");
596            }
597            void write_name(const char *name) {
598                write_file(name);
599                fprintf(stderr,"ABAC::Attribute::write_name is deprecated, please use ABAC::Attribute::write_name\n");
600            }
601/***
602f  abac_chunk_t cert_chunk()
603     returns a XML structure of the attribute certificate in a abac_chunk_t
604     Throws an exception if the certificate isn't baked
605     the chunk can be passed to libabac's Context::load_attribute_chunk()
606     (C:abac_attribute_cert_chunk)
607***/
608            abac_chunk_t cert_chunk() {
609                abac_chunk_t ret=abac_attribute_cert_chunk(m_attr);
610                if(ret.len == 0)
611                    throw std::logic_error("Cert is not baked");
612                return ret;
613            }
614
615        private:
616            abac_attribute_t *m_attr;
617    };
618
619    int Context::load_id_id(ID& id)
620    { return abac_context_load_id_id(m_ctx, id.m_id); }
621
622    /* abac query, returns a vector of credentials on success, NULL on fail */
623    inline std::vector<Credential> Context::query(char *role, char *principal,
624            bool &success) {
625        std::vector<Credential> credentials = std::vector<Credential>();
626        abac_credential_t **creds;
627        int i, success_int;
628        creds = abac_context_query(m_ctx, role, principal, &success_int);
629        success = success_int;
630
631        for (i = 0; creds[i] != NULL; ++i)
632            credentials.push_back(Credential(creds[i]));
633
634        abac_context_credentials_free(creds);
635        return credentials;
636    }
637
638    inline std::vector<Credential> Context::credentials() {
639        std::vector<Credential> credentials = std::vector<Credential>();
640        abac_credential_t **creds;
641        int i;
642
643        creds = abac_context_credentials(m_ctx);
644        for (i = 0; creds[i] != NULL; ++i)
645            credentials.push_back(Credential(creds[i]));
646
647        abac_context_credentials_free(creds);
648        return credentials;
649    }
650}
651
652#endif /* __ABAC_HH__ */
Note: See TracBrowser for help on using the repository browser.