Skip to content

Commit

Permalink
Merge pull request #266 from documize/core-0519
Browse files Browse the repository at this point in the history
Upgrade rich text editor, dual LDAP/forms authentication
  • Loading branch information
mcmatts committed May 14, 2019
2 parents e59e1f0 + e2a3962 commit 2477c36
Show file tree
Hide file tree
Showing 226 changed files with 12,050 additions and 20,133 deletions.
10 changes: 5 additions & 5 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 12 additions & 11 deletions NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/mux

Copyright (c) 2012 Rodrigo Moraes. All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -197,7 +197,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI


https://github.com/jmoiron/sqlx

Copyright (c) 2013, Jason Moiron

Permission is hereby granted, free of charge, to any person
Expand All @@ -223,7 +223,7 @@ OTHER DEALINGS IN THE SOFTWARE.


https://github.com/mytrile/mime-ext

The MIT License (MIT)

Copyright (c) 2014 Dimitar Kostov
Expand All @@ -247,7 +247,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


https://github.com/nu7hatch/gouuid

Copyright (C) 2011 by Krzysztof Kowalik <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy of
Expand All @@ -270,7 +270,7 @@ SOFTWARE.


https://github.com/rs/xid

Copyright (c) 2015 Olivier Poitrey <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down Expand Up @@ -318,7 +318,7 @@ SOFTWARE.


https://github.com/jordan-wright/email

Elements of the software in this file were modified from github.com/jordan-wright/email and
are subject to the licence below:

Expand Down Expand Up @@ -625,9 +625,9 @@ OTHER DEALINGS IN THE SOFTWARE.
https://github.com/blueimp/JavaScript-MD5

JavaScript MD5 1.0.1

Copyright 2011, Sebastian Tschan
https://blueimp.net
https://blueimp.net
Licensed under the MIT license:
http://www.opensource.org/licenses/MIT

Expand Down Expand Up @@ -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
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
Expand Down Expand Up @@ -1471,7 +1471,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


https://github.com/arasatasaygin/is.js
https://github.com/arasatasaygin/is.js

The MIT License (MIT)

Expand Down Expand Up @@ -1853,6 +1853,7 @@ SOFTWARE.


gopkg.in/ldap.v2
gopkg.in/ldap.v3

The MIT License (MIT)

Expand Down Expand Up @@ -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
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
THE SOFTWARE.
THE SOFTWARE.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ All you need to provide is PostgreSQL, Microsoft SQL Server or any MySQL variant

## 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.*
>
Expand Down Expand Up @@ -45,17 +45,19 @@ Heck, Documize will probably run just fine on a Raspberry Pi.
- Brave
- Vivaldi
- Opera
- Edge (v42+)
- Microsoft Edge (v42+)

## Technology Stack

- Go (v1.12.4)
- Go (v1.12.5)
- Ember JS (v3.8.0)

## Authentication Options

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

<https://documize.com>
Expand Down
91 changes: 65 additions & 26 deletions domain/auth/ldap/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

h.Runtime.Log.Info("LDAP login request " + username + " @ " + dom)

// Get the org and it's associated LDAP config.
org, err := h.Store.Organization.GetOrganizationByDomain(dom)
if err != nil {
Expand All @@ -298,56 +296,97 @@ func (h *Handler) Authenticate(w http.ResponseWriter, r *http.Request) {

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)
if err != nil {
response.WriteBadRequestError(w, method, "unable to dial LDAP server")
h.Runtime.Log.Error(method, err)
return
}
defer l.Close()

lu, ok, err := authenticate(l, lc, username, password)
if err != nil {
response.WriteBadRequestError(w, method, "error during LDAP authentication")
h.Runtime.Log.Error(method, err)
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)
if err != nil && err != sql.ErrNoRows {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
u, err = h.Store.User.GetByDomain(ctx, dom, lu.Email)
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)
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)
// 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
}

u = convertUser(lc, lu)
u.Salt = secrets.GenerateSalt()
u.Password = secrets.GeneratePassword(secrets.GenerateRandomPassword(), u.Salt)
h.Runtime.Log.Info("Trying forms auth as LDAP login login failed for " + username + " @ " + dom)

