...

Source file src/github.com/go-ldap/ldap/v3/modify.go

Documentation: github.com/go-ldap/ldap/v3

     1  package ldap
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	ber "github.com/go-asn1-ber/asn1-ber"
     8  )
     9  
    10  // Change operation choices
    11  const (
    12  	AddAttribute       = 0
    13  	DeleteAttribute    = 1
    14  	ReplaceAttribute   = 2
    15  	IncrementAttribute = 3 // (https://tools.ietf.org/html/rfc4525)
    16  )
    17  
    18  // PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
    19  type PartialAttribute struct {
    20  	// Type is the type of the partial attribute
    21  	Type string
    22  	// Vals are the values of the partial attribute
    23  	Vals []string
    24  }
    25  
    26  func (p *PartialAttribute) encode() *ber.Packet {
    27  	seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
    28  	seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.Type, "Type"))
    29  	set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
    30  	for _, value := range p.Vals {
    31  		set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
    32  	}
    33  	seq.AppendChild(set)
    34  	return seq
    35  }
    36  
    37  // Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
    38  type Change struct {
    39  	// Operation is the type of change to be made
    40  	Operation uint
    41  	// Modification is the attribute to be modified
    42  	Modification PartialAttribute
    43  }
    44  
    45  func (c *Change) encode() *ber.Packet {
    46  	change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
    47  	change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
    48  	change.AppendChild(c.Modification.encode())
    49  	return change
    50  }
    51  
    52  // ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
    53  type ModifyRequest struct {
    54  	// DN is the distinguishedName of the directory entry to modify
    55  	DN string
    56  	// Changes contain the attributes to modify
    57  	Changes []Change
    58  	// Controls hold optional controls to send with the request
    59  	Controls []Control
    60  }
    61  
    62  // Add appends the given attribute to the list of changes to be made
    63  func (req *ModifyRequest) Add(attrType string, attrVals []string) {
    64  	req.appendChange(AddAttribute, attrType, attrVals)
    65  }
    66  
    67  // Delete appends the given attribute to the list of changes to be made
    68  func (req *ModifyRequest) Delete(attrType string, attrVals []string) {
    69  	req.appendChange(DeleteAttribute, attrType, attrVals)
    70  }
    71  
    72  // Replace appends the given attribute to the list of changes to be made
    73  func (req *ModifyRequest) Replace(attrType string, attrVals []string) {
    74  	req.appendChange(ReplaceAttribute, attrType, attrVals)
    75  }
    76  
    77  // Increment appends the given attribute to the list of changes to be made
    78  func (req *ModifyRequest) Increment(attrType string, attrVal string) {
    79  	req.appendChange(IncrementAttribute, attrType, []string{attrVal})
    80  }
    81  
    82  func (req *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
    83  	req.Changes = append(req.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
    84  }
    85  
    86  func (req *ModifyRequest) appendTo(envelope *ber.Packet) error {
    87  	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
    88  	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
    89  	changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
    90  	for _, change := range req.Changes {
    91  		changes.AppendChild(change.encode())
    92  	}
    93  	pkt.AppendChild(changes)
    94  
    95  	envelope.AppendChild(pkt)
    96  	if len(req.Controls) > 0 {
    97  		envelope.AppendChild(encodeControls(req.Controls))
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  // NewModifyRequest creates a modify request for the given DN
   104  func NewModifyRequest(dn string, controls []Control) *ModifyRequest {
   105  	return &ModifyRequest{
   106  		DN:       dn,
   107  		Controls: controls,
   108  	}
   109  }
   110  
   111  // Modify performs the ModifyRequest
   112  func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
   113  	msgCtx, err := l.doRequest(modifyRequest)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	defer l.finishMessage(msgCtx)
   118  
   119  	packet, err := l.readPacket(msgCtx)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	if packet.Children[1].Tag == ApplicationModifyResponse {
   125  		err := GetLDAPError(packet)
   126  		if err != nil {
   127  			return err
   128  		}
   129  	} else {
   130  		return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag)
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  // ModifyResult holds the server's response to a modify request
   137  type ModifyResult struct {
   138  	// Controls are the returned controls
   139  	Controls []Control
   140  	// Referral is the returned referral
   141  	Referral string
   142  }
   143  
   144  // ModifyWithResult performs the ModifyRequest and returns the result
   145  func (l *Conn) ModifyWithResult(modifyRequest *ModifyRequest) (*ModifyResult, error) {
   146  	msgCtx, err := l.doRequest(modifyRequest)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	defer l.finishMessage(msgCtx)
   151  
   152  	result := &ModifyResult{
   153  		Controls: make([]Control, 0),
   154  	}
   155  
   156  	l.Debug.Printf("%d: waiting for response", msgCtx.id)
   157  	packet, err := l.readPacket(msgCtx)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	switch packet.Children[1].Tag {
   163  	case ApplicationModifyResponse:
   164  		if err = GetLDAPError(packet); err != nil {
   165  			result.Referral = getReferral(err, packet)
   166  
   167  			return result, err
   168  		}
   169  		if len(packet.Children) == 3 {
   170  			for _, child := range packet.Children[2].Children {
   171  				decodedChild, err := DecodeControl(child)
   172  				if err != nil {
   173  					return nil, errors.New("failed to decode child control: " + err.Error())
   174  				}
   175  				result.Controls = append(result.Controls, decodedChild)
   176  			}
   177  		}
   178  	}
   179  	l.Debug.Printf("%d: returning", msgCtx.id)
   180  	return result, nil
   181  }
   182  

View as plain text