func (as SqlOAuthStore) SaveAccessData(accessData *model.AccessData) StoreChannel {

	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if result.Err = accessData.IsValid(); result.Err != nil {
			storeChannel <- result
			close(storeChannel)
			return
		}

		if err := as.GetMaster().Insert(accessData); err != nil {
			result.Err = model.NewLocAppError("SqlOAuthStore.SaveAccessData", "store.sql_oauth.save_access_data.app_error", nil, err.Error())
		} else {
			result.Data = accessData
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}
func TestOAuthStoreGetAccessData(t *testing.T) {
	Setup()

	a1 := model.AccessData{}
	a1.AuthCode = model.NewId()
	a1.Token = model.NewId()
	a1.RefreshToken = model.NewId()
	Must(store.OAuth().SaveAccessData(&a1))

	if result := <-store.OAuth().GetAccessData(a1.Token); result.Err != nil {
		t.Fatal(result.Err)
	} else {
		ra1 := result.Data.(*model.AccessData)
		if a1.Token != ra1.Token {
			t.Fatal("tokens didn't match")
		}
	}

	if err := (<-store.OAuth().GetAccessDataByAuthCode(a1.AuthCode)).Err; err != nil {
		t.Fatal(err)
	}

	if err := (<-store.OAuth().GetAccessDataByAuthCode("junk")).Err; err != nil {
		t.Fatal(err)
	}
}
func (as SqlOAuthStore) SaveAccessData(accessData *model.AccessData) StoreChannel {

	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if result.Err = accessData.IsValid(); result.Err != nil {
			storeChannel <- result
			close(storeChannel)
			return
		}

		if err := as.GetMaster().Insert(accessData); err != nil {
			result.Err = model.NewAppError("SqlOAuthStore.SaveAccessData", "We couldn't save the access token.", err.Error())
		} else {
			result.Data = accessData
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}
func TestOAuthStoreSaveAccessData(t *testing.T) {
	Setup()

	a1 := model.AccessData{}
	a1.AuthCode = model.NewId()
	a1.Token = model.NewId()
	a1.RefreshToken = model.NewId()

	if err := (<-store.OAuth().SaveAccessData(&a1)).Err; err != nil {
		t.Fatal(err)
	}
}
func TestOAuthGetAccessDataByUserForApp(t *testing.T) {
	Setup()

	a1 := model.OAuthApp{}
	a1.CreatorId = model.NewId()
	a1.Name = "TestApp" + model.NewId()
	a1.CallbackUrls = []string{"https://nowhere.com"}
	a1.Homepage = "https://nowhere.com"
	Must(store.OAuth().SaveApp(&a1))

	// allow the app
	p := model.Preference{}
	p.UserId = a1.CreatorId
	p.Category = model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP
	p.Name = a1.Id
	p.Value = "true"
	Must(store.Preference().Save(&model.Preferences{p}))

	if result := <-store.OAuth().GetAuthorizedApps(a1.CreatorId); result.Err != nil {
		t.Fatal(result.Err)
	} else {
		apps := result.Data.([]*model.OAuthApp)
		if len(apps) == 0 {
			t.Fatal("It should have return apps")
		}
	}

	// save the token
	ad1 := model.AccessData{}
	ad1.ClientId = a1.Id
	ad1.UserId = a1.CreatorId
	ad1.Token = model.NewId()
	ad1.RefreshToken = model.NewId()

	if err := (<-store.OAuth().SaveAccessData(&ad1)).Err; err != nil {
		t.Fatal(err)
	}

	if result := <-store.OAuth().GetAccessDataByUserForApp(a1.CreatorId, a1.Id); result.Err != nil {
		t.Fatal(result.Err)
	} else {
		accessData := result.Data.([]*model.AccessData)
		if len(accessData) == 0 {
			t.Fatal("It should have return access data")
		}
	}
}
func TestOAuthStoreRemoveAccessData(t *testing.T) {
	Setup()

	a1 := model.AccessData{}
	a1.ClientId = model.NewId()
	a1.UserId = model.NewId()
	a1.Token = model.NewId()
	a1.RefreshToken = model.NewId()
	Must(store.OAuth().SaveAccessData(&a1))

	if err := (<-store.OAuth().RemoveAccessData(a1.Token)).Err; err != nil {
		t.Fatal(err)
	}

	if result := (<-store.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)); result.Err != nil {
	} else {
		if result.Data != nil {
			t.Fatal("did not delete access token")
		}
	}
}
func TestOAuthStoreRemoveAccessData(t *testing.T) {
	Setup()

	a1 := model.AccessData{}
	a1.AuthCode = model.NewId()
	a1.Token = model.NewId()
	a1.RefreshToken = model.NewId()
	Must(store.OAuth().SaveAccessData(&a1))

	if err := (<-store.OAuth().RemoveAccessData(a1.Token)).Err; err != nil {
		t.Fatal(err)
	}

	if result := <-store.OAuth().GetAccessDataByAuthCode(a1.AuthCode); result.Err != nil {
		t.Fatal(result.Err)
	} else {
		if result.Data != nil {
			t.Fatal("did not delete access token")
		}
	}
}
func TestOAuthStoreGetAccessData(t *testing.T) {
	Setup()

	a1 := model.AccessData{}
	a1.ClientId = model.NewId()
	a1.UserId = model.NewId()
	a1.Token = model.NewId()
	a1.RefreshToken = model.NewId()
	a1.ExpiresAt = model.GetMillis()
	Must(store.OAuth().SaveAccessData(&a1))

	if result := <-store.OAuth().GetAccessData(a1.Token); result.Err != nil {
		t.Fatal(result.Err)
	} else {
		ra1 := result.Data.(*model.AccessData)
		if a1.Token != ra1.Token {
			t.Fatal("tokens didn't match")
		}
	}

	if err := (<-store.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)).Err; err != nil {
		t.Fatal(err)
	}

	if err := (<-store.OAuth().GetPreviousAccessData("user", "junk")).Err; err != nil {
		t.Fatal(err)
	}
}
Beispiel #9
0
func newSessionUpdateToken(appName string, accessData *model.AccessData, user *model.User) (*model.AccessResponse, *model.AppError) {
	var session *model.Session
	<-Srv.Store.Session().Remove(accessData.Token) //remove the previous session

	if result, err := newSession(appName, user); err != nil {
		return nil, err
	} else {
		session = result
	}

	accessData.Token = session.Token
	accessData.ExpiresAt = session.ExpiresAt
	if result := <-Srv.Store.OAuth().UpdateAccessData(accessData); result.Err != nil {
		l4g.Error(result.Err)
		return nil, model.NewLocAppError("getAccessToken", "web.get_access_token.internal_saving.app_error", nil, "")
	}
	accessRsp := &model.AccessResponse{
		AccessToken: session.Token,
		TokenType:   model.ACCESS_TOKEN_TYPE,
		ExpiresIn:   int32(*utils.Cfg.ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24),
	}

	return accessRsp, nil
}
Beispiel #10
0
func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
	if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
		c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.disabled.app_error", nil, "")
		c.Err.StatusCode = http.StatusNotImplemented
		return
	}

	c.LogAudit("attempt")

	r.ParseForm()

	code := r.FormValue("code")
	refreshToken := r.FormValue("refresh_token")

	grantType := r.FormValue("grant_type")
	switch grantType {
	case model.ACCESS_TOKEN_GRANT_TYPE:
		if len(code) == 0 {
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.missing_code.app_error", nil, "")
			return
		}
	case model.REFRESH_TOKEN_GRANT_TYPE:
		if len(refreshToken) == 0 {
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.missing_refresh_token.app_error", nil, "")
			return
		}
	default:
		c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.bad_grant.app_error", nil, "")
		return
	}

	clientId := r.FormValue("client_id")
	if len(clientId) != 26 {
		c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.bad_client_id.app_error", nil, "")
		return
	}

	secret := r.FormValue("client_secret")
	if len(secret) == 0 {
		c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.bad_client_secret.app_error", nil, "")
		return
	}

	var app *model.OAuthApp
	achan := Srv.Store.OAuth().GetApp(clientId)
	if result := <-achan; result.Err != nil {
		c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "")
		return
	} else {
		app = result.Data.(*model.OAuthApp)
	}

	if app.ClientSecret != secret {
		c.LogAudit("fail - invalid client credentials")
		c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "")
		return
	}

	var user *model.User
	var accessData *model.AccessData
	var accessRsp *model.AccessResponse
	if grantType == model.ACCESS_TOKEN_GRANT_TYPE {
		redirectUri := r.FormValue("redirect_uri")
		authData := GetAuthData(code)

		if authData == nil {
			c.LogAudit("fail - invalid auth code")
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "")
			return
		}

		if authData.IsExpired() {
			<-Srv.Store.OAuth().RemoveAuthData(authData.Code)
			c.LogAudit("fail - auth code expired")
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "")
			return
		}

		if authData.RedirectUri != redirectUri {
			c.LogAudit("fail - redirect uri provided did not match previous redirect uri")
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.redirect_uri.app_error", nil, "")
			return
		}

		if !model.ComparePassword(code, fmt.Sprintf("%v:%v:%v:%v", clientId, redirectUri, authData.CreateAt, authData.UserId)) {
			c.LogAudit("fail - auth code is invalid")
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "")
			return
		}

		uchan := Srv.Store.User().Get(authData.UserId)
		if result := <-uchan; result.Err != nil {
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "")
			return
		} else {
			user = result.Data.(*model.User)
		}

		tchan := Srv.Store.OAuth().GetPreviousAccessData(user.Id, clientId)
		if result := <-tchan; result.Err != nil {
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.internal.app_error", nil, "")
			return
		} else if result.Data != nil {
			accessData := result.Data.(*model.AccessData)
			if accessData.IsExpired() {
				if access, err := newSessionUpdateToken(app.Name, accessData, user); err != nil {
					c.Err = err
					return
				} else {
					accessRsp = access
				}
			} else {
				//return the same token and no need to create a new session
				accessRsp = &model.AccessResponse{
					AccessToken: accessData.Token,
					TokenType:   model.ACCESS_TOKEN_TYPE,
					ExpiresIn:   int32((accessData.ExpiresAt - model.GetMillis()) / 1000),
				}
			}
		} else {
			// create a new session and return new access token
			var session *model.Session
			if result, err := newSession(app.Name, user); err != nil {
				c.Err = err
				return
			} else {
				session = result
			}

			accessData = &model.AccessData{ClientId: clientId, UserId: user.Id, Token: session.Token, RefreshToken: model.NewId(), RedirectUri: redirectUri, ExpiresAt: session.ExpiresAt}

			if result := <-Srv.Store.OAuth().SaveAccessData(accessData); result.Err != nil {
				l4g.Error(result.Err)
				c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.internal_saving.app_error", nil, "")
				return
			}

			accessRsp = &model.AccessResponse{
				AccessToken:  session.Token,
				TokenType:    model.ACCESS_TOKEN_TYPE,
				RefreshToken: accessData.RefreshToken,
				ExpiresIn:    int32(*utils.Cfg.ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24),
			}
		}

		<-Srv.Store.OAuth().RemoveAuthData(authData.Code)
	} else {
		// when grantType is refresh_token
		if result := <-Srv.Store.OAuth().GetAccessDataByRefreshToken(refreshToken); result.Err != nil {
			c.LogAudit("fail - refresh token is invalid")
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.refresh_token.app_error", nil, "")
			return
		} else {
			accessData = result.Data.(*model.AccessData)
		}

		uchan := Srv.Store.User().Get(accessData.UserId)
		if result := <-uchan; result.Err != nil {
			c.Err = model.NewLocAppError("getAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "")
			return
		} else {
			user = result.Data.(*model.User)
		}

		if access, err := newSessionUpdateToken(app.Name, accessData, user); err != nil {
			c.Err = err
			return
		} else {
			accessRsp = access
		}
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Cache-Control", "no-store")
	w.Header().Set("Pragma", "no-cache")

	c.LogAuditWithUserId(user.Id, "success")

	w.Write([]byte(accessRsp.ToJson()))
}