Skip to content

Commit

Permalink
feat: Add client.Device.SamlProfile
Browse files Browse the repository at this point in the history
  • Loading branch information
shinmog committed Sep 22, 2022
1 parent 9a6f3cd commit a97fbae
Show file tree
Hide file tree
Showing 9 changed files with 614 additions and 0 deletions.
11 changes: 11 additions & 0 deletions dev/profile/saml/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package saml

const (
BindingPost = "post"
BindingRedirect = "redirect"
)

const (
singular = "saml identity provider profile"
plural = "saml identity provider profiles"
)
16 changes: 16 additions & 0 deletions dev/profile/saml/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
Package saml is the client.Device.SamlProfile namespace.
For Panorama, there are two possibilities: managing this object on Panorama
itself or inside of a Template.
To manage objects save on Panorama, leave "tmpl", "ts", and "vsys" params empty.
To manage objects in a template, specify the template name and the vsys (if
unspecified, defaults to "shared").
PAN-OS 8.0+
Normalized object: Entry
*/
package saml
141 changes: 141 additions & 0 deletions dev/profile/saml/entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package saml

import (
"encoding/xml"

"github.com/PaloAltoNetworks/pango/util"
"github.com/PaloAltoNetworks/pango/version"
)

// Entry is a normalized, version independent representation of a
// SAML identity provider profile.
//
// PAN-OS 8.0+
type Entry struct {
Name string
AdminUseOnly bool
IdentityProviderId string
IdentityProviderCertificate string // Required in PAN-OS 10.0+
SsoUrl string
SsoBinding string
SloUrl string
SloBinding string
ValidateIdentityProviderCertificate bool
SignSamlMessage bool
MaxClockSkew int
}

// Copy copies the information from source Entry `s` to this object. As the
// Name field relates to the XPATH of this object, this field is not copied.
func (o *Entry) Copy(s Entry) {
o.AdminUseOnly = s.AdminUseOnly
o.IdentityProviderId = s.IdentityProviderId
o.IdentityProviderCertificate = s.IdentityProviderCertificate
o.SsoUrl = s.SsoUrl
o.SsoBinding = s.SsoBinding
o.SloUrl = s.SloUrl
o.SloBinding = s.SloBinding
o.ValidateIdentityProviderCertificate = s.ValidateIdentityProviderCertificate
o.SignSamlMessage = s.SignSamlMessage
o.MaxClockSkew = s.MaxClockSkew
}

/** Structs / functions for this namespace. **/

func (o Entry) Specify(v version.Number) (string, interface{}) {
_, fn := versioning(v)
return o.Name, fn(o)
}

type normalizer interface {
Normalize() []Entry
Names() []string
}

type container_v1 struct {
Answer []entry_v1 `xml:"entry"`
}

func (o container_v1) Names() []string {
ans := make([]string, 0, len(o.Answer))
for i := range o.Answer {
ans = append(ans, o.Answer[i].Name)
}

return ans
}

func (o *container_v1) Normalize() []Entry {
ans := make([]Entry, 0, len(o.Answer))
for i := range o.Answer {
ans = append(ans, o.Answer[i].normalize())
}

return ans
}

type entry_v1 struct {
XMLName xml.Name `xml:"entry"`
Name string `xml:"name,attr"`
AdminUseOnly string `xml:"admin-use-only"`
IdentityProviderId string `xml:"entity-id"`
IdentityProviderCertificate string `xml:"certificate"`
SsoUrl string `xml:"sso-url"`
SsoBinding string `xml:"sso-bindings"`
SloUrl string `xml:"slo-url,omitempty"`
SloBinding string `xml:"slo-bindings,omitempty"`
ValidateIdentityProviderCertificate string `xml:"validate-idp-certificate"`
SignSamlMessage string `xml:"want-auth-requests-signed"`
MaxClockSkew int `xml:"max-clock-skew,omitempty"`
}

func (e *entry_v1) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type local entry_v1
ans := local{
SloBinding: BindingPost,
ValidateIdentityProviderCertificate: util.YesNo(true),
SignSamlMessage: util.YesNo(true),
MaxClockSkew: 60,
}
if err := d.DecodeElement(&ans, &start); err != nil {
return err
}
*e = entry_v1(ans)
return nil
}

func (o *entry_v1) normalize() Entry {
ans := Entry{
Name: o.Name,
AdminUseOnly: util.AsBool(o.AdminUseOnly),
IdentityProviderId: o.IdentityProviderId,
IdentityProviderCertificate: o.IdentityProviderCertificate,
SsoUrl: o.SsoUrl,
SsoBinding: o.SsoBinding,
SloUrl: o.SloUrl,
SloBinding: o.SloBinding,
ValidateIdentityProviderCertificate: util.AsBool(o.ValidateIdentityProviderCertificate),
SignSamlMessage: util.AsBool(o.SignSamlMessage),
MaxClockSkew: o.MaxClockSkew,
}

return ans
}

func specify_v1(e Entry) interface{} {
ans := entry_v1{
Name: e.Name,
AdminUseOnly: util.YesNo(e.AdminUseOnly),
IdentityProviderId: e.IdentityProviderId,
IdentityProviderCertificate: e.IdentityProviderCertificate,
SsoUrl: e.SsoUrl,
SsoBinding: e.SsoBinding,
SloUrl: e.SloUrl,
SloBinding: e.SloBinding,
ValidateIdentityProviderCertificate: util.YesNo(e.ValidateIdentityProviderCertificate),
SignSamlMessage: util.YesNo(e.SignSamlMessage),
MaxClockSkew: e.MaxClockSkew,
}

return ans
}
92 changes: 92 additions & 0 deletions dev/profile/saml/funcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package saml

