summaryrefslogtreecommitdiffstats
path: root/model
diff options
context:
space:
mode:
Diffstat (limited to 'model')
-rw-r--r--model/access.go25
-rw-r--r--model/access_test.go10
-rw-r--r--model/authorize.go5
-rw-r--r--model/client.go46
-rw-r--r--model/oauth.go40
-rw-r--r--model/oauth_test.go8
-rw-r--r--model/preference.go3
7 files changed, 126 insertions, 11 deletions
diff --git a/model/access.go b/model/access.go
index 877b3c4f0..85417fce9 100644
--- a/model/access.go
+++ b/model/access.go
@@ -15,10 +15,12 @@ const (
)
type AccessData struct {
- AuthCode string `json:"auth_code"`
+ ClientId string `json:"client_id"`
+ UserId string `json:"user_id"`
Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
RedirectUri string `json:"redirect_uri"`
+ ExpiresAt int64 `json:"expires_at"`
}
type AccessResponse struct {
@@ -33,8 +35,12 @@ type AccessResponse struct {
// correctly.
func (ad *AccessData) IsValid() *AppError {
- if len(ad.AuthCode) == 0 || len(ad.AuthCode) > 128 {
- return NewLocAppError("AccessData.IsValid", "model.access.is_valid.auth_code.app_error", nil, "")
+ if len(ad.ClientId) == 0 || len(ad.ClientId) > 26 {
+ return NewLocAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "")
+ }
+
+ if len(ad.UserId) == 0 || len(ad.UserId) > 26 {
+ return NewLocAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "")
}
if len(ad.Token) != 26 {
@@ -52,6 +58,19 @@ func (ad *AccessData) IsValid() *AppError {
return nil
}
+func (me *AccessData) IsExpired() bool {
+
+ if me.ExpiresAt <= 0 {
+ return false
+ }
+
+ if GetMillis() > me.ExpiresAt {
+ return true
+ }
+
+ return false
+}
+
func (ad *AccessData) ToJson() string {
b, err := json.Marshal(ad)
if err != nil {
diff --git a/model/access_test.go b/model/access_test.go
index a018a2919..0eca302ba 100644
--- a/model/access_test.go
+++ b/model/access_test.go
@@ -10,7 +10,8 @@ import (
func TestAccessJson(t *testing.T) {
a1 := AccessData{}
- a1.AuthCode = NewId()
+ a1.ClientId = NewId()
+ a1.UserId = NewId()
a1.Token = NewId()
a1.RefreshToken = NewId()
@@ -29,7 +30,12 @@ func TestAccessIsValid(t *testing.T) {
t.Fatal("should have failed")
}
- ad.AuthCode = NewId()
+ ad.ClientId = NewId()
+ if err := ad.IsValid(); err == nil {
+ t.Fatal("should have failed")
+ }
+
+ ad.UserId = NewId()
if err := ad.IsValid(); err == nil {
t.Fatal("should have failed")
}
diff --git a/model/authorize.go b/model/authorize.go
index e0d665bae..2b4017e9c 100644
--- a/model/authorize.go
+++ b/model/authorize.go
@@ -11,6 +11,7 @@ import (
const (
AUTHCODE_EXPIRE_TIME = 60 * 10 // 10 minutes
AUTHCODE_RESPONSE_TYPE = "code"
+ DEFAULT_SCOPE = "user"
)
type AuthData struct {
@@ -71,6 +72,10 @@ func (ad *AuthData) PreSave() {
if ad.CreateAt == 0 {
ad.CreateAt = GetMillis()
}
+
+ if len(ad.Scope) == 0 {
+ ad.Scope = DEFAULT_SCOPE
+ }
}
func (ad *AuthData) ToJson() string {
diff --git a/model/client.go b/model/client.go
index 23648050f..cad551613 100644
--- a/model/client.go
+++ b/model/client.go
@@ -1446,6 +1446,8 @@ func (c *Client) GetTeamMembers(teamId string) (*Result, *AppError) {
}
}
+// RegisterApp creates a new OAuth2 app to be used with the OAuth2 Provider. On success
+// it returns the created app. Must be authenticated as a user.
func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
return nil, err
@@ -1456,6 +1458,9 @@ func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
}
}
+// AllowOAuth allows a new session by an OAuth2 App. On success
+// it returns the url to be redirected back to the app which initiated the oauth2 flow.
+// Must be authenticated as a user.
func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*Result, *AppError) {
if r, err := c.DoApiGet("/oauth/allow?response_type="+rspType+"&client_id="+clientId+"&redirect_uri="+url.QueryEscape(redirect)+"&scope="+scope+"&state="+url.QueryEscape(state), "", ""); err != nil {
return nil, err
@@ -1466,8 +1471,47 @@ func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*
}
}
+// GetOAuthAppsByUser returns the OAuth2 Apps registered by the user. On success
+// it returns a list of OAuth2 Apps from the same user or all the registered apps if the user
+// is a System Administrator. Must be authenticated as a user.
+func (c *Client) GetOAuthAppsByUser() (*Result, *AppError) {
+ if r, err := c.DoApiGet("/oauth/list", "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), OAuthAppListFromJson(r.Body)}, nil
+ }
+}
+
+// GetOAuthAppInfo lookup an OAuth2 App using the client_id. On success
+// it returns a Sanitized OAuth2 App. Must be authenticated as a user.
+func (c *Client) GetOAuthAppInfo(clientId string) (*Result, *AppError) {
+ if r, err := c.DoApiGet("/oauth/app/"+clientId, "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
+ }
+}
+
+// DeleteOAuthApp deletes an OAuth2 app, the app must be deleted by the same user who created it or
+// a System Administrator. On success returs Status OK. Must be authenticated as a user.
+func (c *Client) DeleteOAuthApp(id string) (*Result, *AppError) {
+ data := make(map[string]string)
+ data["id"] = id
+ if r, err := c.DoApiPost("/oauth/delete", MapToJson(data)); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) GetAccessToken(data url.Values) (*Result, *AppError) {
- if r, err := c.DoApiPost("/oauth/access_token", data.Encode()); err != nil {
+ if r, err := c.DoPost(API_URL_SUFFIX+"/oauth/access_token", data.Encode(), "application/x-www-form-urlencoded"); err != nil {
return nil, err
} else {
defer closeBody(r)
diff --git a/model/oauth.go b/model/oauth.go
index c54df107c..cfe643c9a 100644
--- a/model/oauth.go
+++ b/model/oauth.go
@@ -25,8 +25,10 @@ type OAuthApp struct {
ClientSecret string `json:"client_secret"`
Name string `json:"name"`
Description string `json:"description"`
+ IconURL string `json:"icon_url"`
CallbackUrls StringArray `json:"callback_urls"`
Homepage string `json:"homepage"`
+ IsTrusted bool `json:"is_trusted"`
}
// IsValid validates the app and returns an error if it isn't configured
@@ -61,7 +63,13 @@ func (a *OAuthApp) IsValid() *AppError {
return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id)
}
- if len(a.Homepage) == 0 || len(a.Homepage) > 256 {
+ for _, callback := range a.CallbackUrls {
+ if !IsValidHttpUrl(callback) {
+ return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "")
+ }
+ }
+
+ if len(a.Homepage) == 0 || len(a.Homepage) > 256 || !IsValidHttpUrl(a.Homepage) {
return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id)
}
@@ -69,6 +77,12 @@ func (a *OAuthApp) IsValid() *AppError {
return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id)
}
+ if len(a.IconURL) > 0 {
+ if len(a.IconURL) > 512 || !IsValidHttpUrl(a.IconURL) {
+ return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id)
+ }
+ }
+
return nil
}
@@ -85,10 +99,6 @@ func (a *OAuthApp) PreSave() {
a.CreateAt = GetMillis()
a.UpdateAt = a.CreateAt
-
- if len(a.ClientSecret) > 0 {
- a.ClientSecret = HashPassword(a.ClientSecret)
- }
}
// PreUpdate should be run before updating the app in the db.
@@ -157,3 +167,23 @@ func OAuthAppMapFromJson(data io.Reader) map[string]*OAuthApp {
return nil
}
}
+
+func OAuthAppListToJson(l []*OAuthApp) string {
+ b, err := json.Marshal(l)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func OAuthAppListFromJson(data io.Reader) []*OAuthApp {
+ decoder := json.NewDecoder(data)
+ var o []*OAuthApp
+ err := decoder.Decode(&o)
+ if err == nil {
+ return o
+ } else {
+ return nil
+ }
+}
diff --git a/model/oauth_test.go b/model/oauth_test.go
index 2ba36666c..e1f88a993 100644
--- a/model/oauth_test.go
+++ b/model/oauth_test.go
@@ -14,6 +14,7 @@ func TestOAuthAppJson(t *testing.T) {
a1.Name = "TestOAuthApp" + NewId()
a1.CallbackUrls = []string{"https://nowhere.com"}
a1.Homepage = "https://nowhere.com"
+ a1.IconURL = "https://nowhere.com/icon_image.png"
a1.ClientSecret = NewId()
json := a1.ToJson()
@@ -30,6 +31,7 @@ func TestOAuthAppPreSave(t *testing.T) {
a1.Name = "TestOAuthApp" + NewId()
a1.CallbackUrls = []string{"https://nowhere.com"}
a1.Homepage = "https://nowhere.com"
+ a1.IconURL = "https://nowhere.com/icon_image.png"
a1.ClientSecret = NewId()
a1.PreSave()
a1.Etag()
@@ -42,6 +44,7 @@ func TestOAuthAppPreUpdate(t *testing.T) {
a1.Name = "TestOAuthApp" + NewId()
a1.CallbackUrls = []string{"https://nowhere.com"}
a1.Homepage = "https://nowhere.com"
+ a1.IconURL = "https://nowhere.com/icon_image.png"
a1.ClientSecret = NewId()
a1.PreUpdate()
}
@@ -92,4 +95,9 @@ func TestOAuthAppIsValid(t *testing.T) {
if err := app.IsValid(); err != nil {
t.Fatal()
}
+
+ app.IconURL = "https://nowhere.com/icon_image.png"
+ if err := app.IsValid(); err != nil {
+ t.Fatal()
+ }
}
diff --git a/model/preference.go b/model/preference.go
index 779c41e50..b74e25d81 100644
--- a/model/preference.go
+++ b/model/preference.go
@@ -22,6 +22,9 @@ const (
PREFERENCE_CATEGORY_THEME = "theme"
// the name for theme props is the team id
+ PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP = "oauth_app"
+ // the name for oauth_app is the client_id and value is the current scope
+
PREFERENCE_CATEGORY_LAST = "last"
PREFERENCE_NAME_LAST_CHANNEL = "channel"
)