u, err = auth.AddExternalUser(ctx, h.Runtime, h.Store, u, lc.DefaultPermissionAddSpace)
if err != nil {
// 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)
h.Runtime.Log.Error(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.
usr.AttachUserAccounts(ctx, *h.Store, org.RefID, &u)

// No accounts signals data integrity problem
// so we reject login request.
// No accounts signals data integrity problem so we reject login request.
if len(u.Accounts) == 0 {
response.WriteUnauthorizedError(w)
h.Runtime.Log.Error(method, err)
Expand All @@ -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.Token = auth.GenerateJWT(h.Runtime, u.RefID, org.RefID, dom)
authModel.User = u
Expand Down
2 changes: 1 addition & 1 deletion domain/auth/ldap/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
lm "github.com/documize/community/model/auth"
"github.com/documize/community/model/user"
"github.com/pkg/errors"
ld "gopkg.in/ldap.v2"
ld "gopkg.in/ldap.v3"
)

// Connect establishes connection to LDAP server.
Expand Down
1 change: 0 additions & 1 deletion domain/organization/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ func (s Store) GetOrganizationByDomain(subdomain string) (o org.Organization, er
if err == nil {
return
}
s.Runtime.Log.Error("meta", err)

// match on empty domain AS last resort
err = s.Runtime.Db.Get(&o, s.Bind(`SELECT id, c_refid AS refid,
Expand Down
6 changes: 3 additions & 3 deletions domain/user/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (s Store) Add(ctx domain.RequestContext, u user.User) (err error) {
u.Revised = time.Now().UTC()

_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_user (c_refid, c_firstname, c_lastname, c_email, c_initials, c_password, c_salt, c_reset, c_lastversion, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
u.RefID, u.Firstname, u.Lastname, strings.ToLower(u.Email), u.Initials, u.Password, u.Salt, "", u.LastVersion, u.Created, u.Revised)
u.RefID, u.Firstname, u.Lastname, strings.TrimSpace(strings.ToLower(u.Email)), u.Initials, u.Password, u.Salt, "", u.LastVersion, u.Created, u.Revised)

if err != nil {
err = errors.Wrap(err, "execute user insert")
Expand Down Expand Up @@ -74,7 +74,7 @@ func (s Store) GetByDomain(ctx domain.RequestContext, domain, email string) (u u
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion,
u.c_created AS created, u.c_revised AS revised
FROM dmz_user u, dmz_user_account a, dmz_org o
WHERE TRIM(LOWER(u.c_email))=? AND u.c_refid=a.c_userid AND a.c_orgid=o.c_refid AND TRIM(LOWER(o.c_domain))=?`),
WHERE LOWER(u.c_email)=? AND u.c_refid=a.c_userid AND a.c_orgid=o.c_refid AND LOWER(o.c_domain)=?`),
email, domain)

if err != nil && err != sql.ErrNoRows {
Expand All @@ -94,7 +94,7 @@ func (s Store) GetByEmail(ctx domain.RequestContext, email string) (u user.User,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion,
u.c_created AS created, u.c_revised AS revised
FROM dmz_user u
WHERE TRIM(LOWER(u.c_email))=?`),
WHERE LOWER(u.c_email)=?`),
email)

if err != nil && err != sql.ErrNoRows {
Expand Down
6 changes: 3 additions & 3 deletions edition/community.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ func main() {
// Specify the product edition.
rt.Product = domain.Product{}
rt.Product.Major = "2"
rt.Product.Minor = "4"
rt.Product.Patch = "2"
rt.Product.Revision = "190429132654"
rt.Product.Minor = "5"
rt.Product.Patch = "0"
rt.Product.Revision = "190514122933"
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
rt.Product.Edition = domain.CommunityEdition
rt.Product.Title = fmt.Sprintf("%s Edition", rt.Product.Edition)
Expand Down
Loading

0 comments on commit 2477c36

Please sign in to comment.