Skip to content

Commit

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

const (
LdapTypeActiveDirectory = "active-directory"
LdapTypeEdirectory = "e-directory"
LdapTypeSun = "sun"
LdapTypeOther = "other"
)

const (
singular = "ldap profile"
plural = "ldap profiles"
)
16 changes: 16 additions & 0 deletions dev/profile/ldap/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
Package ldap is the client.Device.LdapProfile 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 7.0+
Normalized object: Entry
*/
package ldap
218 changes: 218 additions & 0 deletions dev/profile/ldap/entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package ldap

import (
"encoding/xml"

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

// Entry is a normalized, version independent representation of a
// radius profile.
//
// PAN-OS 7.0+
type Entry struct {
Name string
AdminUseOnly bool
LdapType string
Ssl bool
VerifyServerCertificate bool
Disabled bool
BaseDn string
BindDn string
Password string
BindTimeout int
SearchTimeout int
RetryInterval int
Servers []Server
}

type Server struct {
Name string
Server string
Port 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.LdapType = s.LdapType
o.Ssl = s.Ssl
o.VerifyServerCertificate = s.VerifyServerCertificate
o.Disabled = s.Disabled
o.BaseDn = s.BaseDn
o.BindDn = s.BindDn
o.Password = s.Password
o.BindTimeout = s.BindTimeout
o.SearchTimeout = s.SearchTimeout
o.RetryInterval = s.RetryInterval

if s.Servers == nil {
o.Servers = nil
} else {
o.Servers = make([]Server, 0, len(s.Servers))
for _, x := range s.Servers {
o.Servers = append(o.Servers, Server{
Name: x.Name,
Server: x.Server,
Port: x.Port,
})
}
}
}

/** 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"`
LdapType string `xml:"ldap-type,omitempty"`
Ssl string `xml:"ssl,omitempty"`
VerifyServerCertificate string `xml:"verify-server-certificate"`
Disabled string `xml:"disabled"`
BaseDn string `xml:"base,omitempty"`
BindDn string `xml:"bind-dn,omitempty"`
Password string `xml:"bind-password,omitempty"`
BindTimeout int `xml:"bind-timelimit,omitempty"`
SearchTimeout int `xml:"timelimit,omitempty"`
RetryInterval int `xml:"retry-interval,omitempty"`
Servers *servers `xml:"server"`
}

func (e *entry_v1) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type local entry_v1
ans := local{
LdapType: LdapTypeOther,
Ssl: util.YesNo(true),
BindTimeout: 30,
SearchTimeout: 30,
RetryInterval: 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),
LdapType: o.LdapType,
Ssl: util.AsBool(o.Ssl),
VerifyServerCertificate: util.AsBool(o.VerifyServerCertificate),
Disabled: util.AsBool(o.Disabled),
BaseDn: o.BaseDn,
BindDn: o.BindDn,
Password: o.Password,
BindTimeout: o.BindTimeout,
SearchTimeout: o.SearchTimeout,
RetryInterval: o.RetryInterval,
}

if o.Servers != nil && len(o.Servers.Entries) > 0 {
listing := make([]Server, 0, len(o.Servers.Entries))
for _, x := range o.Servers.Entries {
listing = append(listing, Server{
Name: x.Name,
Server: x.Server,
Port: x.Port,
})
}
ans.Servers = listing
}

return ans
}

type servers struct {
Entries []serverEntry `xml:"entry"`
}

type serverEntry struct {
XMLName xml.Name `xml:"entry"`
Name string `xml:"name,attr"`
Server string `xml:"address"`
Port int `xml:"port,omitempty"`
}

func (e *serverEntry) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type local serverEntry
ans := local{
Port: 389,
}
if err := d.DecodeElement(&ans, &start); err != nil {
return err
}
*e = serverEntry(ans)
return nil
}

func specify_v1(e Entry) interface{} {
ans := entry_v1{
Name: e.Name,
AdminUseOnly: util.YesNo(e.AdminUseOnly),
LdapType: e.LdapType,
VerifyServerCertificate: util.YesNo(e.VerifyServerCertificate),
Disabled: util.YesNo(e.Disabled),
BaseDn: e.BaseDn,
BindDn: e.BindDn,
Password: e.Password,
BindTimeout: e.BindTimeout,
SearchTimeout: e.SearchTimeout,
RetryInterval: e.RetryInterval,
}

if !e.Ssl {
ans.Ssl = util.YesNo(false)
}

if len(e.Servers) > 0 {
listing := make([]serverEntry, 0, len(e.Servers))
for _, x := range e.Servers {
listing = append(listing, serverEntry{
Name: x.Name,
Server: x.Server,
Port: x.Port,
})
}
ans.Servers = &servers{Entries: listing}
}

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

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 if v.Gte(version.Number{8, 1, 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,
},
},
}
}
Loading

0 comments on commit 3401a44

Please sign in to comment.