2019-03-08 08:15:38 -06:00
package api
import (
2019-04-30 07:42:01 -05:00
"context"
2020-11-13 02:52:38 -06:00
"fmt"
2019-03-08 08:15:38 -06:00
"testing"
"time"
2021-01-15 07:43:20 -06:00
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
2019-03-08 08:15:38 -06:00
"github.com/grafana/grafana/pkg/bus"
2020-03-04 05:57:20 -06:00
"github.com/grafana/grafana/pkg/models"
2019-03-08 08:15:38 -06:00
"github.com/grafana/grafana/pkg/services/auth"
2022-02-03 02:20:20 -06:00
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
2020-11-13 02:52:38 -06:00
"github.com/stretchr/testify/assert"
2019-03-08 08:15:38 -06:00
)
2020-11-13 02:52:38 -06:00
func TestUserTokenAPIEndpoint ( t * testing . T ) {
2022-02-03 02:20:20 -06:00
mock := mockstore . NewSQLStoreMock ( )
2020-11-13 02:52:38 -06:00
t . Run ( "When current user attempts to revoke an auth token for a non-existing user" , func ( t * testing . T ) {
2020-03-04 05:57:20 -06:00
cmd := models . RevokeAuthTokenCmd { AuthTokenId : 2 }
2022-02-03 02:20:20 -06:00
mock . ExpectedError = models . ErrUserNotFound
2020-11-13 02:52:38 -06:00
revokeUserAuthTokenScenario ( t , "Should return not found when calling POST on" , "/api/user/revoke-auth-token" ,
"/api/user/revoke-auth-token" , cmd , 200 , func ( sc * scenarioContext ) {
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string { } ) . exec ( )
assert . Equal ( t , 404 , sc . resp . Code )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
2020-11-13 02:52:38 -06:00
t . Run ( "When current user gets auth tokens for a non-existing user" , func ( t * testing . T ) {
2022-02-04 06:41:15 -06:00
mock := & mockstore . SQLStoreMock {
2022-02-03 02:20:20 -06:00
ExpectedUser : & models . User { Id : 200 } ,
ExpectedError : models . ErrUserNotFound ,
}
2020-11-13 02:52:38 -06:00
getUserAuthTokensScenario ( t , "Should return not found when calling GET on" , "/api/user/auth-tokens" , "/api/user/auth-tokens" , 200 , func ( sc * scenarioContext ) {
2019-03-08 08:15:38 -06:00
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , 404 , sc . resp . Code )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
2020-11-13 02:52:38 -06:00
t . Run ( "When logging out an existing user from all devices" , func ( t * testing . T ) {
2022-02-04 06:41:15 -06:00
mock := & mockstore . SQLStoreMock {
2022-02-03 02:20:20 -06:00
ExpectedUser : & models . User { Id : 200 } ,
}
2020-11-13 02:52:38 -06:00
logoutUserFromAllDevicesInternalScenario ( t , "Should be successful" , 1 , func ( sc * scenarioContext ) {
2019-03-08 08:15:38 -06:00
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string { } ) . exec ( )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , 200 , sc . resp . Code )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
2020-11-13 02:52:38 -06:00
t . Run ( "When logout a non-existing user from all devices" , func ( t * testing . T ) {
logoutUserFromAllDevicesInternalScenario ( t , "Should return not found" , testUserID , func ( sc * scenarioContext ) {
2022-02-03 02:20:20 -06:00
mock . ExpectedError = models . ErrUserNotFound
2019-03-08 08:15:38 -06:00
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string { } ) . exec ( )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , 404 , sc . resp . Code )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
2020-11-13 02:52:38 -06:00
t . Run ( "When revoke an auth token for a user" , func ( t * testing . T ) {
2020-03-04 05:57:20 -06:00
cmd := models . RevokeAuthTokenCmd { AuthTokenId : 2 }
token := & models . UserToken { Id : 1 }
2022-02-04 06:41:15 -06:00
mock := & mockstore . SQLStoreMock {
2022-02-03 02:20:20 -06:00
ExpectedUser : & models . User { Id : 200 } ,
}
2019-03-08 08:15:38 -06:00
2020-11-13 02:52:38 -06:00
revokeUserAuthTokenInternalScenario ( t , "Should be successful" , cmd , 200 , token , func ( sc * scenarioContext ) {
2020-03-04 05:57:20 -06:00
sc . userAuthTokenService . GetUserTokenProvider = func ( ctx context . Context , userId , userTokenId int64 ) ( * models . UserToken , error ) {
return & models . UserToken { Id : 2 } , nil
2019-03-08 08:15:38 -06:00
}
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string { } ) . exec ( )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , 200 , sc . resp . Code )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
2020-11-13 02:52:38 -06:00
t . Run ( "When revoke the active auth token used by himself" , func ( t * testing . T ) {
2020-03-04 05:57:20 -06:00
cmd := models . RevokeAuthTokenCmd { AuthTokenId : 2 }
token := & models . UserToken { Id : 2 }
2022-02-03 02:20:20 -06:00
mock := mockstore . NewSQLStoreMock ( )
2020-11-13 02:52:38 -06:00
revokeUserAuthTokenInternalScenario ( t , "Should not be successful" , cmd , testUserID , token , func ( sc * scenarioContext ) {
2021-12-28 09:08:07 -06:00
bus . AddHandler ( "test" , func ( ctx context . Context , cmd * models . GetUserByIdQuery ) error {
2020-11-13 02:52:38 -06:00
cmd . Result = & models . User { Id : testUserID }
return nil
} )
2020-03-04 05:57:20 -06:00
sc . userAuthTokenService . GetUserTokenProvider = func ( ctx context . Context , userId , userTokenId int64 ) ( * models . UserToken , error ) {
2019-03-08 08:15:38 -06:00
return token , nil
}
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string { } ) . exec ( )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , 400 , sc . resp . Code )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
2020-11-13 02:52:38 -06:00
t . Run ( "When gets auth tokens for a user" , func ( t * testing . T ) {
2020-03-04 05:57:20 -06:00
currentToken := & models . UserToken { Id : 1 }
2022-02-03 02:20:20 -06:00
mock := mockstore . NewSQLStoreMock ( )
2020-11-13 02:52:38 -06:00
getUserAuthTokensInternalScenario ( t , "Should be successful" , currentToken , func ( sc * scenarioContext ) {
2020-03-04 05:57:20 -06:00
tokens := [ ] * models . UserToken {
2019-03-08 08:15:38 -06:00
{
Id : 1 ,
ClientIp : "127.0.0.1" ,
UserAgent : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36" ,
CreatedAt : time . Now ( ) . Unix ( ) ,
SeenAt : time . Now ( ) . Unix ( ) ,
} ,
{
Id : 2 ,
ClientIp : "127.0.0.2" ,
UserAgent : "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1" ,
CreatedAt : time . Now ( ) . Unix ( ) ,
2019-07-08 07:30:02 -05:00
SeenAt : 0 ,
2019-03-08 08:15:38 -06:00
} ,
}
2020-03-04 05:57:20 -06:00
sc . userAuthTokenService . GetUserTokensProvider = func ( ctx context . Context , userId int64 ) ( [ ] * models . UserToken , error ) {
2019-03-08 08:15:38 -06:00
return tokens , nil
}
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string { } ) . exec ( )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , 200 , sc . resp . Code )
2019-03-08 08:15:38 -06:00
result := sc . ToJSON ( )
2020-11-13 02:52:38 -06:00
assert . Len ( t , result . MustArray ( ) , 2 )
2019-03-08 08:15:38 -06:00
resultOne := result . GetIndex ( 0 )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , tokens [ 0 ] . Id , resultOne . Get ( "id" ) . MustInt64 ( ) )
assert . True ( t , resultOne . Get ( "isActive" ) . MustBool ( ) )
assert . Equal ( t , "127.0.0.1" , resultOne . Get ( "clientIp" ) . MustString ( ) )
assert . Equal ( t , time . Unix ( tokens [ 0 ] . CreatedAt , 0 ) . Format ( time . RFC3339 ) , resultOne . Get ( "createdAt" ) . MustString ( ) )
assert . Equal ( t , time . Unix ( tokens [ 0 ] . SeenAt , 0 ) . Format ( time . RFC3339 ) , resultOne . Get ( "seenAt" ) . MustString ( ) )
assert . Equal ( t , "Other" , resultOne . Get ( "device" ) . MustString ( ) )
assert . Equal ( t , "Chrome" , resultOne . Get ( "browser" ) . MustString ( ) )
assert . Equal ( t , "72.0" , resultOne . Get ( "browserVersion" ) . MustString ( ) )
assert . Equal ( t , "Linux" , resultOne . Get ( "os" ) . MustString ( ) )
assert . Empty ( t , resultOne . Get ( "osVersion" ) . MustString ( ) )
2019-06-11 07:12:52 -05:00
2019-03-08 08:15:38 -06:00
resultTwo := result . GetIndex ( 1 )
2020-11-13 02:52:38 -06:00
assert . Equal ( t , tokens [ 1 ] . Id , resultTwo . Get ( "id" ) . MustInt64 ( ) )
assert . False ( t , resultTwo . Get ( "isActive" ) . MustBool ( ) )
assert . Equal ( t , "127.0.0.2" , resultTwo . Get ( "clientIp" ) . MustString ( ) )
assert . Equal ( t , time . Unix ( tokens [ 1 ] . CreatedAt , 0 ) . Format ( time . RFC3339 ) , resultTwo . Get ( "createdAt" ) . MustString ( ) )
assert . Equal ( t , time . Unix ( tokens [ 1 ] . CreatedAt , 0 ) . Format ( time . RFC3339 ) , resultTwo . Get ( "seenAt" ) . MustString ( ) )
assert . Equal ( t , "iPhone" , resultTwo . Get ( "device" ) . MustString ( ) )
assert . Equal ( t , "Mobile Safari" , resultTwo . Get ( "browser" ) . MustString ( ) )
assert . Equal ( t , "11.0" , resultTwo . Get ( "browserVersion" ) . MustString ( ) )
assert . Equal ( t , "iOS" , resultTwo . Get ( "os" ) . MustString ( ) )
assert . Equal ( t , "11.0" , resultTwo . Get ( "osVersion" ) . MustString ( ) )
2022-02-03 02:20:20 -06:00
} , mock )
2019-03-08 08:15:38 -06:00
} )
}
2020-11-13 02:52:38 -06:00
func revokeUserAuthTokenScenario ( t * testing . T , desc string , url string , routePattern string , cmd models . RevokeAuthTokenCmd ,
2022-02-03 02:20:20 -06:00
userId int64 , fn scenarioFunc , sqlStore sqlstore . Store ) {
2020-11-13 02:52:38 -06:00
t . Run ( fmt . Sprintf ( "%s %s" , desc , url ) , func ( t * testing . T ) {
t . Cleanup ( bus . ClearBusHandlers )
2019-03-08 08:15:38 -06:00
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ( )
hs := HTTPServer {
Bus : bus . GetBus ( ) ,
AuthTokenService : fakeAuthTokenService ,
2022-02-03 02:20:20 -06:00
SQLStore : sqlStore ,
2019-03-08 08:15:38 -06:00
}
2020-11-13 02:52:38 -06:00
sc := setupScenarioContext ( t , url )
2019-03-08 08:15:38 -06:00
sc . userAuthTokenService = fakeAuthTokenService
2021-01-15 07:43:20 -06:00
sc . defaultHandler = routing . Wrap ( func ( c * models . ReqContext ) response . Response {
2021-11-29 03:18:01 -06:00
c . Req . Body = mockRequestBody ( cmd )
2019-03-08 08:15:38 -06:00
sc . context = c
sc . context . UserId = userId
2020-11-13 02:52:38 -06:00
sc . context . OrgId = testOrgID
2020-03-04 05:57:20 -06:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 08:15:38 -06:00
2021-11-29 03:18:01 -06:00
return hs . RevokeUserAuthToken ( c )
2019-03-08 08:15:38 -06:00
} )
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
} )
}
2022-02-03 02:20:20 -06:00
func getUserAuthTokensScenario ( t * testing . T , desc string , url string , routePattern string , userId int64 , fn scenarioFunc , sqlStore sqlstore . Store ) {
2020-11-13 02:52:38 -06:00
t . Run ( fmt . Sprintf ( "%s %s" , desc , url ) , func ( t * testing . T ) {
t . Cleanup ( bus . ClearBusHandlers )
2019-03-08 08:15:38 -06:00
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ( )
hs := HTTPServer {
Bus : bus . GetBus ( ) ,
AuthTokenService : fakeAuthTokenService ,
2022-02-03 02:20:20 -06:00
SQLStore : sqlStore ,
2019-03-08 08:15:38 -06:00
}
2020-11-13 02:52:38 -06:00
sc := setupScenarioContext ( t , url )
2019-03-08 08:15:38 -06:00
sc . userAuthTokenService = fakeAuthTokenService
2021-01-15 07:43:20 -06:00
sc . defaultHandler = routing . Wrap ( func ( c * models . ReqContext ) response . Response {
2019-03-08 08:15:38 -06:00
sc . context = c
sc . context . UserId = userId
2020-11-13 02:52:38 -06:00
sc . context . OrgId = testOrgID
2020-03-04 05:57:20 -06:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 08:15:38 -06:00
return hs . GetUserAuthTokens ( c )
} )
sc . m . Get ( routePattern , sc . defaultHandler )
fn ( sc )
} )
}
2022-02-03 02:20:20 -06:00
func logoutUserFromAllDevicesInternalScenario ( t * testing . T , desc string , userId int64 , fn scenarioFunc , sqlStore sqlstore . Store ) {
2020-11-13 02:52:38 -06:00
t . Run ( desc , func ( t * testing . T ) {
t . Cleanup ( bus . ClearBusHandlers )
2019-03-08 08:15:38 -06:00
hs := HTTPServer {
Bus : bus . GetBus ( ) ,
AuthTokenService : auth . NewFakeUserAuthTokenService ( ) ,
2022-02-03 02:20:20 -06:00
SQLStore : sqlStore ,
2019-03-08 08:15:38 -06:00
}
2020-11-13 02:52:38 -06:00
sc := setupScenarioContext ( t , "/" )
2021-01-15 07:43:20 -06:00
sc . defaultHandler = routing . Wrap ( func ( c * models . ReqContext ) response . Response {
2019-03-08 08:15:38 -06:00
sc . context = c
2020-11-13 02:52:38 -06:00
sc . context . UserId = testUserID
sc . context . OrgId = testOrgID
2020-03-04 05:57:20 -06:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 08:15:38 -06:00
2019-04-30 07:42:01 -05:00
return hs . logoutUserFromAllDevicesInternal ( context . Background ( ) , userId )
2019-03-08 08:15:38 -06:00
} )
sc . m . Post ( "/" , sc . defaultHandler )
fn ( sc )
} )
}
2020-11-13 02:52:38 -06:00
func revokeUserAuthTokenInternalScenario ( t * testing . T , desc string , cmd models . RevokeAuthTokenCmd , userId int64 ,
2022-02-03 02:20:20 -06:00
token * models . UserToken , fn scenarioFunc , sqlStore sqlstore . Store ) {
2020-11-13 02:52:38 -06:00
t . Run ( desc , func ( t * testing . T ) {
t . Cleanup ( bus . ClearBusHandlers )
2019-03-08 08:15:38 -06:00
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ( )
hs := HTTPServer {
Bus : bus . GetBus ( ) ,
AuthTokenService : fakeAuthTokenService ,
2022-02-03 02:20:20 -06:00
SQLStore : sqlStore ,
2019-03-08 08:15:38 -06:00
}
2020-11-13 02:52:38 -06:00
sc := setupScenarioContext ( t , "/" )
2019-03-08 08:15:38 -06:00
sc . userAuthTokenService = fakeAuthTokenService
2021-01-15 07:43:20 -06:00
sc . defaultHandler = routing . Wrap ( func ( c * models . ReqContext ) response . Response {
2019-03-08 08:15:38 -06:00
sc . context = c
2020-11-13 02:52:38 -06:00
sc . context . UserId = testUserID
sc . context . OrgId = testOrgID
2020-03-04 05:57:20 -06:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 08:15:38 -06:00
sc . context . UserToken = token
return hs . revokeUserAuthTokenInternal ( c , userId , cmd )
} )
sc . m . Post ( "/" , sc . defaultHandler )
fn ( sc )
} )
}
2022-02-03 02:20:20 -06:00
func getUserAuthTokensInternalScenario ( t * testing . T , desc string , token * models . UserToken , fn scenarioFunc , sqlStore sqlstore . Store ) {
2020-11-13 02:52:38 -06:00
t . Run ( desc , func ( t * testing . T ) {
t . Cleanup ( bus . ClearBusHandlers )
2019-03-08 08:15:38 -06:00
fakeAuthTokenService := auth . NewFakeUserAuthTokenService ( )
hs := HTTPServer {
Bus : bus . GetBus ( ) ,
AuthTokenService : fakeAuthTokenService ,
2022-02-03 02:20:20 -06:00
SQLStore : sqlStore ,
2019-03-08 08:15:38 -06:00
}
2020-11-13 02:52:38 -06:00
sc := setupScenarioContext ( t , "/" )
2019-03-08 08:15:38 -06:00
sc . userAuthTokenService = fakeAuthTokenService
2021-01-15 07:43:20 -06:00
sc . defaultHandler = routing . Wrap ( func ( c * models . ReqContext ) response . Response {
2019-03-08 08:15:38 -06:00
sc . context = c
2020-11-13 02:52:38 -06:00
sc . context . UserId = testUserID
sc . context . OrgId = testOrgID
2020-03-04 05:57:20 -06:00
sc . context . OrgRole = models . ROLE_ADMIN
2019-03-08 08:15:38 -06:00
sc . context . UserToken = token
2020-11-13 02:52:38 -06:00
return hs . getUserAuthTokensInternal ( c , testUserID )
2019-03-08 08:15:38 -06:00
} )
sc . m . Get ( "/" , sc . defaultHandler )
fn ( sc )
} )
}