2019-03-08 19:42:50 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
2020-11-13 15:51:07 +03:00
"bytes"
2019-03-08 19:42:50 +03:00
"encoding/json"
2020-11-13 15:51:07 +03:00
"io/ioutil"
2019-03-08 19:42:50 +03:00
"testing"
2019-04-12 10:50:21 +03:00
"code.gitea.io/gitea/modules/setting"
2019-03-08 19:42:50 +03:00
"github.com/stretchr/testify/assert"
)
const defaultAuthorize = "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=a&response_type=code&state=thestate"
func TestNoClientID ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-08 19:42:50 +03:00
req := NewRequest ( t , "GET" , "/login/oauth/authorize" )
ctx := loginUser ( t , "user2" )
ctx . MakeRequest ( t , req , 400 )
}
func TestLoginRedirect ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-08 19:42:50 +03:00
req := NewRequest ( t , "GET" , "/login/oauth/authorize" )
assert . Contains ( t , MakeRequest ( t , req , 302 ) . Body . String ( ) , "/user/login" )
}
func TestShowAuthorize ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-08 19:42:50 +03:00
req := NewRequest ( t , "GET" , defaultAuthorize )
ctx := loginUser ( t , "user4" )
resp := ctx . MakeRequest ( t , req , 200 )
htmlDoc := NewHTMLParser ( t , resp . Body )
htmlDoc . AssertElement ( t , "#authorize-app" , true )
htmlDoc . GetCSRF ( )
}
func TestRedirectWithExistingGrant ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-08 19:42:50 +03:00
req := NewRequest ( t , "GET" , defaultAuthorize )
ctx := loginUser ( t , "user1" )
resp := ctx . MakeRequest ( t , req , 302 )
u , err := resp . Result ( ) . Location ( )
assert . NoError ( t , err )
assert . Equal ( t , "thestate" , u . Query ( ) . Get ( "state" ) )
assert . Truef ( t , len ( u . Query ( ) . Get ( "code" ) ) > 30 , "authorization code '%s' should be longer then 30" , u . Query ( ) . Get ( "code" ) )
}
func TestAccessTokenExchange ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-08 19:42:50 +03:00
req := NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
resp := MakeRequest ( t , req , 200 )
type response struct {
AccessToken string ` json:"access_token" `
TokenType string ` json:"token_type" `
ExpiresIn int64 ` json:"expires_in" `
RefreshToken string ` json:"refresh_token" `
}
parsed := new ( response )
assert . NoError ( t , json . Unmarshal ( resp . Body . Bytes ( ) , parsed ) )
assert . True ( t , len ( parsed . AccessToken ) > 10 )
assert . True ( t , len ( parsed . RefreshToken ) > 10 )
}
func TestAccessTokenExchangeWithoutPKCE ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-04-15 18:54:50 +03:00
req := NewRequestWithJSON ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
resp := MakeRequest ( t , req , 200 )
type response struct {
AccessToken string ` json:"access_token" `
TokenType string ` json:"token_type" `
ExpiresIn int64 ` json:"expires_in" `
RefreshToken string ` json:"refresh_token" `
}
parsed := new ( response )
assert . NoError ( t , json . Unmarshal ( resp . Body . Bytes ( ) , parsed ) )
assert . True ( t , len ( parsed . AccessToken ) > 10 )
assert . True ( t , len ( parsed . RefreshToken ) > 10 )
}
func TestAccessTokenExchangeJSON ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-04-15 18:54:50 +03:00
req := NewRequestWithJSON ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
2019-03-08 19:42:50 +03:00
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
} )
MakeRequest ( t , req , 400 )
}
func TestAccessTokenExchangeWithInvalidCredentials ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-08 19:42:50 +03:00
// invalid client id
req := NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "???" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
MakeRequest ( t , req , 400 )
// invalid client secret
req = NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "???" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
MakeRequest ( t , req , 400 )
// invalid redirect uri
req = NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "???" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
MakeRequest ( t , req , 400 )
// invalid authorization code
req = NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "???" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
MakeRequest ( t , req , 400 )
// invalid grant_type
req = NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "???" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
MakeRequest ( t , req , 400 )
}
2019-03-11 05:54:59 +03:00
func TestAccessTokenExchangeWithBasicAuth ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-03-11 05:54:59 +03:00
req := NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
req . Header . Add ( "Authorization" , "Basic ZGE3ZGEzYmEtOWExMy00MTY3LTg1NmYtMzg5OWRlMGIwMTM4OjRNSzhOYTZSNTVzbWRDWTBXdUNDdW1aNmhqUlBuR1k1c2FXVlJISGpKaUE9" )
resp := MakeRequest ( t , req , 200 )
type response struct {
AccessToken string ` json:"access_token" `
TokenType string ` json:"token_type" `
ExpiresIn int64 ` json:"expires_in" `
RefreshToken string ` json:"refresh_token" `
}
parsed := new ( response )
assert . NoError ( t , json . Unmarshal ( resp . Body . Bytes ( ) , parsed ) )
assert . True ( t , len ( parsed . AccessToken ) > 10 )
assert . True ( t , len ( parsed . RefreshToken ) > 10 )
// use wrong client_secret
req = NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
req . Header . Add ( "Authorization" , "Basic ZGE3ZGEzYmEtOWExMy00MTY3LTg1NmYtMzg5OWRlMGIwMTM4OmJsYWJsYQ==" )
resp = MakeRequest ( t , req , 400 )
// missing header
req = NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
resp = MakeRequest ( t , req , 400 )
}
2019-04-12 10:50:21 +03:00
func TestRefreshTokenInvalidation ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-04-12 10:50:21 +03:00
req := NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "authorization_code" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"code" : "authcode" ,
"code_verifier" : "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt" , // test PKCE additionally
} )
resp := MakeRequest ( t , req , 200 )
type response struct {
AccessToken string ` json:"access_token" `
TokenType string ` json:"token_type" `
ExpiresIn int64 ` json:"expires_in" `
RefreshToken string ` json:"refresh_token" `
}
parsed := new ( response )
assert . NoError ( t , json . Unmarshal ( resp . Body . Bytes ( ) , parsed ) )
// test without invalidation
setting . OAuth2 . InvalidateRefreshTokens = false
refreshReq := NewRequestWithValues ( t , "POST" , "/login/oauth/access_token" , map [ string ] string {
"grant_type" : "refresh_token" ,
"client_id" : "da7da3ba-9a13-4167-856f-3899de0b0138" ,
"client_secret" : "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=" ,
"redirect_uri" : "a" ,
"refresh_token" : parsed . RefreshToken ,
} )
2021-01-29 18:35:30 +03:00
2020-11-13 15:51:07 +03:00
bs , err := ioutil . ReadAll ( refreshReq . Body )
assert . NoError ( t , err )
refreshReq . Body = ioutil . NopCloser ( bytes . NewReader ( bs ) )
2019-04-12 10:50:21 +03:00
MakeRequest ( t , refreshReq , 200 )
2020-11-13 15:51:07 +03:00
refreshReq . Body = ioutil . NopCloser ( bytes . NewReader ( bs ) )
2019-04-12 10:50:21 +03:00
MakeRequest ( t , refreshReq , 200 )
// test with invalidation
setting . OAuth2 . InvalidateRefreshTokens = true
2020-11-13 15:51:07 +03:00
refreshReq . Body = ioutil . NopCloser ( bytes . NewReader ( bs ) )
2019-04-12 10:50:21 +03:00
MakeRequest ( t , refreshReq , 200 )
2020-11-13 15:51:07 +03:00
refreshReq . Body = ioutil . NopCloser ( bytes . NewReader ( bs ) )
2019-04-12 10:50:21 +03:00
MakeRequest ( t , refreshReq , 400 )
}