import (
"fmt"

"github.com/PaloAltoNetworks/pango/namespace"
"github.com/PaloAltoNetworks/pango/util"
"github.com/PaloAltoNetworks/pango/version"
)

func versioning(v version.Number) (normalizer, func(Entry) interface{}) {
if v.Gte(version.Number{10, 0, 0, ""}) {
return &container_v1{}, specify_v1
} else {
return &container_v1{}, specify_v1
}
}

func specifier(e ...Entry) []namespace.Specifier {
ans := make([]namespace.Specifier, 0, len(e))

var val namespace.Specifier
for _, x := range e {
val = x
ans = append(ans, val)
}

return ans
}

func container(v version.Number) normalizer {
r, _ := versioning(v)
return r
}

func first(ans normalizer, err error) (Entry, error) {
if err != nil {
return Entry{}, err
}

return ans.Normalize()[0], nil
}

func all(ans normalizer, err error) ([]Entry, error) {
if err != nil {
return nil, err
}

return ans.Normalize(), nil
}

func toNames(e []interface{}) ([]string, error) {
ans := make([]string, len(e))
for i := range e {
switch v := e[i].(type) {
case string:
ans[i] = v
case Entry:
ans[i] = v.Name
default:
return nil, fmt.Errorf("invalid type: %s", v)
}
}

return ans, nil
}

// FirewallNamespace returns an initialized namespace.
func FirewallNamespace(client util.XapiClient) *Firewall {
return &Firewall{
ns: &namespace.Standard{
Common: namespace.Common{
Singular: singular,
Plural: plural,
Client: client,
},
},
}
}

// PanoramaNamespace returns an initialized namespace.
func PanoramaNamespace(client util.XapiClient) *Panorama {
return &Panorama{
ns: &namespace.Standard{
Common: namespace.Common{
Singular: singular,
Plural: plural,
Client: client,
},
},
}
}
109 changes: 109 additions & 0 deletions dev/profile/saml/fw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package saml

import (
"github.com/PaloAltoNetworks/pango/namespace"
"github.com/PaloAltoNetworks/pango/util"
)

// Firewall is the client.Device.SamlProfile namespace.
type Firewall struct {
ns *namespace.Standard
}

// GetList performs GET to retrieve a list of all objects.
func (c *Firewall) GetList(vsys string) ([]string, error) {
ans := c.container()
return c.ns.Listing(util.Get, c.pather(vsys), ans)
}

// ShowList performs SHOW to retrieve a list of all objects.
func (c *Firewall) ShowList(vsys string) ([]string, error) {
ans := c.container()
return c.ns.Listing(util.Show, c.pather(vsys), ans)
}

// Get performs GET to retrieve information for the given object.
func (c *Firewall) Get(vsys, name string) (Entry, error) {
ans := c.container()
err := c.ns.Object(util.Get, c.pather(vsys), name, ans)
return first(ans, err)
}

// Show performs SHOW to retrieve information for the given object.
func (c *Firewall) Show(vsys, name string) (Entry, error) {
ans := c.container()
err := c.ns.Object(util.Show, c.pather(vsys), name, ans)
return first(ans, err)
}

// GetAll performs GET to retrieve all objects configured.
func (c *Firewall) GetAll(vsys string) ([]Entry, error) {
ans := c.container()
err := c.ns.Objects(util.Get, c.pather(vsys), ans)
return all(ans, err)
}

// ShowAll performs SHOW to retrieve information for all objects.
func (c *Firewall) ShowAll(vsys string) ([]Entry, error) {
ans := c.container()
err := c.ns.Objects(util.Show, c.pather(vsys), ans)
return all(ans, err)
}

// Set performs SET to configure the specified objects.
func (c *Firewall) Set(vsys string, e ...Entry) error {
return c.ns.Set(c.pather(vsys), specifier(e...))
}

// Edit performs EDIT to configure the specified object.
func (c *Firewall) Edit(vsys string, e Entry) error {
return c.ns.Edit(c.pather(vsys), e)
}

// Delete performs DELETE to remove the specified objects.
//
// Objects can be either a string or an Entry object.
func (c *Firewall) Delete(vsys string, e ...interface{}) error {
names, nErr := toNames(e)
return c.ns.Delete(c.pather(vsys), names, nErr)
}

// FromPanosConfig retrieves the object stored in the retrieved config.
func (c *Firewall) FromPanosConfig(vsys, name string) (Entry, error) {
ans := c.container()
err := c.ns.FromPanosConfig(c.pather(vsys), name, ans)
return first(ans, err)
}

// AllFromPanosConfig retrieves all objects stored in the retrieved config.
func (c *Firewall) AllFromPanosConfig(vsys string) ([]Entry, error) {
ans := c.container()
err := c.ns.AllFromPanosConfig(c.pather(vsys), ans)
return all(ans, err)
}

func (c *Firewall) pather(vsys string) namespace.Pather {
return func(v []string) ([]string, error) {
return c.xpath(vsys, v)
}
}

func (c *Firewall) xpath(vsys string, vals []string) ([]string, error) {
if vsys == "" {
vsys = "shared"
}

ans := make([]string, 0, 8)
ans = append(ans, util.VsysXpathPrefix(vsys)...)
ans = append(ans,
"server-profile",
"saml-idp",
util.AsEntryXpath(vals),
)

return ans, nil
}

func (c *Firewall) container() normalizer {
return container(c.ns.Client.Versioning())
}
Loading

0 comments on commit a97fbae

Please sign in to comment.