github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/ldap.v2/control.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ldap 6 7 import ( 8 "fmt" 9 "strconv" 10 11 "gopkg.in/asn1-ber.v1" 12 ) 13 14 const ( 15 // ControlTypePaging - https://www.ietf.org/rfc/rfc2696.txt 16 ControlTypePaging = "1.2.840.113556.1.4.319" 17 // ControlTypeBeheraPasswordPolicy - https://tools.ietf.org/html/draft-behera-ldap-password-policy-10 18 ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1" 19 // ControlTypeVChuPasswordMustChange - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 20 ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4" 21 // ControlTypeVChuPasswordWarning - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 22 ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5" 23 // ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296 24 ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2" 25 ) 26 27 // ControlTypeMap maps controls to text descriptions 28 var ControlTypeMap = map[string]string{ 29 ControlTypePaging: "Paging", 30 ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft", 31 ControlTypeManageDsaIT: "Manage DSA IT", 32 } 33 34 // Control defines an interface controls provide to encode and describe themselves 35 type Control interface { 36 // GetControlType returns the OID 37 GetControlType() string 38 // Encode returns the ber packet representation 39 Encode() *ber.Packet 40 // String returns a human-readable description 41 String() string 42 } 43 44 // ControlString implements the Control interface for simple controls 45 type ControlString struct { 46 ControlType string 47 Criticality bool 48 ControlValue string 49 } 50 51 // GetControlType returns the OID 52 func (c *ControlString) GetControlType() string { 53 return c.ControlType 54 } 55 56 // Encode returns the ber packet representation 57 func (c *ControlString) Encode() *ber.Packet { 58 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") 59 packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")")) 60 if c.Criticality { 61 packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) 62 } 63 packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(c.ControlValue), "Control Value")) 64 return packet 65 } 66 67 // String returns a human-readable description 68 func (c *ControlString) String() string { 69 return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue) 70 } 71 72 // ControlPaging implements the paging control described in https://www.ietf.org/rfc/rfc2696.txt 73 type ControlPaging struct { 74 // PagingSize indicates the page size 75 PagingSize uint32 76 // Cookie is an opaque value returned by the server to track a paging cursor 77 Cookie []byte 78 } 79 80 // GetControlType returns the OID 81 func (c *ControlPaging) GetControlType() string { 82 return ControlTypePaging 83 } 84 85 // Encode returns the ber packet representation 86 func (c *ControlPaging) Encode() *ber.Packet { 87 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") 88 packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")")) 89 90 p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)") 91 seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value") 92 seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.PagingSize), "Paging Size")) 93 cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie") 94 cookie.Value = c.Cookie 95 cookie.Data.Write(c.Cookie) 96 seq.AppendChild(cookie) 97 p2.AppendChild(seq) 98 99 packet.AppendChild(p2) 100 return packet 101 } 102 103 // String returns a human-readable description 104 func (c *ControlPaging) String() string { 105 return fmt.Sprintf( 106 "Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q", 107 ControlTypeMap[ControlTypePaging], 108 ControlTypePaging, 109 false, 110 c.PagingSize, 111 c.Cookie) 112 } 113 114 // SetCookie stores the given cookie in the paging control 115 func (c *ControlPaging) SetCookie(cookie []byte) { 116 c.Cookie = cookie 117 } 118 119 // ControlBeheraPasswordPolicy implements the control described in https://tools.ietf.org/html/draft-behera-ldap-password-policy-10 120 type ControlBeheraPasswordPolicy struct { 121 // Expire contains the number of seconds before a password will expire 122 Expire int64 123 // Grace indicates the remaining number of times a user will be allowed to authenticate with an expired password 124 Grace int64 125 // Error indicates the error code 126 Error int8 127 // ErrorString is a human readable error 128 ErrorString string 129 } 130 131 // GetControlType returns the OID 132 func (c *ControlBeheraPasswordPolicy) GetControlType() string { 133 return ControlTypeBeheraPasswordPolicy 134 } 135 136 // Encode returns the ber packet representation 137 func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet { 138 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") 139 packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeBeheraPasswordPolicy, "Control Type ("+ControlTypeMap[ControlTypeBeheraPasswordPolicy]+")")) 140 141 return packet 142 } 143 144 // String returns a human-readable description 145 func (c *ControlBeheraPasswordPolicy) String() string { 146 return fmt.Sprintf( 147 "Control Type: %s (%q) Criticality: %t Expire: %d Grace: %d Error: %d, ErrorString: %s", 148 ControlTypeMap[ControlTypeBeheraPasswordPolicy], 149 ControlTypeBeheraPasswordPolicy, 150 false, 151 c.Expire, 152 c.Grace, 153 c.Error, 154 c.ErrorString) 155 } 156 157 // ControlVChuPasswordMustChange implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 158 type ControlVChuPasswordMustChange struct { 159 // MustChange indicates if the password is required to be changed 160 MustChange bool 161 } 162 163 // GetControlType returns the OID 164 func (c *ControlVChuPasswordMustChange) GetControlType() string { 165 return ControlTypeVChuPasswordMustChange 166 } 167 168 // Encode returns the ber packet representation 169 func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet { 170 return nil 171 } 172 173 // String returns a human-readable description 174 func (c *ControlVChuPasswordMustChange) String() string { 175 return fmt.Sprintf( 176 "Control Type: %s (%q) Criticality: %t MustChange: %v", 177 ControlTypeMap[ControlTypeVChuPasswordMustChange], 178 ControlTypeVChuPasswordMustChange, 179 false, 180 c.MustChange) 181 } 182 183 // ControlVChuPasswordWarning implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 184 type ControlVChuPasswordWarning struct { 185 // Expire indicates the time in seconds until the password expires 186 Expire int64 187 } 188 189 // GetControlType returns the OID 190 func (c *ControlVChuPasswordWarning) GetControlType() string { 191 return ControlTypeVChuPasswordWarning 192 } 193 194 // Encode returns the ber packet representation 195 func (c *ControlVChuPasswordWarning) Encode() *ber.Packet { 196 return nil 197 } 198 199 // String returns a human-readable description 200 func (c *ControlVChuPasswordWarning) String() string { 201 return fmt.Sprintf( 202 "Control Type: %s (%q) Criticality: %t Expire: %b", 203 ControlTypeMap[ControlTypeVChuPasswordWarning], 204 ControlTypeVChuPasswordWarning, 205 false, 206 c.Expire) 207 } 208 209 // ControlManageDsaIT implements the control described in https://tools.ietf.org/html/rfc3296 210 type ControlManageDsaIT struct { 211 // Criticality indicates if this control is required 212 Criticality bool 213 } 214 215 // GetControlType returns the OID 216 func (c *ControlManageDsaIT) GetControlType() string { 217 return ControlTypeManageDsaIT 218 } 219 220 // Encode returns the ber packet representation 221 func (c *ControlManageDsaIT) Encode() *ber.Packet { 222 //FIXME 223 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") 224 packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeManageDsaIT, "Control Type ("+ControlTypeMap[ControlTypeManageDsaIT]+")")) 225 if c.Criticality { 226 packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) 227 } 228 return packet 229 } 230 231 // String returns a human-readable description 232 func (c *ControlManageDsaIT) String() string { 233 return fmt.Sprintf( 234 "Control Type: %s (%q) Criticality: %t", 235 ControlTypeMap[ControlTypeManageDsaIT], 236 ControlTypeManageDsaIT, 237 c.Criticality) 238 } 239 240 // NewControlManageDsaIT returns a ControlManageDsaIT control 241 func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT { 242 return &ControlManageDsaIT{Criticality: Criticality} 243 } 244 245 // FindControl returns the first control of the given type in the list, or nil 246 func FindControl(controls []Control, controlType string) Control { 247 for _, c := range controls { 248 if c.GetControlType() == controlType { 249 return c 250 } 251 } 252 return nil 253 } 254 255 // DecodeControl returns a control read from the given packet, or nil if no recognized control can be made 256 func DecodeControl(packet *ber.Packet) Control { 257 var ( 258 ControlType = "" 259 Criticality = false 260 value *ber.Packet 261 ) 262 263 switch len(packet.Children) { 264 case 0: 265 // at least one child is required for control type 266 return nil 267 268 case 1: 269 // just type, no criticality or value 270 packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" 271 ControlType = packet.Children[0].Value.(string) 272 273 case 2: 274 packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" 275 ControlType = packet.Children[0].Value.(string) 276 277 // Children[1] could be criticality or value (both are optional) 278 // duck-type on whether this is a boolean 279 if _, ok := packet.Children[1].Value.(bool); ok { 280 packet.Children[1].Description = "Criticality" 281 Criticality = packet.Children[1].Value.(bool) 282 } else { 283 packet.Children[1].Description = "Control Value" 284 value = packet.Children[1] 285 } 286 287 case 3: 288 packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" 289 ControlType = packet.Children[0].Value.(string) 290 291 packet.Children[1].Description = "Criticality" 292 Criticality = packet.Children[1].Value.(bool) 293 294 packet.Children[2].Description = "Control Value" 295 value = packet.Children[2] 296 297 default: 298 // more than 3 children is invalid 299 return nil 300 } 301 302 switch ControlType { 303 case ControlTypeManageDsaIT: 304 return NewControlManageDsaIT(Criticality) 305 case ControlTypePaging: 306 value.Description += " (Paging)" 307 c := new(ControlPaging) 308 if value.Value != nil { 309 valueChildren := ber.DecodePacket(value.Data.Bytes()) 310 value.Data.Truncate(0) 311 value.Value = nil 312 value.AppendChild(valueChildren) 313 } 314 value = value.Children[0] 315 value.Description = "Search Control Value" 316 value.Children[0].Description = "Paging Size" 317 value.Children[1].Description = "Cookie" 318 c.PagingSize = uint32(value.Children[0].Value.(int64)) 319 c.Cookie = value.Children[1].Data.Bytes() 320 value.Children[1].Value = c.Cookie 321 return c 322 case ControlTypeBeheraPasswordPolicy: 323 value.Description += " (Password Policy - Behera)" 324 c := NewControlBeheraPasswordPolicy() 325 if value.Value != nil { 326 valueChildren := ber.DecodePacket(value.Data.Bytes()) 327 value.Data.Truncate(0) 328 value.Value = nil 329 value.AppendChild(valueChildren) 330 } 331 332 sequence := value.Children[0] 333 334 for _, child := range sequence.Children { 335 if child.Tag == 0 { 336 //Warning 337 warningPacket := child.Children[0] 338 packet := ber.DecodePacket(warningPacket.Data.Bytes()) 339 val, ok := packet.Value.(int64) 340 if ok { 341 if warningPacket.Tag == 0 { 342 //timeBeforeExpiration 343 c.Expire = val 344 warningPacket.Value = c.Expire 345 } else if warningPacket.Tag == 1 { 346 //graceAuthNsRemaining 347 c.Grace = val 348 warningPacket.Value = c.Grace 349 } 350 } 351 } else if child.Tag == 1 { 352 // Error 353 packet := ber.DecodePacket(child.Data.Bytes()) 354 val, ok := packet.Value.(int8) 355 if !ok { 356 // what to do? 357 val = -1 358 } 359 c.Error = val 360 child.Value = c.Error 361 c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error] 362 } 363 } 364 return c 365 case ControlTypeVChuPasswordMustChange: 366 c := &ControlVChuPasswordMustChange{MustChange: true} 367 return c 368 case ControlTypeVChuPasswordWarning: 369 c := &ControlVChuPasswordWarning{Expire: -1} 370 expireStr := ber.DecodeString(value.Data.Bytes()) 371 372 expire, err := strconv.ParseInt(expireStr, 10, 64) 373 if err != nil { 374 return nil 375 } 376 c.Expire = expire 377 value.Value = c.Expire 378 379 return c 380 default: 381 c := new(ControlString) 382 c.ControlType = ControlType 383 c.Criticality = Criticality 384 if value != nil { 385 c.ControlValue = value.Value.(string) 386 } 387 return c 388 } 389 } 390 391 // NewControlString returns a generic control 392 func NewControlString(controlType string, criticality bool, controlValue string) *ControlString { 393 return &ControlString{ 394 ControlType: controlType, 395 Criticality: criticality, 396 ControlValue: controlValue, 397 } 398 } 399 400 // NewControlPaging returns a paging control 401 func NewControlPaging(pagingSize uint32) *ControlPaging { 402 return &ControlPaging{PagingSize: pagingSize} 403 } 404 405 // NewControlBeheraPasswordPolicy returns a ControlBeheraPasswordPolicy 406 func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy { 407 return &ControlBeheraPasswordPolicy{ 408 Expire: -1, 409 Grace: -1, 410 Error: -1, 411 } 412 } 413 414 func encodeControls(controls []Control) *ber.Packet { 415 packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls") 416 for _, control := range controls { 417 packet.AppendChild(control.Encode()) 418 } 419 return packet 420 }