2023-11-22 19:26:21 +03:00
// Copyright 2023 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"encoding/hex"
"net/http"
"net/url"
"strings"
"testing"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
2024-07-30 22:41:10 +03:00
"github.com/stretchr/testify/require"
2023-11-22 19:26:21 +03:00
)
// GetSessionForLTACookie returns a new session with only the LTA cookie being set.
func GetSessionForLTACookie ( t * testing . T , ltaCookie * http . Cookie ) * TestSession {
t . Helper ( )
ch := http . Header { }
ch . Add ( "Cookie" , ltaCookie . String ( ) )
cr := http . Request { Header : ch }
session := emptyTestSession ( t )
baseURL , err := url . Parse ( setting . AppURL )
2024-07-30 22:41:10 +03:00
require . NoError ( t , err )
2023-11-22 19:26:21 +03:00
session . jar . SetCookies ( baseURL , cr . Cookies ( ) )
return session
}
// GetLTACookieValue returns the value of the LTA cookie.
func GetLTACookieValue ( t * testing . T , sess * TestSession ) string {
t . Helper ( )
rememberCookie := sess . GetCookie ( setting . CookieRememberName )
assert . NotNil ( t , rememberCookie )
cookieValue , err := url . QueryUnescape ( rememberCookie . Value )
2024-07-30 22:41:10 +03:00
require . NoError ( t , err )
2023-11-22 19:26:21 +03:00
return cookieValue
}
// TestSessionCookie checks if the session cookie provides authentication.
func TestSessionCookie ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
sess := loginUser ( t , "user1" )
assert . NotNil ( t , sess . GetCookie ( setting . SessionConfig . CookieName ) )
req := NewRequest ( t , "GET" , "/user/settings" )
sess . MakeRequest ( t , req , http . StatusOK )
}
// TestLTACookie checks if the LTA cookie that's returned is valid, exists in the database
// and provides authentication of no session cookie is present.
func TestLTACookie ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } )
sess := emptyTestSession ( t )
req := NewRequestWithValues ( t , "POST" , "/user/login" , map [ string ] string {
"_csrf" : GetCSRF ( t , sess , "/user/login" ) ,
"user_name" : user . Name ,
"password" : userPassword ,
"remember" : "true" ,
} )
sess . MakeRequest ( t , req , http . StatusSeeOther )
// Checks if the database entry exist for the user.
ltaCookieValue := GetLTACookieValue ( t , sess )
lookupKey , validator , found := strings . Cut ( ltaCookieValue , ":" )
assert . True ( t , found )
rawValidator , err := hex . DecodeString ( validator )
2024-07-30 22:41:10 +03:00
require . NoError ( t , err )
2023-11-22 19:26:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & auth . AuthorizationToken { LookupKey : lookupKey , HashedValidator : auth . HashValidator ( rawValidator ) , UID : user . ID } )
// Check if the LTA cookie it provides authentication.
// If LTA cookie provides authentication /user/login shouldn't return status 200.
session := GetSessionForLTACookie ( t , sess . GetCookie ( setting . CookieRememberName ) )
req = NewRequest ( t , "GET" , "/user/login" )
session . MakeRequest ( t , req , http . StatusSeeOther )
}
// TestLTAPasswordChange checks that LTA doesn't provide authentication when a
// password change has happened and that the new LTA does provide authentication.
func TestLTAPasswordChange ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } )
sess := loginUserWithPasswordRemember ( t , user . Name , userPassword , true )
oldRememberCookie := sess . GetCookie ( setting . CookieRememberName )
assert . NotNil ( t , oldRememberCookie )
// Make a simple password change.
req := NewRequestWithValues ( t , "POST" , "/user/settings/account" , map [ string ] string {
"_csrf" : GetCSRF ( t , sess , "/user/settings/account" ) ,
"old_password" : userPassword ,
"password" : "password2" ,
"retype" : "password2" ,
} )
sess . MakeRequest ( t , req , http . StatusSeeOther )
rememberCookie := sess . GetCookie ( setting . CookieRememberName )
assert . NotNil ( t , rememberCookie )
// Check if the password really changed.
assert . NotEqualValues ( t , unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } ) . Passwd , user . Passwd )
// /user/settings/account should provide with a new LTA cookie, so check for that.
// If LTA cookie provides authentication /user/login shouldn't return status 200.
session := GetSessionForLTACookie ( t , rememberCookie )
req = NewRequest ( t , "GET" , "/user/login" )
session . MakeRequest ( t , req , http . StatusSeeOther )
// Check if the old LTA token is invalidated.
session = GetSessionForLTACookie ( t , oldRememberCookie )
req = NewRequest ( t , "GET" , "/user/login" )
session . MakeRequest ( t , req , http . StatusOK )
}
// TestLTAExpiry tests that the LTA expiry works.
func TestLTAExpiry ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } )
sess := loginUserWithPasswordRemember ( t , user . Name , userPassword , true )
ltaCookieValie := GetLTACookieValue ( t , sess )
lookupKey , _ , found := strings . Cut ( ltaCookieValie , ":" )
assert . True ( t , found )
// Ensure it's not expired.
lta := unittest . AssertExistsAndLoadBean ( t , & auth . AuthorizationToken { UID : user . ID , LookupKey : lookupKey } )
assert . False ( t , lta . IsExpired ( ) )
// Manually stub LTA's expiry.
_ , err := db . GetEngine ( db . DefaultContext ) . ID ( lta . ID ) . Table ( "forgejo_auth_token" ) . Cols ( "expiry" ) . Update ( & auth . AuthorizationToken { Expiry : timeutil . TimeStampNow ( ) } )
2024-07-30 22:41:10 +03:00
require . NoError ( t , err )
2023-11-22 19:26:21 +03:00
// Ensure it's expired.
lta = unittest . AssertExistsAndLoadBean ( t , & auth . AuthorizationToken { UID : user . ID , LookupKey : lookupKey } )
assert . True ( t , lta . IsExpired ( ) )
// Should return 200 OK, because LTA doesn't provide authorization anymore.
session := GetSessionForLTACookie ( t , sess . GetCookie ( setting . CookieRememberName ) )
req := NewRequest ( t , "GET" , "/user/login" )
session . MakeRequest ( t , req , http . StatusOK )
// Ensure it's deleted.
unittest . AssertNotExistsBean ( t , & auth . AuthorizationToken { UID : user . ID , LookupKey : lookupKey } )
}