summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorJoram Wilander <jwawilander@gmail.com>2017-09-01 14:28:15 -0400
committerGitHub <noreply@github.com>2017-09-01 14:28:15 -0400
commite2042c4b6579aa367bdf764ddecbca4e1bd38772 (patch)
treedc92c71098412235cb3a582daafd395af7b9afe4 /app
parentb6456a675d140d6d80eb0874a5b6a89008e28eaa (diff)
downloadchat-e2042c4b6579aa367bdf764ddecbca4e1bd38772.tar.gz
chat-e2042c4b6579aa367bdf764ddecbca4e1bd38772.tar.bz2
chat-e2042c4b6579aa367bdf764ddecbca4e1bd38772.zip
Add built-in plugin for getting LDAP attributes (#7317)
Diffstat (limited to 'app')
-rw-r--r--app/plugin/api.go8
-rw-r--r--app/plugin/ldapextras/configuration.go9
-rw-r--r--app/plugin/ldapextras/plugin.go73
-rw-r--r--app/plugins.go66
4 files changed, 155 insertions, 1 deletions
diff --git a/app/plugin/api.go b/app/plugin/api.go
index 41838b818..4604bf8ce 100644
--- a/app/plugin/api.go
+++ b/app/plugin/api.go
@@ -32,6 +32,14 @@ type API interface {
// Creates a post
CreatePost(post *model.Post) (*model.Post, *model.AppError)
+ // Get LDAP attributes for a user
+ GetLdapUserAttributes(userId string, attributes []string) (map[string]string, *model.AppError)
+
+ // Temporary for built-in plugins, copied from api4/context.go ServeHTTP function.
+ // If a request has a valid token for an active session, the session is returned otherwise
+ // it errors.
+ GetSessionFromRequest(r *http.Request) (*model.Session, *model.AppError)
+
// Returns a localized string. If a request is given, its headers will be used to pick a locale.
I18n(id string, r *http.Request) string
}
diff --git a/app/plugin/ldapextras/configuration.go b/app/plugin/ldapextras/configuration.go
new file mode 100644
index 000000000..078c29925
--- /dev/null
+++ b/app/plugin/ldapextras/configuration.go
@@ -0,0 +1,9 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package ldapextras
+
+type Configuration struct {
+ Enabled bool
+ Attributes []string
+}
diff --git a/app/plugin/ldapextras/plugin.go b/app/plugin/ldapextras/plugin.go
new file mode 100644
index 000000000..3198125aa
--- /dev/null
+++ b/app/plugin/ldapextras/plugin.go
@@ -0,0 +1,73 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package ldapextras
+
+import (
+ "fmt"
+ "net/http"
+ "sync/atomic"
+
+ l4g "github.com/alecthomas/log4go"
+ "github.com/gorilla/mux"
+
+ "github.com/mattermost/platform/app/plugin"
+ "github.com/mattermost/platform/model"
+ "github.com/mattermost/platform/utils"
+)
+
+type Plugin struct {
+ plugin.Base
+ api plugin.API
+ configuration atomic.Value
+}
+
+func (p *Plugin) Initialize(api plugin.API) {
+ p.api = api
+ p.OnConfigurationChange()
+ api.PluginRouter().HandleFunc("/users/{user_id:[A-Za-z0-9]+}/attributes", p.handleGetAttributes).Methods("GET")
+}
+
+func (p *Plugin) config() *Configuration {
+ return p.configuration.Load().(*Configuration)
+}
+
+func (p *Plugin) OnConfigurationChange() {
+ var configuration Configuration
+ if err := p.api.LoadPluginConfiguration(&configuration); err != nil {
+ l4g.Error(err.Error())
+ }
+ p.configuration.Store(&configuration)
+}
+
+func (p *Plugin) handleGetAttributes(w http.ResponseWriter, r *http.Request) {
+ config := p.config()
+ if !config.Enabled || len(config.Attributes) == 0 {
+ http.Error(w, "This plugin is not configured", http.StatusNotImplemented)
+ return
+ }
+
+ session, err := p.api.GetSessionFromRequest(r)
+
+ if session == nil || err != nil {
+ http.Error(w, "Invalid session", http.StatusUnauthorized)
+ return
+ }
+
+ // Only requires a valid session, no other permission checks required
+
+ params := mux.Vars(r)
+ id := params["user_id"]
+
+ if len(id) != 26 {
+ http.Error(w, "Invalid user id", http.StatusUnauthorized)
+ }
+
+ attributes, err := p.api.GetLdapUserAttributes(id, config.Attributes)
+ if err != nil {
+ err.Translate(utils.T)
+ http.Error(w, fmt.Sprintf("Errored getting attributes: %v", err.Error()), http.StatusInternalServerError)
+ }
+
+ w.Write([]byte(model.MapToJson(attributes)))
+}
diff --git a/app/plugins.go b/app/plugins.go
index 51f6414a3..1101f2b65 100644
--- a/app/plugins.go
+++ b/app/plugins.go
@@ -15,11 +15,13 @@ import (
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
+ "github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"github.com/mattermost/platform/app/plugin"
"github.com/mattermost/platform/app/plugin/jira"
+ "github.com/mattermost/platform/app/plugin/ldapextras"
)
type PluginAPI struct {
@@ -59,6 +61,67 @@ func (api *PluginAPI) CreatePost(post *model.Post) (*model.Post, *model.AppError
return CreatePostMissingChannel(post, true)
}
+func (api *PluginAPI) GetLdapUserAttributes(userId string, attributes []string) (map[string]string, *model.AppError) {
+ ldapInterface := einterfaces.GetLdapInterface()
+ if ldapInterface == nil {
+ return nil, model.NewAppError("GetLdapUserAttributes", "ent.ldap.disabled.app_error", nil, "", http.StatusNotImplemented)
+ }
+
+ user, err := GetUser(userId)
+ if err != nil {
+ return nil, err
+ }
+
+ return ldapInterface.GetUserAttributes(*user.AuthData, attributes)
+}
+
+func (api *PluginAPI) GetSessionFromRequest(r *http.Request) (*model.Session, *model.AppError) {
+ token := ""
+ isTokenFromQueryString := false
+
+ // Attempt to parse token out of the header
+ authHeader := r.Header.Get(model.HEADER_AUTH)
+ if len(authHeader) > 6 && strings.ToUpper(authHeader[0:6]) == model.HEADER_BEARER {
+ // Default session token
+ token = authHeader[7:]
+
+ } else if len(authHeader) > 5 && strings.ToLower(authHeader[0:5]) == model.HEADER_TOKEN {
+ // OAuth token
+ token = authHeader[6:]
+ }
+
+ // Attempt to parse the token from the cookie
+ if len(token) == 0 {
+ if cookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil {
+ token = cookie.Value
+
+ if r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML {
+ return nil, model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to be a CSRF attempt", http.StatusUnauthorized)
+ }
+ }
+ }
+
+ // Attempt to parse token out of the query string
+ if len(token) == 0 {
+ token = r.URL.Query().Get("access_token")
+ isTokenFromQueryString = true
+ }
+
+ if len(token) == 0 {
+ return nil, model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token, http.StatusUnauthorized)
+ }
+
+ session, err := GetSession(token)
+
+ if err != nil {
+ return nil, model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token, http.StatusUnauthorized)
+ } else if !session.IsOAuth && isTokenFromQueryString {
+ return nil, model.NewAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token, http.StatusUnauthorized)
+ }
+
+ return session, nil
+}
+
func (api *PluginAPI) I18n(id string, r *http.Request) string {
if r != nil {
f, _ := utils.GetTranslationsAndLocale(nil, r)
@@ -70,7 +133,8 @@ func (api *PluginAPI) I18n(id string, r *http.Request) string {
func InitPlugins() {
plugins := map[string]plugin.Plugin{
- "jira": &jira.Plugin{},
+ "jira": &jira.Plugin{},
+ "ldapextras": &ldapextras.Plugin{},
}
for id, p := range plugins {
l4g.Info("Initializing plugin: " + id)