From ff3971b8304def1d592e522a391f545560b00788 Mon Sep 17 00:00:00 2001
From: Lauris BH <lauris@nix.lv>
Date: Fri, 11 May 2018 10:55:32 +0300
Subject: [PATCH] Add LDAP integration tests (#3897)

* Add LDAP service for tests

* Add LDAP login source and test user sign-in

* Add checks to test if user data is correct

* Add LDAP user sync test

* Add failed user sign-in test
---
 .drone.yml                       |   8 ++
 integrations/auth_ldap_test.go   | 194 +++++++++++++++++++++++++++++++
 models/fixtures/login_source.yml |   1 +
 3 files changed, 203 insertions(+)
 create mode 100644 integrations/auth_ldap_test.go
 create mode 100644 models/fixtures/login_source.yml

diff --git a/.drone.yml b/.drone.yml
index c568050d447a..1fd42fa4eccd 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -134,6 +134,7 @@ pipeline:
     group: test
     environment:
       TAGS: bindata
+      TEST_LDAP: "1"
     commands:
       - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
       - apt-get install -y git-lfs
@@ -148,6 +149,7 @@ pipeline:
     group: test
     environment:
       TAGS: bindata
+      TEST_LDAP: "1"
     commands:
       - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
       - apt-get install -y git-lfs
@@ -161,6 +163,7 @@ pipeline:
     group: test
     environment:
       TAGS: bindata
+      TEST_LDAP: "1"
     commands:
       - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
       - apt-get install -y git-lfs
@@ -336,3 +339,8 @@ services:
       - POSTGRES_DB=test
     when:
       event: [ push, tag, pull_request ]
+
+  ldap:
+    image: gitea/test-openldap:latest
+    when:
+      event: [ push, tag, pull_request ]
diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go
new file mode 100644
index 000000000000..df26f95ed01f
--- /dev/null
+++ b/integrations/auth_ldap_test.go
@@ -0,0 +1,194 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integrations
+
+import (
+	"net/http"
+	"os"
+	"strings"
+	"testing"
+
+	"code.gitea.io/gitea/models"
+
+	"github.com/Unknwon/i18n"
+	"github.com/stretchr/testify/assert"
+)
+
+type ldapUser struct {
+	UserName    string
+	Password    string
+	FullName    string
+	Email       string
+	OtherEmails []string
+	IsAdmin     bool
+	SSHKeys     []string
+}
+
+var gitLDAPUsers = []ldapUser{
+	{
+		UserName:    "professor",
+		Password:    "professor",
+		FullName:    "Hubert Farnsworth",
+		Email:       "professor@planetexpress.com",
+		OtherEmails: []string{"hubert@planetexpress.com"},
+		IsAdmin:     true,
+	},
+	{
+		UserName: "hermes",
+		Password: "hermes",
+		FullName: "Conrad Hermes",
+		Email:    "hermes@planetexpress.com",
+		IsAdmin:  true,
+	},
+	{
+		UserName: "fry",
+		Password: "fry",
+		FullName: "Philip Fry",
+		Email:    "fry@planetexpress.com",
+	},
+	{
+		UserName: "leela",
+		Password: "leela",
+		FullName: "Leela Turanga",
+		Email:    "leela@planetexpress.com",
+	},
+	{
+		UserName: "bender",
+		Password: "bender",
+		FullName: "Bender Rodríguez",
+		Email:    "bender@planetexpress.com",
+	},
+}
+
+var otherLDAPUsers = []ldapUser{
+	{
+		UserName: "zoidberg",
+		Password: "zoidberg",
+		FullName: "John Zoidberg",
+		Email:    "zoidberg@planetexpress.com",
+	},
+	{
+		UserName: "amy",
+		Password: "amy",
+		FullName: "Amy Kroker",
+		Email:    "amy@planetexpress.com",
+	},
+}
+
+func skipLDAPTests() bool {
+	return os.Getenv("TEST_LDAP") != "1"
+}
+
+func getLDAPServerHost() string {
+	host := os.Getenv("TEST_LDAP_HOST")
+	if len(host) == 0 {
+		host = "ldap"
+	}
+	return host
+}
+
+func addAuthSourceLDAP(t *testing.T) {
+	session := loginUser(t, "user1")
+	csrf := GetCSRF(t, session, "/admin/auths/new")
+	req := NewRequestWithValues(t, "POST", "/admin/auths/new", map[string]string{
+		"_csrf":              csrf,
+		"type":               "2",
+		"name":               "ldap",
+		"host":               getLDAPServerHost(),
+		"port":               "389",
+		"bind_dn":            "uid=gitea,ou=service,dc=planetexpress,dc=com",
+		"bind_password":      "password",
+		"user_base":          "ou=people,dc=planetexpress,dc=com",
+		"filter":             "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))",
+		"admin_filter":       "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)",
+		"attribute_username": "uid",
+		"attribute_name":     "givenName",
+		"attribute_surname":  "sn",
+		"attribute_mail":     "mail",
+		"is_sync_enabled":    "on",
+		"is_active":          "on",
+	})
+	session.MakeRequest(t, req, http.StatusFound)
+}
+
+func TestLDAPUserSignin(t *testing.T) {
+	if skipLDAPTests() {
+		t.Skip()
+		return
+	}
+	prepareTestEnv(t)
+	addAuthSourceLDAP(t)
+
+	u := gitLDAPUsers[0]
+
+	session := loginUserWithPassword(t, u.UserName, u.Password)
+	req := NewRequest(t, "GET", "/user/settings")
+	resp := session.MakeRequest(t, req, http.StatusOK)
+
+	htmlDoc := NewHTMLParser(t, resp.Body)
+
+	assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name"))
+	assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name"))
+	assert.Equal(t, u.Email, htmlDoc.GetInputValueByName("email"))
+}
+
+func TestLDAPUserSync(t *testing.T) {
+	if skipLDAPTests() {
+		t.Skip()
+		return
+	}
+	prepareTestEnv(t)
+	addAuthSourceLDAP(t)
+	models.SyncExternalUsers()
+
+	session := loginUser(t, "user1")
+	// Check if users exists
+	for _, u := range gitLDAPUsers {
+		req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
+		resp := session.MakeRequest(t, req, http.StatusOK)
+
+		htmlDoc := NewHTMLParser(t, resp.Body)
+
+		tr := htmlDoc.doc.Find("table.table tbody tr")
+		if !assert.True(t, tr.Length() == 1) {
+			continue
+		}
+		tds := tr.Find("td")
+		if !assert.True(t, tds.Length() > 0) {
+			continue
+		}
+		assert.Equal(t, u.UserName, strings.TrimSpace(tds.Find("td:nth-child(2) a").Text()))
+		assert.Equal(t, u.Email, strings.TrimSpace(tds.Find("td:nth-child(3) span").Text()))
+		if u.IsAdmin {
+			assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-check-square-o"))
+		} else {
+			assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-square-o"))
+		}
+	}
+
+	// Check if no users exist
+	for _, u := range otherLDAPUsers {
+		req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
+		resp := session.MakeRequest(t, req, http.StatusOK)
+
+		htmlDoc := NewHTMLParser(t, resp.Body)
+
+		tr := htmlDoc.doc.Find("table.table tbody tr")
+		assert.True(t, tr.Length() == 0)
+	}
+}
+
+func TestLDAPUserSigninFailed(t *testing.T) {
+	if skipLDAPTests() {
+		t.Skip()
+		return
+	}
+	prepareTestEnv(t)
+	addAuthSourceLDAP(t)
+
+	u := otherLDAPUsers[0]
+
+	testLoginFailed(t, u.UserName, u.Password, i18n.Tr("en", "form.username_password_incorrect"))
+}
diff --git a/models/fixtures/login_source.yml b/models/fixtures/login_source.yml
new file mode 100644
index 000000000000..ca780a73aa0c
--- /dev/null
+++ b/models/fixtures/login_source.yml
@@ -0,0 +1 @@
+[] # empty