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 {