MM-11693 Allow connections to /plugins for interactive message buttons. (#9333)

* Allow connetions to /plugins for interactive message buttons.

* Adding siteurl to exclusions for AllowedUntrustedInternalConnections

* Adding subpath support for allowing interactive message buttons plugin connections.
This commit is contained in:
Christopher Speller
2018-09-02 00:30:10 -07:00
committed by Carlos Tadeu Panato Junior
parent 68fdaaa995
commit 9f46512759
3 changed files with 144 additions and 3 deletions

View File

@@ -12,6 +12,7 @@ import (
"io"
"net/http"
"net/url"
"path"
"regexp"
"strings"
@@ -882,7 +883,19 @@ func (a *App) DoPostAction(postId, actionId, userId, selectedOption string) *mod
req, _ := http.NewRequest("POST", action.Integration.URL, strings.NewReader(request.ToJson()))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
resp, err := a.HTTPClient(false).Do(req)
// Allow access to plugin routes for action buttons
var httpClient *http.Client
url, _ := url.Parse(action.Integration.URL)
siteURL, _ := url.Parse(*a.Config().ServiceSettings.SiteURL)
subpath, _ := utils.GetSubpathFromConfig(a.Config())
if (url.Hostname() == "localhost" || url.Hostname() == "127.0.0.1" || url.Hostname() == siteURL.Hostname()) && strings.HasPrefix(url.Path, path.Join(subpath, "plugins")) {
httpClient = a.HTTPClient(true)
} else {
httpClient = a.HTTPClient(false)
}
resp, err := httpClient.Do(req)
if err != nil {
return model.NewAppError("DoPostAction", "api.post.do_action.action_integration.app_error", nil, "err="+err.Error(), http.StatusBadRequest)
}

View File

@@ -142,7 +142,7 @@ func TestPostAction(t *testing.T) {
}
assert.Equal(t, "foo", request.Context["s"])
assert.EqualValues(t, 3, request.Context["n"])
fmt.Fprintf(w, `{"update": {"message": "updated"}, "ephemeral_text": "foo"}`)
fmt.Fprintf(w, `{"post": {"message": "updated"}, "ephemeral_text": "foo"}`)
}))
defer ts.Close()
@@ -229,6 +229,134 @@ func TestPostAction(t *testing.T) {
err = th.App.DoPostAction(post2.Id, attachments2[0].Actions[0].Id, th.BasicUser.Id, "selected")
require.Nil(t, err)
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = ""
})
err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.NotNil(t, err)
require.True(t, strings.Contains(err.Error(), "address forbidden"))
interactivePostPlugin := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
Context: model.StringInterface{
"s": "foo",
"n": 3,
},
URL: ts.URL + "/plugins/myplugin/myaction",
},
Name: "action",
Type: "some_type",
DataSource: "some_source",
},
},
},
},
},
}
postplugin, err := th.App.CreatePostAsUser(&interactivePostPlugin)
require.Nil(t, err)
attachmentsPlugin, ok := postplugin.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
err = th.App.DoPostAction(postplugin.Id, attachmentsPlugin[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err)
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.SiteURL = "http://127.1.1.1"
})
interactivePostSiteURL := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
Context: model.StringInterface{
"s": "foo",
"n": 3,
},
URL: "http://127.1.1.1/plugins/myplugin/myaction",
},
Name: "action",
Type: "some_type",
DataSource: "some_source",
},
},
},
},
},
}
postSiteURL, err := th.App.CreatePostAsUser(&interactivePostSiteURL)
require.Nil(t, err)
attachmentsSiteURL, ok := postSiteURL.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
err = th.App.DoPostAction(postSiteURL.Id, attachmentsSiteURL[0].Actions[0].Id, th.BasicUser.Id, "")
require.NotNil(t, err)
require.False(t, strings.Contains(err.Error(), "address forbidden"))
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.SiteURL = ts.URL + "/subpath"
})
interactivePostSubpath := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
Context: model.StringInterface{
"s": "foo",
"n": 3,
},
URL: ts.URL + "/subpath/plugins/myplugin/myaction",
},
Name: "action",
Type: "some_type",
DataSource: "some_source",
},
},
},
},
},
}
postSubpath, err := th.App.CreatePostAsUser(&interactivePostSubpath)
require.Nil(t, err)
attachmentsSubpath, ok := postSubpath.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
err = th.App.DoPostAction(postSubpath.Id, attachmentsSubpath[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err)
}
func TestPostChannelMentions(t *testing.T) {

View File

@@ -52,7 +52,7 @@ func init() {
type DialContextFunction func(ctx context.Context, network, addr string) (net.Conn, error)
var AddressForbidden error = errors.New("address forbidden")
var AddressForbidden error = errors.New("address forbidden, you may need to set AllowedUntrustedInternalConnections to allow an integration access to your internal network")
func dialContextFilter(dial DialContextFunction, allowHost func(host string) bool, allowIP func(ip net.IP) bool) DialContextFunction {
return func(ctx context.Context, network, addr string) (net.Conn, error) {