Some refactoring
Этот коммит содержится в:
10
Godeps/Godeps.json
сгенерированный
10
Godeps/Godeps.json
сгенерированный
@@ -29,6 +29,11 @@
|
|||||||
"Comment": "v1.7-148-gc0e2e1a",
|
"Comment": "v1.7-148-gc0e2e1a",
|
||||||
"Rev": "c0e2e1a7adaa00e47c4f6ae8faaad6991a4570ac"
|
"Rev": "c0e2e1a7adaa00e47c4f6ae8faaad6991a4570ac"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-ldap/ldap",
|
||||||
|
"Comment": "v2.2",
|
||||||
|
"Rev": "e9a325d64989e2844be629682cb085d2c58eef8d"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||||
"Comment": "v1.2-125-gd512f20",
|
"Comment": "v1.2-125-gd512f20",
|
||||||
@@ -113,6 +118,11 @@
|
|||||||
"ImportPath": "golang.org/x/image/tiff",
|
"ImportPath": "golang.org/x/image/tiff",
|
||||||
"Rev": "baddd3465a05d84a6d8d3507547a91cb188c81ea"
|
"Rev": "baddd3465a05d84a6d8d3507547a91cb188c81ea"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/asn1-ber.v1",
|
||||||
|
"Comment": "v1.1",
|
||||||
|
"Rev": "4e86f4367175e39f69d9358a5f17b4dda270378d"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/fsnotify.v1",
|
"ImportPath": "gopkg.in/fsnotify.v1",
|
||||||
"Comment": "v1.2.5",
|
"Comment": "v1.2.5",
|
||||||
|
|||||||
0
Godeps/_workspace/src/github.com/go-ldap/ldap/.gitignore
сгенерированный
поставляемый
Обычный файл
0
Godeps/_workspace/src/github.com/go-ldap/ldap/.gitignore
сгенерированный
поставляемый
Обычный файл
15
Godeps/_workspace/src/github.com/go-ldap/ldap/.travis.yml
сгенерированный
поставляемый
Обычный файл
15
Godeps/_workspace/src/github.com/go-ldap/ldap/.travis.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,15 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- tip
|
||||||
|
go_import_path: gopkg.in/ldap.v2
|
||||||
|
install:
|
||||||
|
- go get gopkg.in/asn1-ber.v1
|
||||||
|
- go get gopkg.in/ldap.v2
|
||||||
|
- go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover
|
||||||
|
- go build -v ./...
|
||||||
|
script:
|
||||||
|
- go test -v -cover ./...
|
||||||
27
Godeps/_workspace/src/github.com/go-ldap/ldap/LICENSE
сгенерированный
поставляемый
Обычный файл
27
Godeps/_workspace/src/github.com/go-ldap/ldap/LICENSE
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
55
Godeps/_workspace/src/github.com/go-ldap/ldap/README.md
сгенерированный
поставляемый
Обычный файл
55
Godeps/_workspace/src/github.com/go-ldap/ldap/README.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,55 @@
|
|||||||
|
[](https://godoc.org/gopkg.in/ldap.v1)
|
||||||
|
[](https://travis-ci.org/go-ldap/ldap)
|
||||||
|
|
||||||
|
# Basic LDAP v3 functionality for the GO programming language.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
For the latest version use:
|
||||||
|
|
||||||
|
go get gopkg.in/ldap.v2
|
||||||
|
|
||||||
|
Import the latest version with:
|
||||||
|
|
||||||
|
import "gopkg.in/ldap.v2"
|
||||||
|
|
||||||
|
|
||||||
|
## Required Libraries:
|
||||||
|
|
||||||
|
- gopkg.in/asn1-ber.v1
|
||||||
|
|
||||||
|
## Working:
|
||||||
|
|
||||||
|
- Connecting to LDAP server
|
||||||
|
- Binding to LDAP server
|
||||||
|
- Searching for entries
|
||||||
|
- Compiling string filters to LDAP filters
|
||||||
|
- Paging Search Results
|
||||||
|
- Modify Requests / Responses
|
||||||
|
- Add Requests / Responses
|
||||||
|
- Delete Requests / Responses
|
||||||
|
- Better Unicode support
|
||||||
|
|
||||||
|
## Examples:
|
||||||
|
|
||||||
|
- search
|
||||||
|
- modify
|
||||||
|
|
||||||
|
## Tests Implemented:
|
||||||
|
|
||||||
|
- Filter Compile / Decompile
|
||||||
|
|
||||||
|
## TODO:
|
||||||
|
|
||||||
|
- [x] Add Requests / Responses
|
||||||
|
- [x] Delete Requests / Responses
|
||||||
|
- [x] Modify DN Requests / Responses
|
||||||
|
- [ ] Compare Requests / Responses
|
||||||
|
- [ ] Implement Tests / Benchmarks
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
|
||||||
|
The design is licensed under the Creative Commons 3.0 Attributions license.
|
||||||
|
Read this article for more details: http://blog.golang.org/gopher
|
||||||
104
Godeps/_workspace/src/github.com/go-ldap/ldap/add.go
сгенерированный
поставляемый
Обычный файл
104
Godeps/_workspace/src/github.com/go-ldap/ldap/add.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,104 @@
|
|||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// AddRequest ::= [APPLICATION 8] SEQUENCE {
|
||||||
|
// entry LDAPDN,
|
||||||
|
// attributes AttributeList }
|
||||||
|
//
|
||||||
|
// AttributeList ::= SEQUENCE OF attribute Attribute
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Attribute struct {
|
||||||
|
attrType string
|
||||||
|
attrVals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Attribute) encode() *ber.Packet {
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attribute")
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.attrType, "Type"))
|
||||||
|
set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
|
||||||
|
for _, value := range a.attrVals {
|
||||||
|
set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
|
||||||
|
}
|
||||||
|
seq.AppendChild(set)
|
||||||
|
return seq
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddRequest struct {
|
||||||
|
dn string
|
||||||
|
attributes []Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AddRequest) encode() *ber.Packet {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.dn, "DN"))
|
||||||
|
attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
|
||||||
|
for _, attribute := range a.attributes {
|
||||||
|
attributes.AppendChild(attribute.encode())
|
||||||
|
}
|
||||||
|
request.AppendChild(attributes)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddRequest) Attribute(attrType string, attrVals []string) {
|
||||||
|
a.attributes = append(a.attributes, Attribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddRequest(dn string) *AddRequest {
|
||||||
|
return &AddRequest{
|
||||||
|
dn: dn,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Add(addRequest *AddRequest) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
packet.AppendChild(addRequest.encode())
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationAddResponse {
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: returning", messageID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
135
Godeps/_workspace/src/github.com/go-ldap/ldap/bind.go
сгенерированный
поставляемый
Обычный файл
135
Godeps/_workspace/src/github.com/go-ldap/ldap/bind.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SimpleBindRequest struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleBindResult struct {
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
|
||||||
|
return &SimpleBindRequest{
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
Controls: controls,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
|
||||||
|
|
||||||
|
request.AppendChild(encodeControls(bindRequest.Controls))
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
encodedBindRequest := simpleBindRequest.encode()
|
||||||
|
packet.AppendChild(encodedBindRequest)
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
packet = <-channel
|
||||||
|
if packet == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve response"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &SimpleBindResult{
|
||||||
|
Controls: make([]Control, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
for _, child := range packet.Children[2].Children {
|
||||||
|
result.Controls = append(result.Controls, DecodeControl(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return result, NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Bind(username, password string) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
||||||
|
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
||||||
|
bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name"))
|
||||||
|
bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password"))
|
||||||
|
packet.AppendChild(bindRequest)
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
packet = <-channel
|
||||||
|
if packet == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve response"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
23
Godeps/_workspace/src/github.com/go-ldap/ldap/client.go
сгенерированный
поставляемый
Обычный файл
23
Godeps/_workspace/src/github.com/go-ldap/ldap/client.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,23 @@
|
|||||||
|
package ldap
|
||||||
|
|
||||||
|
import "crypto/tls"
|
||||||
|
|
||||||
|
// Client knows how to interact with an LDAP server
|
||||||
|
type Client interface {
|
||||||
|
Start()
|
||||||
|
StartTLS(config *tls.Config) error
|
||||||
|
Close()
|
||||||
|
|
||||||
|
Bind(username, password string) error
|
||||||
|
SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error)
|
||||||
|
|
||||||
|
Add(addRequest *AddRequest) error
|
||||||
|
Del(delRequest *DelRequest) error
|
||||||
|
Modify(modifyRequest *ModifyRequest) error
|
||||||
|
|
||||||
|
Compare(dn, attribute, value string) (bool, error)
|
||||||
|
PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
|
||||||
|
|
||||||
|
Search(searchRequest *SearchRequest) (*SearchResult, error)
|
||||||
|
SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)
|
||||||
|
}
|
||||||
85
Godeps/_workspace/src/github.com/go-ldap/ldap/compare.go
сгенерированный
поставляемый
Обычный файл
85
Godeps/_workspace/src/github.com/go-ldap/ldap/compare.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// File contains Compare functionality
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// CompareRequest ::= [APPLICATION 14] SEQUENCE {
|
||||||
|
// entry LDAPDN,
|
||||||
|
// ava AttributeValueAssertion }
|
||||||
|
//
|
||||||
|
// AttributeValueAssertion ::= SEQUENCE {
|
||||||
|
// attributeDesc AttributeDescription,
|
||||||
|
// assertionValue AssertionValue }
|
||||||
|
//
|
||||||
|
// AttributeDescription ::= LDAPString
|
||||||
|
// -- Constrained to <attributedescription>
|
||||||
|
// -- [RFC4512]
|
||||||
|
//
|
||||||
|
// AttributeValue ::= OCTET STRING
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise
|
||||||
|
// false with any error that occurs if any.
|
||||||
|
func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, "Compare Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, dn, "DN"))
|
||||||
|
|
||||||
|
ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion")
|
||||||
|
ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc"))
|
||||||
|
ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagOctetString, value, "AssertionValue"))
|
||||||
|
request.AppendChild(ava)
|
||||||
|
packet.AppendChild(request)
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return false, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return false, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationCompareResponse {
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode == LDAPResultCompareTrue {
|
||||||
|
return true, nil
|
||||||
|
} else if resultCode == LDAPResultCompareFalse {
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
return false, NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
|
}
|
||||||
369
Godeps/_workspace/src/github.com/go-ldap/ldap/conn.go
сгенерированный
поставляемый
Обычный файл
369
Godeps/_workspace/src/github.com/go-ldap/ldap/conn.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,369 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MessageQuit = 0
|
||||||
|
MessageRequest = 1
|
||||||
|
MessageResponse = 2
|
||||||
|
MessageFinish = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type messagePacket struct {
|
||||||
|
Op int
|
||||||
|
MessageID int64
|
||||||
|
Packet *ber.Packet
|
||||||
|
Channel chan *ber.Packet
|
||||||
|
}
|
||||||
|
|
||||||
|
type sendMessageFlags uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
startTLS sendMessageFlags = 1 << iota
|
||||||
|
)
|
||||||
|
|
||||||
|
// Conn represents an LDAP Connection
|
||||||
|
type Conn struct {
|
||||||
|
conn net.Conn
|
||||||
|
isTLS bool
|
||||||
|
isClosing bool
|
||||||
|
isStartingTLS bool
|
||||||
|
Debug debugging
|
||||||
|
chanConfirm chan bool
|
||||||
|
chanResults map[int64]chan *ber.Packet
|
||||||
|
chanMessage chan *messagePacket
|
||||||
|
chanMessageID chan int64
|
||||||
|
wgSender sync.WaitGroup
|
||||||
|
wgClose sync.WaitGroup
|
||||||
|
once sync.Once
|
||||||
|
outstandingRequests uint
|
||||||
|
messageMutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Client = &Conn{}
|
||||||
|
|
||||||
|
// DefaultTimeout is a package-level variable that sets the timeout value
|
||||||
|
// used for the Dial and DialTLS methods.
|
||||||
|
//
|
||||||
|
// WARNING: since this is a package-level variable, setting this value from
|
||||||
|
// multiple places will probably result in undesired behaviour.
|
||||||
|
var DefaultTimeout = 60 * time.Second
|
||||||
|
|
||||||
|
// Dial connects to the given address on the given network using net.Dial
|
||||||
|
// and then returns a new Conn for the connection.
|
||||||
|
func Dial(network, addr string) (*Conn, error) {
|
||||||
|
c, err := net.DialTimeout(network, addr, DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
conn := NewConn(c, false)
|
||||||
|
conn.Start()
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialTLS connects to the given address on the given network using tls.Dial
|
||||||
|
// and then returns a new Conn for the connection.
|
||||||
|
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
||||||
|
dc, err := net.DialTimeout(network, addr, DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
c := tls.Client(dc, config)
|
||||||
|
err = c.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
// Handshake error, close the established connection before we return an error
|
||||||
|
dc.Close()
|
||||||
|
return nil, NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
conn := NewConn(c, true)
|
||||||
|
conn.Start()
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConn returns a new Conn using conn for network I/O.
|
||||||
|
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
||||||
|
return &Conn{
|
||||||
|
conn: conn,
|
||||||
|
chanConfirm: make(chan bool),
|
||||||
|
chanMessageID: make(chan int64),
|
||||||
|
chanMessage: make(chan *messagePacket, 10),
|
||||||
|
chanResults: map[int64]chan *ber.Packet{},
|
||||||
|
isTLS: isTLS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Start() {
|
||||||
|
go l.reader()
|
||||||
|
go l.processMessages()
|
||||||
|
l.wgClose.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection.
|
||||||
|
func (l *Conn) Close() {
|
||||||
|
l.once.Do(func() {
|
||||||
|
l.isClosing = true
|
||||||
|
l.wgSender.Wait()
|
||||||
|
|
||||||
|
l.Debug.Printf("Sending quit message and waiting for confirmation")
|
||||||
|
l.chanMessage <- &messagePacket{Op: MessageQuit}
|
||||||
|
<-l.chanConfirm
|
||||||
|
close(l.chanMessage)
|
||||||
|
|
||||||
|
l.Debug.Printf("Closing network connection")
|
||||||
|
if err := l.conn.Close(); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.wgClose.Done()
|
||||||
|
})
|
||||||
|
l.wgClose.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the next available messageID
|
||||||
|
func (l *Conn) nextMessageID() int64 {
|
||||||
|
if l.chanMessageID != nil {
|
||||||
|
if messageID, ok := <-l.chanMessageID; ok {
|
||||||
|
return messageID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTLS sends the command to start a TLS session and then creates a new TLS Client
|
||||||
|
func (l *Conn) StartTLS(config *tls.Config) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
|
||||||
|
if l.isTLS {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: already encrypted"))
|
||||||
|
}
|
||||||
|
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
|
||||||
|
packet.AppendChild(request)
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessageWithFlags(packet, startTLS)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
l.finishMessage(messageID)
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
l.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess {
|
||||||
|
conn := tls.Client(l.conn, config)
|
||||||
|
|
||||||
|
if err := conn.Handshake(); err != nil {
|
||||||
|
l.Close()
|
||||||
|
return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
l.isTLS = true
|
||||||
|
l.conn = conn
|
||||||
|
} else {
|
||||||
|
return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message))
|
||||||
|
}
|
||||||
|
go l.reader()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) sendMessage(packet *ber.Packet) (chan *ber.Packet, error) {
|
||||||
|
return l.sendMessageWithFlags(packet, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (chan *ber.Packet, error) {
|
||||||
|
if l.isClosing {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
||||||
|
}
|
||||||
|
l.messageMutex.Lock()
|
||||||
|
l.Debug.Printf("flags&startTLS = %d", flags&startTLS)
|
||||||
|
if l.isStartingTLS {
|
||||||
|
l.messageMutex.Unlock()
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: connection is in startls phase."))
|
||||||
|
}
|
||||||
|
if flags&startTLS != 0 {
|
||||||
|
if l.outstandingRequests != 0 {
|
||||||
|
l.messageMutex.Unlock()
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: cannot StartTLS with outstanding requests"))
|
||||||
|
} else {
|
||||||
|
l.isStartingTLS = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.outstandingRequests++
|
||||||
|
|
||||||
|
l.messageMutex.Unlock()
|
||||||
|
|
||||||
|
out := make(chan *ber.Packet)
|
||||||
|
message := &messagePacket{
|
||||||
|
Op: MessageRequest,
|
||||||
|
MessageID: packet.Children[0].Value.(int64),
|
||||||
|
Packet: packet,
|
||||||
|
Channel: out,
|
||||||
|
}
|
||||||
|
l.sendProcessMessage(message)
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) finishMessage(messageID int64) {
|
||||||
|
if l.isClosing {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.messageMutex.Lock()
|
||||||
|
l.outstandingRequests--
|
||||||
|
if l.isStartingTLS {
|
||||||
|
l.isStartingTLS = false
|
||||||
|
}
|
||||||
|
l.messageMutex.Unlock()
|
||||||
|
|
||||||
|
message := &messagePacket{
|
||||||
|
Op: MessageFinish,
|
||||||
|
MessageID: messageID,
|
||||||
|
}
|
||||||
|
l.sendProcessMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
||||||
|
if l.isClosing {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
l.wgSender.Add(1)
|
||||||
|
l.chanMessage <- message
|
||||||
|
l.wgSender.Done()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) processMessages() {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Printf("ldap: recovered panic in processMessages: %v", err)
|
||||||
|
}
|
||||||
|
for messageID, channel := range l.chanResults {
|
||||||
|
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
||||||
|
close(channel)
|
||||||
|
delete(l.chanResults, messageID)
|
||||||
|
}
|
||||||
|
close(l.chanMessageID)
|
||||||
|
l.chanConfirm <- true
|
||||||
|
close(l.chanConfirm)
|
||||||
|
}()
|
||||||
|
|
||||||
|
var messageID int64 = 1
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case l.chanMessageID <- messageID:
|
||||||
|
messageID++
|
||||||
|
case messagePacket, ok := <-l.chanMessage:
|
||||||
|
if !ok {
|
||||||
|
l.Debug.Printf("Shutting down - message channel is closed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch messagePacket.Op {
|
||||||
|
case MessageQuit:
|
||||||
|
l.Debug.Printf("Shutting down - quit message received")
|
||||||
|
return
|
||||||
|
case MessageRequest:
|
||||||
|
// Add to message list and write to network
|
||||||
|
l.Debug.Printf("Sending message %d", messagePacket.MessageID)
|
||||||
|
l.chanResults[messagePacket.MessageID] = messagePacket.Channel
|
||||||
|
// go routine
|
||||||
|
buf := messagePacket.Packet.Bytes()
|
||||||
|
|
||||||
|
_, err := l.conn.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
l.Debug.Printf("Error Sending Message: %s", err.Error())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case MessageResponse:
|
||||||
|
l.Debug.Printf("Receiving message %d", messagePacket.MessageID)
|
||||||
|
if chanResult, ok := l.chanResults[messagePacket.MessageID]; ok {
|
||||||
|
chanResult <- messagePacket.Packet
|
||||||
|
} else {
|
||||||
|
log.Printf("Received unexpected message %d", messagePacket.MessageID)
|
||||||
|
ber.PrintPacket(messagePacket.Packet)
|
||||||
|
}
|
||||||
|
case MessageFinish:
|
||||||
|
// Remove from message list
|
||||||
|
l.Debug.Printf("Finished message %d", messagePacket.MessageID)
|
||||||
|
close(l.chanResults[messagePacket.MessageID])
|
||||||
|
delete(l.chanResults, messagePacket.MessageID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) reader() {
|
||||||
|
cleanstop := false
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Printf("ldap: recovered panic in reader: %v", err)
|
||||||
|
}
|
||||||
|
if !cleanstop {
|
||||||
|
l.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if cleanstop {
|
||||||
|
l.Debug.Printf("reader clean stopping (without closing the connection)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
packet, err := ber.ReadPacket(l.conn)
|
||||||
|
if err != nil {
|
||||||
|
// A read error is expected here if we are closing the connection...
|
||||||
|
if !l.isClosing {
|
||||||
|
l.Debug.Printf("reader error: %s", err.Error())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addLDAPDescriptions(packet)
|
||||||
|
if len(packet.Children) == 0 {
|
||||||
|
l.Debug.Printf("Received bad ldap packet")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.messageMutex.Lock()
|
||||||
|
if l.isStartingTLS {
|
||||||
|
cleanstop = true
|
||||||
|
}
|
||||||
|
l.messageMutex.Unlock()
|
||||||
|
message := &messagePacket{
|
||||||
|
Op: MessageResponse,
|
||||||
|
MessageID: packet.Children[0].Value.(int64),
|
||||||
|
Packet: packet,
|
||||||
|
}
|
||||||
|
if !l.sendProcessMessage(message) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
332
Godeps/_workspace/src/github.com/go-ldap/ldap/control.go
сгенерированный
поставляемый
Обычный файл
332
Godeps/_workspace/src/github.com/go-ldap/ldap/control.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,332 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ControlTypePaging = "1.2.840.113556.1.4.319"
|
||||||
|
ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1"
|
||||||
|
ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4"
|
||||||
|
ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
|
||||||
|
ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ControlTypeMap = map[string]string{
|
||||||
|
ControlTypePaging: "Paging",
|
||||||
|
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
||||||
|
ControlTypeManageDsaIT: "Manage DSA IT",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Control interface {
|
||||||
|
GetControlType() string
|
||||||
|
Encode() *ber.Packet
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlString struct {
|
||||||
|
ControlType string
|
||||||
|
Criticality bool
|
||||||
|
ControlValue string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlString) GetControlType() string {
|
||||||
|
return c.ControlType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlString) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")"))
|
||||||
|
if c.Criticality {
|
||||||
|
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
|
||||||
|
}
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(c.ControlValue), "Control Value"))
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlString) String() string {
|
||||||
|
return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlPaging struct {
|
||||||
|
PagingSize uint32
|
||||||
|
Cookie []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) GetControlType() string {
|
||||||
|
return ControlTypePaging
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")"))
|
||||||
|
|
||||||
|
p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)")
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
|
||||||
|
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(c.PagingSize), "Paging Size"))
|
||||||
|
cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
|
||||||
|
cookie.Value = c.Cookie
|
||||||
|
cookie.Data.Write(c.Cookie)
|
||||||
|
seq.AppendChild(cookie)
|
||||||
|
p2.AppendChild(seq)
|
||||||
|
|
||||||
|
packet.AppendChild(p2)
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q",
|
||||||
|
ControlTypeMap[ControlTypePaging],
|
||||||
|
ControlTypePaging,
|
||||||
|
false,
|
||||||
|
c.PagingSize,
|
||||||
|
c.Cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlPaging) SetCookie(cookie []byte) {
|
||||||
|
c.Cookie = cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlBeheraPasswordPolicy struct {
|
||||||
|
Expire int64
|
||||||
|
Grace int64
|
||||||
|
Error int8
|
||||||
|
ErrorString string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlBeheraPasswordPolicy) GetControlType() string {
|
||||||
|
return ControlTypeBeheraPasswordPolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeBeheraPasswordPolicy, "Control Type ("+ControlTypeMap[ControlTypeBeheraPasswordPolicy]+")"))
|
||||||
|
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlBeheraPasswordPolicy) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q) Criticality: %t Expire: %d Grace: %d Error: %d, ErrorString: %s",
|
||||||
|
ControlTypeMap[ControlTypeBeheraPasswordPolicy],
|
||||||
|
ControlTypeBeheraPasswordPolicy,
|
||||||
|
false,
|
||||||
|
c.Expire,
|
||||||
|
c.Grace,
|
||||||
|
c.Error,
|
||||||
|
c.ErrorString)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlVChuPasswordMustChange struct {
|
||||||
|
MustChange bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlVChuPasswordMustChange) GetControlType() string {
|
||||||
|
return ControlTypeVChuPasswordMustChange
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlVChuPasswordMustChange) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q) Criticality: %t MustChange: %b",
|
||||||
|
ControlTypeMap[ControlTypeVChuPasswordMustChange],
|
||||||
|
ControlTypeVChuPasswordMustChange,
|
||||||
|
false,
|
||||||
|
c.MustChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlVChuPasswordWarning struct {
|
||||||
|
Expire int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlVChuPasswordWarning) GetControlType() string {
|
||||||
|
return ControlTypeVChuPasswordWarning
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlVChuPasswordWarning) Encode() *ber.Packet {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlVChuPasswordWarning) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q) Criticality: %t Expire: %b",
|
||||||
|
ControlTypeMap[ControlTypeVChuPasswordWarning],
|
||||||
|
ControlTypeVChuPasswordWarning,
|
||||||
|
false,
|
||||||
|
c.Expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlManageDsaIT struct {
|
||||||
|
Criticality bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlManageDsaIT) GetControlType() string {
|
||||||
|
return ControlTypeManageDsaIT
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlManageDsaIT) Encode() *ber.Packet {
|
||||||
|
//FIXME
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeManageDsaIT, "Control Type ("+ControlTypeMap[ControlTypeManageDsaIT]+")"))
|
||||||
|
if c.Criticality {
|
||||||
|
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
|
||||||
|
}
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ControlManageDsaIT) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q) Criticality: %t",
|
||||||
|
ControlTypeMap[ControlTypeManageDsaIT],
|
||||||
|
ControlTypeManageDsaIT,
|
||||||
|
c.Criticality)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
|
||||||
|
return &ControlManageDsaIT{Criticality: Criticality}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindControl(controls []Control, controlType string) Control {
|
||||||
|
for _, c := range controls {
|
||||||
|
if c.GetControlType() == controlType {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeControl(packet *ber.Packet) Control {
|
||||||
|
ControlType := packet.Children[0].Value.(string)
|
||||||
|
Criticality := false
|
||||||
|
|
||||||
|
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
|
||||||
|
value := packet.Children[1]
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
value = packet.Children[2]
|
||||||
|
packet.Children[1].Description = "Criticality"
|
||||||
|
Criticality = packet.Children[1].Value.(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
value.Description = "Control Value"
|
||||||
|
switch ControlType {
|
||||||
|
case ControlTypePaging:
|
||||||
|
value.Description += " (Paging)"
|
||||||
|
c := new(ControlPaging)
|
||||||
|
if value.Value != nil {
|
||||||
|
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||||
|
value.Data.Truncate(0)
|
||||||
|
value.Value = nil
|
||||||
|
value.AppendChild(valueChildren)
|
||||||
|
}
|
||||||
|
value = value.Children[0]
|
||||||
|
value.Description = "Search Control Value"
|
||||||
|
value.Children[0].Description = "Paging Size"
|
||||||
|
value.Children[1].Description = "Cookie"
|
||||||
|
c.PagingSize = uint32(value.Children[0].Value.(int64))
|
||||||
|
c.Cookie = value.Children[1].Data.Bytes()
|
||||||
|
value.Children[1].Value = c.Cookie
|
||||||
|
return c
|
||||||
|
case ControlTypeBeheraPasswordPolicy:
|
||||||
|
value.Description += " (Password Policy - Behera)"
|
||||||
|
c := NewControlBeheraPasswordPolicy()
|
||||||
|
if value.Value != nil {
|
||||||
|
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||||
|
value.Data.Truncate(0)
|
||||||
|
value.Value = nil
|
||||||
|
value.AppendChild(valueChildren)
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence := value.Children[0]
|
||||||
|
|
||||||
|
for _, child := range sequence.Children {
|
||||||
|
if child.Tag == 0 {
|
||||||
|
//Warning
|
||||||
|
child := child.Children[0]
|
||||||
|
packet := ber.DecodePacket(child.Data.Bytes())
|
||||||
|
val, ok := packet.Value.(int64)
|
||||||
|
if ok {
|
||||||
|
if child.Tag == 0 {
|
||||||
|
//timeBeforeExpiration
|
||||||
|
c.Expire = val
|
||||||
|
child.Value = c.Expire
|
||||||
|
} else if child.Tag == 1 {
|
||||||
|
//graceAuthNsRemaining
|
||||||
|
c.Grace = val
|
||||||
|
child.Value = c.Grace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if child.Tag == 1 {
|
||||||
|
// Error
|
||||||
|
packet := ber.DecodePacket(child.Data.Bytes())
|
||||||
|
val, ok := packet.Value.(int8)
|
||||||
|
if !ok {
|
||||||
|
// what to do?
|
||||||
|
val = -1
|
||||||
|
}
|
||||||
|
c.Error = val
|
||||||
|
child.Value = c.Error
|
||||||
|
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
case ControlTypeVChuPasswordMustChange:
|
||||||
|
c := &ControlVChuPasswordMustChange{MustChange: true}
|
||||||
|
return c
|
||||||
|
case ControlTypeVChuPasswordWarning:
|
||||||
|
c := &ControlVChuPasswordWarning{Expire: -1}
|
||||||
|
expireStr := ber.DecodeString(value.Data.Bytes())
|
||||||
|
|
||||||
|
expire, err := strconv.ParseInt(expireStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c.Expire = expire
|
||||||
|
value.Value = c.Expire
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c := new(ControlString)
|
||||||
|
c.ControlType = ControlType
|
||||||
|
c.Criticality = Criticality
|
||||||
|
c.ControlValue = value.Value.(string)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControlString(controlType string, criticality bool, controlValue string) *ControlString {
|
||||||
|
return &ControlString{
|
||||||
|
ControlType: controlType,
|
||||||
|
Criticality: criticality,
|
||||||
|
ControlValue: controlValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControlPaging(pagingSize uint32) *ControlPaging {
|
||||||
|
return &ControlPaging{PagingSize: pagingSize}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy {
|
||||||
|
return &ControlBeheraPasswordPolicy{
|
||||||
|
Expire: -1,
|
||||||
|
Grace: -1,
|
||||||
|
Error: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeControls(controls []Control) *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
|
||||||
|
for _, control := range controls {
|
||||||
|
packet.AppendChild(control.Encode())
|
||||||
|
}
|
||||||
|
return packet
|
||||||
|
}
|
||||||
24
Godeps/_workspace/src/github.com/go-ldap/ldap/debug.go
сгенерированный
поставляемый
Обычный файл
24
Godeps/_workspace/src/github.com/go-ldap/ldap/debug.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,24 @@
|
|||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// debbuging type
|
||||||
|
// - has a Printf method to write the debug output
|
||||||
|
type debugging bool
|
||||||
|
|
||||||
|
// write debug output
|
||||||
|
func (debug debugging) Printf(format string, args ...interface{}) {
|
||||||
|
if debug {
|
||||||
|
log.Printf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (debug debugging) PrintPacket(packet *ber.Packet) {
|
||||||
|
if debug {
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
79
Godeps/_workspace/src/github.com/go-ldap/ldap/del.go
сгенерированный
поставляемый
Обычный файл
79
Godeps/_workspace/src/github.com/go-ldap/ldap/del.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,79 @@
|
|||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// DelRequest ::= [APPLICATION 10] LDAPDN
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DelRequest struct {
|
||||||
|
DN string
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DelRequest) encode() *ber.Packet {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypePrimitive, ApplicationDelRequest, d.DN, "Del Request")
|
||||||
|
request.Data.Write([]byte(d.DN))
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDelRequest(DN string,
|
||||||
|
Controls []Control) *DelRequest {
|
||||||
|
return &DelRequest{
|
||||||
|
DN: DN,
|
||||||
|
Controls: Controls,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Del(delRequest *DelRequest) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
packet.AppendChild(delRequest.encode())
|
||||||
|
if delRequest.Controls != nil {
|
||||||
|
packet.AppendChild(encodeControls(delRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationDelResponse {
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: returning", messageID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
155
Godeps/_workspace/src/github.com/go-ldap/ldap/dn.go
сгенерированный
поставляемый
Обычный файл
155
Godeps/_workspace/src/github.com/go-ldap/ldap/dn.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// File contains DN parsing functionallity
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4514
|
||||||
|
//
|
||||||
|
// distinguishedName = [ relativeDistinguishedName
|
||||||
|
// *( COMMA relativeDistinguishedName ) ]
|
||||||
|
// relativeDistinguishedName = attributeTypeAndValue
|
||||||
|
// *( PLUS attributeTypeAndValue )
|
||||||
|
// attributeTypeAndValue = attributeType EQUALS attributeValue
|
||||||
|
// attributeType = descr / numericoid
|
||||||
|
// attributeValue = string / hexstring
|
||||||
|
//
|
||||||
|
// ; The following characters are to be escaped when they appear
|
||||||
|
// ; in the value to be encoded: ESC, one of <escaped>, leading
|
||||||
|
// ; SHARP or SPACE, trailing SPACE, and NULL.
|
||||||
|
// string = [ ( leadchar / pair ) [ *( stringchar / pair )
|
||||||
|
// ( trailchar / pair ) ] ]
|
||||||
|
//
|
||||||
|
// leadchar = LUTF1 / UTFMB
|
||||||
|
// LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A /
|
||||||
|
// %x3D / %x3F-5B / %x5D-7F
|
||||||
|
//
|
||||||
|
// trailchar = TUTF1 / UTFMB
|
||||||
|
// TUTF1 = %x01-1F / %x21 / %x23-2A / %x2D-3A /
|
||||||
|
// %x3D / %x3F-5B / %x5D-7F
|
||||||
|
//
|
||||||
|
// stringchar = SUTF1 / UTFMB
|
||||||
|
// SUTF1 = %x01-21 / %x23-2A / %x2D-3A /
|
||||||
|
// %x3D / %x3F-5B / %x5D-7F
|
||||||
|
//
|
||||||
|
// pair = ESC ( ESC / special / hexpair )
|
||||||
|
// special = escaped / SPACE / SHARP / EQUALS
|
||||||
|
// escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
|
||||||
|
// hexstring = SHARP 1*hexpair
|
||||||
|
// hexpair = HEX HEX
|
||||||
|
//
|
||||||
|
// where the productions <descr>, <numericoid>, <COMMA>, <DQUOTE>,
|
||||||
|
// <EQUALS>, <ESC>, <HEX>, <LANGLE>, <NULL>, <PLUS>, <RANGLE>, <SEMI>,
|
||||||
|
// <SPACE>, <SHARP>, and <UTFMB> are defined in [RFC4512].
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
enchex "encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
ber "gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AttributeTypeAndValue struct {
|
||||||
|
Type string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RelativeDN struct {
|
||||||
|
Attributes []*AttributeTypeAndValue
|
||||||
|
}
|
||||||
|
|
||||||
|
type DN struct {
|
||||||
|
RDNs []*RelativeDN
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseDN(str string) (*DN, error) {
|
||||||
|
dn := new(DN)
|
||||||
|
dn.RDNs = make([]*RelativeDN, 0)
|
||||||
|
rdn := new(RelativeDN)
|
||||||
|
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
attribute := new(AttributeTypeAndValue)
|
||||||
|
escaping := false
|
||||||
|
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
char := str[i]
|
||||||
|
if escaping {
|
||||||
|
escaping = false
|
||||||
|
switch char {
|
||||||
|
case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
|
||||||
|
buffer.WriteByte(char)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Not a special character, assume hex encoded octet
|
||||||
|
if len(str) == i+1 {
|
||||||
|
return nil, errors.New("Got corrupted escaped character")
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := []byte{0}
|
||||||
|
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Sprintf("Failed to decode escaped character: %s", err))
|
||||||
|
} else if n != 1 {
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Sprintf("Expected 1 byte when un-escaping, got %d", n))
|
||||||
|
}
|
||||||
|
buffer.WriteByte(dst[0])
|
||||||
|
i++
|
||||||
|
} else if char == '\\' {
|
||||||
|
escaping = true
|
||||||
|
} else if char == '=' {
|
||||||
|
attribute.Type = buffer.String()
|
||||||
|
buffer.Reset()
|
||||||
|
// Special case: If the first character in the value is # the
|
||||||
|
// following data is BER encoded so we can just fast forward
|
||||||
|
// and decode.
|
||||||
|
if len(str) > i+1 && str[i+1] == '#' {
|
||||||
|
i += 2
|
||||||
|
index := strings.IndexAny(str[i:], ",+")
|
||||||
|
data := str
|
||||||
|
if index > 0 {
|
||||||
|
data = str[i : i+index]
|
||||||
|
} else {
|
||||||
|
data = str[i:]
|
||||||
|
}
|
||||||
|
raw_ber, err := enchex.DecodeString(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Sprintf("Failed to decode BER encoding: %s", err))
|
||||||
|
}
|
||||||
|
packet := ber.DecodePacket(raw_ber)
|
||||||
|
buffer.WriteString(packet.Data.String())
|
||||||
|
i += len(data) - 1
|
||||||
|
}
|
||||||
|
} else if char == ',' || char == '+' {
|
||||||
|
// We're done with this RDN or value, push it
|
||||||
|
attribute.Value = buffer.String()
|
||||||
|
rdn.Attributes = append(rdn.Attributes, attribute)
|
||||||
|
attribute = new(AttributeTypeAndValue)
|
||||||
|
if char == ',' {
|
||||||
|
dn.RDNs = append(dn.RDNs, rdn)
|
||||||
|
rdn = new(RelativeDN)
|
||||||
|
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
||||||
|
}
|
||||||
|
buffer.Reset()
|
||||||
|
} else {
|
||||||
|
buffer.WriteByte(char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if buffer.Len() > 0 {
|
||||||
|
if len(attribute.Type) == 0 {
|
||||||
|
return nil, errors.New("DN ended with incomplete type, value pair")
|
||||||
|
}
|
||||||
|
attribute.Value = buffer.String()
|
||||||
|
rdn.Attributes = append(rdn.Attributes, attribute)
|
||||||
|
dn.RDNs = append(dn.RDNs, rdn)
|
||||||
|
}
|
||||||
|
return dn, nil
|
||||||
|
}
|
||||||
70
Godeps/_workspace/src/github.com/go-ldap/ldap/dn_test.go
сгенерированный
поставляемый
Обычный файл
70
Godeps/_workspace/src/github.com/go-ldap/ldap/dn_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,70 @@
|
|||||||
|
package ldap_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/ldap.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSuccessfulDNParsing(t *testing.T) {
|
||||||
|
testcases := map[string]ldap.DN{
|
||||||
|
"": ldap.DN{[]*ldap.RelativeDN{}},
|
||||||
|
"cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": ldap.DN{[]*ldap.RelativeDN{
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"cn", "Jim, \"Hasse Hö\" Hansson!"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "dummy"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "com"}}}}},
|
||||||
|
"UID=jsmith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"UID", "jsmith"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
|
||||||
|
"OU=Sales+CN=J. Smith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{
|
||||||
|
&ldap.AttributeTypeAndValue{"OU", "Sales"},
|
||||||
|
&ldap.AttributeTypeAndValue{"CN", "J. Smith"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
|
||||||
|
"1.3.6.1.4.1.1466.0=#04024869": ldap.DN{[]*ldap.RelativeDN{
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}}}},
|
||||||
|
"1.3.6.1.4.1.1466.0=#04024869,DC=net": ldap.DN{[]*ldap.RelativeDN{
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}},
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
|
||||||
|
"CN=Lu\\C4\\8Di\\C4\\87": ldap.DN{[]*ldap.RelativeDN{
|
||||||
|
&ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"CN", "Lučić"}}}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for test, answer := range testcases {
|
||||||
|
dn, err := ldap.ParseDN(test)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(dn, &answer) {
|
||||||
|
t.Errorf("Parsed DN %s is not equal to the expected structure", test)
|
||||||
|
for _, rdn := range dn.RDNs {
|
||||||
|
for _, attribs := range rdn.Attributes {
|
||||||
|
t.Logf("#%v\n", attribs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorDNParsing(t *testing.T) {
|
||||||
|
testcases := map[string]string{
|
||||||
|
"*": "DN ended with incomplete type, value pair",
|
||||||
|
"cn=Jim\\0Test": "Failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'",
|
||||||
|
"cn=Jim\\0": "Got corrupted escaped character",
|
||||||
|
"DC=example,=net": "DN ended with incomplete type, value pair",
|
||||||
|
"1=#0402486": "Failed to decode BER encoding: encoding/hex: odd length hex string",
|
||||||
|
}
|
||||||
|
|
||||||
|
for test, answer := range testcases {
|
||||||
|
_, err := ldap.ParseDN(test)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected %s to fail parsing but succeeded\n", test)
|
||||||
|
} else if err.Error() != answer {
|
||||||
|
t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
Godeps/_workspace/src/github.com/go-ldap/ldap/doc.go
сгенерированный
поставляемый
Обычный файл
4
Godeps/_workspace/src/github.com/go-ldap/ldap/doc.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,4 @@
|
|||||||
|
/*
|
||||||
|
Package ldap provides basic LDAP v3 functionality.
|
||||||
|
*/
|
||||||
|
package ldap
|
||||||
137
Godeps/_workspace/src/github.com/go-ldap/ldap/error.go
сгенерированный
поставляемый
Обычный файл
137
Godeps/_workspace/src/github.com/go-ldap/ldap/error.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,137 @@
|
|||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LDAP Result Codes
|
||||||
|
const (
|
||||||
|
LDAPResultSuccess = 0
|
||||||
|
LDAPResultOperationsError = 1
|
||||||
|
LDAPResultProtocolError = 2
|
||||||
|
LDAPResultTimeLimitExceeded = 3
|
||||||
|
LDAPResultSizeLimitExceeded = 4
|
||||||
|
LDAPResultCompareFalse = 5
|
||||||
|
LDAPResultCompareTrue = 6
|
||||||
|
LDAPResultAuthMethodNotSupported = 7
|
||||||
|
LDAPResultStrongAuthRequired = 8
|
||||||
|
LDAPResultReferral = 10
|
||||||
|
LDAPResultAdminLimitExceeded = 11
|
||||||
|
LDAPResultUnavailableCriticalExtension = 12
|
||||||
|
LDAPResultConfidentialityRequired = 13
|
||||||
|
LDAPResultSaslBindInProgress = 14
|
||||||
|
LDAPResultNoSuchAttribute = 16
|
||||||
|
LDAPResultUndefinedAttributeType = 17
|
||||||
|
LDAPResultInappropriateMatching = 18
|
||||||
|
LDAPResultConstraintViolation = 19
|
||||||
|
LDAPResultAttributeOrValueExists = 20
|
||||||
|
LDAPResultInvalidAttributeSyntax = 21
|
||||||
|
LDAPResultNoSuchObject = 32
|
||||||
|
LDAPResultAliasProblem = 33
|
||||||
|
LDAPResultInvalidDNSyntax = 34
|
||||||
|
LDAPResultAliasDereferencingProblem = 36
|
||||||
|
LDAPResultInappropriateAuthentication = 48
|
||||||
|
LDAPResultInvalidCredentials = 49
|
||||||
|
LDAPResultInsufficientAccessRights = 50
|
||||||
|
LDAPResultBusy = 51
|
||||||
|
LDAPResultUnavailable = 52
|
||||||
|
LDAPResultUnwillingToPerform = 53
|
||||||
|
LDAPResultLoopDetect = 54
|
||||||
|
LDAPResultNamingViolation = 64
|
||||||
|
LDAPResultObjectClassViolation = 65
|
||||||
|
LDAPResultNotAllowedOnNonLeaf = 66
|
||||||
|
LDAPResultNotAllowedOnRDN = 67
|
||||||
|
LDAPResultEntryAlreadyExists = 68
|
||||||
|
LDAPResultObjectClassModsProhibited = 69
|
||||||
|
LDAPResultAffectsMultipleDSAs = 71
|
||||||
|
LDAPResultOther = 80
|
||||||
|
|
||||||
|
ErrorNetwork = 200
|
||||||
|
ErrorFilterCompile = 201
|
||||||
|
ErrorFilterDecompile = 202
|
||||||
|
ErrorDebugging = 203
|
||||||
|
ErrorUnexpectedMessage = 204
|
||||||
|
ErrorUnexpectedResponse = 205
|
||||||
|
)
|
||||||
|
|
||||||
|
var LDAPResultCodeMap = map[uint8]string{
|
||||||
|
LDAPResultSuccess: "Success",
|
||||||
|
LDAPResultOperationsError: "Operations Error",
|
||||||
|
LDAPResultProtocolError: "Protocol Error",
|
||||||
|
LDAPResultTimeLimitExceeded: "Time Limit Exceeded",
|
||||||
|
LDAPResultSizeLimitExceeded: "Size Limit Exceeded",
|
||||||
|
LDAPResultCompareFalse: "Compare False",
|
||||||
|
LDAPResultCompareTrue: "Compare True",
|
||||||
|
LDAPResultAuthMethodNotSupported: "Auth Method Not Supported",
|
||||||
|
LDAPResultStrongAuthRequired: "Strong Auth Required",
|
||||||
|
LDAPResultReferral: "Referral",
|
||||||
|
LDAPResultAdminLimitExceeded: "Admin Limit Exceeded",
|
||||||
|
LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
|
||||||
|
LDAPResultConfidentialityRequired: "Confidentiality Required",
|
||||||
|
LDAPResultSaslBindInProgress: "Sasl Bind In Progress",
|
||||||
|
LDAPResultNoSuchAttribute: "No Such Attribute",
|
||||||
|
LDAPResultUndefinedAttributeType: "Undefined Attribute Type",
|
||||||
|
LDAPResultInappropriateMatching: "Inappropriate Matching",
|
||||||
|
LDAPResultConstraintViolation: "Constraint Violation",
|
||||||
|
LDAPResultAttributeOrValueExists: "Attribute Or Value Exists",
|
||||||
|
LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax",
|
||||||
|
LDAPResultNoSuchObject: "No Such Object",
|
||||||
|
LDAPResultAliasProblem: "Alias Problem",
|
||||||
|
LDAPResultInvalidDNSyntax: "Invalid DN Syntax",
|
||||||
|
LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem",
|
||||||
|
LDAPResultInappropriateAuthentication: "Inappropriate Authentication",
|
||||||
|
LDAPResultInvalidCredentials: "Invalid Credentials",
|
||||||
|
LDAPResultInsufficientAccessRights: "Insufficient Access Rights",
|
||||||
|
LDAPResultBusy: "Busy",
|
||||||
|
LDAPResultUnavailable: "Unavailable",
|
||||||
|
LDAPResultUnwillingToPerform: "Unwilling To Perform",
|
||||||
|
LDAPResultLoopDetect: "Loop Detect",
|
||||||
|
LDAPResultNamingViolation: "Naming Violation",
|
||||||
|
LDAPResultObjectClassViolation: "Object Class Violation",
|
||||||
|
LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
|
||||||
|
LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
|
||||||
|
LDAPResultEntryAlreadyExists: "Entry Already Exists",
|
||||||
|
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
|
||||||
|
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
|
||||||
|
LDAPResultOther: "Other",
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
|
||||||
|
if len(packet.Children) >= 2 {
|
||||||
|
response := packet.Children[1]
|
||||||
|
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
|
||||||
|
// Children[1].Children[2] is the diagnosticMessage which is guaranteed to exist as seen here: https://tools.ietf.org/html/rfc4511#section-4.1.9
|
||||||
|
return uint8(response.Children[0].Value.(int64)), response.Children[2].Value.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorNetwork, "Invalid packet format"
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Err error
|
||||||
|
ResultCode uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewError(resultCode uint8, err error) error {
|
||||||
|
return &Error{ResultCode: resultCode, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsErrorWithCode(err error, desiredResultCode uint8) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
serverError, ok := err.(*Error)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverError.ResultCode == desiredResultCode
|
||||||
|
}
|
||||||
305
Godeps/_workspace/src/github.com/go-ldap/ldap/example_test.go
сгенерированный
поставляемый
Обычный файл
305
Godeps/_workspace/src/github.com/go-ldap/ldap/example_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,305 @@
|
|||||||
|
package ldap_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/ldap.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExampleConn_Bind demonstrates how to bind a connection to an ldap user
|
||||||
|
// allowing access to restricted attrabutes that user has access to
|
||||||
|
func ExampleConn_Bind() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleConn_Search demonstrates how to use the search interface
|
||||||
|
func ExampleConn_Search() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
"dc=example,dc=com", // The base dn to search
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
"(&(objectClass=organizationalPerson))", // The filter to apply
|
||||||
|
[]string{"dn", "cn"}, // A list attributes to retrieve
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range sr.Entries {
|
||||||
|
fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleStartTLS demonstrates how to start a TLS connection
|
||||||
|
func ExampleConn_StartTLS() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
// Reconnect with TLS
|
||||||
|
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opertations via l are now encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleConn_Compare demonstrates how to comapre an attribute with a value
|
||||||
|
func ExampleConn_Compare() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
matched, err := l.Compare("cn=user,dc=example,dc=com", "uid", "someuserid")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(matched)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleConn_PasswordModify_admin() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
err = l.Bind("cn=admin,dc=example,dc=com", "password")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordModifyRequest := ldap.NewPasswordModifyRequest("cn=user,dc=example,dc=com", "", "NewPassword")
|
||||||
|
_, err = l.PasswordModify(passwordModifyRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Password could not be changed: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleConn_PasswordModify_generatedPassword() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
err = l.Bind("cn=user,dc=example,dc=com", "password")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "")
|
||||||
|
passwordModifyResponse, err := l.PasswordModify(passwordModifyRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Password could not be changed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
generatedPassword := passwordModifyResponse.GeneratedPassword
|
||||||
|
log.Printf("Generated password: %s\n", generatedPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleConn_PasswordModify_setNewPassword() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
err = l.Bind("cn=user,dc=example,dc=com", "password")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "NewPassword")
|
||||||
|
_, err = l.PasswordModify(passwordModifyRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Password could not be changed: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleConn_Modify() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
// Add a description, and replace the mail attributes
|
||||||
|
modify := ldap.NewModifyRequest("cn=user,dc=example,dc=com")
|
||||||
|
modify.Add("description", []string{"An example user"})
|
||||||
|
modify.Replace("mail", []string{"user@example.org"})
|
||||||
|
|
||||||
|
err = l.Modify(modify)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example User Authentication shows how a typical application can verify a login attempt
|
||||||
|
func Example_userAuthentication() {
|
||||||
|
// The username and password we want to check
|
||||||
|
username := "someuser"
|
||||||
|
password := "userpassword"
|
||||||
|
|
||||||
|
bindusername := "readonly"
|
||||||
|
bindpassword := "password"
|
||||||
|
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
// Reconnect with TLS
|
||||||
|
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First bind with a read only user
|
||||||
|
err = l.Bind(bindusername, bindpassword)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for the given username
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
"dc=example,dc=com",
|
||||||
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
fmt.Sprintf("(&(objectClass=organizationalPerson)&(uid=%s))", username),
|
||||||
|
[]string{"dn"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sr.Entries) != 1 {
|
||||||
|
log.Fatal("User does not exist or too many entries returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
userdn := sr.Entries[0].DN
|
||||||
|
|
||||||
|
// Bind as the user to verify their password
|
||||||
|
err = l.Bind(userdn, password)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebind as the read only user for any futher queries
|
||||||
|
err = l.Bind(bindusername, bindpassword)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_beherappolicy() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
controls := []ldap.Control{}
|
||||||
|
controls = append(controls, ldap.NewControlBeheraPasswordPolicy())
|
||||||
|
bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", controls)
|
||||||
|
|
||||||
|
r, err := l.SimpleBind(bindRequest)
|
||||||
|
ppolicyControl := ldap.FindControl(r.Controls, ldap.ControlTypeBeheraPasswordPolicy)
|
||||||
|
|
||||||
|
var ppolicy *ldap.ControlBeheraPasswordPolicy
|
||||||
|
if ppolicyControl != nil {
|
||||||
|
ppolicy = ppolicyControl.(*ldap.ControlBeheraPasswordPolicy)
|
||||||
|
} else {
|
||||||
|
log.Printf("ppolicyControl response not avaliable.\n")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errStr := "ERROR: Cannot bind: " + err.Error()
|
||||||
|
if ppolicy != nil && ppolicy.Error >= 0 {
|
||||||
|
errStr += ":" + ppolicy.ErrorString
|
||||||
|
}
|
||||||
|
log.Print(errStr)
|
||||||
|
} else {
|
||||||
|
logStr := "Login Ok"
|
||||||
|
if ppolicy != nil {
|
||||||
|
if ppolicy.Expire >= 0 {
|
||||||
|
logStr += fmt.Sprintf(". Password expires in %d seconds\n", ppolicy.Expire)
|
||||||
|
} else if ppolicy.Grace >= 0 {
|
||||||
|
logStr += fmt.Sprintf(". Password expired, %d grace logins remain\n", ppolicy.Grace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Print(logStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_vchuppolicy() {
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
l.Debug = true
|
||||||
|
|
||||||
|
bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", nil)
|
||||||
|
|
||||||
|
r, err := l.SimpleBind(bindRequest)
|
||||||
|
|
||||||
|
passwordMustChangeControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordMustChange)
|
||||||
|
var passwordMustChange *ldap.ControlVChuPasswordMustChange
|
||||||
|
if passwordMustChangeControl != nil {
|
||||||
|
passwordMustChange = passwordMustChangeControl.(*ldap.ControlVChuPasswordMustChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
if passwordMustChange != nil && passwordMustChange.MustChange {
|
||||||
|
log.Printf("Password Must be changed.\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordWarningControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordWarning)
|
||||||
|
|
||||||
|
var passwordWarning *ldap.ControlVChuPasswordWarning
|
||||||
|
if passwordWarningControl != nil {
|
||||||
|
passwordWarning = passwordWarningControl.(*ldap.ControlVChuPasswordWarning)
|
||||||
|
} else {
|
||||||
|
log.Printf("ppolicyControl response not available.\n")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Print("ERROR: Cannot bind: " + err.Error())
|
||||||
|
} else {
|
||||||
|
logStr := "Login Ok"
|
||||||
|
if passwordWarning != nil {
|
||||||
|
if passwordWarning.Expire >= 0 {
|
||||||
|
logStr += fmt.Sprintf(". Password expires in %d seconds\n", passwordWarning.Expire)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Print(logStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
456
Godeps/_workspace/src/github.com/go-ldap/ldap/filter.go
сгенерированный
поставляемый
Обычный файл
456
Godeps/_workspace/src/github.com/go-ldap/ldap/filter.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,456 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
hexpac "encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterAnd = 0
|
||||||
|
FilterOr = 1
|
||||||
|
FilterNot = 2
|
||||||
|
FilterEqualityMatch = 3
|
||||||
|
FilterSubstrings = 4
|
||||||
|
FilterGreaterOrEqual = 5
|
||||||
|
FilterLessOrEqual = 6
|
||||||
|
FilterPresent = 7
|
||||||
|
FilterApproxMatch = 8
|
||||||
|
FilterExtensibleMatch = 9
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterMap = map[uint64]string{
|
||||||
|
FilterAnd: "And",
|
||||||
|
FilterOr: "Or",
|
||||||
|
FilterNot: "Not",
|
||||||
|
FilterEqualityMatch: "Equality Match",
|
||||||
|
FilterSubstrings: "Substrings",
|
||||||
|
FilterGreaterOrEqual: "Greater Or Equal",
|
||||||
|
FilterLessOrEqual: "Less Or Equal",
|
||||||
|
FilterPresent: "Present",
|
||||||
|
FilterApproxMatch: "Approx Match",
|
||||||
|
FilterExtensibleMatch: "Extensible Match",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterSubstringsInitial = 0
|
||||||
|
FilterSubstringsAny = 1
|
||||||
|
FilterSubstringsFinal = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterSubstringsMap = map[uint64]string{
|
||||||
|
FilterSubstringsInitial: "Substrings Initial",
|
||||||
|
FilterSubstringsAny: "Substrings Any",
|
||||||
|
FilterSubstringsFinal: "Substrings Final",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
MatchingRuleAssertionMatchingRule = 1
|
||||||
|
MatchingRuleAssertionType = 2
|
||||||
|
MatchingRuleAssertionMatchValue = 3
|
||||||
|
MatchingRuleAssertionDNAttributes = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
var MatchingRuleAssertionMap = map[uint64]string{
|
||||||
|
MatchingRuleAssertionMatchingRule: "Matching Rule Assertion Matching Rule",
|
||||||
|
MatchingRuleAssertionType: "Matching Rule Assertion Type",
|
||||||
|
MatchingRuleAssertionMatchValue: "Matching Rule Assertion Match Value",
|
||||||
|
MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes",
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompileFilter(filter string) (*ber.Packet, error) {
|
||||||
|
if len(filter) == 0 || filter[0] != '(' {
|
||||||
|
return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('"))
|
||||||
|
}
|
||||||
|
packet, pos, err := compileFilter(filter, 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pos != len(filter) {
|
||||||
|
return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
|
||||||
|
}
|
||||||
|
return packet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecompileFilter(packet *ber.Packet) (ret string, err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ret = "("
|
||||||
|
err = nil
|
||||||
|
childStr := ""
|
||||||
|
|
||||||
|
switch packet.Tag {
|
||||||
|
case FilterAnd:
|
||||||
|
ret += "&"
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
childStr, err = DecompileFilter(child)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret += childStr
|
||||||
|
}
|
||||||
|
case FilterOr:
|
||||||
|
ret += "|"
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
childStr, err = DecompileFilter(child)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret += childStr
|
||||||
|
}
|
||||||
|
case FilterNot:
|
||||||
|
ret += "!"
|
||||||
|
childStr, err = DecompileFilter(packet.Children[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret += childStr
|
||||||
|
|
||||||
|
case FilterSubstrings:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "="
|
||||||
|
for i, child := range packet.Children[1].Children {
|
||||||
|
if i == 0 && child.Tag != FilterSubstringsInitial {
|
||||||
|
ret += "*"
|
||||||
|
}
|
||||||
|
ret += EscapeFilter(ber.DecodeString(child.Data.Bytes()))
|
||||||
|
if child.Tag != FilterSubstringsFinal {
|
||||||
|
ret += "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FilterEqualityMatch:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "="
|
||||||
|
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
|
||||||
|
case FilterGreaterOrEqual:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += ">="
|
||||||
|
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
|
||||||
|
case FilterLessOrEqual:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "<="
|
||||||
|
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
|
||||||
|
case FilterPresent:
|
||||||
|
ret += ber.DecodeString(packet.Data.Bytes())
|
||||||
|
ret += "=*"
|
||||||
|
case FilterApproxMatch:
|
||||||
|
ret += ber.DecodeString(packet.Children[0].Data.Bytes())
|
||||||
|
ret += "~="
|
||||||
|
ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes()))
|
||||||
|
case FilterExtensibleMatch:
|
||||||
|
attr := ""
|
||||||
|
dnAttributes := false
|
||||||
|
matchingRule := ""
|
||||||
|
value := ""
|
||||||
|
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
switch child.Tag {
|
||||||
|
case MatchingRuleAssertionMatchingRule:
|
||||||
|
matchingRule = ber.DecodeString(child.Data.Bytes())
|
||||||
|
case MatchingRuleAssertionType:
|
||||||
|
attr = ber.DecodeString(child.Data.Bytes())
|
||||||
|
case MatchingRuleAssertionMatchValue:
|
||||||
|
value = ber.DecodeString(child.Data.Bytes())
|
||||||
|
case MatchingRuleAssertionDNAttributes:
|
||||||
|
dnAttributes = child.Value.(bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(attr) > 0 {
|
||||||
|
ret += attr
|
||||||
|
}
|
||||||
|
if dnAttributes {
|
||||||
|
ret += ":dn"
|
||||||
|
}
|
||||||
|
if len(matchingRule) > 0 {
|
||||||
|
ret += ":"
|
||||||
|
ret += matchingRule
|
||||||
|
}
|
||||||
|
ret += ":="
|
||||||
|
ret += EscapeFilter(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += ")"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) {
|
||||||
|
for pos < len(filter) && filter[pos] == '(' {
|
||||||
|
child, newPos, err := compileFilter(filter, pos+1)
|
||||||
|
if err != nil {
|
||||||
|
return pos, err
|
||||||
|
}
|
||||||
|
pos = newPos
|
||||||
|
parent.AppendChild(child)
|
||||||
|
}
|
||||||
|
if pos == len(filter) {
|
||||||
|
return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos + 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
|
||||||
|
var (
|
||||||
|
packet *ber.Packet
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
newPos := pos
|
||||||
|
|
||||||
|
currentRune, currentWidth := utf8.DecodeRuneInString(filter[newPos:])
|
||||||
|
|
||||||
|
switch currentRune {
|
||||||
|
case utf8.RuneError:
|
||||||
|
return nil, 0, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos))
|
||||||
|
case '(':
|
||||||
|
packet, newPos, err = compileFilter(filter, pos+currentWidth)
|
||||||
|
newPos++
|
||||||
|
return packet, newPos, err
|
||||||
|
case '&':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd])
|
||||||
|
newPos, err = compileFilterSet(filter, pos+currentWidth, packet)
|
||||||
|
return packet, newPos, err
|
||||||
|
case '|':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr])
|
||||||
|
newPos, err = compileFilterSet(filter, pos+currentWidth, packet)
|
||||||
|
return packet, newPos, err
|
||||||
|
case '!':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot])
|
||||||
|
var child *ber.Packet
|
||||||
|
child, newPos, err = compileFilter(filter, pos+currentWidth)
|
||||||
|
packet.AppendChild(child)
|
||||||
|
return packet, newPos, err
|
||||||
|
default:
|
||||||
|
READING_ATTR := 0
|
||||||
|
READING_EXTENSIBLE_MATCHING_RULE := 1
|
||||||
|
READING_CONDITION := 2
|
||||||
|
|
||||||
|
state := READING_ATTR
|
||||||
|
|
||||||
|
attribute := ""
|
||||||
|
extensibleDNAttributes := false
|
||||||
|
extensibleMatchingRule := ""
|
||||||
|
condition := ""
|
||||||
|
|
||||||
|
for newPos < len(filter) {
|
||||||
|
remainingFilter := filter[newPos:]
|
||||||
|
currentRune, currentWidth = utf8.DecodeRuneInString(remainingFilter)
|
||||||
|
if currentRune == ')' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if currentRune == utf8.RuneError {
|
||||||
|
return packet, newPos, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch state {
|
||||||
|
case READING_ATTR:
|
||||||
|
switch {
|
||||||
|
// Extensible rule, with only DN-matching
|
||||||
|
case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:="):
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
|
||||||
|
extensibleDNAttributes = true
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 5
|
||||||
|
|
||||||
|
// Extensible rule, with DN-matching and a matching OID
|
||||||
|
case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:"):
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
|
||||||
|
extensibleDNAttributes = true
|
||||||
|
state = READING_EXTENSIBLE_MATCHING_RULE
|
||||||
|
newPos += 4
|
||||||
|
|
||||||
|
// Extensible rule, with attr only
|
||||||
|
case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="):
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 2
|
||||||
|
|
||||||
|
// Extensible rule, with no DN attribute matching
|
||||||
|
case currentRune == ':':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
|
||||||
|
state = READING_EXTENSIBLE_MATCHING_RULE
|
||||||
|
newPos += 1
|
||||||
|
|
||||||
|
// Equality condition
|
||||||
|
case currentRune == '=':
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch])
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 1
|
||||||
|
|
||||||
|
// Greater-than or equal
|
||||||
|
case currentRune == '>' && strings.HasPrefix(remainingFilter, ">="):
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual])
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 2
|
||||||
|
|
||||||
|
// Less-than or equal
|
||||||
|
case currentRune == '<' && strings.HasPrefix(remainingFilter, "<="):
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual])
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 2
|
||||||
|
|
||||||
|
// Approx
|
||||||
|
case currentRune == '~' && strings.HasPrefix(remainingFilter, "~="):
|
||||||
|
packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterApproxMatch])
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 2
|
||||||
|
|
||||||
|
// Still reading the attribute name
|
||||||
|
default:
|
||||||
|
attribute += fmt.Sprintf("%c", currentRune)
|
||||||
|
newPos += currentWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
case READING_EXTENSIBLE_MATCHING_RULE:
|
||||||
|
switch {
|
||||||
|
|
||||||
|
// Matching rule OID is done
|
||||||
|
case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="):
|
||||||
|
state = READING_CONDITION
|
||||||
|
newPos += 2
|
||||||
|
|
||||||
|
// Still reading the matching rule oid
|
||||||
|
default:
|
||||||
|
extensibleMatchingRule += fmt.Sprintf("%c", currentRune)
|
||||||
|
newPos += currentWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
case READING_CONDITION:
|
||||||
|
// append to the condition
|
||||||
|
condition += fmt.Sprintf("%c", currentRune)
|
||||||
|
newPos += currentWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if newPos == len(filter) {
|
||||||
|
err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
if packet == nil {
|
||||||
|
err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter"))
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case packet.Tag == FilterExtensibleMatch:
|
||||||
|
// MatchingRuleAssertion ::= SEQUENCE {
|
||||||
|
// matchingRule [1] MatchingRuleID OPTIONAL,
|
||||||
|
// type [2] AttributeDescription OPTIONAL,
|
||||||
|
// matchValue [3] AssertionValue,
|
||||||
|
// dnAttributes [4] BOOLEAN DEFAULT FALSE
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Include the matching rule oid, if specified
|
||||||
|
if len(extensibleMatchingRule) > 0 {
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule, MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the attribute, if specified
|
||||||
|
if len(attribute) > 0 {
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute, MatchingRuleAssertionMap[MatchingRuleAssertionType]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the value (only required child)
|
||||||
|
encodedString, err := escapedStringToEncodedBytes(condition)
|
||||||
|
if err != nil {
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchValue, encodedString, MatchingRuleAssertionMap[MatchingRuleAssertionMatchValue]))
|
||||||
|
|
||||||
|
// Defaults to false, so only include in the sequence if true
|
||||||
|
if extensibleDNAttributes {
|
||||||
|
packet.AppendChild(ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionDNAttributes, extensibleDNAttributes, MatchingRuleAssertionMap[MatchingRuleAssertionDNAttributes]))
|
||||||
|
}
|
||||||
|
|
||||||
|
case packet.Tag == FilterEqualityMatch && condition == "*":
|
||||||
|
packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute, FilterMap[FilterPresent])
|
||||||
|
case packet.Tag == FilterEqualityMatch && strings.Contains(condition, "*"):
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
|
||||||
|
packet.Tag = FilterSubstrings
|
||||||
|
packet.Description = FilterMap[uint64(packet.Tag)]
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
|
||||||
|
parts := strings.Split(condition, "*")
|
||||||
|
for i, part := range parts {
|
||||||
|
if part == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var tag ber.Tag
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
tag = FilterSubstringsInitial
|
||||||
|
case len(parts) - 1:
|
||||||
|
tag = FilterSubstringsFinal
|
||||||
|
default:
|
||||||
|
tag = FilterSubstringsAny
|
||||||
|
}
|
||||||
|
encodedString, err := escapedStringToEncodedBytes(part)
|
||||||
|
if err != nil {
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, tag, encodedString, FilterSubstringsMap[uint64(tag)]))
|
||||||
|
}
|
||||||
|
packet.AppendChild(seq)
|
||||||
|
default:
|
||||||
|
encodedString, err := escapedStringToEncodedBytes(condition)
|
||||||
|
if err != nil {
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, encodedString, "Condition"))
|
||||||
|
}
|
||||||
|
|
||||||
|
newPos += currentWidth
|
||||||
|
return packet, newPos, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from "ABC\xx\xx\xx" form to literal bytes for transport
|
||||||
|
func escapedStringToEncodedBytes(escapedString string) (string, error) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
i := 0
|
||||||
|
for i < len(escapedString) {
|
||||||
|
currentRune, currentWidth := utf8.DecodeRuneInString(escapedString[i:])
|
||||||
|
if currentRune == utf8.RuneError {
|
||||||
|
return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for escaped hex characters and convert them to their literal value for transport.
|
||||||
|
if currentRune == '\\' {
|
||||||
|
// http://tools.ietf.org/search/rfc4515
|
||||||
|
// \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not
|
||||||
|
// being a member of UTF1SUBSET.
|
||||||
|
if i+2 > len(escapedString) {
|
||||||
|
return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter"))
|
||||||
|
}
|
||||||
|
if escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3]); decodeErr != nil {
|
||||||
|
return "", NewError(ErrorFilterCompile, errors.New("ldap: invalid characters for escape in filter"))
|
||||||
|
} else {
|
||||||
|
buffer.WriteByte(escByte[0])
|
||||||
|
i += 2 // +1 from end of loop, so 3 total for \xx.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer.WriteRune(currentRune)
|
||||||
|
}
|
||||||
|
|
||||||
|
i += currentWidth
|
||||||
|
}
|
||||||
|
return buffer.String(), nil
|
||||||
|
}
|
||||||
248
Godeps/_workspace/src/github.com/go-ldap/ldap/filter_test.go
сгенерированный
поставляемый
Обычный файл
248
Godeps/_workspace/src/github.com/go-ldap/ldap/filter_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,248 @@
|
|||||||
|
package ldap_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
"gopkg.in/ldap.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type compileTest struct {
|
||||||
|
filterStr string
|
||||||
|
|
||||||
|
expectedFilter string
|
||||||
|
expectedType int
|
||||||
|
expectedErr string
|
||||||
|
}
|
||||||
|
|
||||||
|
var testFilters = []compileTest{
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(&(sn=Miller)(givenName=Bob))",
|
||||||
|
expectedFilter: "(&(sn=Miller)(givenName=Bob))",
|
||||||
|
expectedType: ldap.FilterAnd,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(|(sn=Miller)(givenName=Bob))",
|
||||||
|
expectedFilter: "(|(sn=Miller)(givenName=Bob))",
|
||||||
|
expectedType: ldap.FilterOr,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(!(sn=Miller))",
|
||||||
|
expectedFilter: "(!(sn=Miller))",
|
||||||
|
expectedType: ldap.FilterNot,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=Miller)",
|
||||||
|
expectedFilter: "(sn=Miller)",
|
||||||
|
expectedType: ldap.FilterEqualityMatch,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=Mill*)",
|
||||||
|
expectedFilter: "(sn=Mill*)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=*Mill)",
|
||||||
|
expectedFilter: "(sn=*Mill)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=*Mill*)",
|
||||||
|
expectedFilter: "(sn=*Mill*)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=*i*le*)",
|
||||||
|
expectedFilter: "(sn=*i*le*)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=Mi*l*r)",
|
||||||
|
expectedFilter: "(sn=Mi*l*r)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
// substring filters escape properly
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(sn=Mi*함*r)`,
|
||||||
|
expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
// already escaped substring filters don't get double-escaped
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(sn=Mi*\ed\95\a8*r)`,
|
||||||
|
expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=Mi*le*)",
|
||||||
|
expectedFilter: "(sn=Mi*le*)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=*i*ler)",
|
||||||
|
expectedFilter: "(sn=*i*ler)",
|
||||||
|
expectedType: ldap.FilterSubstrings,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn>=Miller)",
|
||||||
|
expectedFilter: "(sn>=Miller)",
|
||||||
|
expectedType: ldap.FilterGreaterOrEqual,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn<=Miller)",
|
||||||
|
expectedFilter: "(sn<=Miller)",
|
||||||
|
expectedType: ldap.FilterLessOrEqual,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn=*)",
|
||||||
|
expectedFilter: "(sn=*)",
|
||||||
|
expectedType: ldap.FilterPresent,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: "(sn~=Miller)",
|
||||||
|
expectedFilter: "(sn~=Miller)",
|
||||||
|
expectedType: ldap.FilterApproxMatch,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
|
||||||
|
expectedFilter: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
|
||||||
|
expectedType: ldap.FilterEqualityMatch,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(objectGUID=абвгдеёжзийклмнопрстуфхцчшщъыьэюя)`,
|
||||||
|
expectedFilter: `(objectGUID=\d0\b0\d0\b1\d0\b2\d0\b3\d0\b4\d0\b5\d1\91\d0\b6\d0\b7\d0\b8\d0\b9\d0\ba\d0\bb\d0\bc\d0\bd\d0\be\d0\bf\d1\80\d1\81\d1\82\d1\83\d1\84\d1\85\d1\86\d1\87\d1\88\d1\89\d1\8a\d1\8b\d1\8c\d1\8d\d1\8e\d1\8f)`,
|
||||||
|
expectedType: ldap.FilterEqualityMatch,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(objectGUID=함수목록)`,
|
||||||
|
expectedFilter: `(objectGUID=\ed\95\a8\ec\88\98\eb\aa\a9\eb\a1\9d)`,
|
||||||
|
expectedType: ldap.FilterEqualityMatch,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(objectGUID=`,
|
||||||
|
expectedFilter: ``,
|
||||||
|
expectedType: 0,
|
||||||
|
expectedErr: "unexpected end of filter",
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(objectGUID=함수목록`,
|
||||||
|
expectedFilter: ``,
|
||||||
|
expectedType: 0,
|
||||||
|
expectedErr: "unexpected end of filter",
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(&(objectclass=inetorgperson)(cn=中文))`,
|
||||||
|
expectedFilter: `(&(objectclass=inetorgperson)(cn=\e4\b8\ad\e6\96\87))`,
|
||||||
|
expectedType: 0,
|
||||||
|
},
|
||||||
|
// attr extension
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(memberOf:=foo)`,
|
||||||
|
expectedFilter: `(memberOf:=foo)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
// attr+named matching rule extension
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(memberOf:test:=foo)`,
|
||||||
|
expectedFilter: `(memberOf:test:=foo)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
// attr+oid matching rule extension
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(cn:1.2.3.4.5:=Fred Flintstone)`,
|
||||||
|
expectedFilter: `(cn:1.2.3.4.5:=Fred Flintstone)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
// attr+dn+oid matching rule extension
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
|
||||||
|
expectedFilter: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
// attr+dn extension
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(o:dn:=Ace Industry)`,
|
||||||
|
expectedFilter: `(o:dn:=Ace Industry)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
// dn extension
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(:dn:2.4.6.8.10:=Dino)`,
|
||||||
|
expectedFilter: `(:dn:2.4.6.8.10:=Dino)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
compileTest{
|
||||||
|
filterStr: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
|
||||||
|
expectedFilter: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
|
||||||
|
expectedType: ldap.FilterExtensibleMatch,
|
||||||
|
},
|
||||||
|
|
||||||
|
// compileTest{ filterStr: "()", filterType: FilterExtensibleMatch },
|
||||||
|
}
|
||||||
|
|
||||||
|
var testInvalidFilters = []string{
|
||||||
|
`(objectGUID=\zz)`,
|
||||||
|
`(objectGUID=\a)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
// Test Compiler and Decompiler
|
||||||
|
for _, i := range testFilters {
|
||||||
|
filter, err := ldap.CompileFilter(i.filterStr)
|
||||||
|
if err != nil {
|
||||||
|
if i.expectedErr == "" || !strings.Contains(err.Error(), i.expectedErr) {
|
||||||
|
t.Errorf("Problem compiling '%s' - '%v' (expected error to contain '%v')", i.filterStr, err, i.expectedErr)
|
||||||
|
}
|
||||||
|
} else if filter.Tag != ber.Tag(i.expectedType) {
|
||||||
|
t.Errorf("%q Expected %q got %q", i.filterStr, ldap.FilterMap[uint64(i.expectedType)], ldap.FilterMap[uint64(filter.Tag)])
|
||||||
|
} else {
|
||||||
|
o, err := ldap.DecompileFilter(filter)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
|
||||||
|
} else if i.expectedFilter != o {
|
||||||
|
t.Errorf("%q expected, got %q", i.expectedFilter, o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidFilter(t *testing.T) {
|
||||||
|
for _, filterStr := range testInvalidFilters {
|
||||||
|
if _, err := ldap.CompileFilter(filterStr); err == nil {
|
||||||
|
t.Errorf("Problem compiling %s - expected err", filterStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFilterCompile(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
filters := make([]string, len(testFilters))
|
||||||
|
|
||||||
|
// Test Compiler and Decompiler
|
||||||
|
for idx, i := range testFilters {
|
||||||
|
filters[idx] = i.filterStr
|
||||||
|
}
|
||||||
|
|
||||||
|
maxIdx := len(filters)
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
ldap.CompileFilter(filters[i%maxIdx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFilterDecompile(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
filters := make([]*ber.Packet, len(testFilters))
|
||||||
|
|
||||||
|
// Test Compiler and Decompiler
|
||||||
|
for idx, i := range testFilters {
|
||||||
|
filters[idx], _ = ldap.CompileFilter(i.filterStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
maxIdx := len(filters)
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
ldap.DecompileFilter(filters[i%maxIdx])
|
||||||
|
}
|
||||||
|
}
|
||||||
286
Godeps/_workspace/src/github.com/go-ldap/ldap/ldap.go
сгенерированный
поставляемый
Обычный файл
286
Godeps/_workspace/src/github.com/go-ldap/ldap/ldap.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,286 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
ber "gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LDAP Application Codes
|
||||||
|
const (
|
||||||
|
ApplicationBindRequest = 0
|
||||||
|
ApplicationBindResponse = 1
|
||||||
|
ApplicationUnbindRequest = 2
|
||||||
|
ApplicationSearchRequest = 3
|
||||||
|
ApplicationSearchResultEntry = 4
|
||||||
|
ApplicationSearchResultDone = 5
|
||||||
|
ApplicationModifyRequest = 6
|
||||||
|
ApplicationModifyResponse = 7
|
||||||
|
ApplicationAddRequest = 8
|
||||||
|
ApplicationAddResponse = 9
|
||||||
|
ApplicationDelRequest = 10
|
||||||
|
ApplicationDelResponse = 11
|
||||||
|
ApplicationModifyDNRequest = 12
|
||||||
|
ApplicationModifyDNResponse = 13
|
||||||
|
ApplicationCompareRequest = 14
|
||||||
|
ApplicationCompareResponse = 15
|
||||||
|
ApplicationAbandonRequest = 16
|
||||||
|
ApplicationSearchResultReference = 19
|
||||||
|
ApplicationExtendedRequest = 23
|
||||||
|
ApplicationExtendedResponse = 24
|
||||||
|
)
|
||||||
|
|
||||||
|
var ApplicationMap = map[uint8]string{
|
||||||
|
ApplicationBindRequest: "Bind Request",
|
||||||
|
ApplicationBindResponse: "Bind Response",
|
||||||
|
ApplicationUnbindRequest: "Unbind Request",
|
||||||
|
ApplicationSearchRequest: "Search Request",
|
||||||
|
ApplicationSearchResultEntry: "Search Result Entry",
|
||||||
|
ApplicationSearchResultDone: "Search Result Done",
|
||||||
|
ApplicationModifyRequest: "Modify Request",
|
||||||
|
ApplicationModifyResponse: "Modify Response",
|
||||||
|
ApplicationAddRequest: "Add Request",
|
||||||
|
ApplicationAddResponse: "Add Response",
|
||||||
|
ApplicationDelRequest: "Del Request",
|
||||||
|
ApplicationDelResponse: "Del Response",
|
||||||
|
ApplicationModifyDNRequest: "Modify DN Request",
|
||||||
|
ApplicationModifyDNResponse: "Modify DN Response",
|
||||||
|
ApplicationCompareRequest: "Compare Request",
|
||||||
|
ApplicationCompareResponse: "Compare Response",
|
||||||
|
ApplicationAbandonRequest: "Abandon Request",
|
||||||
|
ApplicationSearchResultReference: "Search Result Reference",
|
||||||
|
ApplicationExtendedRequest: "Extended Request",
|
||||||
|
ApplicationExtendedResponse: "Extended Response",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10)
|
||||||
|
const (
|
||||||
|
BeheraPasswordExpired = 0
|
||||||
|
BeheraAccountLocked = 1
|
||||||
|
BeheraChangeAfterReset = 2
|
||||||
|
BeheraPasswordModNotAllowed = 3
|
||||||
|
BeheraMustSupplyOldPassword = 4
|
||||||
|
BeheraInsufficientPasswordQuality = 5
|
||||||
|
BeheraPasswordTooShort = 6
|
||||||
|
BeheraPasswordTooYoung = 7
|
||||||
|
BeheraPasswordInHistory = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
var BeheraPasswordPolicyErrorMap = map[int8]string{
|
||||||
|
BeheraPasswordExpired: "Password expired",
|
||||||
|
BeheraAccountLocked: "Account locked",
|
||||||
|
BeheraChangeAfterReset: "Password must be changed",
|
||||||
|
BeheraPasswordModNotAllowed: "Policy prevents password modification",
|
||||||
|
BeheraMustSupplyOldPassword: "Policy requires old password in order to change password",
|
||||||
|
BeheraInsufficientPasswordQuality: "Password fails quality checks",
|
||||||
|
BeheraPasswordTooShort: "Password is too short for policy",
|
||||||
|
BeheraPasswordTooYoung: "Password has been changed too recently",
|
||||||
|
BeheraPasswordInHistory: "New password is in list of old passwords",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds descriptions to an LDAP Response packet for debugging
|
||||||
|
func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions"))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
packet.Description = "LDAP Response"
|
||||||
|
packet.Children[0].Description = "Message ID"
|
||||||
|
|
||||||
|
application := uint8(packet.Children[1].Tag)
|
||||||
|
packet.Children[1].Description = ApplicationMap[application]
|
||||||
|
|
||||||
|
switch application {
|
||||||
|
case ApplicationBindRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationBindResponse:
|
||||||
|
addDefaultLDAPResponseDescriptions(packet)
|
||||||
|
case ApplicationUnbindRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationSearchRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationSearchResultEntry:
|
||||||
|
packet.Children[1].Children[0].Description = "Object Name"
|
||||||
|
packet.Children[1].Children[1].Description = "Attributes"
|
||||||
|
for _, child := range packet.Children[1].Children[1].Children {
|
||||||
|
child.Description = "Attribute"
|
||||||
|
child.Children[0].Description = "Attribute Name"
|
||||||
|
child.Children[1].Description = "Attribute Values"
|
||||||
|
for _, grandchild := range child.Children[1].Children {
|
||||||
|
grandchild.Description = "Attribute Value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
addControlDescriptions(packet.Children[2])
|
||||||
|
}
|
||||||
|
case ApplicationSearchResultDone:
|
||||||
|
addDefaultLDAPResponseDescriptions(packet)
|
||||||
|
case ApplicationModifyRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationModifyResponse:
|
||||||
|
case ApplicationAddRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationAddResponse:
|
||||||
|
case ApplicationDelRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationDelResponse:
|
||||||
|
case ApplicationModifyDNRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationModifyDNResponse:
|
||||||
|
case ApplicationCompareRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationCompareResponse:
|
||||||
|
case ApplicationAbandonRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationSearchResultReference:
|
||||||
|
case ApplicationExtendedRequest:
|
||||||
|
addRequestDescriptions(packet)
|
||||||
|
case ApplicationExtendedResponse:
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addControlDescriptions(packet *ber.Packet) {
|
||||||
|
packet.Description = "Controls"
|
||||||
|
for _, child := range packet.Children {
|
||||||
|
child.Description = "Control"
|
||||||
|
child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")"
|
||||||
|
value := child.Children[1]
|
||||||
|
if len(child.Children) == 3 {
|
||||||
|
child.Children[1].Description = "Criticality"
|
||||||
|
value = child.Children[2]
|
||||||
|
}
|
||||||
|
value.Description = "Control Value"
|
||||||
|
|
||||||
|
switch child.Children[0].Value.(string) {
|
||||||
|
case ControlTypePaging:
|
||||||
|
value.Description += " (Paging)"
|
||||||
|
if value.Value != nil {
|
||||||
|
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||||
|
value.Data.Truncate(0)
|
||||||
|
value.Value = nil
|
||||||
|
valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
|
||||||
|
value.AppendChild(valueChildren)
|
||||||
|
}
|
||||||
|
value.Children[0].Description = "Real Search Control Value"
|
||||||
|
value.Children[0].Children[0].Description = "Paging Size"
|
||||||
|
value.Children[0].Children[1].Description = "Cookie"
|
||||||
|
|
||||||
|
case ControlTypeBeheraPasswordPolicy:
|
||||||
|
value.Description += " (Password Policy - Behera Draft)"
|
||||||
|
if value.Value != nil {
|
||||||
|
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||||
|
value.Data.Truncate(0)
|
||||||
|
value.Value = nil
|
||||||
|
value.AppendChild(valueChildren)
|
||||||
|
}
|
||||||
|
sequence := value.Children[0]
|
||||||
|
for _, child := range sequence.Children {
|
||||||
|
if child.Tag == 0 {
|
||||||
|
//Warning
|
||||||
|
child := child.Children[0]
|
||||||
|
packet := ber.DecodePacket(child.Data.Bytes())
|
||||||
|
val, ok := packet.Value.(int64)
|
||||||
|
if ok {
|
||||||
|
if child.Tag == 0 {
|
||||||
|
//timeBeforeExpiration
|
||||||
|
value.Description += " (TimeBeforeExpiration)"
|
||||||
|
child.Value = val
|
||||||
|
} else if child.Tag == 1 {
|
||||||
|
//graceAuthNsRemaining
|
||||||
|
value.Description += " (GraceAuthNsRemaining)"
|
||||||
|
child.Value = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if child.Tag == 1 {
|
||||||
|
// Error
|
||||||
|
packet := ber.DecodePacket(child.Data.Bytes())
|
||||||
|
val, ok := packet.Value.(int8)
|
||||||
|
if !ok {
|
||||||
|
val = -1
|
||||||
|
}
|
||||||
|
child.Description = "Error"
|
||||||
|
child.Value = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRequestDescriptions(packet *ber.Packet) {
|
||||||
|
packet.Description = "LDAP Request"
|
||||||
|
packet.Children[0].Description = "Message ID"
|
||||||
|
packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
addControlDescriptions(packet.Children[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
|
||||||
|
resultCode, _ := getLDAPResultCode(packet)
|
||||||
|
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
|
||||||
|
packet.Children[1].Children[1].Description = "Matched DN"
|
||||||
|
packet.Children[1].Children[2].Description = "Error Message"
|
||||||
|
if len(packet.Children[1].Children) > 3 {
|
||||||
|
packet.Children[1].Children[3].Description = "Referral"
|
||||||
|
}
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
addControlDescriptions(packet.Children[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DebugBinaryFile(fileName string) error {
|
||||||
|
file, err := ioutil.ReadFile(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return NewError(ErrorDebugging, err)
|
||||||
|
}
|
||||||
|
ber.PrintBytes(os.Stdout, file, "")
|
||||||
|
packet := ber.DecodePacket(file)
|
||||||
|
addLDAPDescriptions(packet)
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var hex = "0123456789abcdef"
|
||||||
|
|
||||||
|
func mustEscape(c byte) bool {
|
||||||
|
return c > 0x7f || c == '(' || c == ')' || c == '\\' || c == '*' || c == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapeFilter escapes from the provided LDAP filter string the special
|
||||||
|
// characters in the set `()*\` and those out of the range 0 < c < 0x80,
|
||||||
|
// as defined in RFC4515.
|
||||||
|
func EscapeFilter(filter string) string {
|
||||||
|
escape := 0
|
||||||
|
for i := 0; i < len(filter); i++ {
|
||||||
|
if mustEscape(filter[i]) {
|
||||||
|
escape++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if escape == 0 {
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
buf := make([]byte, len(filter)+escape*2)
|
||||||
|
for i, j := 0, 0; i < len(filter); i++ {
|
||||||
|
c := filter[i]
|
||||||
|
if mustEscape(c) {
|
||||||
|
buf[j+0] = '\\'
|
||||||
|
buf[j+1] = hex[c>>4]
|
||||||
|
buf[j+2] = hex[c&0xf]
|
||||||
|
j += 3
|
||||||
|
} else {
|
||||||
|
buf[j] = c
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
249
Godeps/_workspace/src/github.com/go-ldap/ldap/ldap_test.go
сгенерированный
поставляемый
Обычный файл
249
Godeps/_workspace/src/github.com/go-ldap/ldap/ldap_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,249 @@
|
|||||||
|
package ldap_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/ldap.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ldapServer = "ldap.itd.umich.edu"
|
||||||
|
var ldapPort = uint16(389)
|
||||||
|
var ldapTLSPort = uint16(636)
|
||||||
|
var baseDN = "dc=umich,dc=edu"
|
||||||
|
var filter = []string{
|
||||||
|
"(cn=cis-fac)",
|
||||||
|
"(&(owner=*)(cn=cis-fac))",
|
||||||
|
"(&(objectclass=rfc822mailgroup)(cn=*Computer*))",
|
||||||
|
"(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"}
|
||||||
|
var attributes = []string{
|
||||||
|
"cn",
|
||||||
|
"description"}
|
||||||
|
|
||||||
|
func TestDial(t *testing.T) {
|
||||||
|
fmt.Printf("TestDial: starting...\n")
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
fmt.Printf("TestDial: finished...\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDialTLS(t *testing.T) {
|
||||||
|
fmt.Printf("TestDialTLS: starting...\n")
|
||||||
|
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
fmt.Printf("TestDialTLS: finished...\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStartTLS(t *testing.T) {
|
||||||
|
fmt.Printf("TestStartTLS: starting...\n")
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("TestStartTLS: finished...\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearch(t *testing.T) {
|
||||||
|
fmt.Printf("TestSearch: starting...\n")
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||||
|
filter[0],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchStartTLS(t *testing.T) {
|
||||||
|
fmt.Printf("TestSearchStartTLS: starting...\n")
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||||
|
filter[0],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||||
|
|
||||||
|
fmt.Printf("TestSearchStartTLS: upgrading with startTLS\n")
|
||||||
|
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sr, err = l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchWithPaging(t *testing.T) {
|
||||||
|
fmt.Printf("TestSearchWithPaging: starting...\n")
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
err = l.Bind("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||||
|
filter[2],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
sr, err := l.SearchWithPaging(searchRequest, 5)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchGoroutine(t *testing.T, l *ldap.Conn, results chan *ldap.SearchResult, i int) {
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
baseDN,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||||
|
filter[i],
|
||||||
|
attributes,
|
||||||
|
nil)
|
||||||
|
sr, err := l.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
results <- nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
results <- sr
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMultiGoroutineSearch(t *testing.T, TLS bool, startTLS bool) {
|
||||||
|
fmt.Printf("TestMultiGoroutineSearch: starting...\n")
|
||||||
|
var l *ldap.Conn
|
||||||
|
var err error
|
||||||
|
if TLS {
|
||||||
|
l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
} else {
|
||||||
|
l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if startTLS {
|
||||||
|
fmt.Printf("TestMultiGoroutineSearch: using StartTLS...\n")
|
||||||
|
err := l.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]chan *ldap.SearchResult, len(filter))
|
||||||
|
for i := range filter {
|
||||||
|
results[i] = make(chan *ldap.SearchResult)
|
||||||
|
go searchGoroutine(t, l, results[i], i)
|
||||||
|
}
|
||||||
|
for i := range filter {
|
||||||
|
sr := <-results[i]
|
||||||
|
if sr == nil {
|
||||||
|
t.Errorf("Did not receive results from goroutine for %q", filter[i])
|
||||||
|
} else {
|
||||||
|
fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultiGoroutineSearch(t *testing.T) {
|
||||||
|
testMultiGoroutineSearch(t, false, false)
|
||||||
|
testMultiGoroutineSearch(t, true, true)
|
||||||
|
testMultiGoroutineSearch(t, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEscapeFilter(t *testing.T) {
|
||||||
|
if got, want := ldap.EscapeFilter("a\x00b(c)d*e\\f"), `a\00b\28c\29d\2ae\5cf`; got != want {
|
||||||
|
t.Errorf("Got %s, expected %s", want, got)
|
||||||
|
}
|
||||||
|
if got, want := ldap.EscapeFilter("Lučić"), `Lu\c4\8di\c4\87`; got != want {
|
||||||
|
t.Errorf("Got %s, expected %s", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompare(t *testing.T) {
|
||||||
|
fmt.Printf("TestCompare: starting...\n")
|
||||||
|
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
dn := "cn=math mich,ou=User Groups,ou=Groups,dc=umich,dc=edu"
|
||||||
|
attribute := "cn"
|
||||||
|
value := "math mich"
|
||||||
|
|
||||||
|
sr, err := l.Compare(dn, attribute, value)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("TestCompare: -> %v\n", sr)
|
||||||
|
}
|
||||||
156
Godeps/_workspace/src/github.com/go-ldap/ldap/modify.go
сгенерированный
поставляемый
Обычный файл
156
Godeps/_workspace/src/github.com/go-ldap/ldap/modify.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,156 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// File contains Modify functionality
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// ModifyRequest ::= [APPLICATION 6] SEQUENCE {
|
||||||
|
// object LDAPDN,
|
||||||
|
// changes SEQUENCE OF change SEQUENCE {
|
||||||
|
// operation ENUMERATED {
|
||||||
|
// add (0),
|
||||||
|
// delete (1),
|
||||||
|
// replace (2),
|
||||||
|
// ... },
|
||||||
|
// modification PartialAttribute } }
|
||||||
|
//
|
||||||
|
// PartialAttribute ::= SEQUENCE {
|
||||||
|
// type AttributeDescription,
|
||||||
|
// vals SET OF value AttributeValue }
|
||||||
|
//
|
||||||
|
// AttributeDescription ::= LDAPString
|
||||||
|
// -- Constrained to <attributedescription>
|
||||||
|
// -- [RFC4512]
|
||||||
|
//
|
||||||
|
// AttributeValue ::= OCTET STRING
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AddAttribute = 0
|
||||||
|
DeleteAttribute = 1
|
||||||
|
ReplaceAttribute = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type PartialAttribute struct {
|
||||||
|
attrType string
|
||||||
|
attrVals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PartialAttribute) encode() *ber.Packet {
|
||||||
|
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
|
||||||
|
seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.attrType, "Type"))
|
||||||
|
set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
|
||||||
|
for _, value := range p.attrVals {
|
||||||
|
set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
|
||||||
|
}
|
||||||
|
seq.AppendChild(set)
|
||||||
|
return seq
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyRequest struct {
|
||||||
|
dn string
|
||||||
|
addAttributes []PartialAttribute
|
||||||
|
deleteAttributes []PartialAttribute
|
||||||
|
replaceAttributes []PartialAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
|
||||||
|
m.addAttributes = append(m.addAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
|
||||||
|
m.deleteAttributes = append(m.deleteAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
|
||||||
|
m.replaceAttributes = append(m.replaceAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ModifyRequest) encode() *ber.Packet {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.dn, "DN"))
|
||||||
|
changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
|
||||||
|
for _, attribute := range m.addAttributes {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
|
||||||
|
change.AppendChild(attribute.encode())
|
||||||
|
changes.AppendChild(change)
|
||||||
|
}
|
||||||
|
for _, attribute := range m.deleteAttributes {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
|
||||||
|
change.AppendChild(attribute.encode())
|
||||||
|
changes.AppendChild(change)
|
||||||
|
}
|
||||||
|
for _, attribute := range m.replaceAttributes {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
|
||||||
|
change.AppendChild(attribute.encode())
|
||||||
|
changes.AppendChild(change)
|
||||||
|
}
|
||||||
|
request.AppendChild(changes)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewModifyRequest(
|
||||||
|
dn string,
|
||||||
|
) *ModifyRequest {
|
||||||
|
return &ModifyRequest{
|
||||||
|
dn: dn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
packet.AppendChild(modifyRequest.encode())
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationModifyResponse {
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: returning", messageID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
137
Godeps/_workspace/src/github.com/go-ldap/ldap/passwdmodify.go
сгенерированный
поставляемый
Обычный файл
137
Godeps/_workspace/src/github.com/go-ldap/ldap/passwdmodify.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,137 @@
|
|||||||
|
// This file contains the password modify extended operation as specified in rfc 3062
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc3062
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PasswordModifyRequest struct {
|
||||||
|
UserIdentity string
|
||||||
|
OldPassword string
|
||||||
|
NewPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordModifyResult struct {
|
||||||
|
GeneratedPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID"))
|
||||||
|
extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request")
|
||||||
|
passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request")
|
||||||
|
if r.UserIdentity != "" {
|
||||||
|
passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity"))
|
||||||
|
}
|
||||||
|
if r.OldPassword != "" {
|
||||||
|
passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password"))
|
||||||
|
}
|
||||||
|
if r.NewPassword != "" {
|
||||||
|
passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password"))
|
||||||
|
}
|
||||||
|
|
||||||
|
extendedRequestValue.AppendChild(passwordModifyRequestValue)
|
||||||
|
request.AppendChild(extendedRequestValue)
|
||||||
|
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new PasswordModifyRequest
|
||||||
|
//
|
||||||
|
// According to the RFC 3602:
|
||||||
|
// userIdentity is a string representing the user associated with the request.
|
||||||
|
// This string may or may not be an LDAPDN (RFC 2253).
|
||||||
|
// If userIdentity is empty then the operation will act on the user associated
|
||||||
|
// with the session.
|
||||||
|
//
|
||||||
|
// oldPassword is the current user's password, it can be empty or it can be
|
||||||
|
// needed depending on the session user access rights (usually an administrator
|
||||||
|
// can change a user's password without knowing the current one) and the
|
||||||
|
// password policy (see pwdSafeModify password policy's attribute)
|
||||||
|
//
|
||||||
|
// newPassword is the desired user's password. If empty the server can return
|
||||||
|
// an error or generate a new password that will be available in the
|
||||||
|
// PasswordModifyResult.GeneratedPassword
|
||||||
|
//
|
||||||
|
func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {
|
||||||
|
return &PasswordModifyRequest{
|
||||||
|
UserIdentity: userIdentity,
|
||||||
|
OldPassword: oldPassword,
|
||||||
|
NewPassword: newPassword,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
|
||||||
|
encodedPasswordModifyRequest, err := passwordModifyRequest.encode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
packet.AppendChild(encodedPasswordModifyRequest)
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
result := &PasswordModifyResult{}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
|
||||||
|
if packet == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationExtendedResponse {
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return nil, NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
extendedResponse := packet.Children[1]
|
||||||
|
for _, child := range extendedResponse.Children {
|
||||||
|
if child.Tag == 11 {
|
||||||
|
passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes())
|
||||||
|
if len(passwordModifyReponseValue.Children) == 1 {
|
||||||
|
if passwordModifyReponseValue.Children[0].Tag == 0 {
|
||||||
|
result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
403
Godeps/_workspace/src/github.com/go-ldap/ldap/search.go
сгенерированный
поставляемый
Обычный файл
403
Godeps/_workspace/src/github.com/go-ldap/ldap/search.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,403 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// File contains Search functionality
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
//
|
||||||
|
// SearchRequest ::= [APPLICATION 3] SEQUENCE {
|
||||||
|
// baseObject LDAPDN,
|
||||||
|
// scope ENUMERATED {
|
||||||
|
// baseObject (0),
|
||||||
|
// singleLevel (1),
|
||||||
|
// wholeSubtree (2),
|
||||||
|
// ... },
|
||||||
|
// derefAliases ENUMERATED {
|
||||||
|
// neverDerefAliases (0),
|
||||||
|
// derefInSearching (1),
|
||||||
|
// derefFindingBaseObj (2),
|
||||||
|
// derefAlways (3) },
|
||||||
|
// sizeLimit INTEGER (0 .. maxInt),
|
||||||
|
// timeLimit INTEGER (0 .. maxInt),
|
||||||
|
// typesOnly BOOLEAN,
|
||||||
|
// filter Filter,
|
||||||
|
// attributes AttributeSelection }
|
||||||
|
//
|
||||||
|
// AttributeSelection ::= SEQUENCE OF selector LDAPString
|
||||||
|
// -- The LDAPString is constrained to
|
||||||
|
// -- <attributeSelector> in Section 4.5.1.8
|
||||||
|
//
|
||||||
|
// Filter ::= CHOICE {
|
||||||
|
// and [0] SET SIZE (1..MAX) OF filter Filter,
|
||||||
|
// or [1] SET SIZE (1..MAX) OF filter Filter,
|
||||||
|
// not [2] Filter,
|
||||||
|
// equalityMatch [3] AttributeValueAssertion,
|
||||||
|
// substrings [4] SubstringFilter,
|
||||||
|
// greaterOrEqual [5] AttributeValueAssertion,
|
||||||
|
// lessOrEqual [6] AttributeValueAssertion,
|
||||||
|
// present [7] AttributeDescription,
|
||||||
|
// approxMatch [8] AttributeValueAssertion,
|
||||||
|
// extensibleMatch [9] MatchingRuleAssertion,
|
||||||
|
// ... }
|
||||||
|
//
|
||||||
|
// SubstringFilter ::= SEQUENCE {
|
||||||
|
// type AttributeDescription,
|
||||||
|
// substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
|
||||||
|
// initial [0] AssertionValue, -- can occur at most once
|
||||||
|
// any [1] AssertionValue,
|
||||||
|
// final [2] AssertionValue } -- can occur at most once
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// MatchingRuleAssertion ::= SEQUENCE {
|
||||||
|
// matchingRule [1] MatchingRuleId OPTIONAL,
|
||||||
|
// type [2] AttributeDescription OPTIONAL,
|
||||||
|
// matchValue [3] AssertionValue,
|
||||||
|
// dnAttributes [4] BOOLEAN DEFAULT FALSE }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ScopeBaseObject = 0
|
||||||
|
ScopeSingleLevel = 1
|
||||||
|
ScopeWholeSubtree = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var ScopeMap = map[int]string{
|
||||||
|
ScopeBaseObject: "Base Object",
|
||||||
|
ScopeSingleLevel: "Single Level",
|
||||||
|
ScopeWholeSubtree: "Whole Subtree",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
NeverDerefAliases = 0
|
||||||
|
DerefInSearching = 1
|
||||||
|
DerefFindingBaseObj = 2
|
||||||
|
DerefAlways = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
var DerefMap = map[int]string{
|
||||||
|
NeverDerefAliases: "NeverDerefAliases",
|
||||||
|
DerefInSearching: "DerefInSearching",
|
||||||
|
DerefFindingBaseObj: "DerefFindingBaseObj",
|
||||||
|
DerefAlways: "DerefAlways",
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs.
|
||||||
|
// The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the
|
||||||
|
// same input map of attributes, the output entry will contain the same order of attributes
|
||||||
|
func NewEntry(dn string, attributes map[string][]string) *Entry {
|
||||||
|
var attributeNames []string
|
||||||
|
for attributeName := range attributes {
|
||||||
|
attributeNames = append(attributeNames, attributeName)
|
||||||
|
}
|
||||||
|
sort.Strings(attributeNames)
|
||||||
|
|
||||||
|
var encodedAttributes []*EntryAttribute
|
||||||
|
for _, attributeName := range attributeNames {
|
||||||
|
encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName]))
|
||||||
|
}
|
||||||
|
return &Entry{
|
||||||
|
DN: dn,
|
||||||
|
Attributes: encodedAttributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Entry struct {
|
||||||
|
DN string
|
||||||
|
Attributes []*EntryAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetAttributeValues(attribute string) []string {
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
if attr.Name == attribute {
|
||||||
|
return attr.Values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
if attr.Name == attribute {
|
||||||
|
return attr.ByteValues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [][]byte{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetAttributeValue(attribute string) string {
|
||||||
|
values := e.GetAttributeValues(attribute)
|
||||||
|
if len(values) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return values[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetRawAttributeValue(attribute string) []byte {
|
||||||
|
values := e.GetRawAttributeValues(attribute)
|
||||||
|
if len(values) == 0 {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
return values[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) Print() {
|
||||||
|
fmt.Printf("DN: %s\n", e.DN)
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
attr.Print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) PrettyPrint(indent int) {
|
||||||
|
fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
|
||||||
|
for _, attr := range e.Attributes {
|
||||||
|
attr.PrettyPrint(indent + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
|
||||||
|
func NewEntryAttribute(name string, values []string) *EntryAttribute {
|
||||||
|
var bytes [][]byte
|
||||||
|
for _, value := range values {
|
||||||
|
bytes = append(bytes, []byte(value))
|
||||||
|
}
|
||||||
|
return &EntryAttribute{
|
||||||
|
Name: name,
|
||||||
|
Values: values,
|
||||||
|
ByteValues: bytes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntryAttribute struct {
|
||||||
|
Name string
|
||||||
|
Values []string
|
||||||
|
ByteValues [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EntryAttribute) Print() {
|
||||||
|
fmt.Printf("%s: %s\n", e.Name, e.Values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EntryAttribute) PrettyPrint(indent int) {
|
||||||
|
fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchResult struct {
|
||||||
|
Entries []*Entry
|
||||||
|
Referrals []string
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SearchResult) Print() {
|
||||||
|
for _, entry := range s.Entries {
|
||||||
|
entry.Print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SearchResult) PrettyPrint(indent int) {
|
||||||
|
for _, entry := range s.Entries {
|
||||||
|
entry.PrettyPrint(indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchRequest struct {
|
||||||
|
BaseDN string
|
||||||
|
Scope int
|
||||||
|
DerefAliases int
|
||||||
|
SizeLimit int
|
||||||
|
TimeLimit int
|
||||||
|
TypesOnly bool
|
||||||
|
Filter string
|
||||||
|
Attributes []string
|
||||||
|
Controls []Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SearchRequest) encode() (*ber.Packet, error) {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit"))
|
||||||
|
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit"))
|
||||||
|
request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only"))
|
||||||
|
// compile and encode filter
|
||||||
|
filterPacket, err := CompileFilter(s.Filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.AppendChild(filterPacket)
|
||||||
|
// encode attributes
|
||||||
|
attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
|
||||||
|
for _, attribute := range s.Attributes {
|
||||||
|
attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
|
||||||
|
}
|
||||||
|
request.AppendChild(attributesPacket)
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearchRequest(
|
||||||
|
BaseDN string,
|
||||||
|
Scope, DerefAliases, SizeLimit, TimeLimit int,
|
||||||
|
TypesOnly bool,
|
||||||
|
Filter string,
|
||||||
|
Attributes []string,
|
||||||
|
Controls []Control,
|
||||||
|
) *SearchRequest {
|
||||||
|
return &SearchRequest{
|
||||||
|
BaseDN: BaseDN,
|
||||||
|
Scope: Scope,
|
||||||
|
DerefAliases: DerefAliases,
|
||||||
|
SizeLimit: SizeLimit,
|
||||||
|
TimeLimit: TimeLimit,
|
||||||
|
TypesOnly: TypesOnly,
|
||||||
|
Filter: Filter,
|
||||||
|
Attributes: Attributes,
|
||||||
|
Controls: Controls,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
|
||||||
|
if searchRequest.Controls == nil {
|
||||||
|
searchRequest.Controls = make([]Control, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pagingControl := NewControlPaging(pagingSize)
|
||||||
|
searchRequest.Controls = append(searchRequest.Controls, pagingControl)
|
||||||
|
searchResult := new(SearchResult)
|
||||||
|
for {
|
||||||
|
result, err := l.Search(searchRequest)
|
||||||
|
l.Debug.Printf("Looking for Paging Control...")
|
||||||
|
if err != nil {
|
||||||
|
return searchResult, err
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range result.Entries {
|
||||||
|
searchResult.Entries = append(searchResult.Entries, entry)
|
||||||
|
}
|
||||||
|
for _, referral := range result.Referrals {
|
||||||
|
searchResult.Referrals = append(searchResult.Referrals, referral)
|
||||||
|
}
|
||||||
|
for _, control := range result.Controls {
|
||||||
|
searchResult.Controls = append(searchResult.Controls, control)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("Looking for Paging Control...")
|
||||||
|
pagingResult := FindControl(result.Controls, ControlTypePaging)
|
||||||
|
if pagingResult == nil {
|
||||||
|
pagingControl = nil
|
||||||
|
l.Debug.Printf("Could not find paging control. Breaking...")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie := pagingResult.(*ControlPaging).Cookie
|
||||||
|
if len(cookie) == 0 {
|
||||||
|
pagingControl = nil
|
||||||
|
l.Debug.Printf("Could not find cookie. Breaking...")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pagingControl.SetCookie(cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pagingControl != nil {
|
||||||
|
l.Debug.Printf("Abandoning Paging...")
|
||||||
|
pagingControl.PagingSize = 0
|
||||||
|
l.Search(searchRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||||
|
messageID := l.nextMessageID()
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
|
||||||
|
// encode search request
|
||||||
|
encodedSearchRequest, err := searchRequest.encode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
packet.AppendChild(encodedSearchRequest)
|
||||||
|
// encode search controls
|
||||||
|
if searchRequest.Controls != nil {
|
||||||
|
packet.AppendChild(encodeControls(searchRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
channel, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if channel == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
|
||||||
|
}
|
||||||
|
defer l.finishMessage(messageID)
|
||||||
|
|
||||||
|
result := &SearchResult{
|
||||||
|
Entries: make([]*Entry, 0),
|
||||||
|
Referrals: make([]string, 0),
|
||||||
|
Controls: make([]Control, 0)}
|
||||||
|
|
||||||
|
foundSearchResultDone := false
|
||||||
|
for !foundSearchResultDone {
|
||||||
|
l.Debug.Printf("%d: waiting for response", messageID)
|
||||||
|
packet = <-channel
|
||||||
|
l.Debug.Printf("%d: got response %p", messageID, packet)
|
||||||
|
if packet == nil {
|
||||||
|
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch packet.Children[1].Tag {
|
||||||
|
case 4:
|
||||||
|
entry := new(Entry)
|
||||||
|
entry.DN = packet.Children[1].Children[0].Value.(string)
|
||||||
|
for _, child := range packet.Children[1].Children[1].Children {
|
||||||
|
attr := new(EntryAttribute)
|
||||||
|
attr.Name = child.Children[0].Value.(string)
|
||||||
|
for _, value := range child.Children[1].Children {
|
||||||
|
attr.Values = append(attr.Values, value.Value.(string))
|
||||||
|
attr.ByteValues = append(attr.ByteValues, value.ByteValue)
|
||||||
|
}
|
||||||
|
entry.Attributes = append(entry.Attributes, attr)
|
||||||
|
}
|
||||||
|
result.Entries = append(result.Entries, entry)
|
||||||
|
case 5:
|
||||||
|
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||||
|
if resultCode != 0 {
|
||||||
|
return result, NewError(resultCode, errors.New(resultDescription))
|
||||||
|
}
|
||||||
|
if len(packet.Children) == 3 {
|
||||||
|
for _, child := range packet.Children[2].Children {
|
||||||
|
result.Controls = append(result.Controls, DecodeControl(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foundSearchResultDone = true
|
||||||
|
case 19:
|
||||||
|
result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.Debug.Printf("%d: returning", messageID)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
31
Godeps/_workspace/src/github.com/go-ldap/ldap/search_test.go
сгенерированный
поставляемый
Обычный файл
31
Godeps/_workspace/src/github.com/go-ldap/ldap/search_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,31 @@
|
|||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestNewEntry tests that repeated calls to NewEntry return the same value with the same input
|
||||||
|
func TestNewEntry(t *testing.T) {
|
||||||
|
dn := "testDN"
|
||||||
|
attributes := map[string][]string{
|
||||||
|
"alpha": {"value"},
|
||||||
|
"beta": {"value"},
|
||||||
|
"gamma": {"value"},
|
||||||
|
"delta": {"value"},
|
||||||
|
"epsilon": {"value"},
|
||||||
|
}
|
||||||
|
exectedEntry := NewEntry(dn, attributes)
|
||||||
|
|
||||||
|
iteration := 0
|
||||||
|
for {
|
||||||
|
if iteration == 100 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
testEntry := NewEntry(dn, attributes)
|
||||||
|
if !reflect.DeepEqual(exectedEntry, testEntry) {
|
||||||
|
t.Fatalf("consequent calls to NewEntry did not yield the same result:\n\texpected:\n\t%s\n\tgot:\n\t%s\n", exectedEntry, testEntry)
|
||||||
|
}
|
||||||
|
iteration = iteration + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/.travis.yml
сгенерированный
поставляемый
Обычный файл
15
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/.travis.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,15 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- tip
|
||||||
|
go_import_path: gopkg.in/asn-ber.v1
|
||||||
|
install:
|
||||||
|
- go list -f '{{range .Imports}}{{.}} {{end}}' ./... | xargs go get -v
|
||||||
|
- go list -f '{{range .TestImports}}{{.}} {{end}}' ./... | xargs go get -v
|
||||||
|
- go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover
|
||||||
|
- go build -v ./...
|
||||||
|
script:
|
||||||
|
- go test -v -cover ./...
|
||||||
27
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/LICENSE
сгенерированный
поставляемый
Обычный файл
27
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/LICENSE
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
24
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/README.md
сгенерированный
поставляемый
Обычный файл
24
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/README.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,24 @@
|
|||||||
|
[](https://godoc.org/gopkg.in/asn1-ber.v1) [](https://travis-ci.org/go-asn1-ber/asn1-ber)
|
||||||
|
|
||||||
|
|
||||||
|
ASN1 BER Encoding / Decoding Library for the GO programming language.
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Required libraries:
|
||||||
|
None
|
||||||
|
|
||||||
|
Working:
|
||||||
|
Very basic encoding / decoding needed for LDAP protocol
|
||||||
|
|
||||||
|
Tests Implemented:
|
||||||
|
A few
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
Fix all encoding / decoding to conform to ASN1 BER spec
|
||||||
|
Implement Tests / Benchmarks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
|
||||||
|
The design is licensed under the Creative Commons 3.0 Attributions license.
|
||||||
|
Read this article for more details: http://blog.golang.org/gopher
|
||||||
504
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/ber.go
сгенерированный
поставляемый
Обычный файл
504
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/ber.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,504 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Packet struct {
|
||||||
|
Identifier
|
||||||
|
Value interface{}
|
||||||
|
ByteValue []byte
|
||||||
|
Data *bytes.Buffer
|
||||||
|
Children []*Packet
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Identifier struct {
|
||||||
|
ClassType Class
|
||||||
|
TagType Type
|
||||||
|
Tag Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tag uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
TagEOC Tag = 0x00
|
||||||
|
TagBoolean Tag = 0x01
|
||||||
|
TagInteger Tag = 0x02
|
||||||
|
TagBitString Tag = 0x03
|
||||||
|
TagOctetString Tag = 0x04
|
||||||
|
TagNULL Tag = 0x05
|
||||||
|
TagObjectIdentifier Tag = 0x06
|
||||||
|
TagObjectDescriptor Tag = 0x07
|
||||||
|
TagExternal Tag = 0x08
|
||||||
|
TagRealFloat Tag = 0x09
|
||||||
|
TagEnumerated Tag = 0x0a
|
||||||
|
TagEmbeddedPDV Tag = 0x0b
|
||||||
|
TagUTF8String Tag = 0x0c
|
||||||
|
TagRelativeOID Tag = 0x0d
|
||||||
|
TagSequence Tag = 0x10
|
||||||
|
TagSet Tag = 0x11
|
||||||
|
TagNumericString Tag = 0x12
|
||||||
|
TagPrintableString Tag = 0x13
|
||||||
|
TagT61String Tag = 0x14
|
||||||
|
TagVideotexString Tag = 0x15
|
||||||
|
TagIA5String Tag = 0x16
|
||||||
|
TagUTCTime Tag = 0x17
|
||||||
|
TagGeneralizedTime Tag = 0x18
|
||||||
|
TagGraphicString Tag = 0x19
|
||||||
|
TagVisibleString Tag = 0x1a
|
||||||
|
TagGeneralString Tag = 0x1b
|
||||||
|
TagUniversalString Tag = 0x1c
|
||||||
|
TagCharacterString Tag = 0x1d
|
||||||
|
TagBMPString Tag = 0x1e
|
||||||
|
TagBitmask Tag = 0x1f // xxx11111b
|
||||||
|
|
||||||
|
// HighTag indicates the start of a high-tag byte sequence
|
||||||
|
HighTag Tag = 0x1f // xxx11111b
|
||||||
|
// HighTagContinueBitmask indicates the high-tag byte sequence should continue
|
||||||
|
HighTagContinueBitmask Tag = 0x80 // 10000000b
|
||||||
|
// HighTagValueBitmask obtains the tag value from a high-tag byte sequence byte
|
||||||
|
HighTagValueBitmask Tag = 0x7f // 01111111b
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LengthLongFormBitmask is the mask to apply to the length byte to see if a long-form byte sequence is used
|
||||||
|
LengthLongFormBitmask = 0x80
|
||||||
|
// LengthValueBitmask is the mask to apply to the length byte to get the number of bytes in the long-form byte sequence
|
||||||
|
LengthValueBitmask = 0x7f
|
||||||
|
|
||||||
|
// LengthIndefinite is returned from readLength to indicate an indefinite length
|
||||||
|
LengthIndefinite = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
var tagMap = map[Tag]string{
|
||||||
|
TagEOC: "EOC (End-of-Content)",
|
||||||
|
TagBoolean: "Boolean",
|
||||||
|
TagInteger: "Integer",
|
||||||
|
TagBitString: "Bit String",
|
||||||
|
TagOctetString: "Octet String",
|
||||||
|
TagNULL: "NULL",
|
||||||
|
TagObjectIdentifier: "Object Identifier",
|
||||||
|
TagObjectDescriptor: "Object Descriptor",
|
||||||
|
TagExternal: "External",
|
||||||
|
TagRealFloat: "Real (float)",
|
||||||
|
TagEnumerated: "Enumerated",
|
||||||
|
TagEmbeddedPDV: "Embedded PDV",
|
||||||
|
TagUTF8String: "UTF8 String",
|
||||||
|
TagRelativeOID: "Relative-OID",
|
||||||
|
TagSequence: "Sequence and Sequence of",
|
||||||
|
TagSet: "Set and Set OF",
|
||||||
|
TagNumericString: "Numeric String",
|
||||||
|
TagPrintableString: "Printable String",
|
||||||
|
TagT61String: "T61 String",
|
||||||
|
TagVideotexString: "Videotex String",
|
||||||
|
TagIA5String: "IA5 String",
|
||||||
|
TagUTCTime: "UTC Time",
|
||||||
|
TagGeneralizedTime: "Generalized Time",
|
||||||
|
TagGraphicString: "Graphic String",
|
||||||
|
TagVisibleString: "Visible String",
|
||||||
|
TagGeneralString: "General String",
|
||||||
|
TagUniversalString: "Universal String",
|
||||||
|
TagCharacterString: "Character String",
|
||||||
|
TagBMPString: "BMP String",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Class uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClassUniversal Class = 0 // 00xxxxxxb
|
||||||
|
ClassApplication Class = 64 // 01xxxxxxb
|
||||||
|
ClassContext Class = 128 // 10xxxxxxb
|
||||||
|
ClassPrivate Class = 192 // 11xxxxxxb
|
||||||
|
ClassBitmask Class = 192 // 11xxxxxxb
|
||||||
|
)
|
||||||
|
|
||||||
|
var ClassMap = map[Class]string{
|
||||||
|
ClassUniversal: "Universal",
|
||||||
|
ClassApplication: "Application",
|
||||||
|
ClassContext: "Context",
|
||||||
|
ClassPrivate: "Private",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Type uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypePrimitive Type = 0 // xx0xxxxxb
|
||||||
|
TypeConstructed Type = 32 // xx1xxxxxb
|
||||||
|
TypeBitmask Type = 32 // xx1xxxxxb
|
||||||
|
)
|
||||||
|
|
||||||
|
var TypeMap = map[Type]string{
|
||||||
|
TypePrimitive: "Primitive",
|
||||||
|
TypeConstructed: "Constructed",
|
||||||
|
}
|
||||||
|
|
||||||
|
var Debug bool = false
|
||||||
|
|
||||||
|
func PrintBytes(out io.Writer, buf []byte, indent string) {
|
||||||
|
data_lines := make([]string, (len(buf)/30)+1)
|
||||||
|
num_lines := make([]string, (len(buf)/30)+1)
|
||||||
|
|
||||||
|
for i, b := range buf {
|
||||||
|
data_lines[i/30] += fmt.Sprintf("%02x ", b)
|
||||||
|
num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(data_lines); i++ {
|
||||||
|
out.Write([]byte(indent + data_lines[i] + "\n"))
|
||||||
|
out.Write([]byte(indent + num_lines[i] + "\n\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintPacket(p *Packet) {
|
||||||
|
printPacket(os.Stdout, p, 0, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
|
||||||
|
indent_str := ""
|
||||||
|
|
||||||
|
for len(indent_str) != indent {
|
||||||
|
indent_str += " "
|
||||||
|
}
|
||||||
|
|
||||||
|
class_str := ClassMap[p.ClassType]
|
||||||
|
|
||||||
|
tagtype_str := TypeMap[p.TagType]
|
||||||
|
|
||||||
|
tag_str := fmt.Sprintf("0x%02X", p.Tag)
|
||||||
|
|
||||||
|
if p.ClassType == ClassUniversal {
|
||||||
|
tag_str = tagMap[p.Tag]
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprint(p.Value)
|
||||||
|
description := ""
|
||||||
|
|
||||||
|
if p.Description != "" {
|
||||||
|
description = p.Description + ": "
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(out, "%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
|
||||||
|
|
||||||
|
if printBytes {
|
||||||
|
PrintBytes(out, p.Bytes(), indent_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range p.Children {
|
||||||
|
printPacket(out, child, indent+1, printBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPacket reads a single Packet from the reader
|
||||||
|
func ReadPacket(reader io.Reader) (*Packet, error) {
|
||||||
|
p, _, err := readPacket(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeString(data []byte) string {
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInt64(bytes []byte) (ret int64, err error) {
|
||||||
|
if len(bytes) > 8 {
|
||||||
|
// We'll overflow an int64 in this case.
|
||||||
|
err = fmt.Errorf("integer too large")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
|
||||||
|
ret <<= 8
|
||||||
|
ret |= int64(bytes[bytesRead])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift up and down in order to sign extend the result.
|
||||||
|
ret <<= 64 - uint8(len(bytes))*8
|
||||||
|
ret >>= 64 - uint8(len(bytes))*8
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeInteger(i int64) []byte {
|
||||||
|
n := int64Length(i)
|
||||||
|
out := make([]byte, n)
|
||||||
|
|
||||||
|
var j int
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
out[j] = (byte(i >> uint((n-1)*8)))
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func int64Length(i int64) (numBytes int) {
|
||||||
|
numBytes = 1
|
||||||
|
|
||||||
|
for i > 127 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
for i < -128 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodePacket decodes the given bytes into a single Packet
|
||||||
|
// If a decode error is encountered, nil is returned.
|
||||||
|
func DecodePacket(data []byte) *Packet {
|
||||||
|
p, _, _ := readPacket(bytes.NewBuffer(data))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodePacketErr decodes the given bytes into a single Packet
|
||||||
|
// If a decode error is encountered, nil is returned
|
||||||
|
func DecodePacketErr(data []byte) (*Packet, error) {
|
||||||
|
p, _, err := readPacket(bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readPacket reads a single Packet from the reader, returning the number of bytes read
|
||||||
|
func readPacket(reader io.Reader) (*Packet, int, error) {
|
||||||
|
identifier, length, read, err := readHeader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, read, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &Packet{
|
||||||
|
Identifier: identifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Data = new(bytes.Buffer)
|
||||||
|
p.Children = make([]*Packet, 0, 2)
|
||||||
|
p.Value = nil
|
||||||
|
|
||||||
|
if p.TagType == TypeConstructed {
|
||||||
|
// TODO: if universal, ensure tag type is allowed to be constructed
|
||||||
|
|
||||||
|
// Track how much content we've read
|
||||||
|
contentRead := 0
|
||||||
|
for {
|
||||||
|
if length != LengthIndefinite {
|
||||||
|
// End if we've read what we've been told to
|
||||||
|
if contentRead == length {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Detect if a packet boundary didn't fall on the expected length
|
||||||
|
if contentRead > length {
|
||||||
|
return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the next packet
|
||||||
|
child, r, err := readPacket(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, read, err
|
||||||
|
}
|
||||||
|
contentRead += r
|
||||||
|
read += r
|
||||||
|
|
||||||
|
// Test is this is the EOC marker for our packet
|
||||||
|
if isEOCPacket(child) {
|
||||||
|
if length == LengthIndefinite {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, read, errors.New("eoc child not allowed with definite length")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append and continue
|
||||||
|
p.AppendChild(child)
|
||||||
|
}
|
||||||
|
return p, read, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if length == LengthIndefinite {
|
||||||
|
return nil, read, errors.New("indefinite length used with primitive type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read definite-length content
|
||||||
|
content := make([]byte, length, length)
|
||||||
|
if length > 0 {
|
||||||
|
_, err := io.ReadFull(reader, content)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil, read, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil, read, err
|
||||||
|
}
|
||||||
|
read += length
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.ClassType == ClassUniversal {
|
||||||
|
p.Data.Write(content)
|
||||||
|
p.ByteValue = content
|
||||||
|
|
||||||
|
switch p.Tag {
|
||||||
|
case TagEOC:
|
||||||
|
case TagBoolean:
|
||||||
|
val, _ := parseInt64(content)
|
||||||
|
|
||||||
|
p.Value = val != 0
|
||||||
|
case TagInteger:
|
||||||
|
p.Value, _ = parseInt64(content)
|
||||||
|
case TagBitString:
|
||||||
|
case TagOctetString:
|
||||||
|
// the actual string encoding is not known here
|
||||||
|
// (e.g. for LDAP content is already an UTF8-encoded
|
||||||
|
// string). Return the data without further processing
|
||||||
|
p.Value = DecodeString(content)
|
||||||
|
case TagNULL:
|
||||||
|
case TagObjectIdentifier:
|
||||||
|
case TagObjectDescriptor:
|
||||||
|
case TagExternal:
|
||||||
|
case TagRealFloat:
|
||||||
|
case TagEnumerated:
|
||||||
|
p.Value, _ = parseInt64(content)
|
||||||
|
case TagEmbeddedPDV:
|
||||||
|
case TagUTF8String:
|
||||||
|
p.Value = DecodeString(content)
|
||||||
|
case TagRelativeOID:
|
||||||
|
case TagSequence:
|
||||||
|
case TagSet:
|
||||||
|
case TagNumericString:
|
||||||
|
case TagPrintableString:
|
||||||
|
p.Value = DecodeString(content)
|
||||||
|
case TagT61String:
|
||||||
|
case TagVideotexString:
|
||||||
|
case TagIA5String:
|
||||||
|
case TagUTCTime:
|
||||||
|
case TagGeneralizedTime:
|
||||||
|
case TagGraphicString:
|
||||||
|
case TagVisibleString:
|
||||||
|
case TagGeneralString:
|
||||||
|
case TagUniversalString:
|
||||||
|
case TagCharacterString:
|
||||||
|
case TagBMPString:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.Data.Write(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, read, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) Bytes() []byte {
|
||||||
|
var out bytes.Buffer
|
||||||
|
|
||||||
|
out.Write(encodeIdentifier(p.Identifier))
|
||||||
|
out.Write(encodeLength(p.Data.Len()))
|
||||||
|
out.Write(p.Data.Bytes())
|
||||||
|
|
||||||
|
return out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) AppendChild(child *Packet) {
|
||||||
|
p.Data.Write(child.Bytes())
|
||||||
|
p.Children = append(p.Children, child)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encode(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet {
|
||||||
|
p := new(Packet)
|
||||||
|
|
||||||
|
p.ClassType = ClassType
|
||||||
|
p.TagType = TagType
|
||||||
|
p.Tag = Tag
|
||||||
|
p.Data = new(bytes.Buffer)
|
||||||
|
|
||||||
|
p.Children = make([]*Packet, 0, 2)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Description = Description
|
||||||
|
|
||||||
|
if Value != nil {
|
||||||
|
v := reflect.ValueOf(Value)
|
||||||
|
|
||||||
|
if ClassType == ClassUniversal {
|
||||||
|
switch Tag {
|
||||||
|
case TagOctetString:
|
||||||
|
sv, ok := v.Interface().(string)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
p.Data.Write([]byte(sv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSequence(Description string) *Packet {
|
||||||
|
return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBoolean(ClassType Class, TagType Type, Tag Tag, Value bool, Description string) *Packet {
|
||||||
|
intValue := int64(0)
|
||||||
|
|
||||||
|
if Value {
|
||||||
|
intValue = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Data.Write(encodeInteger(intValue))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInteger(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet {
|
||||||
|
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
switch v := Value.(type) {
|
||||||
|
case int:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case uint:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case int64:
|
||||||
|
p.Data.Write(encodeInteger(v))
|
||||||
|
case uint64:
|
||||||
|
// TODO : check range or add encodeUInt...
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case int32:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case uint32:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case int16:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case uint16:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case int8:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
case uint8:
|
||||||
|
p.Data.Write(encodeInteger(int64(v)))
|
||||||
|
default:
|
||||||
|
// TODO : add support for big.Int ?
|
||||||
|
panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewString(ClassType Class, TagType Type, Tag Tag, Value, Description string) *Packet {
|
||||||
|
p := Encode(ClassType, TagType, Tag, nil, Description)
|
||||||
|
|
||||||
|
p.Value = Value
|
||||||
|
p.Data.Write([]byte(Value))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
168
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/ber_test.go
сгенерированный
поставляемый
Обычный файл
168
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/ber_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,168 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEncodeDecodeInteger(t *testing.T) {
|
||||||
|
for _, v := range []int64{0, 10, 128, 1024, math.MaxInt64, -1, -100, -128, -1024, math.MinInt64} {
|
||||||
|
enc := encodeInteger(v)
|
||||||
|
dec, err := parseInt64(enc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error decoding %d : %s", v, err)
|
||||||
|
}
|
||||||
|
if v != dec {
|
||||||
|
t.Error("TestEncodeDecodeInteger failed for %d (got %d)", v, dec)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolean(t *testing.T) {
|
||||||
|
var value bool = true
|
||||||
|
|
||||||
|
packet := NewBoolean(ClassUniversal, TypePrimitive, TagBoolean, value, "first Packet, True")
|
||||||
|
|
||||||
|
newBoolean, ok := packet.Value.(bool)
|
||||||
|
if !ok || newBoolean != value {
|
||||||
|
t.Error("error during creating packet")
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedPacket := packet.Bytes()
|
||||||
|
|
||||||
|
newPacket := DecodePacket(encodedPacket)
|
||||||
|
|
||||||
|
newBoolean, ok = newPacket.Value.(bool)
|
||||||
|
if !ok || newBoolean != value {
|
||||||
|
t.Error("error during decoding packet")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInteger(t *testing.T) {
|
||||||
|
var value int64 = 10
|
||||||
|
|
||||||
|
packet := NewInteger(ClassUniversal, TypePrimitive, TagInteger, value, "Integer, 10")
|
||||||
|
|
||||||
|
{
|
||||||
|
newInteger, ok := packet.Value.(int64)
|
||||||
|
if !ok || newInteger != value {
|
||||||
|
t.Error("error creating packet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedPacket := packet.Bytes()
|
||||||
|
|
||||||
|
newPacket := DecodePacket(encodedPacket)
|
||||||
|
|
||||||
|
{
|
||||||
|
newInteger, ok := newPacket.Value.(int64)
|
||||||
|
if !ok || int64(newInteger) != value {
|
||||||
|
t.Error("error decoding packet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestString(t *testing.T) {
|
||||||
|
var value string = "Hic sunt dracones"
|
||||||
|
|
||||||
|
packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, value, "String")
|
||||||
|
|
||||||
|
newValue, ok := packet.Value.(string)
|
||||||
|
if !ok || newValue != value {
|
||||||
|
t.Error("error during creating packet")
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedPacket := packet.Bytes()
|
||||||
|
|
||||||
|
newPacket := DecodePacket(encodedPacket)
|
||||||
|
|
||||||
|
newValue, ok = newPacket.Value.(string)
|
||||||
|
if !ok || newValue != value {
|
||||||
|
t.Error("error during decoding packet")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSequenceAndAppendChild(t *testing.T) {
|
||||||
|
|
||||||
|
values := []string{
|
||||||
|
"HIC SVNT LEONES",
|
||||||
|
"Iñtërnâtiônàlizætiøn",
|
||||||
|
"Terra Incognita",
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence := NewSequence("a sequence")
|
||||||
|
for _, s := range values {
|
||||||
|
sequence.AppendChild(NewString(ClassUniversal, TypePrimitive, TagOctetString, s, "String"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sequence.Children) != len(values) {
|
||||||
|
t.Errorf("wrong length for children array should be %d, got %d", len(values), len(sequence.Children))
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedSequence := sequence.Bytes()
|
||||||
|
|
||||||
|
decodedSequence := DecodePacket(encodedSequence)
|
||||||
|
if len(decodedSequence.Children) != len(values) {
|
||||||
|
t.Errorf("wrong length for children array should be %d => %d", len(values), len(decodedSequence.Children))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range values {
|
||||||
|
if decodedSequence.Children[i].Value.(string) != s {
|
||||||
|
t.Errorf("expected %d to be %q, got %q", i, s, decodedSequence.Children[i].Value.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadPacket(t *testing.T) {
|
||||||
|
packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, "Ad impossibilia nemo tenetur", "string")
|
||||||
|
var buffer io.ReadWriter
|
||||||
|
buffer = new(bytes.Buffer)
|
||||||
|
|
||||||
|
buffer.Write(packet.Bytes())
|
||||||
|
|
||||||
|
newPacket, err := ReadPacket(buffer)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("error during ReadPacket", err)
|
||||||
|
}
|
||||||
|
newPacket.ByteValue = nil
|
||||||
|
if !bytes.Equal(newPacket.ByteValue, packet.ByteValue) {
|
||||||
|
t.Error("packets should be the same")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryInteger(t *testing.T) {
|
||||||
|
// data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.7
|
||||||
|
var data = []struct {
|
||||||
|
v int64
|
||||||
|
e []byte
|
||||||
|
}{
|
||||||
|
{v: 0, e: []byte{0x02, 0x01, 0x00}},
|
||||||
|
{v: 127, e: []byte{0x02, 0x01, 0x7F}},
|
||||||
|
{v: 128, e: []byte{0x02, 0x02, 0x00, 0x80}},
|
||||||
|
{v: 256, e: []byte{0x02, 0x02, 0x01, 0x00}},
|
||||||
|
{v: -128, e: []byte{0x02, 0x01, 0x80}},
|
||||||
|
{v: -129, e: []byte{0x02, 0x02, 0xFF, 0x7F}},
|
||||||
|
{v: math.MaxInt64, e: []byte{0x02, 0x08, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
|
||||||
|
{v: math.MinInt64, e: []byte{0x02, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range data {
|
||||||
|
if b := NewInteger(ClassUniversal, TypePrimitive, TagInteger, int64(d.v), "").Bytes(); !bytes.Equal(d.e, b) {
|
||||||
|
t.Errorf("Wrong binary generated for %d : got % X, expected % X", d.v, b, d.e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryOctetString(t *testing.T) {
|
||||||
|
// data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.10
|
||||||
|
|
||||||
|
if !bytes.Equal([]byte{0x04, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, NewString(ClassUniversal, TypePrimitive, TagOctetString, "\x01\x23\x45\x67\x89\xab\xcd\xef", "").Bytes()) {
|
||||||
|
t.Error("wrong binary generated")
|
||||||
|
}
|
||||||
|
}
|
||||||
25
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/content_int.go
сгенерированный
поставляемый
Обычный файл
25
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/content_int.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,25 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
func encodeUnsignedInteger(i uint64) []byte {
|
||||||
|
n := uint64Length(i)
|
||||||
|
out := make([]byte, n)
|
||||||
|
|
||||||
|
var j int
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
out[j] = (byte(i >> uint((n-1)*8)))
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint64Length(i uint64) (numBytes int) {
|
||||||
|
numBytes = 1
|
||||||
|
|
||||||
|
for i > 255 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
29
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/header.go
сгенерированный
поставляемый
Обычный файл
29
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/header.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,29 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readHeader(reader io.Reader) (identifier Identifier, length int, read int, err error) {
|
||||||
|
if i, c, err := readIdentifier(reader); err != nil {
|
||||||
|
return Identifier{}, 0, read, err
|
||||||
|
} else {
|
||||||
|
identifier = i
|
||||||
|
read += c
|
||||||
|
}
|
||||||
|
|
||||||
|
if l, c, err := readLength(reader); err != nil {
|
||||||
|
return Identifier{}, 0, read, err
|
||||||
|
} else {
|
||||||
|
length = l
|
||||||
|
read += c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate length type with identifier (x.600, 8.1.3.2.a)
|
||||||
|
if length == LengthIndefinite && identifier.TagType == TypePrimitive {
|
||||||
|
return Identifier{}, 0, read, errors.New("indefinite length used with primitive type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifier, length, read, nil
|
||||||
|
}
|
||||||
135
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/header_test.go
сгенерированный
поставляемый
Обычный файл
135
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/header_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,135 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadHeader(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
Data []byte
|
||||||
|
ExpectedIdentifier Identifier
|
||||||
|
ExpectedLength int
|
||||||
|
ExpectedBytesRead int
|
||||||
|
ExpectedError string
|
||||||
|
}{
|
||||||
|
"empty": {
|
||||||
|
Data: []byte{},
|
||||||
|
ExpectedIdentifier: Identifier{},
|
||||||
|
ExpectedLength: 0,
|
||||||
|
ExpectedBytesRead: 0,
|
||||||
|
ExpectedError: io.ErrUnexpectedEOF.Error(),
|
||||||
|
},
|
||||||
|
|
||||||
|
"valid short form": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString),
|
||||||
|
127,
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypePrimitive,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedLength: 127,
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
ExpectedError: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"valid long form": {
|
||||||
|
Data: []byte{
|
||||||
|
// 2-byte encoding of tag
|
||||||
|
byte(ClassUniversal) | byte(TypePrimitive) | byte(HighTag),
|
||||||
|
byte(TagCharacterString),
|
||||||
|
|
||||||
|
// 2-byte encoding of length
|
||||||
|
LengthLongFormBitmask | 1,
|
||||||
|
127,
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypePrimitive,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedLength: 127,
|
||||||
|
ExpectedBytesRead: 4,
|
||||||
|
ExpectedError: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"valid indefinite length": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString),
|
||||||
|
LengthLongFormBitmask,
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedLength: LengthIndefinite,
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
ExpectedError: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"invalid indefinite length": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString),
|
||||||
|
LengthLongFormBitmask,
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{},
|
||||||
|
ExpectedLength: 0,
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
ExpectedError: "indefinite length used with primitive type",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
reader := bytes.NewBuffer(tc.Data)
|
||||||
|
identifier, length, read, err := readHeader(reader)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if tc.ExpectedError == "" {
|
||||||
|
t.Errorf("%s: unexpected error: %v", k, err)
|
||||||
|
} else if err.Error() != tc.ExpectedError {
|
||||||
|
t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
|
||||||
|
}
|
||||||
|
} else if tc.ExpectedError != "" {
|
||||||
|
t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if read != tc.ExpectedBytesRead {
|
||||||
|
t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
if identifier.ClassType != tc.ExpectedIdentifier.ClassType {
|
||||||
|
t.Errorf("%s: expected class type %d (%s), got %d (%s)", k,
|
||||||
|
tc.ExpectedIdentifier.ClassType,
|
||||||
|
ClassMap[tc.ExpectedIdentifier.ClassType],
|
||||||
|
identifier.ClassType,
|
||||||
|
ClassMap[identifier.ClassType],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if identifier.TagType != tc.ExpectedIdentifier.TagType {
|
||||||
|
t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k,
|
||||||
|
tc.ExpectedIdentifier.TagType,
|
||||||
|
TypeMap[tc.ExpectedIdentifier.TagType],
|
||||||
|
identifier.TagType,
|
||||||
|
TypeMap[identifier.TagType],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if identifier.Tag != tc.ExpectedIdentifier.Tag {
|
||||||
|
t.Errorf("%s: expected tag %d (%s), got %d (%s)", k,
|
||||||
|
tc.ExpectedIdentifier.Tag,
|
||||||
|
tagMap[tc.ExpectedIdentifier.Tag],
|
||||||
|
identifier.Tag,
|
||||||
|
tagMap[identifier.Tag],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if length != tc.ExpectedLength {
|
||||||
|
t.Errorf("%s: expected length %d, got %d", k, tc.ExpectedLength, length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
103
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/identifier.go
сгенерированный
поставляемый
Обычный файл
103
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/identifier.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,103 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readIdentifier(reader io.Reader) (Identifier, int, error) {
|
||||||
|
identifier := Identifier{}
|
||||||
|
read := 0
|
||||||
|
|
||||||
|
// identifier byte
|
||||||
|
b, err := readByte(reader)
|
||||||
|
if err != nil {
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("error reading identifier byte: %v\n", err)
|
||||||
|
}
|
||||||
|
return Identifier{}, read, err
|
||||||
|
}
|
||||||
|
read++
|
||||||
|
|
||||||
|
identifier.ClassType = Class(b) & ClassBitmask
|
||||||
|
identifier.TagType = Type(b) & TypeBitmask
|
||||||
|
|
||||||
|
if tag := Tag(b) & TagBitmask; tag != HighTag {
|
||||||
|
// short-form tag
|
||||||
|
identifier.Tag = tag
|
||||||
|
return identifier, read, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// high-tag-number tag
|
||||||
|
tagBytes := 0
|
||||||
|
for {
|
||||||
|
b, err := readByte(reader)
|
||||||
|
if err != nil {
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err)
|
||||||
|
}
|
||||||
|
return Identifier{}, read, err
|
||||||
|
}
|
||||||
|
tagBytes++
|
||||||
|
read++
|
||||||
|
|
||||||
|
// Lowest 7 bits get appended to the tag value (x.690, 8.1.2.4.2.b)
|
||||||
|
identifier.Tag <<= 7
|
||||||
|
identifier.Tag |= Tag(b) & HighTagValueBitmask
|
||||||
|
|
||||||
|
// First byte may not be all zeros (x.690, 8.1.2.4.2.c)
|
||||||
|
if tagBytes == 1 && identifier.Tag == 0 {
|
||||||
|
return Identifier{}, read, errors.New("invalid first high-tag-number tag byte")
|
||||||
|
}
|
||||||
|
// Overflow of int64
|
||||||
|
// TODO: support big int tags?
|
||||||
|
if tagBytes > 9 {
|
||||||
|
return Identifier{}, read, errors.New("high-tag-number tag overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top bit of 0 means this is the last byte in the high-tag-number tag (x.690, 8.1.2.4.2.a)
|
||||||
|
if Tag(b)&HighTagContinueBitmask == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifier, read, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeIdentifier(identifier Identifier) []byte {
|
||||||
|
b := []byte{0x0}
|
||||||
|
b[0] |= byte(identifier.ClassType)
|
||||||
|
b[0] |= byte(identifier.TagType)
|
||||||
|
|
||||||
|
if identifier.Tag < HighTag {
|
||||||
|
// Short-form
|
||||||
|
b[0] |= byte(identifier.Tag)
|
||||||
|
} else {
|
||||||
|
// high-tag-number
|
||||||
|
b[0] |= byte(HighTag)
|
||||||
|
|
||||||
|
tag := identifier.Tag
|
||||||
|
|
||||||
|
highBit := uint(63)
|
||||||
|
for {
|
||||||
|
if tag&(1<<highBit) != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
highBit--
|
||||||
|
}
|
||||||
|
|
||||||
|
tagBytes := int(math.Ceil(float64(highBit) / 7.0))
|
||||||
|
for i := tagBytes - 1; i >= 0; i-- {
|
||||||
|
offset := uint(i) * 7
|
||||||
|
mask := Tag(0x7f) << offset
|
||||||
|
tagByte := (tag & mask) >> offset
|
||||||
|
if i != 0 {
|
||||||
|
tagByte |= 0x80
|
||||||
|
}
|
||||||
|
b = append(b, byte(tagByte))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
344
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/identifier_test.go
сгенерированный
поставляемый
Обычный файл
344
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/identifier_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,344 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadIdentifier(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
Data []byte
|
||||||
|
|
||||||
|
ExpectedIdentifier Identifier
|
||||||
|
ExpectedBytesRead int
|
||||||
|
ExpectedError string
|
||||||
|
}{
|
||||||
|
"empty": {
|
||||||
|
Data: []byte{},
|
||||||
|
ExpectedBytesRead: 0,
|
||||||
|
ExpectedError: io.ErrUnexpectedEOF.Error(),
|
||||||
|
},
|
||||||
|
|
||||||
|
"universal primitive eoc": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypePrimitive,
|
||||||
|
Tag: TagEOC,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"universal primitive character string": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypePrimitive,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
"universal constructed bit string": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagBitString,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"universal constructed character string": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
"application constructed object descriptor": {
|
||||||
|
Data: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassApplication,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"context constructed object descriptor": {
|
||||||
|
Data: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassContext,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"private constructed object descriptor": {
|
||||||
|
Data: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassPrivate,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
"high-tag-number tag missing bytes": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag)},
|
||||||
|
ExpectedError: io.ErrUnexpectedEOF.Error(),
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"high-tag-number tag invalid first byte": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), 0x0},
|
||||||
|
ExpectedError: "invalid first high-tag-number tag byte",
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
},
|
||||||
|
"high-tag-number tag invalid first byte with continue bit": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask)},
|
||||||
|
ExpectedError: "invalid first high-tag-number tag byte",
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
},
|
||||||
|
"high-tag-number tag continuation missing bytes": {
|
||||||
|
Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x1)},
|
||||||
|
ExpectedError: io.ErrUnexpectedEOF.Error(),
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
},
|
||||||
|
"high-tag-number tag overflow": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(HighTagContinueBitmask | 0x1),
|
||||||
|
byte(0x1),
|
||||||
|
},
|
||||||
|
ExpectedError: "high-tag-number tag overflow",
|
||||||
|
ExpectedBytesRead: 11,
|
||||||
|
},
|
||||||
|
"max high-tag-number tag": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(0x7f),
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: Tag(0x7FFFFFFFFFFFFFFF), // 01111111...(63)...11111b
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 10,
|
||||||
|
},
|
||||||
|
"high-tag-number encoding of low-tag value": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
|
||||||
|
byte(TagObjectDescriptor),
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
},
|
||||||
|
"max high-tag-number tag ignores extra data": {
|
||||||
|
Data: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(0x7f),
|
||||||
|
byte(0x01), // extra data, shouldn't be read
|
||||||
|
byte(0x02), // extra data, shouldn't be read
|
||||||
|
byte(0x03), // extra data, shouldn't be read
|
||||||
|
},
|
||||||
|
ExpectedIdentifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: Tag(0x7FFFFFFFFFFFFFFF), // 01111111...(63)...11111b
|
||||||
|
},
|
||||||
|
ExpectedBytesRead: 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
reader := bytes.NewBuffer(tc.Data)
|
||||||
|
identifier, read, err := readIdentifier(reader)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if tc.ExpectedError == "" {
|
||||||
|
t.Errorf("%s: unexpected error: %v", k, err)
|
||||||
|
} else if err.Error() != tc.ExpectedError {
|
||||||
|
t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
|
||||||
|
}
|
||||||
|
} else if tc.ExpectedError != "" {
|
||||||
|
t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if read != tc.ExpectedBytesRead {
|
||||||
|
t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
if identifier.ClassType != tc.ExpectedIdentifier.ClassType {
|
||||||
|
t.Errorf("%s: expected class type %d (%s), got %d (%s)", k,
|
||||||
|
tc.ExpectedIdentifier.ClassType,
|
||||||
|
ClassMap[tc.ExpectedIdentifier.ClassType],
|
||||||
|
identifier.ClassType,
|
||||||
|
ClassMap[identifier.ClassType],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if identifier.TagType != tc.ExpectedIdentifier.TagType {
|
||||||
|
t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k,
|
||||||
|
tc.ExpectedIdentifier.TagType,
|
||||||
|
TypeMap[tc.ExpectedIdentifier.TagType],
|
||||||
|
identifier.TagType,
|
||||||
|
TypeMap[identifier.TagType],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if identifier.Tag != tc.ExpectedIdentifier.Tag {
|
||||||
|
t.Errorf("%s: expected tag %d (%s), got %d (%s)", k,
|
||||||
|
tc.ExpectedIdentifier.Tag,
|
||||||
|
tagMap[tc.ExpectedIdentifier.Tag],
|
||||||
|
identifier.Tag,
|
||||||
|
tagMap[identifier.Tag],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeIdentifier(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
Identifier Identifier
|
||||||
|
ExpectedBytes []byte
|
||||||
|
}{
|
||||||
|
"universal primitive eoc": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypePrimitive,
|
||||||
|
Tag: TagEOC,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)},
|
||||||
|
},
|
||||||
|
"universal primitive character string": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypePrimitive,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)},
|
||||||
|
},
|
||||||
|
|
||||||
|
"universal constructed bit string": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagBitString,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)},
|
||||||
|
},
|
||||||
|
"universal constructed character string": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagCharacterString,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)},
|
||||||
|
},
|
||||||
|
|
||||||
|
"application constructed object descriptor": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassApplication,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
|
||||||
|
},
|
||||||
|
"context constructed object descriptor": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassContext,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
|
||||||
|
},
|
||||||
|
"private constructed object descriptor": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassPrivate,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagObjectDescriptor,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
|
||||||
|
},
|
||||||
|
|
||||||
|
"max low-tag-number tag": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagBMPString,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBMPString),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"min high-tag-number tag": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: TagBMPString + 1,
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
|
||||||
|
byte(TagBMPString + 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"max high-tag-number tag": {
|
||||||
|
Identifier: Identifier{
|
||||||
|
ClassType: ClassUniversal,
|
||||||
|
TagType: TypeConstructed,
|
||||||
|
Tag: Tag(math.MaxInt64),
|
||||||
|
},
|
||||||
|
ExpectedBytes: []byte{
|
||||||
|
byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(HighTagContinueBitmask | 0x7f),
|
||||||
|
byte(0x7f),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
b := encodeIdentifier(tc.Identifier)
|
||||||
|
if bytes.Compare(tc.ExpectedBytes, b) != 0 {
|
||||||
|
t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/length.go
сгенерированный
поставляемый
Обычный файл
71
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/length.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,71 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readLength(reader io.Reader) (length int, read int, err error) {
|
||||||
|
// length byte
|
||||||
|
b, err := readByte(reader)
|
||||||
|
if err != nil {
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("error reading length byte: %v\n", err)
|
||||||
|
}
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
read++
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == 0xFF:
|
||||||
|
// Invalid 0xFF (x.600, 8.1.3.5.c)
|
||||||
|
return 0, read, errors.New("invalid length byte 0xff")
|
||||||
|
|
||||||
|
case b == LengthLongFormBitmask:
|
||||||
|
// Indefinite form, we have to decode packets until we encounter an EOC packet (x.600, 8.1.3.6)
|
||||||
|
length = LengthIndefinite
|
||||||
|
|
||||||
|
case b&LengthLongFormBitmask == 0:
|
||||||
|
// Short definite form, extract the length from the bottom 7 bits (x.600, 8.1.3.4)
|
||||||
|
length = int(b) & LengthValueBitmask
|
||||||
|
|
||||||
|
case b&LengthLongFormBitmask != 0:
|
||||||
|
// Long definite form, extract the number of length bytes to follow from the bottom 7 bits (x.600, 8.1.3.5.b)
|
||||||
|
lengthBytes := int(b) & LengthValueBitmask
|
||||||
|
// Protect against overflow
|
||||||
|
// TODO: support big int length?
|
||||||
|
if lengthBytes > 8 {
|
||||||
|
return 0, read, errors.New("long-form length overflow")
|
||||||
|
}
|
||||||
|
for i := 0; i < lengthBytes; i++ {
|
||||||
|
b, err = readByte(reader)
|
||||||
|
if err != nil {
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("error reading long-form length byte %d: %v\n", i, err)
|
||||||
|
}
|
||||||
|
return 0, read, err
|
||||||
|
}
|
||||||
|
read++
|
||||||
|
|
||||||
|
// x.600, 8.1.3.5
|
||||||
|
length <<= 8
|
||||||
|
length |= int(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0, read, errors.New("invalid length byte")
|
||||||
|
}
|
||||||
|
|
||||||
|
return length, read, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeLength(length int) []byte {
|
||||||
|
length_bytes := encodeUnsignedInteger(uint64(length))
|
||||||
|
if length > 127 || len(length_bytes) > 1 {
|
||||||
|
longFormBytes := []byte{(LengthLongFormBitmask | byte(len(length_bytes)))}
|
||||||
|
longFormBytes = append(longFormBytes, length_bytes...)
|
||||||
|
length_bytes = longFormBytes
|
||||||
|
}
|
||||||
|
return length_bytes
|
||||||
|
}
|
||||||
158
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/length_test.go
сгенерированный
поставляемый
Обычный файл
158
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/length_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,158 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadLength(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
Data []byte
|
||||||
|
|
||||||
|
ExpectedLength int
|
||||||
|
ExpectedBytesRead int
|
||||||
|
ExpectedError string
|
||||||
|
}{
|
||||||
|
"empty": {
|
||||||
|
Data: []byte{},
|
||||||
|
ExpectedBytesRead: 0,
|
||||||
|
ExpectedError: io.ErrUnexpectedEOF.Error(),
|
||||||
|
},
|
||||||
|
"invalid first byte": {
|
||||||
|
Data: []byte{0xFF},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
ExpectedError: "invalid length byte 0xff",
|
||||||
|
},
|
||||||
|
|
||||||
|
"indefinite form": {
|
||||||
|
Data: []byte{LengthLongFormBitmask},
|
||||||
|
ExpectedLength: LengthIndefinite,
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
"short-definite-form zero length": {
|
||||||
|
Data: []byte{0},
|
||||||
|
ExpectedLength: 0,
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"short-definite-form length 1": {
|
||||||
|
Data: []byte{1},
|
||||||
|
ExpectedLength: 1,
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
"short-definite-form max length": {
|
||||||
|
Data: []byte{127},
|
||||||
|
ExpectedLength: 127,
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
"long-definite-form missing bytes": {
|
||||||
|
Data: []byte{LengthLongFormBitmask | 1},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
ExpectedError: io.ErrUnexpectedEOF.Error(),
|
||||||
|
},
|
||||||
|
"long-definite-form overflow": {
|
||||||
|
Data: []byte{LengthLongFormBitmask | 9},
|
||||||
|
ExpectedBytesRead: 1,
|
||||||
|
ExpectedError: "long-form length overflow",
|
||||||
|
},
|
||||||
|
"long-definite-form zero length": {
|
||||||
|
Data: []byte{LengthLongFormBitmask | 1, 0x0},
|
||||||
|
ExpectedLength: 0,
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
},
|
||||||
|
"long-definite-form length 127": {
|
||||||
|
Data: []byte{LengthLongFormBitmask | 1, 127},
|
||||||
|
ExpectedLength: 127,
|
||||||
|
ExpectedBytesRead: 2,
|
||||||
|
},
|
||||||
|
"long-definite-form max length": {
|
||||||
|
Data: []byte{
|
||||||
|
LengthLongFormBitmask | 8,
|
||||||
|
0x7F,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
},
|
||||||
|
ExpectedLength: math.MaxInt64,
|
||||||
|
ExpectedBytesRead: 9,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
reader := bytes.NewBuffer(tc.Data)
|
||||||
|
length, read, err := readLength(reader)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if tc.ExpectedError == "" {
|
||||||
|
t.Errorf("%s: unexpected error: %v", k, err)
|
||||||
|
} else if err.Error() != tc.ExpectedError {
|
||||||
|
t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
|
||||||
|
}
|
||||||
|
} else if tc.ExpectedError != "" {
|
||||||
|
t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if read != tc.ExpectedBytesRead {
|
||||||
|
t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
if length != tc.ExpectedLength {
|
||||||
|
t.Errorf("%s: expected length %d, got %d", k, tc.ExpectedLength, length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeLength(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
Length int
|
||||||
|
ExpectedBytes []byte
|
||||||
|
}{
|
||||||
|
"0": {
|
||||||
|
Length: 0,
|
||||||
|
ExpectedBytes: []byte{0},
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
Length: 1,
|
||||||
|
ExpectedBytes: []byte{1},
|
||||||
|
},
|
||||||
|
|
||||||
|
"max short-form length": {
|
||||||
|
Length: 127,
|
||||||
|
ExpectedBytes: []byte{127},
|
||||||
|
},
|
||||||
|
"min long-form length": {
|
||||||
|
Length: 128,
|
||||||
|
ExpectedBytes: []byte{LengthLongFormBitmask | 1, 128},
|
||||||
|
},
|
||||||
|
|
||||||
|
"max long-form length": {
|
||||||
|
Length: math.MaxInt64,
|
||||||
|
ExpectedBytes: []byte{
|
||||||
|
LengthLongFormBitmask | 8,
|
||||||
|
0x7F,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
b := encodeLength(tc.Length)
|
||||||
|
if bytes.Compare(tc.ExpectedBytes, b) != 0 {
|
||||||
|
t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
182
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/suite_test.go
сгенерированный
поставляемый
Обычный файл
182
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/suite_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,182 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errEOF = io.ErrUnexpectedEOF.Error()
|
||||||
|
|
||||||
|
// Tests from http://www.strozhevsky.com/free_docs/free_asn1_testsuite_descr.pdf
|
||||||
|
// Source files and descriptions at http://www.strozhevsky.com/free_docs/TEST_SUITE.zip
|
||||||
|
var testcases = []struct {
|
||||||
|
// File contains the path to the BER-encoded file
|
||||||
|
File string
|
||||||
|
// Error indicates whether a decoding error is expected
|
||||||
|
Error string
|
||||||
|
// AbnormalEncoding indicates whether a normalized re-encoding is expected to differ from the original source
|
||||||
|
AbnormalEncoding bool
|
||||||
|
// IndefiniteEncoding indicates the source file used indefinite-length encoding, so the re-encoding is expected to differ (since the length is known)
|
||||||
|
IndefiniteEncoding bool
|
||||||
|
}{
|
||||||
|
// Common blocks
|
||||||
|
{File: "tests/tc1.ber", Error: "high-tag-number tag overflow"},
|
||||||
|
{File: "tests/tc2.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc3.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc4.ber", Error: "invalid length byte 0xff"},
|
||||||
|
{File: "tests/tc5.ber", Error: "", AbnormalEncoding: true},
|
||||||
|
// Real numbers (some expected failures are disabled until support is added)
|
||||||
|
{File: "tests/tc6.ber", Error: ""}, // Error: "REAL value +0 must be encoded with zero-length value block"},
|
||||||
|
{File: "tests/tc7.ber", Error: ""}, // Error: "REAL value -0 must be encoded as a special value"},
|
||||||
|
{File: "tests/tc8.ber", Error: ""},
|
||||||
|
{File: "tests/tc9.ber", Error: ""}, // Error: "Bits 6 and 5 of information octet for REAL are equal to 11"
|
||||||
|
{File: "tests/tc10.ber", Error: ""},
|
||||||
|
{File: "tests/tc11.ber", Error: ""}, // Error: "Incorrect NR form"
|
||||||
|
{File: "tests/tc12.ber", Error: ""}, // Error: "Encoding of "special value" not from ASN.1 standard"
|
||||||
|
{File: "tests/tc13.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc14.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc15.ber", Error: ""}, // Error: "Too big value of exponent"
|
||||||
|
{File: "tests/tc16.ber", Error: ""}, // Error: "Too big value of mantissa"
|
||||||
|
{File: "tests/tc17.ber", Error: ""}, // Error: "Too big values for exponent and mantissa + using of "scaling factor" value"
|
||||||
|
// Integers
|
||||||
|
{File: "tests/tc18.ber", Error: ""},
|
||||||
|
{File: "tests/tc19.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc20.ber", Error: ""},
|
||||||
|
// Object identifiers
|
||||||
|
{File: "tests/tc21.ber", Error: ""},
|
||||||
|
{File: "tests/tc22.ber", Error: ""},
|
||||||
|
{File: "tests/tc23.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc24.ber", Error: ""},
|
||||||
|
// Booleans
|
||||||
|
{File: "tests/tc25.ber", Error: ""},
|
||||||
|
{File: "tests/tc26.ber", Error: ""},
|
||||||
|
{File: "tests/tc27.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc28.ber", Error: ""},
|
||||||
|
{File: "tests/tc29.ber", Error: ""},
|
||||||
|
// Null
|
||||||
|
{File: "tests/tc30.ber", Error: ""},
|
||||||
|
{File: "tests/tc31.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc32.ber", Error: ""},
|
||||||
|
// Bitstring (some expected failures are disabled until support is added)
|
||||||
|
{File: "tests/tc33.ber", Error: ""}, // Error: "Too big value for "unused bits""
|
||||||
|
{File: "tests/tc34.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc35.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from BIT STRING types as internal types for constructive encoding"
|
||||||
|
{File: "tests/tc36.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of "unused bits" in internal BIT STRINGs with constructive form of encoding"
|
||||||
|
{File: "tests/tc37.ber", Error: ""},
|
||||||
|
{File: "tests/tc38.ber", Error: "", IndefiniteEncoding: true},
|
||||||
|
{File: "tests/tc39.ber", Error: ""},
|
||||||
|
{File: "tests/tc40.ber", Error: ""},
|
||||||
|
// Octet string (some expected failures are disabled until support is added)
|
||||||
|
{File: "tests/tc41.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from OCTET STRING types as internal types for constructive encoding"
|
||||||
|
{File: "tests/tc42.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc43.ber", Error: errEOF},
|
||||||
|
{File: "tests/tc44.ber", Error: ""},
|
||||||
|
{File: "tests/tc45.ber", Error: ""},
|
||||||
|
// Bitstring
|
||||||
|
{File: "tests/tc46.ber", Error: "indefinite length used with primitive type"},
|
||||||
|
{File: "tests/tc47.ber", Error: "eoc child not allowed with definite length"},
|
||||||
|
{File: "tests/tc48.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of more than 7 "unused bits" in BIT STRING with constrictive encoding form"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuiteDecodePacket(t *testing.T) {
|
||||||
|
// Debug = true
|
||||||
|
for _, tc := range testcases {
|
||||||
|
file := tc.File
|
||||||
|
|
||||||
|
dataIn, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: %v", file, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("%s: decode %d\n", file, len(dataIn))
|
||||||
|
packet, err := DecodePacketErr(dataIn)
|
||||||
|
if err != nil {
|
||||||
|
if tc.Error == "" {
|
||||||
|
t.Errorf("%s: unexpected error during DecodePacket: %v", file, err)
|
||||||
|
} else if tc.Error != err.Error() {
|
||||||
|
t.Errorf("%s: expected error %q during DecodePacket, got %q", file, tc.Error, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tc.Error != "" {
|
||||||
|
t.Errorf("%s: expected error %q, got none", file, tc.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dataOut := packet.Bytes()
|
||||||
|
if tc.AbnormalEncoding || tc.IndefiniteEncoding {
|
||||||
|
// Abnormal encodings and encodings that used indefinite length should re-encode differently
|
||||||
|
if bytes.Equal(dataOut, dataIn) {
|
||||||
|
t.Errorf("%s: data should have been re-encoded differently", file)
|
||||||
|
}
|
||||||
|
} else if !bytes.Equal(dataOut, dataIn) {
|
||||||
|
// Make sure the serialized data matches the source
|
||||||
|
t.Errorf("%s: data should be the same", file)
|
||||||
|
}
|
||||||
|
|
||||||
|
packet, err = DecodePacketErr(dataOut)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: unexpected error: %v", file, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the re-serialized data matches our original serialization
|
||||||
|
dataOut2 := packet.Bytes()
|
||||||
|
if !bytes.Equal(dataOut, dataOut2) {
|
||||||
|
t.Errorf("%s: data should be the same", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuiteReadPacket(t *testing.T) {
|
||||||
|
for _, tc := range testcases {
|
||||||
|
file := tc.File
|
||||||
|
|
||||||
|
dataIn, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: %v", file, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := bytes.NewBuffer(dataIn)
|
||||||
|
packet, err := ReadPacket(buffer)
|
||||||
|
if err != nil {
|
||||||
|
if tc.Error == "" {
|
||||||
|
t.Errorf("%s: unexpected error during ReadPacket: %v", file, err)
|
||||||
|
} else if tc.Error != err.Error() {
|
||||||
|
t.Errorf("%s: expected error %q during ReadPacket, got %q", file, tc.Error, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tc.Error != "" {
|
||||||
|
t.Errorf("%s: expected error %q, got none", file, tc.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dataOut := packet.Bytes()
|
||||||
|
if tc.AbnormalEncoding || tc.IndefiniteEncoding {
|
||||||
|
// Abnormal encodings and encodings that used indefinite length should re-encode differently
|
||||||
|
if bytes.Equal(dataOut, dataIn) {
|
||||||
|
t.Errorf("%s: data should have been re-encoded differently", file)
|
||||||
|
}
|
||||||
|
} else if !bytes.Equal(dataOut, dataIn) {
|
||||||
|
// Make sure the serialized data matches the source
|
||||||
|
t.Errorf("%s: data should be the same", file)
|
||||||
|
}
|
||||||
|
|
||||||
|
packet, err = DecodePacketErr(dataOut)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: unexpected error: %v", file, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the re-serialized data matches our original serialization
|
||||||
|
dataOut2 := packet.Bytes()
|
||||||
|
if !bytes.Equal(dataOut, dataOut2) {
|
||||||
|
t.Errorf("%s: data should be the same", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc1.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc1.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc10.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc10.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<07><04><><EFBFBD><EFBFBD>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc11.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc11.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
015625
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc12.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc12.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
I
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc13.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc13.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc14.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc14.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc15.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc15.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<0C> <><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc16.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc16.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc17.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc17.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<14> <09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc18.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc18.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<03><>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc19.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc19.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc2.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc2.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc20.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc20.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc21.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc21.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
Q
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc22.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc22.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0F>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc23.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc23.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<><7F><EFBFBD><EFBFBD><EFBFBD>
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc24.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc24.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
Î`†HˆŸO …îåJ…ä¿c‹Û/
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc25.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc25.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc26.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc26.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc27.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc27.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc28.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc28.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<01>
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc29.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc29.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc3.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc3.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc30.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc30.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc31.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc31.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc32.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc32.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc33.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc33.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc34.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc34.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc35.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc35.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc36.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc36.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc37.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc37.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc38.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc38.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc39.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc39.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc4.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc4.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc40.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc40.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc41.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc41.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc42.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc42.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc43.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc43.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
$
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc44.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc44.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc45.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc45.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc46.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc46.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc47.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc47.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc48.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc48.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc5.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc5.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc6.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc6.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
+0.E-5
|
||||||
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc7.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc7.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
-0.E-5
|
||||||
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc8.ber
сгенерированный
поставляемый
Обычный файл
Двоичные данные
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc8.ber
сгенерированный
поставляемый
Обычный файл
Двоичный файл не отображается.
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc9.ber
сгенерированный
поставляемый
Обычный файл
1
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/tests/tc9.ber
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
件
|
||||||
24
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/util.go
сгенерированный
поставляемый
Обычный файл
24
Godeps/_workspace/src/gopkg.in/asn1-ber.v1/util.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,24 @@
|
|||||||
|
package ber
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
func readByte(reader io.Reader) (byte, error) {
|
||||||
|
bytes := make([]byte, 1, 1)
|
||||||
|
_, err := io.ReadFull(reader, bytes)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return bytes[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEOCPacket(p *Packet) bool {
|
||||||
|
return p != nil &&
|
||||||
|
p.Tag == TagEOC &&
|
||||||
|
p.ClassType == ClassUniversal &&
|
||||||
|
p.TagType == TypePrimitive &&
|
||||||
|
len(p.ByteValue) == 0 &&
|
||||||
|
len(p.Children) == 0
|
||||||
|
}
|
||||||
31
Makefile
31
Makefile
@@ -6,6 +6,9 @@ BUILD_NUMBER ?= $(BUILD_NUMBER:)
|
|||||||
BUILD_DATE = $(shell date -u)
|
BUILD_DATE = $(shell date -u)
|
||||||
BUILD_HASH = $(shell git rev-parse HEAD)
|
BUILD_HASH = $(shell git rev-parse HEAD)
|
||||||
|
|
||||||
|
ENTERPRISE_DIR ?= ../enterprise
|
||||||
|
BUILD_ENTERPRISE ?= true
|
||||||
|
|
||||||
GO=$(GOPATH)/bin/godep go
|
GO=$(GOPATH)/bin/godep go
|
||||||
ESLINT=node_modules/eslint/bin/eslint.js
|
ESLINT=node_modules/eslint/bin/eslint.js
|
||||||
|
|
||||||
@@ -31,6 +34,10 @@ all: dist-local
|
|||||||
|
|
||||||
dist: | build-server build-client go-test package
|
dist: | build-server build-client go-test package
|
||||||
mv ./model/version.go.bak ./model/version.go
|
mv ./model/version.go.bak ./model/version.go
|
||||||
|
@if [ "$(BUILD_ENTERPRISE)" = "true" ] && [ -d "$(ENTERPRISE_DIR)" ]; then \
|
||||||
|
mv ./mattermost.go.bak ./mattermost.go; \
|
||||||
|
mv ./config/config.json.bak ./config/config.json 2> /dev/null || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
dist-local: | start-docker dist
|
dist-local: | start-docker dist
|
||||||
|
|
||||||
@@ -79,9 +86,21 @@ build-server:
|
|||||||
sed -i'.make_mac_work' 's|_BUILD_NUMBER_|$(BUILD_NUMBER)|g' ./model/version.go
|
sed -i'.make_mac_work' 's|_BUILD_NUMBER_|$(BUILD_NUMBER)|g' ./model/version.go
|
||||||
sed -i'.make_mac_work' 's|_BUILD_DATE_|$(BUILD_DATE)|g' ./model/version.go
|
sed -i'.make_mac_work' 's|_BUILD_DATE_|$(BUILD_DATE)|g' ./model/version.go
|
||||||
sed -i'.make_mac_work' 's|_BUILD_HASH_|$(BUILD_HASH)|g' ./model/version.go
|
sed -i'.make_mac_work' 's|_BUILD_HASH_|$(BUILD_HASH)|g' ./model/version.go
|
||||||
|
|
||||||
|
@if [ "$(BUILD_ENTERPRISE)" = "true" ] && [ -d "$(ENTERPRISE_DIR)" ]; then \
|
||||||
|
cp ./config/config.json ./config/config.json.bak; \
|
||||||
|
jq -s '.[0] * .[1]' ./config/config.json $(ENTERPRISE_DIR)/config/enterprise-config-additions.json > config.json.tmp; \
|
||||||
|
mv config.json.tmp ./config/config.json; \
|
||||||
|
sed -e '/\/\/ENTERPRISE_IMPORTS/ {' -e 'r $(ENTERPRISE_DIR)/imports' -e 'd' -e '}' -i'.bak' mattermost.go; \
|
||||||
|
sed -i'.make_mac_work' 's|_BUILD_ENTERPRISE_READY_|true|g' ./model/version.go; \
|
||||||
|
else \
|
||||||
|
sed -i'.make_mac_work' 's|_BUILD_ENTERPRISE_READY_|false|g' ./model/version.go; \
|
||||||
|
fi
|
||||||
|
|
||||||
rm ./model/version.go.make_mac_work
|
rm ./model/version.go.make_mac_work
|
||||||
|
|
||||||
$(GO) build $(GOFLAGS) ./...
|
$(GO) build $(GOFLAGS) ./...
|
||||||
|
$(GO) generate $(GOFLAGS) ./...
|
||||||
$(GO) install $(GOFLAGS) ./...
|
$(GO) install $(GOFLAGS) ./...
|
||||||
|
|
||||||
package:
|
package:
|
||||||
@@ -242,6 +261,13 @@ run: start-docker .prepare-go .prepare-jsx
|
|||||||
@echo Starting react processo
|
@echo Starting react processo
|
||||||
cd web/react && npm start &
|
cd web/react && npm start &
|
||||||
|
|
||||||
|
@if [ "$(BUILD_ENTERPRISE)" = "true" ] && [ -d "$(ENTERPRISE_DIR)" ]; then \
|
||||||
|
cp ./config/config.json ./config/config.json.bak; \
|
||||||
|
jq -s '.[0] * .[1]' ./config/config.json $(ENTERPRISE_DIR)/config/enterprise-config-additions.json > config.json.tmp; \
|
||||||
|
mv config.json.tmp ./config/config.json; \
|
||||||
|
sed -e '/\/\/ENTERPRISE_IMPORTS/ {' -e 'r $(ENTERPRISE_DIR)/imports' -e 'd' -e '}' -i'.bak' mattermost.go; \
|
||||||
|
fi
|
||||||
|
|
||||||
@echo Starting go web server
|
@echo Starting go web server
|
||||||
$(GO) run $(GOFLAGS) mattermost.go -config=config.json &
|
$(GO) run $(GOFLAGS) mattermost.go -config=config.json &
|
||||||
|
|
||||||
@@ -270,6 +296,11 @@ stop:
|
|||||||
docker rm -v ${DOCKER_CONTAINER_NAME} > /dev/null; \
|
docker rm -v ${DOCKER_CONTAINER_NAME} > /dev/null; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@if [ "$(BUILD_ENTERPRISE)" = "true" ] && [ -d "$(ENTERPRISE_DIR)" ]; then \
|
||||||
|
mv ./config/config.json.bak ./config/config.json 2> /dev/null || true; \
|
||||||
|
mv ./mattermost.go.bak ./mattermost.go 2> /dev/null || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
setup-mac:
|
setup-mac:
|
||||||
echo $$(boot2docker ip 2> /dev/null) dockerhost | sudo tee -a /etc/hosts
|
echo $$(boot2docker ip 2> /dev/null) dockerhost | sudo tee -a /etc/hosts
|
||||||
|
|
||||||
|
|||||||
@@ -221,8 +221,9 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
teamSignup.User.TeamId = rteam.Id
|
teamSignup.User.TeamId = rteam.Id
|
||||||
teamSignup.User.EmailVerified = true
|
teamSignup.User.EmailVerified = true
|
||||||
|
|
||||||
ruser := CreateUser(c, rteam, &teamSignup.User)
|
ruser, err := CreateUser(rteam, &teamSignup.User)
|
||||||
if c.Err != nil {
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
100
api/user.go
100
api/user.go
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/disintegration/imaging"
|
"github.com/disintegration/imaging"
|
||||||
"github.com/golang/freetype"
|
"github.com/golang/freetype"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/mattermost/platform/einterfaces"
|
||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/store"
|
"github.com/mattermost/platform/store"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
@@ -44,6 +45,7 @@ func InitUser(r *mux.Router) {
|
|||||||
sr.Handle("/reset_password", ApiAppHandler(resetPassword)).Methods("POST")
|
sr.Handle("/reset_password", ApiAppHandler(resetPassword)).Methods("POST")
|
||||||
sr.Handle("/login", ApiAppHandler(login)).Methods("POST")
|
sr.Handle("/login", ApiAppHandler(login)).Methods("POST")
|
||||||
sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST")
|
sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST")
|
||||||
|
sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST")
|
||||||
sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
|
sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
|
||||||
|
|
||||||
sr.Handle("/newimage", ApiUserRequired(uploadProfileImage)).Methods("POST")
|
sr.Handle("/newimage", ApiUserRequired(uploadProfileImage)).Methods("POST")
|
||||||
@@ -59,7 +61,7 @@ func InitUser(r *mux.Router) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
|
if !utils.Cfg.EmailSettings.EnableSignUpWithEmail || !utils.Cfg.TeamSettings.EnableUserCreation {
|
||||||
c.Err = model.NewAppError("signupTeam", "User sign-up with email is disabled.", "")
|
c.Err = model.NewAppError("signupTeam", "User sign-up with email is disabled.", "")
|
||||||
c.Err.StatusCode = http.StatusNotImplemented
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
return
|
return
|
||||||
@@ -118,8 +120,9 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
user.EmailVerified = true
|
user.EmailVerified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
ruser := CreateUser(c, team, user)
|
ruser, err := CreateUser(team, user)
|
||||||
if c.Err != nil {
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,12 +166,7 @@ func IsVerifyHashRequired(user *model.User, team *model.Team, hash string) bool
|
|||||||
return shouldVerifyHash
|
return shouldVerifyHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
func CreateUser(team *model.Team, user *model.User) (*model.User, *model.AppError) {
|
||||||
|
|
||||||
if !utils.Cfg.TeamSettings.EnableUserCreation {
|
|
||||||
c.Err = model.NewAppError("CreateUser", "User creation has been disabled. Please ask your systems administrator for details.", "")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
channelRole := ""
|
channelRole := ""
|
||||||
if team.Email == user.Email {
|
if team.Email == user.Email {
|
||||||
@@ -178,8 +176,7 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
|||||||
// Below is a speical case where the first user in the entire
|
// Below is a speical case where the first user in the entire
|
||||||
// system is granted the system_admin role instead of admin
|
// system is granted the system_admin role instead of admin
|
||||||
if result := <-Srv.Store.User().GetTotalUsersCount(); result.Err != nil {
|
if result := <-Srv.Store.User().GetTotalUsersCount(); result.Err != nil {
|
||||||
c.Err = result.Err
|
return nil, result.Err
|
||||||
return nil
|
|
||||||
} else {
|
} else {
|
||||||
count := result.Data.(int64)
|
count := result.Data.(int64)
|
||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
@@ -194,9 +191,8 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
|||||||
user.MakeNonNil()
|
user.MakeNonNil()
|
||||||
|
|
||||||
if result := <-Srv.Store.User().Save(user); result.Err != nil {
|
if result := <-Srv.Store.User().Save(user); result.Err != nil {
|
||||||
c.Err = result.Err
|
|
||||||
l4g.Error("Couldn't save the user err=%v", result.Err)
|
l4g.Error("Couldn't save the user err=%v", result.Err)
|
||||||
return nil
|
return nil, result.Err
|
||||||
} else {
|
} else {
|
||||||
ruser := result.Data.(*model.User)
|
ruser := result.Data.(*model.User)
|
||||||
|
|
||||||
@@ -225,7 +221,7 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
|||||||
|
|
||||||
PublishAndForget(message)
|
PublishAndForget(message)
|
||||||
|
|
||||||
return ruser
|
return ruser, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +309,7 @@ func LoginById(c *Context, w http.ResponseWriter, r *http.Request, userId, passw
|
|||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
user := result.Data.(*model.User)
|
user := result.Data.(*model.User)
|
||||||
if checkUserPassword(c, user, password) {
|
if checkUserLoginAttempts(c, user) && checkUserPassword(c, user, password) {
|
||||||
Login(c, w, r, user, deviceId)
|
Login(c, w, r, user, deviceId)
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
@@ -339,7 +335,7 @@ func LoginByEmail(c *Context, w http.ResponseWriter, r *http.Request, email, nam
|
|||||||
} else {
|
} else {
|
||||||
user := result.Data.(*model.User)
|
user := result.Data.(*model.User)
|
||||||
|
|
||||||
if checkUserPassword(c, user, password) {
|
if checkUserLoginAttempts(c, user) && checkUserPassword(c, user, password) {
|
||||||
Login(c, w, r, user, deviceId)
|
Login(c, w, r, user, deviceId)
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
@@ -348,8 +344,7 @@ func LoginByEmail(c *Context, w http.ResponseWriter, r *http.Request, email, nam
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkUserPassword(c *Context, user *model.User, password string) bool {
|
func checkUserLoginAttempts(c *Context, user *model.User) bool {
|
||||||
|
|
||||||
if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
|
if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
|
||||||
c.LogAuditWithUserId(user.Id, "fail")
|
c.LogAuditWithUserId(user.Id, "fail")
|
||||||
c.Err = model.NewAppError("checkUserPassword", "Your account is locked because of too many failed password attempts. Please reset your password.", "user_id="+user.Id)
|
c.Err = model.NewAppError("checkUserPassword", "Your account is locked because of too many failed password attempts. Please reset your password.", "user_id="+user.Id)
|
||||||
@@ -357,6 +352,11 @@ func checkUserPassword(c *Context, user *model.User, password string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkUserPassword(c *Context, user *model.User, password string) bool {
|
||||||
|
|
||||||
if !model.ComparePassword(user.Password, password) {
|
if !model.ComparePassword(user.Password, password) {
|
||||||
c.LogAuditWithUserId(user.Id, "fail")
|
c.LogAuditWithUserId(user.Id, "fail")
|
||||||
c.Err = model.NewAppError("checkUserPassword", "Login failed because of invalid password", "user_id="+user.Id)
|
c.Err = model.NewAppError("checkUserPassword", "Login failed because of invalid password", "user_id="+user.Id)
|
||||||
@@ -500,6 +500,70 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write([]byte(user.ToJson()))
|
w.Write([]byte(user.ToJson()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loginLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !*utils.Cfg.LdapSettings.Enable {
|
||||||
|
c.Err = model.NewAppError("loginLdap", "LDAP not enabled on this server", "")
|
||||||
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
props := model.MapFromJson(r.Body)
|
||||||
|
|
||||||
|
password := props["password"]
|
||||||
|
id := props["id"]
|
||||||
|
teamName := props["teamName"]
|
||||||
|
|
||||||
|
if len(password) == 0 {
|
||||||
|
c.Err = model.NewAppError("loginLdap", "Password field must not be blank", "")
|
||||||
|
c.Err.StatusCode = http.StatusForbidden
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(id) == 0 {
|
||||||
|
c.Err = model.NewAppError("loginLdap", "Need an ID", "")
|
||||||
|
c.Err.StatusCode = http.StatusForbidden
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
teamc := Srv.Store.Team().GetByName(teamName)
|
||||||
|
|
||||||
|
ldapInterface := einterfaces.GetLdapInterface()
|
||||||
|
if ldapInterface == nil {
|
||||||
|
c.Err = model.NewAppError("loginLdap", "LDAP not available on this server", "")
|
||||||
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var team *model.Team
|
||||||
|
if result := <-teamc; result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
team = result.Data.(*model.Team)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := ldapInterface.DoLogin(team, id, password)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkUserLoginAttempts(c, user) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// User is authenticated at this point
|
||||||
|
|
||||||
|
Login(c, w, r, user, props["device_id"])
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
user.Sanitize(map[string]bool{})
|
||||||
|
} else {
|
||||||
|
user = &model.User{}
|
||||||
|
}
|
||||||
|
w.Write([]byte(user.ToJson()))
|
||||||
|
}
|
||||||
|
|
||||||
func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
|
func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
props := model.MapFromJson(r.Body)
|
props := model.MapFromJson(r.Body)
|
||||||
id := props["id"]
|
id := props["id"]
|
||||||
|
|||||||
22
einterfaces/ldap.go
Обычный файл
22
einterfaces/ldap.go
Обычный файл
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package einterfaces
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/platform/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LdapInterface interface {
|
||||||
|
DoLogin(team *model.Team, id string, password string) (*model.User, *model.AppError)
|
||||||
|
}
|
||||||
|
|
||||||
|
var theLdapInterface LdapInterface
|
||||||
|
|
||||||
|
func RegisterLdapInterface(newInterface LdapInterface) {
|
||||||
|
theLdapInterface = newInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLdapInterface() LdapInterface {
|
||||||
|
return theLdapInterface
|
||||||
|
}
|
||||||
29
einterfaces/oauthproviders.go
Обычный файл
29
einterfaces/oauthproviders.go
Обычный файл
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package einterfaces
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/platform/model"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OauthProvider interface {
|
||||||
|
GetIdentifier() string
|
||||||
|
GetUserFromJson(data io.Reader) *model.User
|
||||||
|
GetAuthDataFromJson(data io.Reader) string
|
||||||
|
}
|
||||||
|
|
||||||
|
var oauthProviders = make(map[string]OauthProvider)
|
||||||
|
|
||||||
|
func RegisterOauthProvider(name string, newProvider OauthProvider) {
|
||||||
|
oauthProviders[name] = newProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOauthProvider(name string) OauthProvider {
|
||||||
|
provider, ok := oauthProviders[name]
|
||||||
|
if ok {
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -23,8 +23,16 @@ import (
|
|||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
"github.com/mattermost/platform/web"
|
"github.com/mattermost/platform/web"
|
||||||
|
|
||||||
|
// Plugins
|
||||||
|
_ "github.com/mattermost/platform/model/gitlab"
|
||||||
|
|
||||||
|
// Enterprise Deps
|
||||||
|
_ "github.com/go-ldap/ldap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//ENTERPRISE_IMPORTS
|
||||||
|
|
||||||
var flagCmdCreateTeam bool
|
var flagCmdCreateTeam bool
|
||||||
var flagCmdCreateUser bool
|
var flagCmdCreateUser bool
|
||||||
var flagCmdAssignRole bool
|
var flagCmdAssignRole bool
|
||||||
@@ -51,6 +59,7 @@ func main() {
|
|||||||
|
|
||||||
pwd, _ := os.Getwd()
|
pwd, _ := os.Getwd()
|
||||||
l4g.Info("Current version is %v (%v/%v/%v)", model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash)
|
l4g.Info("Current version is %v (%v/%v/%v)", model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash)
|
||||||
|
l4g.Info("Enterprise Enabled: %t", model.BuildEnterpriseReady)
|
||||||
l4g.Info("Current working directory is %v", pwd)
|
l4g.Info("Current working directory is %v", pwd)
|
||||||
l4g.Info("Loaded config file from %v", utils.FindConfigFile(flagConfigFile))
|
l4g.Info("Loaded config file from %v", utils.FindConfigFile(flagConfigFile))
|
||||||
|
|
||||||
@@ -112,6 +121,7 @@ func runSecurityAndDiagnosticsJobAndForget() {
|
|||||||
|
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
|
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
|
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
|
||||||
|
v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
|
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
|
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
|
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
|
||||||
@@ -283,10 +293,6 @@ func cmdCreateUser() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &api.Context{}
|
|
||||||
c.RequestId = model.NewId()
|
|
||||||
c.IpAddress = "cmd_line"
|
|
||||||
|
|
||||||
var team *model.Team
|
var team *model.Team
|
||||||
user := &model.User{}
|
user := &model.User{}
|
||||||
user.Email = flagEmail
|
user.Email = flagEmail
|
||||||
@@ -302,10 +308,10 @@ func cmdCreateUser() {
|
|||||||
user.TeamId = team.Id
|
user.TeamId = team.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
api.CreateUser(c, team, user)
|
_, err := api.CreateUser(team, user)
|
||||||
if c.Err != nil {
|
if err != nil {
|
||||||
if c.Err.Message != "An account with that email already exists." {
|
if err.Message != "An account with that email already exists." {
|
||||||
l4g.Error("%v", c.Err)
|
l4g.Error("%v", err)
|
||||||
flushLogAndExit(1)
|
flushLogAndExit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +326,7 @@ func cmdVersion() {
|
|||||||
fmt.Fprintln(os.Stderr, "Build Number: "+model.BuildNumber)
|
fmt.Fprintln(os.Stderr, "Build Number: "+model.BuildNumber)
|
||||||
fmt.Fprintln(os.Stderr, "Build Date: "+model.BuildDate)
|
fmt.Fprintln(os.Stderr, "Build Date: "+model.BuildDate)
|
||||||
fmt.Fprintln(os.Stderr, "Build Hash: "+model.BuildHash)
|
fmt.Fprintln(os.Stderr, "Build Hash: "+model.BuildHash)
|
||||||
|
fmt.Fprintln(os.Stderr, "Build Enterprise Ready: "+model.BuildEnterpriseReady)
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const (
|
|||||||
DATABASE_DRIVER_POSTGRES = "postgres"
|
DATABASE_DRIVER_POSTGRES = "postgres"
|
||||||
|
|
||||||
SERVICE_GITLAB = "gitlab"
|
SERVICE_GITLAB = "gitlab"
|
||||||
|
SERVICE_GOOGLE = "google"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServiceSettings struct {
|
type ServiceSettings struct {
|
||||||
@@ -133,6 +134,26 @@ type TeamSettings struct {
|
|||||||
EnableTeamListing *bool
|
EnableTeamListing *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LdapSettings struct {
|
||||||
|
// Basic
|
||||||
|
Enable *bool
|
||||||
|
LdapServer *string
|
||||||
|
LdapPort *int
|
||||||
|
BaseDN *string
|
||||||
|
BindUsername *string
|
||||||
|
BindPassword *string
|
||||||
|
|
||||||
|
// User Mapping
|
||||||
|
FirstNameAttribute *string
|
||||||
|
LastNameAttribute *string
|
||||||
|
EmailAttribute *string
|
||||||
|
UsernameAttribute *string
|
||||||
|
IdAttribute *string
|
||||||
|
|
||||||
|
// Advansed
|
||||||
|
QueryTimeout *int
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ServiceSettings ServiceSettings
|
ServiceSettings ServiceSettings
|
||||||
TeamSettings TeamSettings
|
TeamSettings TeamSettings
|
||||||
@@ -144,6 +165,8 @@ type Config struct {
|
|||||||
PrivacySettings PrivacySettings
|
PrivacySettings PrivacySettings
|
||||||
SupportSettings SupportSettings
|
SupportSettings SupportSettings
|
||||||
GitLabSettings SSOSettings
|
GitLabSettings SSOSettings
|
||||||
|
GoogleSettings SSOSettings
|
||||||
|
LdapSettings LdapSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Config) ToJson() string {
|
func (o *Config) ToJson() string {
|
||||||
@@ -156,8 +179,11 @@ func (o *Config) ToJson() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Config) GetSSOService(service string) *SSOSettings {
|
func (o *Config) GetSSOService(service string) *SSOSettings {
|
||||||
if service == SERVICE_GITLAB {
|
switch service {
|
||||||
|
case SERVICE_GITLAB:
|
||||||
return &o.GitLabSettings
|
return &o.GitLabSettings
|
||||||
|
case SERVICE_GOOGLE:
|
||||||
|
return &o.GoogleSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -251,6 +277,21 @@ func (o *Config) SetDefaults() {
|
|||||||
o.SupportSettings.SupportEmail = new(string)
|
o.SupportSettings.SupportEmail = new(string)
|
||||||
*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
|
*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LdapPort == nil {
|
||||||
|
o.LdapSettings.LdapPort = new(int)
|
||||||
|
*o.LdapSettings.LdapPort = 389
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.QueryTimeout == nil {
|
||||||
|
o.LdapSettings.QueryTimeout = new(int)
|
||||||
|
*o.LdapSettings.QueryTimeout = 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.Enable == nil {
|
||||||
|
o.LdapSettings.Enable = new(bool)
|
||||||
|
*o.LdapSettings.Enable = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Config) IsValid() *AppError {
|
func (o *Config) IsValid() *AppError {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
package model
|
package oauthgitlab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/mattermost/platform/einterfaces"
|
||||||
|
"github.com/mattermost/platform/model"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -14,6 +16,9 @@ const (
|
|||||||
USER_AUTH_SERVICE_GITLAB = "gitlab"
|
USER_AUTH_SERVICE_GITLAB = "gitlab"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GitLabProvider struct {
|
||||||
|
}
|
||||||
|
|
||||||
type GitLabUser struct {
|
type GitLabUser struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -22,13 +27,18 @@ type GitLabUser struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserFromGitLabUser(glu *GitLabUser) *User {
|
func init() {
|
||||||
user := &User{}
|
provider := &GitLabProvider{}
|
||||||
|
einterfaces.RegisterOauthProvider(USER_AUTH_SERVICE_GITLAB, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func userFromGitLabUser(glu *GitLabUser) *model.User {
|
||||||
|
user := &model.User{}
|
||||||
username := glu.Username
|
username := glu.Username
|
||||||
if username == "" {
|
if username == "" {
|
||||||
username = glu.Login
|
username = glu.Login
|
||||||
}
|
}
|
||||||
user.Username = CleanUsername(username)
|
user.Username = model.CleanUsername(username)
|
||||||
splitName := strings.Split(glu.Name, " ")
|
splitName := strings.Split(glu.Name, " ")
|
||||||
if len(splitName) == 2 {
|
if len(splitName) == 2 {
|
||||||
user.FirstName = splitName[0]
|
user.FirstName = splitName[0]
|
||||||
@@ -46,7 +56,7 @@ func UserFromGitLabUser(glu *GitLabUser) *User {
|
|||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func GitLabUserFromJson(data io.Reader) *GitLabUser {
|
func gitLabUserFromJson(data io.Reader) *GitLabUser {
|
||||||
decoder := json.NewDecoder(data)
|
decoder := json.NewDecoder(data)
|
||||||
var glu GitLabUser
|
var glu GitLabUser
|
||||||
err := decoder.Decode(&glu)
|
err := decoder.Decode(&glu)
|
||||||
@@ -57,6 +67,18 @@ func GitLabUserFromJson(data io.Reader) *GitLabUser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (glu *GitLabUser) GetAuthData() string {
|
func (glu *GitLabUser) getAuthData() string {
|
||||||
return strconv.FormatInt(glu.Id, 10)
|
return strconv.FormatInt(glu.Id, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *GitLabProvider) GetIdentifier() string {
|
||||||
|
return USER_AUTH_SERVICE_GITLAB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GitLabProvider) GetUserFromJson(data io.Reader) *model.User {
|
||||||
|
return userFromGitLabUser(gitLabUserFromJson(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GitLabProvider) GetAuthDataFromJson(data io.Reader) string {
|
||||||
|
return gitLabUserFromJson(data).getAuthData()
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ var CurrentVersion string = versions[0]
|
|||||||
var BuildNumber = "_BUILD_NUMBER_"
|
var BuildNumber = "_BUILD_NUMBER_"
|
||||||
var BuildDate = "_BUILD_DATE_"
|
var BuildDate = "_BUILD_DATE_"
|
||||||
var BuildHash = "_BUILD_HASH_"
|
var BuildHash = "_BUILD_HASH_"
|
||||||
|
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_"
|
||||||
|
|
||||||
func SplitVersion(version string) (int64, int64, int64) {
|
func SplitVersion(version string) (int64, int64, int64) {
|
||||||
parts := strings.Split(version, ".")
|
parts := strings.Split(version, ".")
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ func (us SqlUserStore) GetTotalActiveUsersCount() StoreChannel {
|
|||||||
go func() {
|
go func() {
|
||||||
result := StoreResult{}
|
result := StoreResult{}
|
||||||
|
|
||||||
time := model.GetMillis() - (1000 * 60 * 60 * 12)
|
time := model.GetMillis() - (1000 * 60 * 60 * 24)
|
||||||
|
|
||||||
if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE LastActivityAt > :Time", map[string]interface{}{"Time": time}); err != nil {
|
if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE LastActivityAt > :Time", map[string]interface{}{"Time": time}); err != nil {
|
||||||
result.Err = model.NewAppError("SqlUserStore.GetTotalActiveUsersCount", "We could not count the users", err.Error())
|
result.Err = model.NewAppError("SqlUserStore.GetTotalActiveUsersCount", "We could not count the users", err.Error())
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ func getClientConfig(c *model.Config) map[string]string {
|
|||||||
props["BuildNumber"] = model.BuildNumber
|
props["BuildNumber"] = model.BuildNumber
|
||||||
props["BuildDate"] = model.BuildDate
|
props["BuildDate"] = model.BuildDate
|
||||||
props["BuildHash"] = model.BuildHash
|
props["BuildHash"] = model.BuildHash
|
||||||
|
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
|
||||||
|
|
||||||
props["SiteName"] = c.TeamSettings.SiteName
|
props["SiteName"] = c.TeamSettings.SiteName
|
||||||
props["EnableTeamCreation"] = strconv.FormatBool(c.TeamSettings.EnableTeamCreation)
|
props["EnableTeamCreation"] = strconv.FormatBool(c.TeamSettings.EnableTeamCreation)
|
||||||
@@ -203,6 +204,7 @@ func getClientConfig(c *model.Config) map[string]string {
|
|||||||
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
|
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
|
||||||
|
|
||||||
props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
|
props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
|
||||||
|
props["EnableSignUpWithGoogle"] = strconv.FormatBool(c.GoogleSettings.Enable)
|
||||||
|
|
||||||
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
|
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
|
||||||
|
|
||||||
@@ -217,5 +219,7 @@ func getClientConfig(c *model.Config) map[string]string {
|
|||||||
props["ProfileHeight"] = fmt.Sprintf("%v", c.FileSettings.ProfileHeight)
|
props["ProfileHeight"] = fmt.Sprintf("%v", c.FileSettings.ProfileHeight)
|
||||||
props["ProfileWidth"] = fmt.Sprintf("%v", c.FileSettings.ProfileWidth)
|
props["ProfileWidth"] = fmt.Sprintf("%v", c.FileSettings.ProfileWidth)
|
||||||
|
|
||||||
|
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const (
|
|||||||
PROP_DIAGNOSTIC_CATEGORY = "c"
|
PROP_DIAGNOSTIC_CATEGORY = "c"
|
||||||
VAL_DIAGNOSTIC_CATEGORY_DEFAULT = "d"
|
VAL_DIAGNOSTIC_CATEGORY_DEFAULT = "d"
|
||||||
PROP_DIAGNOSTIC_BUILD = "b"
|
PROP_DIAGNOSTIC_BUILD = "b"
|
||||||
|
PROP_DIAGNOSTIC_ENTERPRISE_READY = "be"
|
||||||
PROP_DIAGNOSTIC_DATABASE = "db"
|
PROP_DIAGNOSTIC_DATABASE = "db"
|
||||||
PROP_DIAGNOSTIC_OS = "os"
|
PROP_DIAGNOSTIC_OS = "os"
|
||||||
PROP_DIAGNOSTIC_USER_COUNT = "uc"
|
PROP_DIAGNOSTIC_USER_COUNT = "uc"
|
||||||
|
|||||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user