From bc84bc4a289f7111f13a0fe95203a2bdbe9b38c0 Mon Sep 17 00:00:00 2001 From: Gibheer Date: Wed, 31 May 2017 21:03:51 +0200 Subject: [PATCH] add location support This commit adds basic support for adding, deleting, ... locations. This needed a bit of rework for the ResourceName, as it was kind of stupid to have different implementations server internally and in the lib. There is still some need for cleanup, but it works basically. --- cmd/pkiadm/location.go | 130 ++++++++++++++++++++++++++++++ cmd/pkiadm/main.go | 10 +++ cmd/pkiadmd/certificate.go | 19 ++--- cmd/pkiadmd/csr.go | 15 ++-- cmd/pkiadmd/location.go | 157 ++++++++++++++++++++++++++++++++++--- cmd/pkiadmd/main.go | 35 +++++---- cmd/pkiadmd/private_key.go | 18 ++--- cmd/pkiadmd/public_key.go | 14 ++-- cmd/pkiadmd/serial.go | 6 +- cmd/pkiadmd/storage.go | 47 +++++------ cmd/pkiadmd/subject.go | 12 +-- location.go | 61 ++++++++++++++ resourcetype_string.go | 45 +++++++++-- transport.go | 1 + 14 files changed, 472 insertions(+), 98 deletions(-) create mode 100644 cmd/pkiadm/location.go create mode 100644 location.go diff --git a/cmd/pkiadm/location.go b/cmd/pkiadm/location.go new file mode 100644 index 0000000..6110f87 --- /dev/null +++ b/cmd/pkiadm/location.go @@ -0,0 +1,130 @@ +package main + +import ( + "fmt" + "os" + "strings" + "text/tabwriter" + + "github.com/gibheer/pkiadm" + "github.com/pkg/errors" + flag "github.com/spf13/pflag" +) + +func createLocation(args []string, client *pkiadm.Client) error { + fs := flag.NewFlagSet("pkiadm create-location", flag.ExitOnError) + fs.Usage = func() { + fmt.Printf("Usage of %s:\n", "pkiadm create-location") + fmt.Println(` +Create a new file containing the referenced resources, which will be converted to pem format. +The pre command will be run before writing the file and the post command will be run after the file is written. +Resource names are defined as "type/id", where type is one of private, public, csr or cert. +`) + fs.PrintDefaults() + } + loc := pkiadm.Location{} + fs.StringVar(&loc.ID, "id", "", "the ID of the location to modify") + if err := parseLocationArgs(&loc, fs, args); err != nil { + return err + } + if err := client.CreateLocation(loc); err != nil { + return errors.Wrap(err, "could not create new location") + } + return nil +} + +func setLocation(args []string, client *pkiadm.Client) error { + fs := flag.NewFlagSet("pkiadm set-location", flag.ExitOnError) + loc := pkiadm.Location{} + fs.StringVar(&loc.ID, "id", "", "the ID of the location to modify") + if err := parseLocationArgs(&loc, fs, args); err != nil { + return err + } + fieldList := []string{} + for _, field := range []string{"path", "pre-cmd", "post-cmd", "resources"} { + flag := fs.Lookup(field) + if flag.Changed { + fieldList = append(fieldList, field) + } + } + if err := client.SetLocation(loc, fieldList); err != nil { + return errors.Wrap(err, "could not change location") + } + return nil +} + +func parseLocationArgs(loc *pkiadm.Location, fs *flag.FlagSet, args []string) error { + resources := []string{} + fs.StringVar(&loc.Path, "path", "", "the filename of the location where replaces will be placed") + fs.StringSliceVar(&resources, "resources", []string{}, "the resource description to add to the location") + fs.StringVar(&loc.PreCommand, "pre-cmd", "", "the pre command to run before writing the file") + fs.StringVar(&loc.PostCommand, "post-cmd", "", "the oste command to run after writing the file") + fs.Parse(args) + + for _, res := range resources { + parts := strings.Split(res, "/") + if len(parts) != 2 { + return errors.Errorf("could not parse resource: '%s'\n", res) + } + resType, err := pkiadm.StringToResourceType(parts[0]) + if err != nil { + return errors.Errorf("invalid resource type '%s'", parts[0]) + } + loc.Dependencies = append(loc.Dependencies, pkiadm.ResourceName{parts[1], resType}) + } + return nil +} + +func deleteLocation(args []string, client *pkiadm.Client) error { + fs := flag.NewFlagSet("pkiadm delete-location", flag.ExitOnError) + id := fs.String("id", "", "the id of the location to delete") + fs.Parse(args) + + if err := client.DeleteLocation(*id); err != nil { + return errors.Wrap(err, "could not remove location") + } + return nil +} + +func showLocation(args []string, client *pkiadm.Client) error { + fs := flag.NewFlagSet("pkiadm show-location", flag.ExitOnError) + id := fs.String("id", "", "the id to view in detail") + fs.Parse(args) + + loc, err := client.ShowLocation(*id) + if err != nil { + return err + } + deps := []string{} + for _, dep := range loc.Dependencies { + deps = append(deps, dep.String()) + } + out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight) + fmt.Fprintf(out, "ID:\t%s\t\n", loc.ID) + fmt.Fprintf(out, "path:\t%s\t\n", loc.Path) + fmt.Fprintf(out, "pre-cmd:\t%s\t\n", ReplaceEmpty(loc.PreCommand)) + fmt.Fprintf(out, "post-cmd:\t%s\t\n", ReplaceEmpty(loc.PostCommand)) + fmt.Fprintf(out, "deps:\t%s\t\n", strings.Join(deps, ", ")) + out.Flush() + return nil +} + +func listLocation(args []string, client *pkiadm.Client) error { + fs := flag.NewFlagSet("pkiadm list-location", flag.ExitOnError) + fs.Parse(args) + + locs, err := client.ListLocation() + if err != nil { + return err + } + if len(locs) == 0 { + return nil + } + out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight) + fmt.Fprintf(out, "%s\t%s\t%s\t\n", "id", "path", "deps") + for _, loc := range locs { + fmt.Fprintf(out, "%s\t%s\t%d\t\n", loc.ID, loc.Path, len(loc.Dependencies)) + } + out.Flush() + return nil +} diff --git a/cmd/pkiadm/main.go b/cmd/pkiadm/main.go index 9eeae99..85f98cc 100644 --- a/cmd/pkiadm/main.go +++ b/cmd/pkiadm/main.go @@ -50,6 +50,16 @@ func main() { err = setPrivateKey(args, client) case `show-private`: err = showPrivateKey(args, client) + case `create-location`: + err = createLocation(args, client) + case `delete-location`: + err = deleteLocation(args, client) + case `list-location`: + err = listLocation(args, client) + case `set-location`: + err = setLocation(args, client) + case `show-location`: + err = showLocation(args, client) default: fmt.Printf("unknown subcommand '%s'\n", cmd) printCommands() diff --git a/cmd/pkiadmd/certificate.go b/cmd/pkiadmd/certificate.go index 512083c..16b450f 100644 --- a/cmd/pkiadmd/certificate.go +++ b/cmd/pkiadmd/certificate.go @@ -5,6 +5,7 @@ import ( "time" "github.com/gibheer/pki" + "github.com/gibheer/pkiadm" ) type ( @@ -14,16 +15,16 @@ type ( IsCA bool Duration time.Duration - PrivateKey ResourceName - Serial ResourceName - CSR ResourceName - CA ResourceName + PrivateKey pkiadm.ResourceName + Serial pkiadm.ResourceName + CSR pkiadm.ResourceName + CA pkiadm.ResourceName Data []byte } ) -func NewCertificate(id string, privateKey, serial, csr, ca ResourceName, isCA bool, duration time.Duration) (*Certificate, error) { +func NewCertificate(id string, privateKey, serial, csr, ca pkiadm.ResourceName, isCA bool, duration time.Duration) (*Certificate, error) { return &Certificate{ ID: id, PrivateKey: privateKey, @@ -36,8 +37,8 @@ func NewCertificate(id string, privateKey, serial, csr, ca ResourceName, isCA bo } // Return the unique ResourceName -func (c *Certificate) Name() ResourceName { - return ResourceName{c.ID, RTCertificate} +func (c *Certificate) Name() pkiadm.ResourceName { + return pkiadm.ResourceName{c.ID, pkiadm.RTCertificate} } // AddDependency registers a depending resource to be retuened by Dependencies() @@ -116,8 +117,8 @@ func (c *Certificate) Pem() ([]byte, error) { return c.Data, nil } func (c *Certificate) Checksum() []byte { return Hash(c.Data) } // DependsOn must return the resource names it is depending on. -func (c *Certificate) DependsOn() []ResourceName { - res := []ResourceName{ +func (c *Certificate) DependsOn() []pkiadm.ResourceName { + res := []pkiadm.ResourceName{ c.PrivateKey, c.Serial, c.CSR, diff --git a/cmd/pkiadmd/csr.go b/cmd/pkiadmd/csr.go index 38bf3d5..3f08602 100644 --- a/cmd/pkiadmd/csr.go +++ b/cmd/pkiadmd/csr.go @@ -5,6 +5,7 @@ import ( "net" "github.com/gibheer/pki" + "github.com/gibheer/pkiadm" ) type ( @@ -19,8 +20,8 @@ type ( IPAddresses []net.IP // PrivateKey is needed to sign the certificate sign request. - PrivateKey ResourceName - Subject ResourceName + PrivateKey pkiadm.ResourceName + Subject pkiadm.ResourceName // Data contains the pem representation of the CSR. Data []byte @@ -28,7 +29,7 @@ type ( ) // NewCSR creates a new CSR. -func NewCSR(id string, pk, subject ResourceName, commonName string, dnsNames []string, +func NewCSR(id string, pk, subject pkiadm.ResourceName, commonName string, dnsNames []string, emailAddresses []string, iPAddresses []net.IP) (*CSR, error) { return &CSR{ ID: id, @@ -42,8 +43,8 @@ func NewCSR(id string, pk, subject ResourceName, commonName string, dnsNames []s } // Return the unique ResourceName -func (c *CSR) Name() ResourceName { - return ResourceName{c.ID, RTCSR} +func (c *CSR) Name() pkiadm.ResourceName { + return pkiadm.ResourceName{c.ID, pkiadm.RTCSR} } // AddDependency registers a depending resource to be retuened by Dependencies() @@ -88,8 +89,8 @@ func (c *CSR) Pem() ([]byte, error) { return c.Data, nil } func (c *CSR) Checksum() []byte { return Hash(c.Data) } // DependsOn must return the resource names it is depending on. -func (c *CSR) DependsOn() []ResourceName { - return []ResourceName{c.PrivateKey} +func (c *CSR) DependsOn() []pkiadm.ResourceName { + return []pkiadm.ResourceName{c.PrivateKey} } func (c *CSR) GetCSR() (*pki.CertificateRequest, error) { diff --git a/cmd/pkiadmd/location.go b/cmd/pkiadmd/location.go index a5ae157..e82239c 100644 --- a/cmd/pkiadmd/location.go +++ b/cmd/pkiadmd/location.go @@ -2,6 +2,11 @@ package main import ( "fmt" + "io/ioutil" + "os" + "os/exec" + + "github.com/gibheer/pkiadm" ) const ( @@ -12,12 +17,15 @@ type ( Location struct { ID string + PreCommand string + PostCommand string + Path string - Dependencies []ResourceName + Dependencies []pkiadm.ResourceName } ) -func NewLocation(id, path string, res []ResourceName) (*Location, error) { +func NewLocation(id, path, preCom, postCom string, res []pkiadm.ResourceName) (*Location, error) { if id == "" { return nil, ENoIDGiven } @@ -32,8 +40,8 @@ func NewLocation(id, path string, res []ResourceName) (*Location, error) { return l, nil } -func (l *Location) Name() ResourceName { - return ResourceName{l.ID, RTLocation} +func (l *Location) Name() pkiadm.ResourceName { + return pkiadm.ResourceName{l.ID, pkiadm.RTLocation} } // Refresh writes all resources into the single file. @@ -50,12 +58,25 @@ func (l *Location) Refresh(lookup *Storage) error { } raw = append(raw, output...) } - // TODO write to file - fmt.Printf("found %d characters for file: %s\n", len(raw), l.Path) + if l.PreCommand != "" { + cmd := exec.Command(l.PreCommand, l.Path) + if err := cmd.Run(); err != nil { + return err + } + } + if err := ioutil.WriteFile(l.Path, raw, 0600); err != nil { + return err + } + if l.PostCommand != "" { + cmd := exec.Command(l.PostCommand, l.Path) + if err := cmd.Run(); err != nil { + return err + } + } return nil } -func (l *Location) DependsOn() []ResourceName { return l.Dependencies } +func (l *Location) DependsOn() []pkiadm.ResourceName { return l.Dependencies } // Pem is not used by location, as it does not contain any data. func (l *Location) Pem() ([]byte, error) { return []byte{}, nil } @@ -63,9 +84,119 @@ func (l *Location) Pem() ([]byte, error) { return []byte{}, nil } // Checksum is not used by Location, as it does not contain any data. func (l *Location) Checksum() []byte { return []byte{} } -//func (l *Location) MarshalJSON() ([]byte, error) { -// return json.Marshal(*l) -//} -//func (l *Location) UnmarshalJSON(raw []byte) error { -// return json.Unmarshal(raw, l) -//} +func (s *Server) CreateLocation(inLoc pkiadm.Location, res *pkiadm.Result) error { + s.lock() + defer s.unlock() + + deps := []pkiadm.ResourceName{} + for _, dep := range inLoc.Dependencies { + deps = append(deps, pkiadm.ResourceName{ID: dep.ID, Type: dep.Type}) + } + loc, err := NewLocation(inLoc.ID, inLoc.Path, inLoc.PreCommand, inLoc.PostCommand, deps) + if err != nil { + res.SetError(err, "Could not create location '%s'", inLoc.ID) + return nil + } + if err := s.storage.AddLocation(loc); err != nil { + res.SetError(err, "Could not add location '%s'", inLoc.ID) + return nil + } + return s.store(res) +} + +func (s *Server) SetLocation(changeset pkiadm.LocationChange, res *pkiadm.Result) error { + s.lock() + defer s.unlock() + + changed := changeset.Location + locName := pkiadm.ResourceName{changed.ID, pkiadm.RTLocation} + loc, err := s.storage.GetLocation(locName) + if err != nil { + res.SetError(err, "could not find location '%s'", changeset.Location.ID) + return nil + } + for _, field := range changeset.FieldList { + switch field { + case "path": + // TODO remove old file? + loc.Path = changed.Path + case "pre-cmd": + loc.PreCommand = changed.PreCommand + case "post-cmd": + loc.PostCommand = changed.PostCommand + case "resources": + loc.Dependencies = changed.Dependencies + default: + res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field) + return nil + } + } + if err := s.storage.Update(locName); err != nil { + res.SetError(err, "Could not update location '%s'", loc.ID) + return nil + } + return s.store(res) +} + +func (s *Server) DeleteLocation(inLoc pkiadm.Location, res *pkiadm.Result) error { + s.lock() + defer s.unlock() + + loc, err := s.storage.GetLocation(pkiadm.ResourceName{inLoc.ID, pkiadm.RTLocation}) + if err != nil { + res.SetError(err, "could not find location '%s'", inLoc.ID) + return nil + } + + if err := os.Remove(loc.Path); err != nil { + res.SetError(err, "Could not remove file '%s' for location '%s'", loc.Path, loc.ID) + return nil + } + if err := s.storage.Remove(loc); err != nil { + res.SetError(err, "Could not remove location '%s'", loc.ID) + return nil + } + if loc.PostCommand != "" { + cmd := exec.Command(loc.PostCommand, loc.Path) + if err := cmd.Run(); err != nil { + res.SetError(err, "Could not run post command after deleting '%s'", loc.ID) + return nil + } + } + return s.store(res) +} + +func (s *Server) ShowLocation(inLoc pkiadm.PrivateKey, res *pkiadm.ResultLocations) error { + s.lock() + defer s.unlock() + + loc, err := s.storage.GetLocation(pkiadm.ResourceName{inLoc.ID, pkiadm.RTLocation}) + if err != nil { + res.Result.SetError(err, "Could not find location '%s'", inLoc.ID) + return nil + } + res.Locations = []pkiadm.Location{pkiadm.Location{ + ID: loc.ID, + Path: loc.Path, + PreCommand: loc.PreCommand, + PostCommand: loc.PostCommand, + Dependencies: loc.Dependencies, + }} + return nil +} + +func (s *Server) ListLocation(filter pkiadm.Filter, res *pkiadm.ResultLocations) error { + s.lock() + defer s.unlock() + + for _, loc := range s.storage.Locations { + res.Locations = append(res.Locations, pkiadm.Location{ + ID: loc.ID, + Path: loc.Path, + PreCommand: loc.PreCommand, + PostCommand: loc.PostCommand, + Dependencies: loc.Dependencies, + }) + } + return nil +} diff --git a/cmd/pkiadmd/main.go b/cmd/pkiadmd/main.go index 159e313..c63e527 100644 --- a/cmd/pkiadmd/main.go +++ b/cmd/pkiadmd/main.go @@ -10,15 +10,15 @@ import ( "github.com/gibheer/pkiadm" ) -const ( - RTPrivateKey ResourceType = iota - RTPublicKey - RTCSR - RTCertificate - RTLocation - RTSerial - RTSubject -) +//const ( +// RTPrivateKey ResourceType = iota +// RTPublicKey +// RTCSR +// RTCertificate +// RTLocation +// RTSerial +// RTSubject +//) const ( ENoIDGiven = Error("no ID given") @@ -32,7 +32,7 @@ const ( type ( Resource interface { // Return the unique ResourceName - Name() ResourceName + Name() pkiadm.ResourceName // AddDependency registers a depending resource to be retuened by Dependencies() // Refresh must trigger a rebuild of the resource. Refresh(*Storage) error @@ -40,21 +40,22 @@ type ( Pem() ([]byte, error) Checksum() []byte // DependsOn must return the resource names it is depending on. - DependsOn() []ResourceName + DependsOn() []pkiadm.ResourceName } - ResourceName struct { - ID string - Type ResourceType - } + // ResourceName struct { + // ID string + // Type ResourceType + // } ResourceType uint Error string ) -func (e Error) Error() string { return string(e) } -func (r ResourceName) String() string { return r.Type.String() + "/" + r.ID } +func (e Error) Error() string { return string(e) } + +//func (r ResourceName) String() string { return r.Type.String() + "/" + r.ID } func main() { os.Exit(_main()) diff --git a/cmd/pkiadmd/private_key.go b/cmd/pkiadmd/private_key.go index 7f4392e..4889f2a 100644 --- a/cmd/pkiadmd/private_key.go +++ b/cmd/pkiadmd/private_key.go @@ -39,8 +39,8 @@ func NewPrivateKey(id string, pkType pkiadm.PrivateKeyType, bits uint) (*Private return &pk, nil } -func (p *PrivateKey) Name() ResourceName { - return ResourceName{p.ID, RTPrivateKey} +func (p *PrivateKey) Name() pkiadm.ResourceName { + return pkiadm.ResourceName{p.ID, pkiadm.RTPrivateKey} } func (p *PrivateKey) Checksum() []byte { @@ -51,8 +51,8 @@ func (p *PrivateKey) Pem() ([]byte, error) { return p.Key, nil } -func (p *PrivateKey) DependsOn() []ResourceName { - return []ResourceName{} +func (p *PrivateKey) DependsOn() []pkiadm.ResourceName { + return []pkiadm.ResourceName{} } func (p *PrivateKey) Refresh(_ *Storage) error { @@ -149,13 +149,13 @@ func (s *Server) CreatePrivateKey(inPk pkiadm.PrivateKey, res *pkiadm.Result) er res.SetError(err, "Could not add private key '%s'", inPk.ID) return nil } - return nil + return s.store(res) } func (s *Server) SetPrivateKey(changeset pkiadm.PrivateKeyChange, res *pkiadm.Result) error { s.lock() defer s.unlock() - pk, err := s.storage.GetPrivateKey(ResourceName{ID: changeset.PrivateKey.ID, Type: RTPrivateKey}) + pk, err := s.storage.GetPrivateKey(pkiadm.ResourceName{ID: changeset.PrivateKey.ID, Type: pkiadm.RTPrivateKey}) if err != nil { res.SetError(err, "Could not find private key '%s'", changeset.PrivateKey.ID) return nil @@ -172,7 +172,7 @@ func (s *Server) SetPrivateKey(changeset pkiadm.PrivateKeyChange, res *pkiadm.Re return nil } } - if err := s.storage.Update(ResourceName{ID: pk.ID, Type: RTPrivateKey}); err != nil { + if err := s.storage.Update(pkiadm.ResourceName{ID: pk.ID, Type: pkiadm.RTPrivateKey}); err != nil { res.SetError(err, "Could not update private key '%s'", changeset.PrivateKey.ID) return nil } @@ -182,7 +182,7 @@ func (s *Server) DeletePrivateKey(inPk pkiadm.ResourceName, res *pkiadm.Result) s.lock() defer s.unlock() - pk, err := s.storage.GetPrivateKey(ResourceName{ID: inPk.ID, Type: RTPrivateKey}) + pk, err := s.storage.GetPrivateKey(pkiadm.ResourceName{ID: inPk.ID, Type: pkiadm.RTPrivateKey}) if err != nil { res.SetError(err, "Could not find private key '%s'", inPk.ID) return nil @@ -198,7 +198,7 @@ func (s *Server) ShowPrivateKey(inPk pkiadm.ResourceName, res *pkiadm.ResultPriv s.lock() defer s.unlock() - pk, err := s.storage.GetPrivateKey(ResourceName{ID: inPk.ID, Type: RTPrivateKey}) + pk, err := s.storage.GetPrivateKey(pkiadm.ResourceName{ID: inPk.ID, Type: pkiadm.RTPrivateKey}) if err != nil { res.Result.SetError(err, "Could not find private key '%s'", inPk.ID) return nil diff --git a/cmd/pkiadmd/public_key.go b/cmd/pkiadmd/public_key.go index 9774a96..2dc33cc 100644 --- a/cmd/pkiadmd/public_key.go +++ b/cmd/pkiadmd/public_key.go @@ -2,6 +2,8 @@ package main import ( "encoding/pem" + + "github.com/gibheer/pkiadm" ) const ( @@ -14,7 +16,7 @@ type ( PublicKey struct { ID string - PrivateKey ResourceName + PrivateKey pkiadm.ResourceName Type PublicKeyType // mark the type of the public key Key []byte } @@ -22,7 +24,7 @@ type ( PublicKeyType uint ) -func NewPublicKey(id string, pk ResourceName) (*PublicKey, error) { +func NewPublicKey(id string, pk pkiadm.ResourceName) (*PublicKey, error) { pub := PublicKey{ ID: id, PrivateKey: pk, @@ -30,8 +32,8 @@ func NewPublicKey(id string, pk ResourceName) (*PublicKey, error) { return &pub, nil } -func (p *PublicKey) Name() ResourceName { - return ResourceName{p.ID, RTPublicKey} +func (p *PublicKey) Name() pkiadm.ResourceName { + return pkiadm.ResourceName{p.ID, pkiadm.RTPublicKey} } func (p *PublicKey) Refresh(lookup *Storage) error { @@ -57,8 +59,8 @@ func (p *PublicKey) Refresh(lookup *Storage) error { return nil } -func (p *PublicKey) DependsOn() []ResourceName { - return []ResourceName{p.PrivateKey} +func (p *PublicKey) DependsOn() []pkiadm.ResourceName { + return []pkiadm.ResourceName{p.PrivateKey} } func (p *PublicKey) Pem() ([]byte, error) { diff --git a/cmd/pkiadmd/serial.go b/cmd/pkiadmd/serial.go index f2507bc..ff3750b 100644 --- a/cmd/pkiadmd/serial.go +++ b/cmd/pkiadmd/serial.go @@ -3,6 +3,8 @@ package main import ( "crypto/rand" "math/big" + + "github.com/gibheer/pkiadm" ) const ( @@ -28,7 +30,7 @@ func NewSerial(id string, min, max int64) (*Serial, error) { } // Return the unique ResourceName -func (s *Serial) Name() ResourceName { return ResourceName{s.ID, RTSerial} } +func (s *Serial) Name() pkiadm.ResourceName { return pkiadm.ResourceName{s.ID, pkiadm.RTSerial} } // AddDependency registers a depending resource to be retuened by Dependencies() // Refresh must trigger a rebuild of the resource. @@ -43,7 +45,7 @@ func (s *Serial) Pem() ([]byte, error) { return []byte{}, nil } func (s *Serial) Checksum() []byte { return []byte{} } // DependsOn must return the resource names it is depending on. -func (s *Serial) DependsOn() []ResourceName { return []ResourceName{} } +func (s *Serial) DependsOn() []pkiadm.ResourceName { return []pkiadm.ResourceName{} } // Generate generates a new serial number and stores it to avoid double // assigning. diff --git a/cmd/pkiadmd/storage.go b/cmd/pkiadmd/storage.go index 80f4bd5..5124de4 100644 --- a/cmd/pkiadmd/storage.go +++ b/cmd/pkiadmd/storage.go @@ -7,6 +7,7 @@ import ( "log" "os" + "github.com/gibheer/pkiadm" "github.com/pkg/errors" ) @@ -193,24 +194,24 @@ func (s *Storage) AddLocation(l *Location) error { } // Get figures out the resource to the ResourceName if available. -func (s *Storage) Get(r ResourceName) (Resource, error) { +func (s *Storage) Get(r pkiadm.ResourceName) (Resource, error) { if r.ID == "" { return nil, ENoIDGiven } switch r.Type { - case RTSerial: + case pkiadm.RTSerial: return s.GetSerial(r) - case RTSubject: + case pkiadm.RTSubject: return s.GetSubject(r) - case RTPrivateKey: + case pkiadm.RTPrivateKey: return s.GetPrivateKey(r) - case RTPublicKey: + case pkiadm.RTPublicKey: return s.GetPublicKey(r) - case RTCSR: + case pkiadm.RTCSR: return s.GetCSR(r) - case RTCertificate: + case pkiadm.RTCertificate: return s.GetCertificate(r) - case RTLocation: + case pkiadm.RTLocation: return s.GetLocation(r) default: return nil, EUnknownType @@ -218,7 +219,7 @@ func (s *Storage) Get(r ResourceName) (Resource, error) { } // GetSerial returns the Serial matching the ResourceName. -func (s *Storage) GetSerial(r ResourceName) (*Serial, error) { +func (s *Storage) GetSerial(r pkiadm.ResourceName) (*Serial, error) { if se, found := s.Serials[r.ID]; found { return se, nil } @@ -226,7 +227,7 @@ func (s *Storage) GetSerial(r ResourceName) (*Serial, error) { } // GetSubject returns the Subject matching the ResourceName. -func (s *Storage) GetSubject(r ResourceName) (*Subject, error) { +func (s *Storage) GetSubject(r pkiadm.ResourceName) (*Subject, error) { if se, found := s.Subjects[r.ID]; found { return se, nil } @@ -234,7 +235,7 @@ func (s *Storage) GetSubject(r ResourceName) (*Subject, error) { } // GetPrivateKey returns the PrivateKey to the ResourceName. -func (s *Storage) GetPrivateKey(r ResourceName) (*PrivateKey, error) { +func (s *Storage) GetPrivateKey(r pkiadm.ResourceName) (*PrivateKey, error) { if pk, found := s.PrivateKeys[r.ID]; found { return pk, nil } @@ -242,7 +243,7 @@ func (s *Storage) GetPrivateKey(r ResourceName) (*PrivateKey, error) { } // GetPublicKey returns the PublicKey to the ResourceName. -func (s *Storage) GetPublicKey(r ResourceName) (*PublicKey, error) { +func (s *Storage) GetPublicKey(r pkiadm.ResourceName) (*PublicKey, error) { if res, found := s.PublicKeys[r.ID]; found { return res, nil } @@ -250,7 +251,7 @@ func (s *Storage) GetPublicKey(r ResourceName) (*PublicKey, error) { } // GetCSR returns the CSR to the CSR. -func (s *Storage) GetCSR(r ResourceName) (*CSR, error) { +func (s *Storage) GetCSR(r pkiadm.ResourceName) (*CSR, error) { if res, found := s.CSRs[r.ID]; found { return res, nil } @@ -258,7 +259,7 @@ func (s *Storage) GetCSR(r ResourceName) (*CSR, error) { } // GetCertificate returns the Certificate matching the ResourceName. -func (s *Storage) GetCertificate(r ResourceName) (*Certificate, error) { +func (s *Storage) GetCertificate(r pkiadm.ResourceName) (*Certificate, error) { if res, found := s.Certificates[r.ID]; found { return res, nil } @@ -266,7 +267,7 @@ func (s *Storage) GetCertificate(r ResourceName) (*Certificate, error) { } // GetLocation returns the Location matching the ResourceName. -func (s *Storage) GetLocation(r ResourceName) (*Location, error) { +func (s *Storage) GetLocation(r pkiadm.ResourceName) (*Location, error) { if res, found := s.Locations[r.ID]; found { return res, nil } @@ -277,19 +278,19 @@ func (s *Storage) GetLocation(r ResourceName) (*Location, error) { func (s *Storage) Remove(r Resource) error { // TODO implement unable to remove when having dependencies switch r.Name().Type { - case RTSerial: + case pkiadm.RTSerial: delete(s.Serials, r.Name().ID) - case RTSubject: + case pkiadm.RTSubject: delete(s.Subjects, r.Name().ID) - case RTPrivateKey: + case pkiadm.RTPrivateKey: delete(s.PrivateKeys, r.Name().ID) - case RTPublicKey: + case pkiadm.RTPublicKey: delete(s.PublicKeys, r.Name().ID) - case RTCSR: + case pkiadm.RTCSR: delete(s.CSRs, r.Name().ID) - case RTCertificate: + case pkiadm.RTCertificate: delete(s.Certificates, r.Name().ID) - case RTLocation: + case pkiadm.RTLocation: delete(s.Locations, r.Name().ID) default: return EUnknownType @@ -303,7 +304,7 @@ func (s *Storage) Remove(r Resource) error { } // Update sends a refresh through all resources depending on the one given. -func (s *Storage) Update(rn ResourceName) error { +func (s *Storage) Update(rn pkiadm.ResourceName) error { r, err := s.Get(rn) if err != nil { return err diff --git a/cmd/pkiadmd/subject.go b/cmd/pkiadmd/subject.go index a4879df..bdf7985 100644 --- a/cmd/pkiadmd/subject.go +++ b/cmd/pkiadmd/subject.go @@ -24,7 +24,7 @@ func NewSubject(id string, name pkix.Name) (*Subject, error) { } // Return the unique ResourceName -func (sub *Subject) Name() ResourceName { return ResourceName{sub.ID, RTSubject} } +func (sub *Subject) Name() pkiadm.ResourceName { return pkiadm.ResourceName{sub.ID, pkiadm.RTSubject} } // AddDependency registers a depending resource to be retuened by Dependencies() // Refresh must trigger a rebuild of the resource. @@ -36,7 +36,7 @@ func (sub *Subject) Pem() ([]byte, error) { return []byte{}, nil } func (sub *Subject) Checksum() []byte { return []byte{} } // DependsOn must return the resource names it is depending on. -func (sub *Subject) DependsOn() []ResourceName { return []ResourceName{} } +func (sub *Subject) DependsOn() []pkiadm.ResourceName { return []pkiadm.ResourceName{} } // GetName returns the stored name definition. func (sub *Subject) GetName() pkix.Name { @@ -65,7 +65,7 @@ func (s *Server) SetSubject(changeset pkiadm.SubjectChange, res *pkiadm.Result) s.lock() defer s.unlock() - subj, err := s.storage.GetSubject(ResourceName{ID: changeset.Subject.ID, Type: RTSubject}) + subj, err := s.storage.GetSubject(pkiadm.ResourceName{ID: changeset.Subject.ID, Type: pkiadm.RTSubject}) if err != nil { res.SetError(err, "Could not find subject '%s'", changeset.Subject.ID) return nil @@ -96,7 +96,7 @@ func (s *Server) SetSubject(changeset pkiadm.SubjectChange, res *pkiadm.Result) return nil } } - if err := s.storage.Update(ResourceName{ID: subj.ID, Type: RTSubject}); err != nil { + if err := s.storage.Update(pkiadm.ResourceName{ID: subj.ID, Type: pkiadm.RTSubject}); err != nil { res.SetError(err, "Could not update subject '%s'", changeset.Subject.ID) return nil } @@ -122,7 +122,7 @@ func (s *Server) DeleteSubject(inSubj pkiadm.ResourceName, res *pkiadm.Result) e s.lock() defer s.unlock() - subj, err := s.storage.Get(ResourceName{ID: inSubj.ID, Type: RTSubject}) + subj, err := s.storage.Get(pkiadm.ResourceName{ID: inSubj.ID, Type: pkiadm.RTSubject}) if err == ENotFound { return nil } else if err != nil { @@ -142,7 +142,7 @@ func (s *Server) ShowSubject(inSubj pkiadm.ResourceName, res *pkiadm.ResultSubje s.lock() defer s.unlock() - subj, err := s.storage.GetSubject(ResourceName{ID: inSubj.ID, Type: RTSubject}) + subj, err := s.storage.GetSubject(pkiadm.ResourceName{ID: inSubj.ID, Type: pkiadm.RTSubject}) if err == ENotFound { return nil } else if err != nil { diff --git a/location.go b/location.go new file mode 100644 index 0000000..995159c --- /dev/null +++ b/location.go @@ -0,0 +1,61 @@ +package pkiadm + +type ( + Location struct { + ID string + Path string + Dependencies []ResourceName + PreCommand string + PostCommand string + Checksum []byte + } + LocationChange struct { + Location Location + FieldList []string + } + + ResultLocations struct { + Result Result + Locations []Location + } +) + +func (c *Client) CreateLocation(loc Location) error { + return c.exec("CreateLocation", loc) +} + +func (c *Client) DeleteLocation(id string) error { + loc := ResourceName{ID: id, Type: RTLocation} + return c.exec("DeleteLocation", loc) +} + +func (c *Client) SetLocation(loc Location, fieldList []string) error { + changeset := LocationChange{loc, fieldList} + return c.exec("SetLocation", changeset) +} + +func (c *Client) ShowLocation(id string) (Location, error) { + loc := ResourceName{ID: id, Type: RTLocation} + result := &ResultLocations{} + if err := c.query("ShowLocation", loc, result); err != nil { + return Location{}, err + } + if result.Result.HasError { + return Location{}, result.Result.Error + } + for _, location := range result.Locations { + return location, nil + } + return Location{}, nil +} + +func (c *Client) ListLocation() ([]Location, error) { + result := &ResultLocations{} + if err := c.query("ListLocation", Filter{}, result); err != nil { + return []Location{}, err + } + if result.Result.HasError { + return []Location{}, result.Result.Error + } + return result.Locations, nil +} diff --git a/resourcetype_string.go b/resourcetype_string.go index bc05ab1..f9b8cb7 100644 --- a/resourcetype_string.go +++ b/resourcetype_string.go @@ -4,13 +4,46 @@ package pkiadm import "fmt" -const _ResourceType_name = "RTPrivateKeyRTPublicKeyRTCSRRTCertificateRTLocationRTSerialRTSubject" - -var _ResourceType_index = [...]uint8{0, 12, 23, 28, 41, 51, 59, 68} - func (i ResourceType) String() string { - if i >= ResourceType(len(_ResourceType_index)-1) { + switch i { + case RTPrivateKey: + return "private" + case RTPublicKey: + return "public" + case RTCSR: + return "csr" + case RTCertificate: + return "cert" + case RTSubject: + return "subject" + case RTSerial: + return "serial" + case RTLocation: + return "location" + case RTUnknown: + return "unknown" + default: return fmt.Sprintf("ResourceType(%d)", i) } - return _ResourceType_name[_ResourceType_index[i]:_ResourceType_index[i+1]] +} + +func StringToResourceType(in string) (ResourceType, error) { + switch in { + case "private": + return RTPrivateKey, nil + case "public": + return RTPublicKey, nil + case "csr": + return RTCSR, nil + case "cert": + return RTCertificate, nil + case "location": + return RTLocation, nil + case "subject": + return RTSubject, nil + case "serial": + return RTSerial, nil + default: + return RTUnknown, fmt.Errorf("unknown resource type") + } } diff --git a/transport.go b/transport.go index ec7689e..9cdfbab 100644 --- a/transport.go +++ b/transport.go @@ -37,6 +37,7 @@ const ( RTLocation RTSerial RTSubject + RTUnknown ) type ResourceName struct {