mirror of
https://github.com/documize/community.git
synced 2025-07-18 20:59:43 +02:00
Support dual login via LDAP and forms authentication
Closes #256 as we now support dual login -- LDAP and forms authentication. Also bumped the vendored library to LDAP.v3 as it contains bug fixes.
This commit is contained in:
parent
faf9a555d2
commit
b054addb9c
42 changed files with 977 additions and 582 deletions
10
Gopkg.lock
generated
10
Gopkg.lock
generated
|
@ -299,12 +299,12 @@
|
||||||
version = "v1.2"
|
version = "v1.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:93aaeb913621a3a53aaa78592c00f46d63e3bb0ea76e2d9b07327b50959a5778"
|
digest = "1:e9a0fa7c2dfc90e0fae16be5825ad98074d8704f5fcebfdc289a8e8fb0f8e4b5"
|
||||||
name = "gopkg.in/ldap.v2"
|
name = "gopkg.in/ldap.v3"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "bb7a9ca6e4fbc2129e3db588a34bc970ffe811a9"
|
revision = "9f0d712775a0973b7824a1585a86a4ea1d5263d9"
|
||||||
version = "v2.5.1"
|
version = "v3.0.3"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
@ -334,7 +334,7 @@
|
||||||
"golang.org/x/oauth2",
|
"golang.org/x/oauth2",
|
||||||
"gopkg.in/alexcesaro/quotedprintable.v3",
|
"gopkg.in/alexcesaro/quotedprintable.v3",
|
||||||
"gopkg.in/andygrunwald/go-jira.v1",
|
"gopkg.in/andygrunwald/go-jira.v1",
|
||||||
"gopkg.in/ldap.v2",
|
"gopkg.in/ldap.v3",
|
||||||
]
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
23
NOTICES.md
23
NOTICES.md
|
@ -36,7 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
https://github.com/gorilla/context
|
https://github.com/gorilla/context
|
||||||
https://github.com/gorilla/mux
|
https://github.com/gorilla/mux
|
||||||
|
|
||||||
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
|
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -197,7 +197,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||||
|
|
||||||
|
|
||||||
https://github.com/jmoiron/sqlx
|
https://github.com/jmoiron/sqlx
|
||||||
|
|
||||||
Copyright (c) 2013, Jason Moiron
|
Copyright (c) 2013, Jason Moiron
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
@ -223,7 +223,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/mytrile/mime-ext
|
https://github.com/mytrile/mime-ext
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014 Dimitar Kostov
|
Copyright (c) 2014 Dimitar Kostov
|
||||||
|
@ -247,7 +247,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/nu7hatch/gouuid
|
https://github.com/nu7hatch/gouuid
|
||||||
|
|
||||||
Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch>
|
Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
@ -270,7 +270,7 @@ SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/rs/xid
|
https://github.com/rs/xid
|
||||||
|
|
||||||
Copyright (c) 2015 Olivier Poitrey <rs@dailymotion.com>
|
Copyright (c) 2015 Olivier Poitrey <rs@dailymotion.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -318,7 +318,7 @@ SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/jordan-wright/email
|
https://github.com/jordan-wright/email
|
||||||
|
|
||||||
Elements of the software in this file were modified from github.com/jordan-wright/email and
|
Elements of the software in this file were modified from github.com/jordan-wright/email and
|
||||||
are subject to the licence below:
|
are subject to the licence below:
|
||||||
|
|
||||||
|
@ -625,9 +625,9 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
https://github.com/blueimp/JavaScript-MD5
|
https://github.com/blueimp/JavaScript-MD5
|
||||||
|
|
||||||
JavaScript MD5 1.0.1
|
JavaScript MD5 1.0.1
|
||||||
|
|
||||||
Copyright 2011, Sebastian Tschan
|
Copyright 2011, Sebastian Tschan
|
||||||
https://blueimp.net
|
https://blueimp.net
|
||||||
Licensed under the MIT license:
|
Licensed under the MIT license:
|
||||||
http://www.opensource.org/licenses/MIT
|
http://www.opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
@ -834,7 +834,7 @@ such a program is covered only if its contents constitute a work based
|
||||||
on the Library (independent of the use of the Library in a tool for
|
on the Library (independent of the use of the Library in a tool for
|
||||||
writing it). Whether that is true depends on what the Library does
|
writing it). Whether that is true depends on what the Library does
|
||||||
and what the program that uses the Library does.
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
complete source code as you receive it, in any medium, provided that
|
complete source code as you receive it, in any medium, provided that
|
||||||
you conspicuously and appropriately publish on each copy an
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
@ -1471,7 +1471,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/arasatasaygin/is.js
|
https://github.com/arasatasaygin/is.js
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
@ -1853,6 +1853,7 @@ SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
gopkg.in/ldap.v2
|
gopkg.in/ldap.v2
|
||||||
|
gopkg.in/ldap.v3
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
@ -2568,4 +2569,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
12
README.md
12
README.md
|
@ -13,13 +13,13 @@ All you need to provide is PostgreSQL, Microsoft SQL Server or any MySQL variant
|
||||||
|
|
||||||
## Latest Release
|
## Latest Release
|
||||||
|
|
||||||
[Community Edition: v2.4.2](https://github.com/documize/community/releases)
|
[Community Edition: v2.5.0](https://github.com/documize/community/releases)
|
||||||
|
|
||||||
[Enterprise Edition: v2.4.2](https://www.documize.com/downloads)
|
[Enterprise Edition: v2.5.0](https://www.documize.com/downloads)
|
||||||
|
|
||||||
> *We provide frequent product updates for both cloud and self-hosted customers.*
|
> *We provide frequent product updates for both cloud and self-hosted customers.*
|
||||||
>
|
>
|
||||||
> **Harvey Kandola, CEO/Founder, Documize, Inc.**
|
> **Harvey Kandola, CEO/Founder @ Documize**
|
||||||
|
|
||||||
## OS support
|
## OS support
|
||||||
|
|
||||||
|
@ -45,17 +45,19 @@ Heck, Documize will probably run just fine on a Raspberry Pi.
|
||||||
- Brave
|
- Brave
|
||||||
- Vivaldi
|
- Vivaldi
|
||||||
- Opera
|
- Opera
|
||||||
- Edge (v42+)
|
- Microsoft Edge (v42+)
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
- Go (v1.12.4)
|
- Go (v1.12.5)
|
||||||
- Ember JS (v3.8.0)
|
- Ember JS (v3.8.0)
|
||||||
|
|
||||||
## Authentication Options
|
## Authentication Options
|
||||||
|
|
||||||
Besides email/password login, you can also connect to LDAP/Active Directory or Red Hat Keycloak server.
|
Besides email/password login, you can also connect to LDAP/Active Directory or Red Hat Keycloak server.
|
||||||
|
|
||||||
|
Dual authentication of LDAP and email/password is also supported.
|
||||||
|
|
||||||
## The Legal Bit
|
## The Legal Bit
|
||||||
|
|
||||||
<https://documize.com>
|
<https://documize.com>
|
||||||
|
|
|
@ -278,8 +278,6 @@ func (h *Handler) Authenticate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
dom = h.Store.Organization.CheckDomain(ctx, dom) // TODO optimize by removing this once js allows empty domains
|
dom = h.Store.Organization.CheckDomain(ctx, dom) // TODO optimize by removing this once js allows empty domains
|
||||||
|
|
||||||
h.Runtime.Log.Info("LDAP login request " + username + " @ " + dom)
|
|
||||||
|
|
||||||
// Get the org and it's associated LDAP config.
|
// Get the org and it's associated LDAP config.
|
||||||
org, err := h.Store.Organization.GetOrganizationByDomain(dom)
|
org, err := h.Store.Organization.GetOrganizationByDomain(dom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -298,6 +296,13 @@ func (h *Handler) Authenticate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
ctx.OrgID = org.RefID
|
ctx.OrgID = org.RefID
|
||||||
|
|
||||||
|
// We first connect to LDAP and try to authenticate user.
|
||||||
|
// If user auth fails and dual authentication is enabled,
|
||||||
|
// we try to authenticate with email/password combo.
|
||||||
|
var u user.User
|
||||||
|
|
||||||
|
// Try LDAP
|
||||||
|
h.Runtime.Log.Info("LDAP login request " + username + " @ " + dom)
|
||||||
l, err := connect(lc)
|
l, err := connect(lc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.WriteBadRequestError(w, method, "unable to dial LDAP server")
|
response.WriteBadRequestError(w, method, "unable to dial LDAP server")
|
||||||
|
@ -305,49 +310,83 @@ func (h *Handler) Authenticate(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
lu, ok, err := authenticate(l, lc, username, password)
|
lu, ok, err := authenticate(l, lc, username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.WriteBadRequestError(w, method, "error during LDAP authentication")
|
response.WriteBadRequestError(w, method, "error during LDAP authentication")
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ok {
|
|
||||||
h.Runtime.Log.Info("LDAP failed login request for " + username + " @ " + dom)
|
|
||||||
response.WriteUnauthorizedError(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Runtime.Log.Info("LDAP logon completed " + lu.Email)
|
// If OK then we complete LDAP specific processing
|
||||||
|
if ok {
|
||||||
|
h.Runtime.Log.Info("LDAP logon completed " + lu.Email)
|
||||||
|
|
||||||
u, err := h.Store.User.GetByDomain(ctx, dom, lu.Email)
|
u, err = h.Store.User.GetByDomain(ctx, dom, lu.Email)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
response.WriteServerError(w, method, err)
|
|
||||||
h.Runtime.Log.Error(method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create user account if not found
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
h.Runtime.Log.Info("Adding new LDAP user " + lu.Email + " @ " + dom)
|
|
||||||
|
|
||||||
u = convertUser(lc, lu)
|
|
||||||
u.Salt = secrets.GenerateSalt()
|
|
||||||
u.Password = secrets.GeneratePassword(secrets.GenerateRandomPassword(), u.Salt)
|
|
||||||
|
|
||||||
u, err = auth.AddExternalUser(ctx, h.Runtime, h.Store, u, lc.DefaultPermissionAddSpace)
|
|
||||||
if err != nil {
|
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create user account if not found
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
h.Runtime.Log.Info("Adding new LDAP user " + lu.Email + " @ " + dom)
|
||||||
|
|
||||||
|
u = convertUser(lc, lu)
|
||||||
|
u.Salt = secrets.GenerateSalt()
|
||||||
|
u.Password = secrets.GeneratePassword(secrets.GenerateRandomPassword(), u.Salt)
|
||||||
|
|
||||||
|
u, err = auth.AddExternalUser(ctx, h.Runtime, h.Store, u, lc.DefaultPermissionAddSpace)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If LDAP authentication failed, we check to see if we are allowed
|
||||||
|
// to perform authentication via regular email/password.
|
||||||
|
if !ok {
|
||||||
|
// Return as unauthorized if dual authentication not enabled.
|
||||||
|
if !lc.AllowFormsAuth {
|
||||||
|
h.Runtime.Log.Info("LDAP failed login request for " + username + " @ " + dom)
|
||||||
|
response.WriteUnauthorizedError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Runtime.Log.Info("Trying forms auth as LDAP login login failed for " + username + " @ " + dom)
|
||||||
|
|
||||||
|
// Now try regular email/password authentication.
|
||||||
|
u, err = h.Store.User.GetByDomain(ctx, dom, username)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
response.WriteUnauthorizedError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
h.Runtime.Log.Error("unable to fetch user", err)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(u.Reset) > 0 || len(u.Password) == 0 {
|
||||||
|
response.WriteUnauthorizedError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Password correct and active user
|
||||||
|
if username != strings.TrimSpace(strings.ToLower(u.Email)) || !secrets.MatchPassword(u.Password, password, u.Salt) {
|
||||||
|
response.WriteUnauthorizedError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Below is standard flow for user authentication regardless
|
||||||
|
// if they used LDAP or email/password combo.
|
||||||
|
|
||||||
// Attach user accounts and work out permissions.
|
// Attach user accounts and work out permissions.
|
||||||
usr.AttachUserAccounts(ctx, *h.Store, org.RefID, &u)
|
usr.AttachUserAccounts(ctx, *h.Store, org.RefID, &u)
|
||||||
|
|
||||||
// No accounts signals data integrity problem
|
// No accounts signals data integrity problem so we reject login request.
|
||||||
// so we reject login request.
|
|
||||||
if len(u.Accounts) == 0 {
|
if len(u.Accounts) == 0 {
|
||||||
response.WriteUnauthorizedError(w)
|
response.WriteUnauthorizedError(w)
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
|
@ -366,7 +405,7 @@ func (h *Handler) Authenticate(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate JWT token
|
// Send back newly generated JWT token.
|
||||||
authModel := ath.AuthenticationModel{}
|
authModel := ath.AuthenticationModel{}
|
||||||
authModel.Token = auth.GenerateJWT(h.Runtime, u.RefID, org.RefID, dom)
|
authModel.Token = auth.GenerateJWT(h.Runtime, u.RefID, org.RefID, dom)
|
||||||
authModel.User = u
|
authModel.User = u
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
lm "github.com/documize/community/model/auth"
|
lm "github.com/documize/community/model/auth"
|
||||||
"github.com/documize/community/model/user"
|
"github.com/documize/community/model/user"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
ld "gopkg.in/ldap.v2"
|
ld "gopkg.in/ldap.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Connect establishes connection to LDAP server.
|
// Connect establishes connection to LDAP server.
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"ignore_dirs": ["tmp", "dist", "dist-prod"]
|
"ignore_dirs": ["tmp", "dist", "dist-prod", "tests", "node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,7 @@ export default Component.extend(ModalMixin, Notifier, {
|
||||||
ldapConfig = JSON.parse(ldapConfig);
|
ldapConfig = JSON.parse(ldapConfig);
|
||||||
ldapConfig.defaultPermissionAddSpace = ldapConfig.hasOwnProperty('defaultPermissionAddSpace') ? ldapConfig.defaultPermissionAddSpace : false;
|
ldapConfig.defaultPermissionAddSpace = ldapConfig.hasOwnProperty('defaultPermissionAddSpace') ? ldapConfig.defaultPermissionAddSpace : false;
|
||||||
ldapConfig.disableLogout = ldapConfig.hasOwnProperty('disableLogout') ? ldapConfig.disableLogout : true;
|
ldapConfig.disableLogout = ldapConfig.hasOwnProperty('disableLogout') ? ldapConfig.disableLogout : true;
|
||||||
|
ldapConfig.allowFormsAuth = ldapConfig.hasOwnProperty('allowFormsAuth') ? ldapConfig.allowFormsAuth : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('ldapConfig', ldapConfig);
|
this.set('ldapConfig', ldapConfig);
|
||||||
|
|
|
@ -15,8 +15,9 @@ import Mixin from '@ember/object/mixin';
|
||||||
export default Mixin.create({
|
export default Mixin.create({
|
||||||
appMeta: service(),
|
appMeta: service(),
|
||||||
isAuthProviderDocumize: true,
|
isAuthProviderDocumize: true,
|
||||||
IsAuthProviderKeycloak: false,
|
isAuthProviderKeycloak: false,
|
||||||
IsAuthProviderLDAP: false,
|
isAuthProviderLDAP: false,
|
||||||
|
isDualAuth: false,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -25,5 +26,16 @@ export default Mixin.create({
|
||||||
this.set('isAuthProviderDocumize', this.get('appMeta.authProvider') === constants.AuthProvider.Documize);
|
this.set('isAuthProviderDocumize', this.get('appMeta.authProvider') === constants.AuthProvider.Documize);
|
||||||
this.set('isAuthProviderKeycloak', this.get('appMeta.authProvider') === constants.AuthProvider.Keycloak);
|
this.set('isAuthProviderKeycloak', this.get('appMeta.authProvider') === constants.AuthProvider.Keycloak);
|
||||||
this.set('isAuthProviderLDAP', this.get('appMeta.authProvider') === constants.AuthProvider.LDAP);
|
this.set('isAuthProviderLDAP', this.get('appMeta.authProvider') === constants.AuthProvider.LDAP);
|
||||||
|
|
||||||
|
if (this.get('appMeta.authProvider') === constants.AuthProvider.LDAP) {
|
||||||
|
let config = this.get('appMeta.authConfig');
|
||||||
|
|
||||||
|
if (!_.isUndefined(config) && !_.isNull(config) && !_.isEmpty(config) ) {
|
||||||
|
config = JSON.parse(config);
|
||||||
|
this.set('isDualAuth', config.allowFormsAuth);
|
||||||
|
} else {
|
||||||
|
this.set('isDualAuth', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
{{focus-input type="email" value=email id="authEmail" class="form-control mousetrap" placeholder="" autocomplete="username email"}}
|
{{focus-input type="email" value=email id="authEmail" class="form-control mousetrap" placeholder="" autocomplete="username email"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isAuthProviderLDAP}}
|
{{#if isAuthProviderLDAP}}
|
||||||
<label for="authUsername">Network Username</label>
|
<label for="authUsername">Username</label>
|
||||||
{{focus-input type="text" value=username id="authUsername" class="form-control mousetrap" placeholder="network domain username" autocomplete="username"}}
|
{{focus-input type="text" value=username id="authUsername" class="form-control mousetrap" placeholder="network domain username" autocomplete="username"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
{{input type="password" value=password id="authPassword" class="form-control" autocomplete="current-password"}}
|
{{input type="password" value=password id="authPassword" class="form-control" autocomplete="current-password"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isAuthProviderLDAP}}
|
{{#if isAuthProviderLDAP}}
|
||||||
<label for="authPassword">Network Password</label>
|
<label for="authPassword">Password</label>
|
||||||
{{input type="password" value=password id="authPassword" class="form-control" autocomplete="current-password"}}
|
{{input type="password" value=password id="authPassword" class="form-control" autocomplete="current-password"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
https://github.com/gorilla/context
|
https://github.com/gorilla/context
|
||||||
https://github.com/gorilla/mux
|
https://github.com/gorilla/mux
|
||||||
|
|
||||||
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
|
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -199,7 +199,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||||
|
|
||||||
|
|
||||||
https://github.com/jmoiron/sqlx
|
https://github.com/jmoiron/sqlx
|
||||||
|
|
||||||
Copyright (c) 2013, Jason Moiron
|
Copyright (c) 2013, Jason Moiron
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
@ -225,7 +225,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/mytrile/mime-ext
|
https://github.com/mytrile/mime-ext
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014 Dimitar Kostov
|
Copyright (c) 2014 Dimitar Kostov
|
||||||
|
@ -249,7 +249,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/nu7hatch/gouuid
|
https://github.com/nu7hatch/gouuid
|
||||||
|
|
||||||
Copyright (C) 2011 by Krzysztof Kowalik chris@nu7hat.ch
|
Copyright (C) 2011 by Krzysztof Kowalik chris@nu7hat.ch
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
@ -272,7 +272,7 @@ SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/rs/xid
|
https://github.com/rs/xid
|
||||||
|
|
||||||
Copyright (c) 2015 Olivier Poitrey rs@dailymotion.com
|
Copyright (c) 2015 Olivier Poitrey rs@dailymotion.com
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -320,7 +320,7 @@ SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/jordan-wright/email
|
https://github.com/jordan-wright/email
|
||||||
|
|
||||||
Elements of the software in this file were modified from github.com/jordan-wright/email and
|
Elements of the software in this file were modified from github.com/jordan-wright/email and
|
||||||
are subject to the licence below:
|
are subject to the licence below:
|
||||||
|
|
||||||
|
@ -627,9 +627,9 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
https://github.com/blueimp/JavaScript-MD5
|
https://github.com/blueimp/JavaScript-MD5
|
||||||
|
|
||||||
JavaScript MD5 1.0.1
|
JavaScript MD5 1.0.1
|
||||||
|
|
||||||
Copyright 2011, Sebastian Tschan
|
Copyright 2011, Sebastian Tschan
|
||||||
https://blueimp.net
|
https://blueimp.net
|
||||||
Licensed under the MIT license:
|
Licensed under the MIT license:
|
||||||
http://www.opensource.org/licenses/MIT
|
http://www.opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
@ -836,7 +836,7 @@ such a program is covered only if its contents constitute a work based
|
||||||
on the Library (independent of the use of the Library in a tool for
|
on the Library (independent of the use of the Library in a tool for
|
||||||
writing it). Whether that is true depends on what the Library does
|
writing it). Whether that is true depends on what the Library does
|
||||||
and what the program that uses the Library does.
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Librarys
|
1. You may copy and distribute verbatim copies of the Librarys
|
||||||
complete source code as you receive it, in any medium, provided that
|
complete source code as you receive it, in any medium, provided that
|
||||||
you conspicuously and appropriately publish on each copy an
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
@ -1473,7 +1473,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/arasatasaygin/is.js
|
https://github.com/arasatasaygin/is.js
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
@ -1855,6 +1855,7 @@ SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
gopkg.in/ldap.v2
|
gopkg.in/ldap.v2
|
||||||
|
gopkg.in/ldap.v3
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,11 @@
|
||||||
<label for="ldap-defaultPermissionAddSpace">Can Create Spaces</label>
|
<label for="ldap-defaultPermissionAddSpace">Can Create Spaces</label>
|
||||||
{{x-toggle value=ldapConfig.defaultPermissionAddSpace size="medium" theme="light" onToggle=(action (mut ldapConfig.defaultPermissionAddSpace))}}
|
{{x-toggle value=ldapConfig.defaultPermissionAddSpace size="medium" theme="light" onToggle=(action (mut ldapConfig.defaultPermissionAddSpace))}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ldap-allowFormsAuth">Dual Login</label>
|
||||||
|
{{x-toggle value=ldapConfig.allowFormsAuth size="medium" theme="light" onToggle=(action (mut ldapConfig.allowFormsAuth))}}
|
||||||
|
<small class="form-text text-muted">Enable login via LDAP and regular Documize email/password (useful for testing LDAP)</small>
|
||||||
|
</div>
|
||||||
{{ui/ui-button color=constants.Color.Yellow light=true label="Test →" onClick=(action "onLDAPPreview")}}
|
{{ui/ui-button color=constants.Color.Yellow light=true label="Test →" onClick=(action "onLDAPPreview")}}
|
||||||
{{ui/ui-button-gap}}
|
{{ui/ui-button-gap}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="view-customize">
|
<div class="view-customize">
|
||||||
{{#if isAuthProviderDocumize}}
|
{{#if (or isAuthProviderDocumize IsDualAuth)}}
|
||||||
{{ui/ui-button color=constants.Color.Green light=true icon=constants.Icon.Person label=constants.Label.Add onClick=(action "onOpenUserModal")}}
|
{{ui/ui-button color=constants.Color.Green light=true icon=constants.Icon.Person label=constants.Label.Add onClick=(action "onOpenUserModal")}}
|
||||||
<div id="add-user-modal" class="modal" tabindex="-1" role="dialog">
|
<div id="add-user-modal" class="modal" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="view-customize">
|
<div class="view-customize">
|
||||||
{{#if isAuthProviderKeycloak}}
|
{{#if (or isAuthProviderKeycloak isDualAuth)}}
|
||||||
{{ui/ui-spacer size=300}}
|
{{ui/ui-spacer size=300}}
|
||||||
{{#if syncInProgress}}
|
{{#if syncInProgress}}
|
||||||
{{ui/ui-button color=constants.Color.Gray light=true icon=constants.Icon.Locked label="Keycloak user sync running..."}}
|
{{ui/ui-button color=constants.Color.Gray light=true icon=constants.Icon.Locked label="Keycloak user sync running..."}}
|
||||||
|
@ -187,7 +187,7 @@
|
||||||
<label for="edit-email">Email</label>
|
<label for="edit-email">Email</label>
|
||||||
{{input id="edit-email" type="text" class="form-control" value=editUser.email}}
|
{{input id="edit-email" type="text" class="form-control" value=editUser.email}}
|
||||||
</div>
|
</div>
|
||||||
{{#if isAuthProviderDocumize}}
|
{{#if (or isAuthProviderDocumize IsDualAuth)}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="edit-password">Password</label>
|
<label for="edit-password">Password</label>
|
||||||
{{input id="edit-password" type="password" class="form-control" value=password.password}}
|
{{input id="edit-password" type="password" class="form-control" value=password.password}}
|
||||||
|
|
|
@ -44,6 +44,7 @@ type LDAPConfig struct {
|
||||||
GroupFilter string `json:"groupFilter"`
|
GroupFilter string `json:"groupFilter"`
|
||||||
DisableLogout bool `json:"disableLogout"`
|
DisableLogout bool `json:"disableLogout"`
|
||||||
DefaultPermissionAddSpace bool `json:"defaultPermissionAddSpace"`
|
DefaultPermissionAddSpace bool `json:"defaultPermissionAddSpace"`
|
||||||
|
AllowFormsAuth bool `json:"allowFormsAuth"` // enable dual login via LDAP + email/password
|
||||||
AttributeUserRDN string `json:"attributeUserRDN"` // usually uid (LDAP) or sAMAccountName (AD)
|
AttributeUserRDN string `json:"attributeUserRDN"` // usually uid (LDAP) or sAMAccountName (AD)
|
||||||
AttributeUserFirstname string `json:"attributeUserFirstname"` // usually givenName
|
AttributeUserFirstname string `json:"attributeUserFirstname"` // usually givenName
|
||||||
AttributeUserLastname string `json:"attributeUserLastname"` // usually sn
|
AttributeUserLastname string `json:"attributeUserLastname"` // usually sn
|
||||||
|
|
31
vendor/gopkg.in/ldap.v2/.travis.yml
generated
vendored
31
vendor/gopkg.in/ldap.v2/.travis.yml
generated
vendored
|
@ -1,31 +0,0 @@
|
||||||
language: go
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- VET_VERSIONS="1.6 1.7 1.8 1.9 tip"
|
|
||||||
- LINT_VERSIONS="1.6 1.7 1.8 1.9 tip"
|
|
||||||
go:
|
|
||||||
- 1.2
|
|
||||||
- 1.3
|
|
||||||
- 1.4
|
|
||||||
- 1.5
|
|
||||||
- 1.6
|
|
||||||
- 1.7
|
|
||||||
- 1.8
|
|
||||||
- 1.9
|
|
||||||
- tip
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
allow_failures:
|
|
||||||
- go: 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 get github.com/golang/lint/golint || true
|
|
||||||
- go build -v ./...
|
|
||||||
script:
|
|
||||||
- make test
|
|
||||||
- make fmt
|
|
||||||
- if [[ "$VET_VERSIONS" == *"$TRAVIS_GO_VERSION"* ]]; then make vet; fi
|
|
||||||
- if [[ "$LINT_VERSIONS" == *"$TRAVIS_GO_VERSION"* ]]; then make lint; fi
|
|
52
vendor/gopkg.in/ldap.v2/Makefile
generated
vendored
52
vendor/gopkg.in/ldap.v2/Makefile
generated
vendored
|
@ -1,52 +0,0 @@
|
||||||
.PHONY: default install build test quicktest fmt vet lint
|
|
||||||
|
|
||||||
GO_VERSION := $(shell go version | cut -d' ' -f3 | cut -d. -f2)
|
|
||||||
|
|
||||||
# Only use the `-race` flag on newer versions of Go
|
|
||||||
IS_OLD_GO := $(shell test $(GO_VERSION) -le 2 && echo true)
|
|
||||||
ifeq ($(IS_OLD_GO),true)
|
|
||||||
RACE_FLAG :=
|
|
||||||
else
|
|
||||||
RACE_FLAG := -race -cpu 1,2,4
|
|
||||||
endif
|
|
||||||
|
|
||||||
default: fmt vet lint build quicktest
|
|
||||||
|
|
||||||
install:
|
|
||||||
go get -t -v ./...
|
|
||||||
|
|
||||||
build:
|
|
||||||
go build -v ./...
|
|
||||||
|
|
||||||
test:
|
|
||||||
go test -v $(RACE_FLAG) -cover ./...
|
|
||||||
|
|
||||||
quicktest:
|
|
||||||
go test ./...
|
|
||||||
|
|
||||||
# Capture output and force failure when there is non-empty output
|
|
||||||
fmt:
|
|
||||||
@echo gofmt -l .
|
|
||||||
@OUTPUT=`gofmt -l . 2>&1`; \
|
|
||||||
if [ "$$OUTPUT" ]; then \
|
|
||||||
echo "gofmt must be run on the following files:"; \
|
|
||||||
echo "$$OUTPUT"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Only run on go1.5+
|
|
||||||
vet:
|
|
||||||
go tool vet -atomic -bool -copylocks -nilfunc -printf -shadow -rangeloops -unreachable -unsafeptr -unusedresult .
|
|
||||||
|
|
||||||
# https://github.com/golang/lint
|
|
||||||
# go get github.com/golang/lint/golint
|
|
||||||
# Capture output and force failure when there is non-empty output
|
|
||||||
# Only run on go1.5+
|
|
||||||
lint:
|
|
||||||
@echo golint ./...
|
|
||||||
@OUTPUT=`golint ./... 2>&1`; \
|
|
||||||
if [ "$$OUTPUT" ]; then \
|
|
||||||
echo "golint errors:"; \
|
|
||||||
echo "$$OUTPUT"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
13
vendor/gopkg.in/ldap.v2/atomic_value.go
generated
vendored
13
vendor/gopkg.in/ldap.v2/atomic_value.go
generated
vendored
|
@ -1,13 +0,0 @@
|
||||||
// +build go1.4
|
|
||||||
|
|
||||||
package ldap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync/atomic"
|
|
||||||
)
|
|
||||||
|
|
||||||
// For compilers that support it, we just use the underlying sync/atomic.Value
|
|
||||||
// type.
|
|
||||||
type atomicValue struct {
|
|
||||||
atomic.Value
|
|
||||||
}
|
|
28
vendor/gopkg.in/ldap.v2/atomic_value_go13.go
generated
vendored
28
vendor/gopkg.in/ldap.v2/atomic_value_go13.go
generated
vendored
|
@ -1,28 +0,0 @@
|
||||||
// +build !go1.4
|
|
||||||
|
|
||||||
package ldap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a helper type that emulates the use of the "sync/atomic.Value"
|
|
||||||
// struct that's available in Go 1.4 and up.
|
|
||||||
type atomicValue struct {
|
|
||||||
value interface{}
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (av *atomicValue) Store(val interface{}) {
|
|
||||||
av.lock.Lock()
|
|
||||||
av.value = val
|
|
||||||
av.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (av *atomicValue) Load() interface{} {
|
|
||||||
av.lock.RLock()
|
|
||||||
ret := av.value
|
|
||||||
av.lock.RUnlock()
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
155
vendor/gopkg.in/ldap.v2/error.go
generated
vendored
155
vendor/gopkg.in/ldap.v2/error.go
generated
vendored
|
@ -1,155 +0,0 @@
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
// LDAPResultCodeMap contains string descriptions for LDAP error codes
|
|
||||||
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",
|
|
||||||
|
|
||||||
ErrorNetwork: "Network Error",
|
|
||||||
ErrorFilterCompile: "Filter Compile Error",
|
|
||||||
ErrorFilterDecompile: "Filter Decompile Error",
|
|
||||||
ErrorDebugging: "Debugging Error",
|
|
||||||
ErrorUnexpectedMessage: "Unexpected Message",
|
|
||||||
ErrorUnexpectedResponse: "Unexpected Response",
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
|
|
||||||
if packet == nil {
|
|
||||||
return ErrorUnexpectedResponse, "Empty packet"
|
|
||||||
} else if len(packet.Children) >= 2 {
|
|
||||||
response := packet.Children[1]
|
|
||||||
if response == nil {
|
|
||||||
return ErrorUnexpectedResponse, "Empty response in packet"
|
|
||||||
}
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error holds LDAP error information
|
|
||||||
type Error struct {
|
|
||||||
// Err is the underlying error
|
|
||||||
Err error
|
|
||||||
// ResultCode is the LDAP error code
|
|
||||||
ResultCode uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewError creates an LDAP error with the given code and underlying error
|
|
||||||
func NewError(resultCode uint8, err error) error {
|
|
||||||
return &Error{ResultCode: resultCode, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
|
|
||||||
func IsErrorWithCode(err error, desiredResultCode uint8) bool {
|
|
||||||
if err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
serverError, ok := err.(*Error)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return serverError.ResultCode == desiredResultCode
|
|
||||||
}
|
|
0
vendor/gopkg.in/ldap.v2/.gitignore → vendor/gopkg.in/ldap.v3/.gitignore
generated
vendored
0
vendor/gopkg.in/ldap.v2/.gitignore → vendor/gopkg.in/ldap.v3/.gitignore
generated
vendored
31
vendor/gopkg.in/ldap.v3/.travis.yml
generated
vendored
Normal file
31
vendor/gopkg.in/ldap.v3/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.5.x"
|
||||||
|
- "1.6.x"
|
||||||
|
- "1.7.x"
|
||||||
|
- "1.8.x"
|
||||||
|
- "1.9.x"
|
||||||
|
- "1.10.x"
|
||||||
|
- "1.11.x"
|
||||||
|
- "1.12.x"
|
||||||
|
- tip
|
||||||
|
|
||||||
|
git:
|
||||||
|
depth: 1
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
go_import_path: gopkg.in/ldap.v3
|
||||||
|
install:
|
||||||
|
- go get gopkg.in/asn1-ber.v1
|
||||||
|
- go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover
|
||||||
|
- go get github.com/golang/lint/golint || go get golang.org/x/lint/golint || true
|
||||||
|
- go build -v ./...
|
||||||
|
script:
|
||||||
|
- make test
|
||||||
|
- make fmt
|
||||||
|
- make vet
|
||||||
|
- make lint
|
12
vendor/gopkg.in/ldap.v3/CONTRIBUTING.md
generated
vendored
Normal file
12
vendor/gopkg.in/ldap.v3/CONTRIBUTING.md
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Contribution Guidelines
|
||||||
|
|
||||||
|
We welcome contribution and improvements.
|
||||||
|
|
||||||
|
## Guiding Principles
|
||||||
|
|
||||||
|
To begin with here is a draft from an email exchange:
|
||||||
|
|
||||||
|
* take compatibility seriously (our semvers, compatibility with older go versions, etc)
|
||||||
|
* don't tag untested code for release
|
||||||
|
* beware of baking in implicit behavior based on other libraries/tools choices
|
||||||
|
* be as high-fidelity as possible in plumbing through LDAP data (don't mask errors or reduce power of someone using the library)
|
0
vendor/gopkg.in/ldap.v2/LICENSE → vendor/gopkg.in/ldap.v3/LICENSE
generated
vendored
0
vendor/gopkg.in/ldap.v2/LICENSE → vendor/gopkg.in/ldap.v3/LICENSE
generated
vendored
82
vendor/gopkg.in/ldap.v3/Makefile
generated
vendored
Normal file
82
vendor/gopkg.in/ldap.v3/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
.PHONY: default install build test quicktest fmt vet lint
|
||||||
|
|
||||||
|
# List of all release tags "supported" by our current Go version
|
||||||
|
# E.g. ":go1.1:go1.2:go1.3:go1.4:go1.5:go1.6:go1.7:go1.8:go1.9:go1.10:go1.11:go1.12:"
|
||||||
|
GO_RELEASE_TAGS := $(shell go list -f ':{{join (context.ReleaseTags) ":"}}:' runtime)
|
||||||
|
|
||||||
|
# Only use the `-race` flag on newer versions of Go (version 1.3 and newer)
|
||||||
|
ifeq (,$(findstring :go1.3:,$(GO_RELEASE_TAGS)))
|
||||||
|
RACE_FLAG :=
|
||||||
|
else
|
||||||
|
RACE_FLAG := -race -cpu 1,2,4
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Run `go vet` on Go 1.12 and newer. For Go 1.5-1.11, use `go tool vet`
|
||||||
|
ifneq (,$(findstring :go1.12:,$(GO_RELEASE_TAGS)))
|
||||||
|
GO_VET := go vet \
|
||||||
|
-atomic \
|
||||||
|
-bool \
|
||||||
|
-copylocks \
|
||||||
|
-nilfunc \
|
||||||
|
-printf \
|
||||||
|
-rangeloops \
|
||||||
|
-unreachable \
|
||||||
|
-unsafeptr \
|
||||||
|
-unusedresult \
|
||||||
|
.
|
||||||
|
else ifneq (,$(findstring :go1.5:,$(GO_RELEASE_TAGS)))
|
||||||
|
GO_VET := go tool vet \
|
||||||
|
-atomic \
|
||||||
|
-bool \
|
||||||
|
-copylocks \
|
||||||
|
-nilfunc \
|
||||||
|
-printf \
|
||||||
|
-shadow \
|
||||||
|
-rangeloops \
|
||||||
|
-unreachable \
|
||||||
|
-unsafeptr \
|
||||||
|
-unusedresult \
|
||||||
|
.
|
||||||
|
else
|
||||||
|
GO_VET := @echo "go vet skipped -- not supported on this version of Go"
|
||||||
|
endif
|
||||||
|
|
||||||
|
default: fmt vet lint build quicktest
|
||||||
|
|
||||||
|
install:
|
||||||
|
go get -t -v ./...
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -v ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -v $(RACE_FLAG) -cover ./...
|
||||||
|
|
||||||
|
quicktest:
|
||||||
|
go test ./...
|
||||||
|
|
||||||
|
# Capture output and force failure when there is non-empty output
|
||||||
|
fmt:
|
||||||
|
@echo gofmt -l .
|
||||||
|
@OUTPUT=`gofmt -l . 2>&1`; \
|
||||||
|
if [ "$$OUTPUT" ]; then \
|
||||||
|
echo "gofmt must be run on the following files:"; \
|
||||||
|
echo "$$OUTPUT"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
vet:
|
||||||
|
$(GO_VET)
|
||||||
|
|
||||||
|
# https://github.com/golang/lint
|
||||||
|
# go get github.com/golang/lint/golint
|
||||||
|
# Capture output and force failure when there is non-empty output
|
||||||
|
# Only run on go1.5+
|
||||||
|
lint:
|
||||||
|
@echo golint ./...
|
||||||
|
@OUTPUT=`command -v golint >/dev/null 2>&1 && golint ./... 2>&1`; \
|
||||||
|
if [ "$$OUTPUT" ]; then \
|
||||||
|
echo "golint errors:"; \
|
||||||
|
echo "$$OUTPUT"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
7
vendor/gopkg.in/ldap.v2/README.md → vendor/gopkg.in/ldap.v3/README.md
generated
vendored
7
vendor/gopkg.in/ldap.v2/README.md → vendor/gopkg.in/ldap.v3/README.md
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
[](https://godoc.org/gopkg.in/ldap.v2)
|
[](https://godoc.org/gopkg.in/ldap.v3)
|
||||||
[](https://travis-ci.org/go-ldap/ldap)
|
[](https://travis-ci.org/go-ldap/ldap)
|
||||||
|
|
||||||
# Basic LDAP v3 functionality for the GO programming language.
|
# Basic LDAP v3 functionality for the GO programming language.
|
||||||
|
@ -7,11 +7,11 @@
|
||||||
|
|
||||||
For the latest version use:
|
For the latest version use:
|
||||||
|
|
||||||
go get gopkg.in/ldap.v2
|
go get gopkg.in/ldap.v3
|
||||||
|
|
||||||
Import the latest version with:
|
Import the latest version with:
|
||||||
|
|
||||||
import "gopkg.in/ldap.v2"
|
import "gopkg.in/ldap.v3"
|
||||||
|
|
||||||
## Required Libraries:
|
## Required Libraries:
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ Import the latest version with:
|
||||||
- Modify Requests / Responses
|
- Modify Requests / Responses
|
||||||
- Add Requests / Responses
|
- Add Requests / Responses
|
||||||
- Delete Requests / Responses
|
- Delete Requests / Responses
|
||||||
|
- Modify DN Requests / Responses
|
||||||
|
|
||||||
## Examples:
|
## Examples:
|
||||||
|
|
16
vendor/gopkg.in/ldap.v2/add.go → vendor/gopkg.in/ldap.v3/add.go
generated
vendored
16
vendor/gopkg.in/ldap.v2/add.go → vendor/gopkg.in/ldap.v3/add.go
generated
vendored
|
@ -41,6 +41,8 @@ type AddRequest struct {
|
||||||
DN string
|
DN string
|
||||||
// Attributes list the attributes of the new entry
|
// Attributes list the attributes of the new entry
|
||||||
Attributes []Attribute
|
Attributes []Attribute
|
||||||
|
// Controls hold optional controls to send with the request
|
||||||
|
Controls []Control
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AddRequest) encode() *ber.Packet {
|
func (a AddRequest) encode() *ber.Packet {
|
||||||
|
@ -60,9 +62,10 @@ func (a *AddRequest) Attribute(attrType string, attrVals []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAddRequest returns an AddRequest for the given DN, with no attributes
|
// NewAddRequest returns an AddRequest for the given DN, with no attributes
|
||||||
func NewAddRequest(dn string) *AddRequest {
|
func NewAddRequest(dn string, controls []Control) *AddRequest {
|
||||||
return &AddRequest{
|
return &AddRequest{
|
||||||
DN: dn,
|
DN: dn,
|
||||||
|
Controls: controls,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -72,6 +75,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
|
||||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
packet.AppendChild(addRequest.encode())
|
packet.AppendChild(addRequest.encode())
|
||||||
|
if len(addRequest.Controls) > 0 {
|
||||||
|
packet.AppendChild(encodeControls(addRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
l.Debug.PrintPacket(packet)
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
@ -100,9 +106,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationAddResponse {
|
if packet.Children[1].Tag == ApplicationAddResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return NewError(resultCode, errors.New(resultDescription))
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
108
vendor/gopkg.in/ldap.v2/bind.go → vendor/gopkg.in/ldap.v3/bind.go
generated
vendored
108
vendor/gopkg.in/ldap.v2/bind.go → vendor/gopkg.in/ldap.v3/bind.go
generated
vendored
|
@ -1,11 +1,8 @@
|
||||||
// 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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gopkg.in/asn1-ber.v1"
|
"gopkg.in/asn1-ber.v1"
|
||||||
)
|
)
|
||||||
|
@ -18,6 +15,9 @@ type SimpleBindRequest struct {
|
||||||
Password string
|
Password string
|
||||||
// Controls are optional controls to send with the bind request
|
// Controls are optional controls to send with the bind request
|
||||||
Controls []Control
|
Controls []Control
|
||||||
|
// AllowEmptyPassword sets whether the client allows binding with an empty password
|
||||||
|
// (normally used for unauthenticated bind).
|
||||||
|
AllowEmptyPassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleBindResult contains the response from the server
|
// SimpleBindResult contains the response from the server
|
||||||
|
@ -28,9 +28,10 @@ type SimpleBindResult struct {
|
||||||
// NewSimpleBindRequest returns a bind request
|
// NewSimpleBindRequest returns a bind request
|
||||||
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
|
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
|
||||||
return &SimpleBindRequest{
|
return &SimpleBindRequest{
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
Controls: controls,
|
Controls: controls,
|
||||||
|
AllowEmptyPassword: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,17 +41,22 @@ func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
|
||||||
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
|
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(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
|
||||||
|
|
||||||
request.AppendChild(encodeControls(bindRequest.Controls))
|
|
||||||
|
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleBind performs the simple bind operation defined in the given request
|
// SimpleBind performs the simple bind operation defined in the given request
|
||||||
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
|
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
|
||||||
|
if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
|
||||||
|
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
|
||||||
|
}
|
||||||
|
|
||||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
encodedBindRequest := simpleBindRequest.encode()
|
encodedBindRequest := simpleBindRequest.encode()
|
||||||
packet.AppendChild(encodedBindRequest)
|
packet.AppendChild(encodedBindRequest)
|
||||||
|
if len(simpleBindRequest.Controls) > 0 {
|
||||||
|
packet.AppendChild(encodeControls(simpleBindRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
if l.Debug {
|
if l.Debug {
|
||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
|
@ -73,7 +79,7 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Debug {
|
if l.Debug {
|
||||||
if err := addLDAPDescriptions(packet); err != nil {
|
if err = addLDAPDescriptions(packet); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
|
@ -85,59 +91,45 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
|
||||||
|
|
||||||
if len(packet.Children) == 3 {
|
if len(packet.Children) == 3 {
|
||||||
for _, child := range packet.Children[2].Children {
|
for _, child := range packet.Children[2].Children {
|
||||||
result.Controls = append(result.Controls, DecodeControl(child))
|
decodedChild, decodeErr := DecodeControl(child)
|
||||||
|
if decodeErr != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
|
||||||
|
}
|
||||||
|
result.Controls = append(result.Controls, decodedChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err = GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
return result, err
|
||||||
return result, NewError(resultCode, errors.New(resultDescription))
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind performs a bind with the given username and password
|
// Bind performs a bind with the given username and password.
|
||||||
|
//
|
||||||
|
// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
|
||||||
|
// for that.
|
||||||
func (l *Conn) Bind(username, password string) error {
|
func (l *Conn) Bind(username, password string) error {
|
||||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
req := &SimpleBindRequest{
|
||||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
Username: username,
|
||||||
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
Password: password,
|
||||||
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
AllowEmptyPassword: false,
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
_, err := l.SimpleBind(req)
|
||||||
msgCtx, err := l.sendMessage(packet)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
// UnauthenticatedBind performs an unauthenticated bind.
|
||||||
defer l.finishMessage(msgCtx)
|
//
|
||||||
|
// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
|
||||||
packetResponse, ok := <-msgCtx.responses
|
// authenticated or otherwise validated by the LDAP server.
|
||||||
if !ok {
|
//
|
||||||
return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
|
// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
|
||||||
}
|
// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
|
||||||
packet, err = packetResponse.ReadPacket()
|
func (l *Conn) UnauthenticatedBind(username string) error {
|
||||||
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
|
req := &SimpleBindRequest{
|
||||||
if err != nil {
|
Username: username,
|
||||||
return err
|
Password: "",
|
||||||
}
|
AllowEmptyPassword: true,
|
||||||
|
}
|
||||||
if l.Debug {
|
_, err := l.SimpleBind(req)
|
||||||
if err := addLDAPDescriptions(packet); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
ber.PrintPacket(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
|
||||||
if resultCode != 0 {
|
|
||||||
return NewError(resultCode, errors.New(resultDescription))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
1
vendor/gopkg.in/ldap.v2/client.go → vendor/gopkg.in/ldap.v3/client.go
generated
vendored
1
vendor/gopkg.in/ldap.v2/client.go → vendor/gopkg.in/ldap.v3/client.go
generated
vendored
|
@ -18,6 +18,7 @@ type Client interface {
|
||||||
Add(addRequest *AddRequest) error
|
Add(addRequest *AddRequest) error
|
||||||
Del(delRequest *DelRequest) error
|
Del(delRequest *DelRequest) error
|
||||||
Modify(modifyRequest *ModifyRequest) error
|
Modify(modifyRequest *ModifyRequest) error
|
||||||
|
ModifyDN(modifyDNRequest *ModifyDNRequest) error
|
||||||
|
|
||||||
Compare(dn, attribute, value string) (bool, error)
|
Compare(dn, attribute, value string) (bool, error)
|
||||||
PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
|
PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
|
20
vendor/gopkg.in/ldap.v2/compare.go → vendor/gopkg.in/ldap.v3/compare.go
generated
vendored
20
vendor/gopkg.in/ldap.v2/compare.go → vendor/gopkg.in/ldap.v3/compare.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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
|
// File contains Compare functionality
|
||||||
//
|
//
|
||||||
// https://tools.ietf.org/html/rfc4511
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
@ -41,7 +37,7 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
|
||||||
|
|
||||||
ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion")
|
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.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc"))
|
||||||
ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagOctetString, value, "AssertionValue"))
|
ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "AssertionValue"))
|
||||||
request.AppendChild(ava)
|
request.AppendChild(ava)
|
||||||
packet.AppendChild(request)
|
packet.AppendChild(request)
|
||||||
|
|
||||||
|
@ -72,14 +68,16 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationCompareResponse {
|
if packet.Children[1].Tag == ApplicationCompareResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode == LDAPResultCompareTrue {
|
|
||||||
|
switch {
|
||||||
|
case IsErrorWithCode(err, LDAPResultCompareTrue):
|
||||||
return true, nil
|
return true, nil
|
||||||
} else if resultCode == LDAPResultCompareFalse {
|
case IsErrorWithCode(err, LDAPResultCompareFalse):
|
||||||
return false, nil
|
return false, nil
|
||||||
} else {
|
default:
|
||||||
return false, NewError(resultCode, errors.New(resultDescription))
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)
|
return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag)
|
||||||
}
|
}
|
98
vendor/gopkg.in/ldap.v2/conn.go → vendor/gopkg.in/ldap.v3/conn.go
generated
vendored
98
vendor/gopkg.in/ldap.v2/conn.go → vendor/gopkg.in/ldap.v3/conn.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -10,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -30,6 +27,13 @@ const (
|
||||||
MessageTimeout = 4
|
MessageTimeout = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultLdapPort default ldap port for pure TCP connection
|
||||||
|
DefaultLdapPort = "389"
|
||||||
|
// DefaultLdapsPort default ldap port for SSL connection
|
||||||
|
DefaultLdapsPort = "636"
|
||||||
|
)
|
||||||
|
|
||||||
// PacketResponse contains the packet or error encountered reading a response
|
// PacketResponse contains the packet or error encountered reading a response
|
||||||
type PacketResponse struct {
|
type PacketResponse struct {
|
||||||
// Packet is the packet read from the server
|
// Packet is the packet read from the server
|
||||||
|
@ -81,10 +85,13 @@ const (
|
||||||
|
|
||||||
// Conn represents an LDAP Connection
|
// Conn represents an LDAP Connection
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
|
// requestTimeout is loaded atomically
|
||||||
|
// so we need to ensure 64-bit alignment on 32-bit platforms.
|
||||||
|
requestTimeout int64
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
isTLS bool
|
isTLS bool
|
||||||
closing uint32
|
closing uint32
|
||||||
closeErr atomicValue
|
closeErr atomic.Value
|
||||||
isStartingTLS bool
|
isStartingTLS bool
|
||||||
Debug debugging
|
Debug debugging
|
||||||
chanConfirm chan struct{}
|
chanConfirm chan struct{}
|
||||||
|
@ -94,7 +101,6 @@ type Conn struct {
|
||||||
wgClose sync.WaitGroup
|
wgClose sync.WaitGroup
|
||||||
outstandingRequests uint
|
outstandingRequests uint
|
||||||
messageMutex sync.Mutex
|
messageMutex sync.Mutex
|
||||||
requestTimeout int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Client = &Conn{}
|
var _ Client = &Conn{}
|
||||||
|
@ -121,22 +127,51 @@ func Dial(network, addr string) (*Conn, error) {
|
||||||
// DialTLS connects to the given address on the given network using tls.Dial
|
// DialTLS connects to the given address on the given network using tls.Dial
|
||||||
// and then returns a new Conn for the connection.
|
// and then returns a new Conn for the connection.
|
||||||
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
||||||
dc, err := net.DialTimeout(network, addr, DefaultTimeout)
|
c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewError(ErrorNetwork, err)
|
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 := NewConn(c, true)
|
||||||
conn.Start()
|
conn.Start()
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DialURL connects to the given ldap URL vie TCP using tls.Dial or net.Dial if ldaps://
|
||||||
|
// or ldap:// specified as protocol. On success a new Conn for the connection
|
||||||
|
// is returned.
|
||||||
|
func DialURL(addr string) (*Conn, error) {
|
||||||
|
|
||||||
|
lurl, err := url.Parse(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewError(ErrorNetwork, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
host, port, err := net.SplitHostPort(lurl.Host)
|
||||||
|
if err != nil {
|
||||||
|
// we asume that error is due to missing port
|
||||||
|
host = lurl.Host
|
||||||
|
port = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch lurl.Scheme {
|
||||||
|
case "ldap":
|
||||||
|
if port == "" {
|
||||||
|
port = DefaultLdapPort
|
||||||
|
}
|
||||||
|
return Dial("tcp", net.JoinHostPort(host, port))
|
||||||
|
case "ldaps":
|
||||||
|
if port == "" {
|
||||||
|
port = DefaultLdapsPort
|
||||||
|
}
|
||||||
|
tlsConf := &tls.Config{
|
||||||
|
ServerName: host,
|
||||||
|
}
|
||||||
|
return DialTLS("tcp", net.JoinHostPort(host, port), tlsConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, NewError(ErrorNetwork, fmt.Errorf("Unknown scheme '%s'", lurl.Scheme))
|
||||||
|
}
|
||||||
|
|
||||||
// NewConn returns a new Conn using conn for network I/O.
|
// NewConn returns a new Conn using conn for network I/O.
|
||||||
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
||||||
return &Conn{
|
return &Conn{
|
||||||
|
@ -157,8 +192,8 @@ func (l *Conn) Start() {
|
||||||
l.wgClose.Add(1)
|
l.wgClose.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isClosing returns whether or not we're currently closing.
|
// IsClosing returns whether or not we're currently closing.
|
||||||
func (l *Conn) isClosing() bool {
|
func (l *Conn) IsClosing() bool {
|
||||||
return atomic.LoadUint32(&l.closing) == 1
|
return atomic.LoadUint32(&l.closing) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,30 +277,41 @@ func (l *Conn) StartTLS(config *tls.Config) error {
|
||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess {
|
if err := GetLDAPError(packet); err == nil {
|
||||||
conn := tls.Client(l.conn, config)
|
conn := tls.Client(l.conn, config)
|
||||||
|
|
||||||
if err := conn.Handshake(); err != nil {
|
if connErr := conn.Handshake(); connErr != nil {
|
||||||
l.Close()
|
l.Close()
|
||||||
return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", err))
|
return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", connErr))
|
||||||
}
|
}
|
||||||
|
|
||||||
l.isTLS = true
|
l.isTLS = true
|
||||||
l.conn = conn
|
l.conn = conn
|
||||||
} else {
|
} else {
|
||||||
return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message))
|
return err
|
||||||
}
|
}
|
||||||
go l.reader()
|
go l.reader()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSConnectionState returns the client's TLS connection state.
|
||||||
|
// The return values are their zero values if StartTLS did
|
||||||
|
// not succeed.
|
||||||
|
func (l *Conn) TLSConnectionState() (state tls.ConnectionState, ok bool) {
|
||||||
|
tc, ok := l.conn.(*tls.Conn)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return tc.ConnectionState(), true
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
|
func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
|
||||||
return l.sendMessageWithFlags(packet, 0)
|
return l.sendMessageWithFlags(packet, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
|
func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
|
||||||
if l.isClosing() {
|
if l.IsClosing() {
|
||||||
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
|
||||||
}
|
}
|
||||||
l.messageMutex.Lock()
|
l.messageMutex.Lock()
|
||||||
|
@ -304,7 +350,7 @@ func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags)
|
||||||
func (l *Conn) finishMessage(msgCtx *messageContext) {
|
func (l *Conn) finishMessage(msgCtx *messageContext) {
|
||||||
close(msgCtx.done)
|
close(msgCtx.done)
|
||||||
|
|
||||||
if l.isClosing() {
|
if l.IsClosing() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +371,7 @@ func (l *Conn) finishMessage(msgCtx *messageContext) {
|
||||||
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
func (l *Conn) sendProcessMessage(message *messagePacket) bool {
|
||||||
l.messageMutex.Lock()
|
l.messageMutex.Lock()
|
||||||
defer l.messageMutex.Unlock()
|
defer l.messageMutex.Unlock()
|
||||||
if l.isClosing() {
|
if l.IsClosing() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
l.chanMessage <- message
|
l.chanMessage <- message
|
||||||
|
@ -340,7 +386,7 @@ func (l *Conn) processMessages() {
|
||||||
for messageID, msgCtx := range l.messageContexts {
|
for messageID, msgCtx := range l.messageContexts {
|
||||||
// If we are closing due to an error, inform anyone who
|
// If we are closing due to an error, inform anyone who
|
||||||
// is waiting about the error.
|
// is waiting about the error.
|
||||||
if l.isClosing() && l.closeErr.Load() != nil {
|
if l.IsClosing() && l.closeErr.Load() != nil {
|
||||||
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
|
msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
|
||||||
}
|
}
|
||||||
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
l.Debug.Printf("Closing channel for MessageID %d", messageID)
|
||||||
|
@ -400,7 +446,7 @@ func (l *Conn) processMessages() {
|
||||||
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
|
if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
|
||||||
msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
|
msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing())
|
log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing())
|
||||||
ber.PrintPacket(message.Packet)
|
ber.PrintPacket(message.Packet)
|
||||||
}
|
}
|
||||||
case MessageTimeout:
|
case MessageTimeout:
|
||||||
|
@ -442,7 +488,7 @@ func (l *Conn) reader() {
|
||||||
packet, err := ber.ReadPacket(l.conn)
|
packet, err := ber.ReadPacket(l.conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// A read error is expected here if we are closing the connection...
|
// A read error is expected here if we are closing the connection...
|
||||||
if !l.isClosing() {
|
if !l.IsClosing() {
|
||||||
l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
|
l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
|
||||||
l.Debug.Printf("reader error: %s", err.Error())
|
l.Debug.Printf("reader error: %s", err.Error())
|
||||||
}
|
}
|
123
vendor/gopkg.in/ldap.v2/control.go → vendor/gopkg.in/ldap.v3/control.go
generated
vendored
123
vendor/gopkg.in/ldap.v2/control.go → vendor/gopkg.in/ldap.v3/control.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -22,13 +18,20 @@ const (
|
||||||
ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
|
ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
|
||||||
// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
|
// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
|
||||||
ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
|
ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
|
||||||
|
|
||||||
|
// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
|
||||||
|
ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
|
||||||
|
// ControlTypeMicrosoftShowDeleted - https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
|
||||||
|
ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ControlTypeMap maps controls to text descriptions
|
// ControlTypeMap maps controls to text descriptions
|
||||||
var ControlTypeMap = map[string]string{
|
var ControlTypeMap = map[string]string{
|
||||||
ControlTypePaging: "Paging",
|
ControlTypePaging: "Paging",
|
||||||
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
||||||
ControlTypeManageDsaIT: "Manage DSA IT",
|
ControlTypeManageDsaIT: "Manage DSA IT",
|
||||||
|
ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
|
||||||
|
ControlTypeMicrosoftShowDeleted: "Show Deleted Objects - Microsoft",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control defines an interface controls provide to encode and describe themselves
|
// Control defines an interface controls provide to encode and describe themselves
|
||||||
|
@ -60,7 +63,9 @@ func (c *ControlString) Encode() *ber.Packet {
|
||||||
if c.Criticality {
|
if c.Criticality {
|
||||||
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "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"))
|
if c.ControlValue != "" {
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(c.ControlValue), "Control Value"))
|
||||||
|
}
|
||||||
return packet
|
return packet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +247,64 @@ func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
|
||||||
return &ControlManageDsaIT{Criticality: Criticality}
|
return &ControlManageDsaIT{Criticality: Criticality}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ControlMicrosoftNotification implements the control described in https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
|
||||||
|
type ControlMicrosoftNotification struct{}
|
||||||
|
|
||||||
|
// GetControlType returns the OID
|
||||||
|
func (c *ControlMicrosoftNotification) GetControlType() string {
|
||||||
|
return ControlTypeMicrosoftNotification
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode returns the ber packet representation
|
||||||
|
func (c *ControlMicrosoftNotification) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftNotification, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftNotification]+")"))
|
||||||
|
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a human-readable description
|
||||||
|
func (c *ControlMicrosoftNotification) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q)",
|
||||||
|
ControlTypeMap[ControlTypeMicrosoftNotification],
|
||||||
|
ControlTypeMicrosoftNotification)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewControlMicrosoftNotification returns a ControlMicrosoftNotification control
|
||||||
|
func NewControlMicrosoftNotification() *ControlMicrosoftNotification {
|
||||||
|
return &ControlMicrosoftNotification{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ControlMicrosoftShowDeleted implements the control described in https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
|
||||||
|
type ControlMicrosoftShowDeleted struct{}
|
||||||
|
|
||||||
|
// GetControlType returns the OID
|
||||||
|
func (c *ControlMicrosoftShowDeleted) GetControlType() string {
|
||||||
|
return ControlTypeMicrosoftShowDeleted
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode returns the ber packet representation
|
||||||
|
func (c *ControlMicrosoftShowDeleted) Encode() *ber.Packet {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||||
|
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftShowDeleted, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftShowDeleted]+")"))
|
||||||
|
|
||||||
|
return packet
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a human-readable description
|
||||||
|
func (c *ControlMicrosoftShowDeleted) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Control Type: %s (%q)",
|
||||||
|
ControlTypeMap[ControlTypeMicrosoftShowDeleted],
|
||||||
|
ControlTypeMicrosoftShowDeleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewControlMicrosoftShowDeleted returns a ControlMicrosoftShowDeleted control
|
||||||
|
func NewControlMicrosoftShowDeleted() *ControlMicrosoftShowDeleted {
|
||||||
|
return &ControlMicrosoftShowDeleted{}
|
||||||
|
}
|
||||||
|
|
||||||
// FindControl returns the first control of the given type in the list, or nil
|
// FindControl returns the first control of the given type in the list, or nil
|
||||||
func FindControl(controls []Control, controlType string) Control {
|
func FindControl(controls []Control, controlType string) Control {
|
||||||
for _, c := range controls {
|
for _, c := range controls {
|
||||||
|
@ -253,7 +316,7 @@ func FindControl(controls []Control, controlType string) Control {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
|
// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
|
||||||
func DecodeControl(packet *ber.Packet) Control {
|
func DecodeControl(packet *ber.Packet) (Control, error) {
|
||||||
var (
|
var (
|
||||||
ControlType = ""
|
ControlType = ""
|
||||||
Criticality = false
|
Criticality = false
|
||||||
|
@ -263,7 +326,7 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
switch len(packet.Children) {
|
switch len(packet.Children) {
|
||||||
case 0:
|
case 0:
|
||||||
// at least one child is required for control type
|
// at least one child is required for control type
|
||||||
return nil
|
return nil, fmt.Errorf("at least one child is required for control type")
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// just type, no criticality or value
|
// just type, no criticality or value
|
||||||
|
@ -296,17 +359,20 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// more than 3 children is invalid
|
// more than 3 children is invalid
|
||||||
return nil
|
return nil, fmt.Errorf("more than 3 children is invalid for controls")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ControlType {
|
switch ControlType {
|
||||||
case ControlTypeManageDsaIT:
|
case ControlTypeManageDsaIT:
|
||||||
return NewControlManageDsaIT(Criticality)
|
return NewControlManageDsaIT(Criticality), nil
|
||||||
case ControlTypePaging:
|
case ControlTypePaging:
|
||||||
value.Description += " (Paging)"
|
value.Description += " (Paging)"
|
||||||
c := new(ControlPaging)
|
c := new(ControlPaging)
|
||||||
if value.Value != nil {
|
if value.Value != nil {
|
||||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
value.Data.Truncate(0)
|
value.Data.Truncate(0)
|
||||||
value.Value = nil
|
value.Value = nil
|
||||||
value.AppendChild(valueChildren)
|
value.AppendChild(valueChildren)
|
||||||
|
@ -318,12 +384,15 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
c.PagingSize = uint32(value.Children[0].Value.(int64))
|
c.PagingSize = uint32(value.Children[0].Value.(int64))
|
||||||
c.Cookie = value.Children[1].Data.Bytes()
|
c.Cookie = value.Children[1].Data.Bytes()
|
||||||
value.Children[1].Value = c.Cookie
|
value.Children[1].Value = c.Cookie
|
||||||
return c
|
return c, nil
|
||||||
case ControlTypeBeheraPasswordPolicy:
|
case ControlTypeBeheraPasswordPolicy:
|
||||||
value.Description += " (Password Policy - Behera)"
|
value.Description += " (Password Policy - Behera)"
|
||||||
c := NewControlBeheraPasswordPolicy()
|
c := NewControlBeheraPasswordPolicy()
|
||||||
if value.Value != nil {
|
if value.Value != nil {
|
||||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
value.Data.Truncate(0)
|
value.Data.Truncate(0)
|
||||||
value.Value = nil
|
value.Value = nil
|
||||||
value.AppendChild(valueChildren)
|
value.AppendChild(valueChildren)
|
||||||
|
@ -335,7 +404,10 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
if child.Tag == 0 {
|
if child.Tag == 0 {
|
||||||
//Warning
|
//Warning
|
||||||
warningPacket := child.Children[0]
|
warningPacket := child.Children[0]
|
||||||
packet := ber.DecodePacket(warningPacket.Data.Bytes())
|
packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
val, ok := packet.Value.(int64)
|
val, ok := packet.Value.(int64)
|
||||||
if ok {
|
if ok {
|
||||||
if warningPacket.Tag == 0 {
|
if warningPacket.Tag == 0 {
|
||||||
|
@ -350,7 +422,10 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
}
|
}
|
||||||
} else if child.Tag == 1 {
|
} else if child.Tag == 1 {
|
||||||
// Error
|
// Error
|
||||||
packet := ber.DecodePacket(child.Data.Bytes())
|
packet, err := ber.DecodePacketErr(child.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
val, ok := packet.Value.(int8)
|
val, ok := packet.Value.(int8)
|
||||||
if !ok {
|
if !ok {
|
||||||
// what to do?
|
// what to do?
|
||||||
|
@ -361,22 +436,26 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
|
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c, nil
|
||||||
case ControlTypeVChuPasswordMustChange:
|
case ControlTypeVChuPasswordMustChange:
|
||||||
c := &ControlVChuPasswordMustChange{MustChange: true}
|
c := &ControlVChuPasswordMustChange{MustChange: true}
|
||||||
return c
|
return c, nil
|
||||||
case ControlTypeVChuPasswordWarning:
|
case ControlTypeVChuPasswordWarning:
|
||||||
c := &ControlVChuPasswordWarning{Expire: -1}
|
c := &ControlVChuPasswordWarning{Expire: -1}
|
||||||
expireStr := ber.DecodeString(value.Data.Bytes())
|
expireStr := ber.DecodeString(value.Data.Bytes())
|
||||||
|
|
||||||
expire, err := strconv.ParseInt(expireStr, 10, 64)
|
expire, err := strconv.ParseInt(expireStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil, fmt.Errorf("failed to parse value as int: %s", err)
|
||||||
}
|
}
|
||||||
c.Expire = expire
|
c.Expire = expire
|
||||||
value.Value = c.Expire
|
value.Value = c.Expire
|
||||||
|
|
||||||
return c
|
return c, nil
|
||||||
|
case ControlTypeMicrosoftNotification:
|
||||||
|
return NewControlMicrosoftNotification(), nil
|
||||||
|
case ControlTypeMicrosoftShowDeleted:
|
||||||
|
return NewControlMicrosoftShowDeleted(), nil
|
||||||
default:
|
default:
|
||||||
c := new(ControlString)
|
c := new(ControlString)
|
||||||
c.ControlType = ControlType
|
c.ControlType = ControlType
|
||||||
|
@ -384,7 +463,7 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
c.ControlValue = value.Value.(string)
|
c.ControlValue = value.Value.(string)
|
||||||
}
|
}
|
||||||
return c
|
return c, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
0
vendor/gopkg.in/ldap.v2/debug.go → vendor/gopkg.in/ldap.v3/debug.go
generated
vendored
0
vendor/gopkg.in/ldap.v2/debug.go → vendor/gopkg.in/ldap.v3/debug.go
generated
vendored
8
vendor/gopkg.in/ldap.v2/del.go → vendor/gopkg.in/ldap.v3/del.go
generated
vendored
8
vendor/gopkg.in/ldap.v2/del.go → vendor/gopkg.in/ldap.v3/del.go
generated
vendored
|
@ -40,7 +40,7 @@ func (l *Conn) Del(delRequest *DelRequest) error {
|
||||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
packet.AppendChild(delRequest.encode())
|
packet.AppendChild(delRequest.encode())
|
||||||
if delRequest.Controls != nil {
|
if len(delRequest.Controls) > 0 {
|
||||||
packet.AppendChild(encodeControls(delRequest.Controls))
|
packet.AppendChild(encodeControls(delRequest.Controls))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +71,9 @@ func (l *Conn) Del(delRequest *DelRequest) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationDelResponse {
|
if packet.Children[1].Tag == ApplicationDelResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return NewError(resultCode, errors.New(resultDescription))
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
30
vendor/gopkg.in/ldap.v2/dn.go → vendor/gopkg.in/ldap.v3/dn.go
generated
vendored
30
vendor/gopkg.in/ldap.v2/dn.go → vendor/gopkg.in/ldap.v3/dn.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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 functionality
|
// File contains DN parsing functionality
|
||||||
//
|
//
|
||||||
// https://tools.ietf.org/html/rfc4514
|
// https://tools.ietf.org/html/rfc4514
|
||||||
|
@ -94,7 +90,8 @@ func ParseDN(str string) (*DN, error) {
|
||||||
|
|
||||||
for i := 0; i < len(str); i++ {
|
for i := 0; i < len(str); i++ {
|
||||||
char := str[i]
|
char := str[i]
|
||||||
if escaping {
|
switch {
|
||||||
|
case escaping:
|
||||||
unescapedTrailingSpaces = 0
|
unescapedTrailingSpaces = 0
|
||||||
escaping = false
|
escaping = false
|
||||||
switch char {
|
switch char {
|
||||||
|
@ -104,22 +101,22 @@ func ParseDN(str string) (*DN, error) {
|
||||||
}
|
}
|
||||||
// Not a special character, assume hex encoded octet
|
// Not a special character, assume hex encoded octet
|
||||||
if len(str) == i+1 {
|
if len(str) == i+1 {
|
||||||
return nil, errors.New("Got corrupted escaped character")
|
return nil, errors.New("got corrupted escaped character")
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := []byte{0}
|
dst := []byte{0}
|
||||||
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
|
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to decode escaped character: %s", err)
|
return nil, fmt.Errorf("failed to decode escaped character: %s", err)
|
||||||
} else if n != 1 {
|
} else if n != 1 {
|
||||||
return nil, fmt.Errorf("Expected 1 byte when un-escaping, got %d", n)
|
return nil, fmt.Errorf("expected 1 byte when un-escaping, got %d", n)
|
||||||
}
|
}
|
||||||
buffer.WriteByte(dst[0])
|
buffer.WriteByte(dst[0])
|
||||||
i++
|
i++
|
||||||
} else if char == '\\' {
|
case char == '\\':
|
||||||
unescapedTrailingSpaces = 0
|
unescapedTrailingSpaces = 0
|
||||||
escaping = true
|
escaping = true
|
||||||
} else if char == '=' {
|
case char == '=':
|
||||||
attribute.Type = stringFromBuffer()
|
attribute.Type = stringFromBuffer()
|
||||||
// Special case: If the first character in the value is # the
|
// Special case: If the first character in the value is # the
|
||||||
// following data is BER encoded so we can just fast forward
|
// following data is BER encoded so we can just fast forward
|
||||||
|
@ -135,13 +132,16 @@ func ParseDN(str string) (*DN, error) {
|
||||||
}
|
}
|
||||||
rawBER, err := enchex.DecodeString(data)
|
rawBER, err := enchex.DecodeString(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to decode BER encoding: %s", err)
|
return nil, fmt.Errorf("failed to decode BER encoding: %s", err)
|
||||||
|
}
|
||||||
|
packet, err := ber.DecodePacketErr(rawBER)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode BER packet: %s", err)
|
||||||
}
|
}
|
||||||
packet := ber.DecodePacket(rawBER)
|
|
||||||
buffer.WriteString(packet.Data.String())
|
buffer.WriteString(packet.Data.String())
|
||||||
i += len(data) - 1
|
i += len(data) - 1
|
||||||
}
|
}
|
||||||
} else if char == ',' || char == '+' {
|
case char == ',' || char == '+':
|
||||||
// We're done with this RDN or value, push it
|
// We're done with this RDN or value, push it
|
||||||
if len(attribute.Type) == 0 {
|
if len(attribute.Type) == 0 {
|
||||||
return nil, errors.New("incomplete type, value pair")
|
return nil, errors.New("incomplete type, value pair")
|
||||||
|
@ -154,10 +154,10 @@ func ParseDN(str string) (*DN, error) {
|
||||||
rdn = new(RelativeDN)
|
rdn = new(RelativeDN)
|
||||||
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
||||||
}
|
}
|
||||||
} else if char == ' ' && buffer.Len() == 0 {
|
case char == ' ' && buffer.Len() == 0:
|
||||||
// ignore unescaped leading spaces
|
// ignore unescaped leading spaces
|
||||||
continue
|
continue
|
||||||
} else {
|
default:
|
||||||
if char == ' ' {
|
if char == ' ' {
|
||||||
// Track unescaped spaces in case they are trailing and we need to remove them
|
// Track unescaped spaces in case they are trailing and we need to remove them
|
||||||
unescapedTrailingSpaces++
|
unescapedTrailingSpaces++
|
0
vendor/gopkg.in/ldap.v2/doc.go → vendor/gopkg.in/ldap.v3/doc.go
generated
vendored
0
vendor/gopkg.in/ldap.v2/doc.go → vendor/gopkg.in/ldap.v3/doc.go
generated
vendored
234
vendor/gopkg.in/ldap.v3/error.go
generated
vendored
Normal file
234
vendor/gopkg.in/ldap.v3/error.go
generated
vendored
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
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
|
||||||
|
LDAPResultIsLeaf = 35
|
||||||
|
LDAPResultAliasDereferencingProblem = 36
|
||||||
|
LDAPResultInappropriateAuthentication = 48
|
||||||
|
LDAPResultInvalidCredentials = 49
|
||||||
|
LDAPResultInsufficientAccessRights = 50
|
||||||
|
LDAPResultBusy = 51
|
||||||
|
LDAPResultUnavailable = 52
|
||||||
|
LDAPResultUnwillingToPerform = 53
|
||||||
|
LDAPResultLoopDetect = 54
|
||||||
|
LDAPResultSortControlMissing = 60
|
||||||
|
LDAPResultOffsetRangeError = 61
|
||||||
|
LDAPResultNamingViolation = 64
|
||||||
|
LDAPResultObjectClassViolation = 65
|
||||||
|
LDAPResultNotAllowedOnNonLeaf = 66
|
||||||
|
LDAPResultNotAllowedOnRDN = 67
|
||||||
|
LDAPResultEntryAlreadyExists = 68
|
||||||
|
LDAPResultObjectClassModsProhibited = 69
|
||||||
|
LDAPResultResultsTooLarge = 70
|
||||||
|
LDAPResultAffectsMultipleDSAs = 71
|
||||||
|
LDAPResultVirtualListViewErrorOrControlError = 76
|
||||||
|
LDAPResultOther = 80
|
||||||
|
LDAPResultServerDown = 81
|
||||||
|
LDAPResultLocalError = 82
|
||||||
|
LDAPResultEncodingError = 83
|
||||||
|
LDAPResultDecodingError = 84
|
||||||
|
LDAPResultTimeout = 85
|
||||||
|
LDAPResultAuthUnknown = 86
|
||||||
|
LDAPResultFilterError = 87
|
||||||
|
LDAPResultUserCanceled = 88
|
||||||
|
LDAPResultParamError = 89
|
||||||
|
LDAPResultNoMemory = 90
|
||||||
|
LDAPResultConnectError = 91
|
||||||
|
LDAPResultNotSupported = 92
|
||||||
|
LDAPResultControlNotFound = 93
|
||||||
|
LDAPResultNoResultsReturned = 94
|
||||||
|
LDAPResultMoreResultsToReturn = 95
|
||||||
|
LDAPResultClientLoop = 96
|
||||||
|
LDAPResultReferralLimitExceeded = 97
|
||||||
|
LDAPResultInvalidResponse = 100
|
||||||
|
LDAPResultAmbiguousResponse = 101
|
||||||
|
LDAPResultTLSNotSupported = 112
|
||||||
|
LDAPResultIntermediateResponse = 113
|
||||||
|
LDAPResultUnknownType = 114
|
||||||
|
LDAPResultCanceled = 118
|
||||||
|
LDAPResultNoSuchOperation = 119
|
||||||
|
LDAPResultTooLate = 120
|
||||||
|
LDAPResultCannotCancel = 121
|
||||||
|
LDAPResultAssertionFailed = 122
|
||||||
|
LDAPResultAuthorizationDenied = 123
|
||||||
|
LDAPResultSyncRefreshRequired = 4096
|
||||||
|
|
||||||
|
ErrorNetwork = 200
|
||||||
|
ErrorFilterCompile = 201
|
||||||
|
ErrorFilterDecompile = 202
|
||||||
|
ErrorDebugging = 203
|
||||||
|
ErrorUnexpectedMessage = 204
|
||||||
|
ErrorUnexpectedResponse = 205
|
||||||
|
ErrorEmptyPassword = 206
|
||||||
|
)
|
||||||
|
|
||||||
|
// LDAPResultCodeMap contains string descriptions for LDAP error codes
|
||||||
|
var LDAPResultCodeMap = map[uint16]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",
|
||||||
|
LDAPResultIsLeaf: "Is Leaf",
|
||||||
|
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",
|
||||||
|
LDAPResultSortControlMissing: "Sort Control Missing",
|
||||||
|
LDAPResultOffsetRangeError: "Result Offset Range Error",
|
||||||
|
LDAPResultNamingViolation: "Naming Violation",
|
||||||
|
LDAPResultObjectClassViolation: "Object Class Violation",
|
||||||
|
LDAPResultResultsTooLarge: "Results Too Large",
|
||||||
|
LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
|
||||||
|
LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
|
||||||
|
LDAPResultEntryAlreadyExists: "Entry Already Exists",
|
||||||
|
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
|
||||||
|
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
|
||||||
|
LDAPResultVirtualListViewErrorOrControlError: "Failed because of a problem related to the virtual list view",
|
||||||
|
LDAPResultOther: "Other",
|
||||||
|
LDAPResultServerDown: "Cannot establish a connection",
|
||||||
|
LDAPResultLocalError: "An error occurred",
|
||||||
|
LDAPResultEncodingError: "LDAP encountered an error while encoding",
|
||||||
|
LDAPResultDecodingError: "LDAP encountered an error while decoding",
|
||||||
|
LDAPResultTimeout: "LDAP timeout while waiting for a response from the server",
|
||||||
|
LDAPResultAuthUnknown: "The auth method requested in a bind request is unknown",
|
||||||
|
LDAPResultFilterError: "An error occurred while encoding the given search filter",
|
||||||
|
LDAPResultUserCanceled: "The user canceled the operation",
|
||||||
|
LDAPResultParamError: "An invalid parameter was specified",
|
||||||
|
LDAPResultNoMemory: "Out of memory error",
|
||||||
|
LDAPResultConnectError: "A connection to the server could not be established",
|
||||||
|
LDAPResultNotSupported: "An attempt has been made to use a feature not supported LDAP",
|
||||||
|
LDAPResultControlNotFound: "The controls required to perform the requested operation were not found",
|
||||||
|
LDAPResultNoResultsReturned: "No results were returned from the server",
|
||||||
|
LDAPResultMoreResultsToReturn: "There are more results in the chain of results",
|
||||||
|
LDAPResultClientLoop: "A loop has been detected. For example when following referrals",
|
||||||
|
LDAPResultReferralLimitExceeded: "The referral hop limit has been exceeded",
|
||||||
|
LDAPResultCanceled: "Operation was canceled",
|
||||||
|
LDAPResultNoSuchOperation: "Server has no knowledge of the operation requested for cancellation",
|
||||||
|
LDAPResultTooLate: "Too late to cancel the outstanding operation",
|
||||||
|
LDAPResultCannotCancel: "The identified operation does not support cancellation or the cancel operation cannot be performed",
|
||||||
|
LDAPResultAssertionFailed: "An assertion control given in the LDAP operation evaluated to false causing the operation to not be performed",
|
||||||
|
LDAPResultSyncRefreshRequired: "Refresh Required",
|
||||||
|
LDAPResultInvalidResponse: "Invalid Response",
|
||||||
|
LDAPResultAmbiguousResponse: "Ambiguous Response",
|
||||||
|
LDAPResultTLSNotSupported: "Tls Not Supported",
|
||||||
|
LDAPResultIntermediateResponse: "Intermediate Response",
|
||||||
|
LDAPResultUnknownType: "Unknown Type",
|
||||||
|
LDAPResultAuthorizationDenied: "Authorization Denied",
|
||||||
|
|
||||||
|
ErrorNetwork: "Network Error",
|
||||||
|
ErrorFilterCompile: "Filter Compile Error",
|
||||||
|
ErrorFilterDecompile: "Filter Decompile Error",
|
||||||
|
ErrorDebugging: "Debugging Error",
|
||||||
|
ErrorUnexpectedMessage: "Unexpected Message",
|
||||||
|
ErrorUnexpectedResponse: "Unexpected Response",
|
||||||
|
ErrorEmptyPassword: "Empty password not allowed by the client",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error holds LDAP error information
|
||||||
|
type Error struct {
|
||||||
|
// Err is the underlying error
|
||||||
|
Err error
|
||||||
|
// ResultCode is the LDAP error code
|
||||||
|
ResultCode uint16
|
||||||
|
// MatchedDN is the matchedDN returned if any
|
||||||
|
MatchedDN string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLDAPError creates an Error out of a BER packet representing a LDAPResult
|
||||||
|
// The return is an error object. It can be casted to a Error structure.
|
||||||
|
// This function returns nil if resultCode in the LDAPResult sequence is success(0).
|
||||||
|
func GetLDAPError(packet *ber.Packet) error {
|
||||||
|
if packet == nil {
|
||||||
|
return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty packet")}
|
||||||
|
} else if len(packet.Children) >= 2 {
|
||||||
|
response := packet.Children[1]
|
||||||
|
if response == nil {
|
||||||
|
return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")}
|
||||||
|
}
|
||||||
|
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
|
||||||
|
resultCode := uint16(response.Children[0].Value.(int64))
|
||||||
|
if resultCode == 0 { // No error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Error{ResultCode: resultCode, MatchedDN: response.Children[1].Value.(string),
|
||||||
|
Err: fmt.Errorf("%s", response.Children[2].Value.(string))}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewError creates an LDAP error with the given code and underlying error
|
||||||
|
func NewError(resultCode uint16, err error) error {
|
||||||
|
return &Error{ResultCode: resultCode, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
|
||||||
|
func IsErrorWithCode(err error, desiredResultCode uint16) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
serverError, ok := err.(*Error)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverError.ResultCode == desiredResultCode
|
||||||
|
}
|
4
vendor/gopkg.in/ldap.v2/filter.go → vendor/gopkg.in/ldap.v3/filter.go
generated
vendored
4
vendor/gopkg.in/ldap.v2/filter.go → vendor/gopkg.in/ldap.v3/filter.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
86
vendor/gopkg.in/ldap.v2/ldap.go → vendor/gopkg.in/ldap.v3/ldap.go
generated
vendored
86
vendor/gopkg.in/ldap.v2/ldap.go → vendor/gopkg.in/ldap.v3/ldap.go
generated
vendored
|
@ -1,11 +1,8 @@
|
||||||
// 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
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -101,13 +98,13 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||||
|
|
||||||
switch application {
|
switch application {
|
||||||
case ApplicationBindRequest:
|
case ApplicationBindRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationBindResponse:
|
case ApplicationBindResponse:
|
||||||
addDefaultLDAPResponseDescriptions(packet)
|
err = addDefaultLDAPResponseDescriptions(packet)
|
||||||
case ApplicationUnbindRequest:
|
case ApplicationUnbindRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationSearchRequest:
|
case ApplicationSearchRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationSearchResultEntry:
|
case ApplicationSearchResultEntry:
|
||||||
packet.Children[1].Children[0].Description = "Object Name"
|
packet.Children[1].Children[0].Description = "Object Name"
|
||||||
packet.Children[1].Children[1].Description = "Attributes"
|
packet.Children[1].Children[1].Description = "Attributes"
|
||||||
|
@ -120,37 +117,37 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(packet.Children) == 3 {
|
if len(packet.Children) == 3 {
|
||||||
addControlDescriptions(packet.Children[2])
|
err = addControlDescriptions(packet.Children[2])
|
||||||
}
|
}
|
||||||
case ApplicationSearchResultDone:
|
case ApplicationSearchResultDone:
|
||||||
addDefaultLDAPResponseDescriptions(packet)
|
err = addDefaultLDAPResponseDescriptions(packet)
|
||||||
case ApplicationModifyRequest:
|
case ApplicationModifyRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationModifyResponse:
|
case ApplicationModifyResponse:
|
||||||
case ApplicationAddRequest:
|
case ApplicationAddRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationAddResponse:
|
case ApplicationAddResponse:
|
||||||
case ApplicationDelRequest:
|
case ApplicationDelRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationDelResponse:
|
case ApplicationDelResponse:
|
||||||
case ApplicationModifyDNRequest:
|
case ApplicationModifyDNRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationModifyDNResponse:
|
case ApplicationModifyDNResponse:
|
||||||
case ApplicationCompareRequest:
|
case ApplicationCompareRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationCompareResponse:
|
case ApplicationCompareResponse:
|
||||||
case ApplicationAbandonRequest:
|
case ApplicationAbandonRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationSearchResultReference:
|
case ApplicationSearchResultReference:
|
||||||
case ApplicationExtendedRequest:
|
case ApplicationExtendedRequest:
|
||||||
addRequestDescriptions(packet)
|
err = addRequestDescriptions(packet)
|
||||||
case ApplicationExtendedResponse:
|
case ApplicationExtendedResponse:
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func addControlDescriptions(packet *ber.Packet) {
|
func addControlDescriptions(packet *ber.Packet) error {
|
||||||
packet.Description = "Controls"
|
packet.Description = "Controls"
|
||||||
for _, child := range packet.Children {
|
for _, child := range packet.Children {
|
||||||
var value *ber.Packet
|
var value *ber.Packet
|
||||||
|
@ -159,7 +156,7 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
switch len(child.Children) {
|
switch len(child.Children) {
|
||||||
case 0:
|
case 0:
|
||||||
// at least one child is required for control type
|
// at least one child is required for control type
|
||||||
continue
|
return fmt.Errorf("at least one child is required for control type")
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// just type, no criticality or value
|
// just type, no criticality or value
|
||||||
|
@ -188,8 +185,9 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// more than 3 children is invalid
|
// more than 3 children is invalid
|
||||||
continue
|
return fmt.Errorf("more than 3 children for control packet found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -197,7 +195,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
case ControlTypePaging:
|
case ControlTypePaging:
|
||||||
value.Description += " (Paging)"
|
value.Description += " (Paging)"
|
||||||
if value.Value != nil {
|
if value.Value != nil {
|
||||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
value.Data.Truncate(0)
|
value.Data.Truncate(0)
|
||||||
value.Value = nil
|
value.Value = nil
|
||||||
valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
|
valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
|
||||||
|
@ -210,7 +211,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
case ControlTypeBeheraPasswordPolicy:
|
case ControlTypeBeheraPasswordPolicy:
|
||||||
value.Description += " (Password Policy - Behera Draft)"
|
value.Description += " (Password Policy - Behera Draft)"
|
||||||
if value.Value != nil {
|
if value.Value != nil {
|
||||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
value.Data.Truncate(0)
|
value.Data.Truncate(0)
|
||||||
value.Value = nil
|
value.Value = nil
|
||||||
value.AppendChild(valueChildren)
|
value.AppendChild(valueChildren)
|
||||||
|
@ -220,7 +224,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
if child.Tag == 0 {
|
if child.Tag == 0 {
|
||||||
//Warning
|
//Warning
|
||||||
warningPacket := child.Children[0]
|
warningPacket := child.Children[0]
|
||||||
packet := ber.DecodePacket(warningPacket.Data.Bytes())
|
packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
val, ok := packet.Value.(int64)
|
val, ok := packet.Value.(int64)
|
||||||
if ok {
|
if ok {
|
||||||
if warningPacket.Tag == 0 {
|
if warningPacket.Tag == 0 {
|
||||||
|
@ -235,7 +242,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
}
|
}
|
||||||
} else if child.Tag == 1 {
|
} else if child.Tag == 1 {
|
||||||
// Error
|
// Error
|
||||||
packet := ber.DecodePacket(child.Data.Bytes())
|
packet, err := ber.DecodePacketErr(child.Data.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||||
|
}
|
||||||
val, ok := packet.Value.(int8)
|
val, ok := packet.Value.(int8)
|
||||||
if !ok {
|
if !ok {
|
||||||
val = -1
|
val = -1
|
||||||
|
@ -246,28 +256,31 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRequestDescriptions(packet *ber.Packet) {
|
func addRequestDescriptions(packet *ber.Packet) error {
|
||||||
packet.Description = "LDAP Request"
|
packet.Description = "LDAP Request"
|
||||||
packet.Children[0].Description = "Message ID"
|
packet.Children[0].Description = "Message ID"
|
||||||
packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
|
packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
|
||||||
if len(packet.Children) == 3 {
|
if len(packet.Children) == 3 {
|
||||||
addControlDescriptions(packet.Children[2])
|
return addControlDescriptions(packet.Children[2])
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
|
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error {
|
||||||
resultCode, _ := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
|
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[err.(*Error).ResultCode] + ")"
|
||||||
packet.Children[1].Children[1].Description = "Matched DN"
|
packet.Children[1].Children[1].Description = "Matched DN (" + err.(*Error).MatchedDN + ")"
|
||||||
packet.Children[1].Children[2].Description = "Error Message"
|
packet.Children[1].Children[2].Description = "Error Message"
|
||||||
if len(packet.Children[1].Children) > 3 {
|
if len(packet.Children[1].Children) > 3 {
|
||||||
packet.Children[1].Children[3].Description = "Referral"
|
packet.Children[1].Children[3].Description = "Referral"
|
||||||
}
|
}
|
||||||
if len(packet.Children) == 3 {
|
if len(packet.Children) == 3 {
|
||||||
addControlDescriptions(packet.Children[2])
|
return addControlDescriptions(packet.Children[2])
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugBinaryFile reads and prints packets from the given filename
|
// DebugBinaryFile reads and prints packets from the given filename
|
||||||
|
@ -277,8 +290,13 @@ func DebugBinaryFile(fileName string) error {
|
||||||
return NewError(ErrorDebugging, err)
|
return NewError(ErrorDebugging, err)
|
||||||
}
|
}
|
||||||
ber.PrintBytes(os.Stdout, file, "")
|
ber.PrintBytes(os.Stdout, file, "")
|
||||||
packet := ber.DecodePacket(file)
|
packet, err := ber.DecodePacketErr(file)
|
||||||
addLDAPDescriptions(packet)
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode packet: %s", err)
|
||||||
|
}
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
ber.PrintPacket(packet)
|
ber.PrintPacket(packet)
|
||||||
|
|
||||||
return nil
|
return nil
|
104
vendor/gopkg.in/ldap.v3/moddn.go
generated
vendored
Normal file
104
vendor/gopkg.in/ldap.v3/moddn.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Package ldap - moddn.go contains ModifyDN functionality
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
// ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
|
||||||
|
// entry LDAPDN,
|
||||||
|
// newrdn RelativeLDAPDN,
|
||||||
|
// deleteoldrdn BOOLEAN,
|
||||||
|
// newSuperior [0] LDAPDN OPTIONAL }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/asn1-ber.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModifyDNRequest holds the request to modify a DN
|
||||||
|
type ModifyDNRequest struct {
|
||||||
|
DN string
|
||||||
|
NewRDN string
|
||||||
|
DeleteOldRDN bool
|
||||||
|
NewSuperior string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewModifyDNRequest creates a new request which can be passed to ModifyDN().
|
||||||
|
//
|
||||||
|
// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an
|
||||||
|
// empty string for just changing the object's RDN.
|
||||||
|
//
|
||||||
|
// For moving the object without renaming, the "rdn" must be the first
|
||||||
|
// RDN of the given DN.
|
||||||
|
//
|
||||||
|
// A call like
|
||||||
|
// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
|
||||||
|
// will setup the request to just rename uid=someone,dc=example,dc=org to
|
||||||
|
// uid=newname,dc=example,dc=org.
|
||||||
|
func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest {
|
||||||
|
return &ModifyDNRequest{
|
||||||
|
DN: dn,
|
||||||
|
NewRDN: rdn,
|
||||||
|
DeleteOldRDN: delOld,
|
||||||
|
NewSuperior: newSup,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ModifyDNRequest) encode() *ber.Packet {
|
||||||
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request")
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN"))
|
||||||
|
request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN"))
|
||||||
|
if m.NewSuperior != "" {
|
||||||
|
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior"))
|
||||||
|
}
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument
|
||||||
|
// to NewModifyDNRequest() is not "").
|
||||||
|
func (l *Conn) ModifyDN(m *ModifyDNRequest) error {
|
||||||
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
|
packet.AppendChild(m.encode())
|
||||||
|
|
||||||
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
msgCtx, err := l.sendMessage(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer l.finishMessage(msgCtx)
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: waiting for response", msgCtx.id)
|
||||||
|
packetResponse, ok := <-msgCtx.responses
|
||||||
|
if !ok {
|
||||||
|
return NewError(ErrorNetwork, errors.New("ldap: channel closed"))
|
||||||
|
}
|
||||||
|
packet, err = packetResponse.ReadPacket()
|
||||||
|
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Debug {
|
||||||
|
if err := addLDAPDescriptions(packet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ber.PrintPacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.Children[1].Tag == ApplicationModifyDNResponse {
|
||||||
|
err := GetLDAPError(packet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Debug.Printf("%d: returning", msgCtx.id)
|
||||||
|
return nil
|
||||||
|
}
|
77
vendor/gopkg.in/ldap.v2/modify.go → vendor/gopkg.in/ldap.v3/modify.go
generated
vendored
77
vendor/gopkg.in/ldap.v2/modify.go → vendor/gopkg.in/ldap.v3/modify.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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
|
// File contains Modify functionality
|
||||||
//
|
//
|
||||||
// https://tools.ietf.org/html/rfc4511
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
@ -62,54 +58,56 @@ func (p *PartialAttribute) encode() *ber.Packet {
|
||||||
return seq
|
return seq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
|
||||||
|
type Change struct {
|
||||||
|
// Operation is the type of change to be made
|
||||||
|
Operation uint
|
||||||
|
// Modification is the attribute to be modified
|
||||||
|
Modification PartialAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Change) encode() *ber.Packet {
|
||||||
|
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||||
|
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
|
||||||
|
change.AppendChild(c.Modification.encode())
|
||||||
|
return change
|
||||||
|
}
|
||||||
|
|
||||||
// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
|
// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
|
||||||
type ModifyRequest struct {
|
type ModifyRequest struct {
|
||||||
// DN is the distinguishedName of the directory entry to modify
|
// DN is the distinguishedName of the directory entry to modify
|
||||||
DN string
|
DN string
|
||||||
// AddAttributes contain the attributes to add
|
// Changes contain the attributes to modify
|
||||||
AddAttributes []PartialAttribute
|
Changes []Change
|
||||||
// DeleteAttributes contain the attributes to delete
|
// Controls hold optional controls to send with the request
|
||||||
DeleteAttributes []PartialAttribute
|
Controls []Control
|
||||||
// ReplaceAttributes contain the attributes to replace
|
|
||||||
ReplaceAttributes []PartialAttribute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add inserts the given attribute to the list of attributes to add
|
// Add appends the given attribute to the list of changes to be made
|
||||||
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
|
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
|
||||||
m.AddAttributes = append(m.AddAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
|
m.appendChange(AddAttribute, attrType, attrVals)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete inserts the given attribute to the list of attributes to delete
|
// Delete appends the given attribute to the list of changes to be made
|
||||||
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
|
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
|
||||||
m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
|
m.appendChange(DeleteAttribute, attrType, attrVals)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace inserts the given attribute to the list of attributes to replace
|
// Replace appends the given attribute to the list of changes to be made
|
||||||
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
|
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
|
||||||
m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
|
m.appendChange(ReplaceAttribute, attrType, attrVals)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
|
||||||
|
m.Changes = append(m.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ModifyRequest) encode() *ber.Packet {
|
func (m ModifyRequest) encode() *ber.Packet {
|
||||||
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
|
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
|
||||||
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
|
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
|
||||||
changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
|
changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
|
||||||
for _, attribute := range m.AddAttributes {
|
for _, change := range m.Changes {
|
||||||
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
changes.AppendChild(change.encode())
|
||||||
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)
|
request.AppendChild(changes)
|
||||||
return request
|
return request
|
||||||
|
@ -118,9 +116,11 @@ func (m ModifyRequest) encode() *ber.Packet {
|
||||||
// NewModifyRequest creates a modify request for the given DN
|
// NewModifyRequest creates a modify request for the given DN
|
||||||
func NewModifyRequest(
|
func NewModifyRequest(
|
||||||
dn string,
|
dn string,
|
||||||
|
controls []Control,
|
||||||
) *ModifyRequest {
|
) *ModifyRequest {
|
||||||
return &ModifyRequest{
|
return &ModifyRequest{
|
||||||
DN: dn,
|
DN: dn,
|
||||||
|
Controls: controls,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +129,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
|
||||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||||
packet.AppendChild(modifyRequest.encode())
|
packet.AppendChild(modifyRequest.encode())
|
||||||
|
if len(modifyRequest.Controls) > 0 {
|
||||||
|
packet.AppendChild(encodeControls(modifyRequest.Controls))
|
||||||
|
}
|
||||||
|
|
||||||
l.Debug.PrintPacket(packet)
|
l.Debug.PrintPacket(packet)
|
||||||
|
|
||||||
|
@ -157,9 +160,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationModifyResponse {
|
if packet.Children[1].Tag == ApplicationModifyResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return NewError(resultCode, errors.New(resultDescription))
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
17
vendor/gopkg.in/ldap.v2/passwdmodify.go → vendor/gopkg.in/ldap.v3/passwdmodify.go
generated
vendored
17
vendor/gopkg.in/ldap.v2/passwdmodify.go → vendor/gopkg.in/ldap.v3/passwdmodify.go
generated
vendored
|
@ -32,6 +32,8 @@ type PasswordModifyRequest struct {
|
||||||
type PasswordModifyResult struct {
|
type PasswordModifyResult struct {
|
||||||
// GeneratedPassword holds a password generated by the server, if present
|
// GeneratedPassword holds a password generated by the server, if present
|
||||||
GeneratedPassword string
|
GeneratedPassword string
|
||||||
|
// Referral are the returned referral
|
||||||
|
Referral string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
|
func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
|
||||||
|
@ -124,12 +126,19 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet.Children[1].Tag == ApplicationExtendedResponse {
|
if packet.Children[1].Tag == ApplicationExtendedResponse {
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return nil, NewError(resultCode, errors.New(resultDescription))
|
if IsErrorWithCode(err, LDAPResultReferral) {
|
||||||
|
for _, child := range packet.Children[1].Children {
|
||||||
|
if child.Tag == 3 {
|
||||||
|
result.Referral = child.Children[0].Value.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
|
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
extendedResponse := packet.Children[1]
|
extendedResponse := packet.Children[1]
|
22
vendor/gopkg.in/ldap.v2/search.go → vendor/gopkg.in/ldap.v3/search.go
generated
vendored
22
vendor/gopkg.in/ldap.v2/search.go → vendor/gopkg.in/ldap.v3/search.go
generated
vendored
|
@ -1,7 +1,3 @@
|
||||||
// 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
|
// File contains Search functionality
|
||||||
//
|
//
|
||||||
// https://tools.ietf.org/html/rfc4511
|
// https://tools.ietf.org/html/rfc4511
|
||||||
|
@ -313,10 +309,10 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32)
|
||||||
} else {
|
} else {
|
||||||
castControl, ok := control.(*ControlPaging)
|
castControl, ok := control.(*ControlPaging)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control)
|
return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
|
||||||
}
|
}
|
||||||
if castControl.PagingSize != pagingSize {
|
if castControl.PagingSize != pagingSize {
|
||||||
return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
|
return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
|
||||||
}
|
}
|
||||||
pagingControl = castControl
|
pagingControl = castControl
|
||||||
}
|
}
|
||||||
|
@ -379,7 +375,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||||
}
|
}
|
||||||
packet.AppendChild(encodedSearchRequest)
|
packet.AppendChild(encodedSearchRequest)
|
||||||
// encode search controls
|
// encode search controls
|
||||||
if searchRequest.Controls != nil {
|
if len(searchRequest.Controls) > 0 {
|
||||||
packet.AppendChild(encodeControls(searchRequest.Controls))
|
packet.AppendChild(encodeControls(searchRequest.Controls))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,13 +427,17 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||||
}
|
}
|
||||||
result.Entries = append(result.Entries, entry)
|
result.Entries = append(result.Entries, entry)
|
||||||
case 5:
|
case 5:
|
||||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
err := GetLDAPError(packet)
|
||||||
if resultCode != 0 {
|
if err != nil {
|
||||||
return result, NewError(resultCode, errors.New(resultDescription))
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(packet.Children) == 3 {
|
if len(packet.Children) == 3 {
|
||||||
for _, child := range packet.Children[2].Children {
|
for _, child := range packet.Children[2].Children {
|
||||||
result.Controls = append(result.Controls, DecodeControl(child))
|
decodedChild, err := DecodeControl(child)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode child control: %s", err)
|
||||||
|
}
|
||||||
|
result.Controls = append(result.Controls, decodedChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foundSearchResultDone = true
|
foundSearchResultDone = true
|
Loading…
Add table
Add a link
Reference in a new issue