Skip to content

Commit

Permalink
Merge pull request #36 from datadrivers/support-ldap-server
Browse files Browse the repository at this point in the history
Support LDAP server
  • Loading branch information
Nosmoht authored Jul 6, 2020
2 parents 7937bad + 3d98f2c commit b394aac
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 2 deletions.
9 changes: 7 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,22 @@ type Client interface {
BlobstoreDelete(string) error
BlobstoreRead(string) (*Blobstore, error)
BlobstoreUpdate(string, Blobstore) error
CertificateList() (*[]Certificate, error)
CertificateGet(*CertificateRequest) (*Certificate, error)
CertificateCreate(*Certificate) error
CertificateDelete(string) error
CertificateGet(*CertificateRequest) (*Certificate, error)
CertificateList() (*[]Certificate, error)
ContentSelectorCreate(ContentSelector) error
ContentSelectorDelete(string) error
ContentSelectorRead(string) (*ContentSelector, error)
ContentSelectorUpdate(string, ContentSelector) error
ContentType() string
ContentTypeJSON()
ContentTypeTextPlain()
LDAPList() ([]LDAP, error)
LDAPCreate(LDAP) error
LDAPDelete(string) error
LDAPRead(string) (*LDAP, error)
LDAPUpdate(string, LDAP) error
PrivilegeCreate(Privilege) error
PrivilegeDelete(string) error
PrivilegeRead(string) (*Privilege, error)
Expand Down
131 changes: 131 additions & 0 deletions ldap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package client

import (
"encoding/json"
"fmt"
"net/http"
)

const (
ldapAPIEndpoint = "service/rest/beta/security/ldap"
)

// LDAP data structure
type LDAP struct {
AuthPassword string `json:"authPassword"`
AuthRealm string `json:"authRealm,omitempty"`
AuthSchema string `json:"authScheme"`
AuthUserName string `json:"authUsername,omitempty"`
ConnectionRetryDelaySeconds uint `json:"connectionRetryDelaySeconds"`
ConnectionTimeoutSeconds uint `json:"connectionTimeoutSeconds"`
GroupBaseDn string `json:"groupBaseDn,omitempty"`
GroupIDAttribute string `json:"groupIdAttribute,omitempty"`
GroupMemberAttribute string `json:"groupMemberAttribute,omitempty"`
GroupMemberFormat string `json:"groupMemberFormat,omitempty"`
GroupObjectClass string `json:"groupObjectClass,omitempty"`
GroupSubtree bool `json:"groupSubtree,omitempty"`
GroupType string `json:"groupType"`
Host string `json:"host"`
ID string `json:"id"`
LDAPGroupsAsRoles bool `json:"ldapGroupsAsRoles,omitempty"`
MaxIncidentCount uint `json:"maxIncidentsCount"`
Name string `json:"name"`
Port uint `json:"port"`
Protocol string `json:"protocol"`
SearchBase string `json:"searchBase"`
UseBaseCon string `json:"userBaseDn,omitempty"`
UseSubtree bool `json:"userSubtree,omitempty"`
UseTrustStore bool `json:"useTrustStore,omitempty"`
UserEmailAddressAttribute string `json:"userEmailAddressAttribute,omitempty"`
UserIDAttribute string `json:"userIdAttribute,omitempty"`
UserLDAPFilter string `json:"userLdapFilter,omitempty"`
UserMemberOffAttribute string `json:"userMemberOfAttribute,omitempty"`
UserObjectClass string `json:"userObjectClass,omitempty"`
UserPasswordAttribute string `json:"userPasswordAttribute,omitempty"`
UserRealNameAttribute string `json:"userRealNameAttribute,omitempty"`
}

func (c *client) LDAPList() ([]LDAP, error) {
body, resp, err := c.Get(ldapAPIEndpoint, nil)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("could not get LDAP server: HTTP: %d, %v", resp.StatusCode, string(body))
}

var result []LDAP
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("could not unmarshal LDAP server: %v", err)
}

return result, nil
}

func (c *client) LDAPCreate(ldap LDAP) error {
ioReader, err := jsonMarshalInterfaceToIOReader(ldap)
if err != nil {
return err
}

body, resp, err := c.Post(ldapAPIEndpoint, ioReader)
if err != nil {
return err
}

if resp.StatusCode != http.StatusCreated {
return fmt.Errorf("could not create LDAP server: HTTP: %d, %v", resp.StatusCode, string(body))
}

return nil
}

