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) } }
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 }
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())) }