func (c *client) LDAPRead(name string) (*LDAP, error) {
body, resp, err := c.Get(fmt.Sprintf("%s/%s", ldapAPIEndpoint, name), nil)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("could not get LDAP server '%s': HTTP: %d, %v", name, resp.StatusCode, string(body))
}

ldapServer := &LDAP{}
if err := json.Unmarshal(body, ldapServer); err != nil {
return nil, fmt.Errorf("could not unmarshal LDAP server '%s': %v", name, err)
}

return ldapServer, nil
}

func (c *client) LDAPUpdate(name string, ldap LDAP) error {
ioReader, err := jsonMarshalInterfaceToIOReader(ldap)
if err != nil {
return err
}

body, resp, err := c.Put(fmt.Sprintf("%s/%s", ldapAPIEndpoint, name), ioReader)
if err != nil {
return err
}

if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("could not update LDAP server `%s`: HTTP: %d, :%v", name, resp.StatusCode, string(body))
}

return nil
}

func (c *client) LDAPDelete(name string) error {
body, resp, err := c.Delete(fmt.Sprintf("%s/%s", ldapAPIEndpoint, name))
if err != nil {
return err
}

if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("could not delete LDAP server '%s': HTTP: %d, %v", name, resp.StatusCode, string(body))
}

return nil
}
81 changes: 81 additions & 0 deletions ldap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package client

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestLDAPList(t *testing.T) {
client := getTestClient()

ldapServer, err := client.LDAPList()
assert.Nil(t, err)
assert.NotNil(t, ldapServer)
}

func TestLDAP(t *testing.T) {
client := getTestClient()

// https://hub.docker.com/r/mwaeckerlin/openldap/
ldap := LDAP{
AuthPassword: "1234567890",
AuthSchema: "SIMPLE",
AuthUserName: "admin",
ConnectionTimeoutSeconds: uint(1),
GroupType: "STATIC",
Host: "127.0.0.1",
Name: "ci-test",
Port: 389,
Protocol: "LDAP",
SearchBase: "dc=example,dc=com",
UserEmailAddressAttribute: "mail",
UserIDAttribute: "uid",
UserObjectClass: "inetOrgPerson",
UserRealNameAttribute: "cn",
}
err := client.LDAPCreate(ldap)
assert.Nil(t, err)

if err == nil {
createdLDAP, err := client.LDAPRead(ldap.Name)
assert.Nil(t, err)
assert.NotNil(t, createdLDAP)
assert.NotNil(t, createdLDAP.ID)
assert.Equal(t, ldap.AuthSchema, createdLDAP.AuthSchema)
assert.Equal(t, ldap.AuthUserName, createdLDAP.AuthUserName)
assert.Equal(t, ldap.Host, createdLDAP.Host)
assert.Equal(t, ldap.Port, createdLDAP.Port)
assert.Equal(t, ldap.ConnectionTimeoutSeconds, createdLDAP.ConnectionTimeoutSeconds)
// GroupType is not returned :-/
// assert.Equal(t, ldap.GroupType, createdLDAP.GroupType)
assert.Equal(t, ldap.Name, createdLDAP.Name)
assert.Equal(t, ldap.Protocol, createdLDAP.Protocol)
assert.Equal(t, ldap.SearchBase, createdLDAP.SearchBase)
assert.Equal(t, ldap.UserEmailAddressAttribute, createdLDAP.UserEmailAddressAttribute)
assert.Equal(t, ldap.UserIDAttribute, createdLDAP.UserIDAttribute)
assert.Equal(t, ldap.UserObjectClass, createdLDAP.UserObjectClass)
assert.Equal(t, ldap.UserRealNameAttribute, createdLDAP.UserRealNameAttribute)

createdLDAP.Host = "127.0.0.2"
// As GroupType is not returned while read, it needs to be set again
createdLDAP.GroupType = "DYNAMIC"
// As AuthPassword is not returned while read, it needs to be set again
createdLDAP.AuthPassword = ldap.AuthPassword
err = client.LDAPUpdate(ldap.Name, *createdLDAP)
assert.Nil(t, err)

updatedLDAP, err := client.LDAPRead(createdLDAP.Name)
assert.Nil(t, err)
assert.NotNil(t, updatedLDAP)
assert.Equal(t, createdLDAP.Host, updatedLDAP.Host)

err = client.LDAPDelete(ldap.Name)
assert.Nil(t, err)

deletedLDAP, err := client.LDAPRead(ldap.Name)
// If the server was delete we get 404 and therefore expect an error
assert.NotNil(t, err)
assert.Nil(t, deletedLDAP)
}
}

0 comments on commit b394aac

Please sign in to comment.