2019-11-02 21:32:58 +07:00
|
|
|
package suites
|
|
|
|
|
|
|
|
import (
|
2019-11-25 03:27:59 +07:00
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
2019-11-02 21:32:58 +07:00
|
|
|
"testing"
|
2019-11-25 03:27:59 +07:00
|
|
|
"time"
|
2019-11-02 21:32:58 +07:00
|
|
|
|
2019-12-07 23:40:42 +07:00
|
|
|
"github.com/clems4ever/authelia/internal/storage"
|
|
|
|
"github.com/stretchr/testify/require"
|
2019-11-02 21:32:58 +07:00
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
)
|
|
|
|
|
2019-11-25 03:27:59 +07:00
|
|
|
type StandaloneWebDriverSuite struct {
|
2019-11-02 21:32:58 +07:00
|
|
|
*SeleniumSuite
|
|
|
|
}
|
|
|
|
|
2019-11-25 03:27:59 +07:00
|
|
|
func NewStandaloneWebDriverSuite() *StandaloneWebDriverSuite {
|
|
|
|
return &StandaloneWebDriverSuite{SeleniumSuite: new(SeleniumSuite)}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneWebDriverSuite) SetupSuite() {
|
|
|
|
wds, err := StartWebDriver()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
s.WebDriverSession = wds
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneWebDriverSuite) TearDownSuite() {
|
|
|
|
err := s.WebDriverSession.Stop()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneWebDriverSuite) SetupTest() {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
s.doLogout(ctx, s.T())
|
|
|
|
s.WebDriverSession.doVisit(s.T(), HomeBaseURL)
|
|
|
|
s.verifyIsHome(ctx, s.T())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneWebDriverSuite) TestShouldLetUserKnowHeIsAlreadyAuthenticated() {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
_ = s.doRegisterAndLogin2FA(ctx, s.T(), "john", "password", false, "")
|
|
|
|
|
|
|
|
// Visit home page to change context
|
|
|
|
s.doVisit(s.T(), HomeBaseURL)
|
|
|
|
s.verifyIsHome(ctx, s.T())
|
|
|
|
|
|
|
|
// Visit the login page and wait for redirection to 2FA page with success icon displayed
|
|
|
|
s.doVisit(s.T(), LoginBaseURL)
|
|
|
|
s.verifyIsSecondFactorPage(ctx, s.T())
|
|
|
|
|
|
|
|
// Check whether the success icon is displayed
|
|
|
|
s.WaitElementLocatedByClassName(ctx, s.T(), "success-icon")
|
|
|
|
}
|
|
|
|
|
2019-12-07 23:40:42 +07:00
|
|
|
func (s *StandaloneWebDriverSuite) TestShouldCheckUserIsAskedToRegisterDevice() {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
username := "john"
|
|
|
|
password := "password"
|
|
|
|
|
|
|
|
// Clean up any TOTP secret already in DB
|
|
|
|
provider := storage.NewSQLiteProvider("/tmp/authelia/db.sqlite3")
|
|
|
|
require.NoError(s.T(), provider.DeleteTOTPSecret(username))
|
|
|
|
|
|
|
|
// Login one factor
|
|
|
|
s.doLoginOneFactor(ctx, s.T(), username, password, false, "")
|
|
|
|
|
|
|
|
// Check the user is asked to register a new device
|
|
|
|
s.WaitElementLocatedByClassName(ctx, s.T(), "state-not-registered")
|
|
|
|
|
|
|
|
// Then register the TOTP factor
|
|
|
|
s.doRegisterTOTP(ctx, s.T())
|
|
|
|
// And logout
|
|
|
|
s.doLogout(ctx, s.T())
|
|
|
|
|
|
|
|
// Login one factor again
|
|
|
|
s.doLoginOneFactor(ctx, s.T(), username, password, false, "")
|
|
|
|
|
|
|
|
// now the user should be asked to perform 2FA
|
|
|
|
s.WaitElementLocatedByClassName(ctx, s.T(), "state-method")
|
|
|
|
}
|
|
|
|
|
2019-11-25 03:27:59 +07:00
|
|
|
type StandaloneSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
}
|
|
|
|
|
2019-11-02 21:32:58 +07:00
|
|
|
func NewStandaloneSuite() *StandaloneSuite {
|
2019-11-25 03:27:59 +07:00
|
|
|
return &StandaloneSuite{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Standard case using nginx
|
|
|
|
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() {
|
|
|
|
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify", AutheliaBaseURL), nil)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
req.Header.Set("X-Forwarded-Proto", "https")
|
|
|
|
req.Header.Set("X-Original-URL", AdminBaseURL)
|
|
|
|
|
|
|
|
client := NewHTTPClient()
|
|
|
|
res, err := client.Do(req)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
s.Assert().Equal(res.StatusCode, 401)
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
s.Assert().Equal(string(body), "Unauthorized")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Standard case using Kubernetes
|
|
|
|
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyRedirectFromXOriginalURL() {
|
|
|
|
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify?rd=%s", AutheliaBaseURL, LoginBaseURL), nil)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
req.Header.Set("X-Forwarded-Proto", "https")
|
|
|
|
req.Header.Set("X-Original-URL", AdminBaseURL)
|
|
|
|
|
|
|
|
client := NewHTTPClient()
|
|
|
|
res, err := client.Do(req)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
s.Assert().Equal(res.StatusCode, 302)
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
s.Assert().Equal(string(body), fmt.Sprintf("Found. Redirecting to %s?rd=%s", LoginBaseURL, AdminBaseURL))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyRedirectFromXOriginalHostURI() {
|
|
|
|
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify?rd=%s", AutheliaBaseURL, LoginBaseURL), nil)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
req.Header.Set("X-Forwarded-Proto", "https")
|
|
|
|
req.Header.Set("X-Forwarded-Host", "secure.example.com:8080")
|
|
|
|
req.Header.Set("X-Forwarded-URI", "/")
|
|
|
|
|
|
|
|
client := NewHTTPClient()
|
|
|
|
res, err := client.Do(req)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
s.Assert().Equal(res.StatusCode, 302)
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
|
|
s.Assert().NoError(err)
|
|
|
|
s.Assert().Equal(string(body), fmt.Sprintf("Found. Redirecting to %s?rd=https://secure.example.com:8080/", LoginBaseURL))
|
|
|
|
}
|
|
|
|
|
2019-12-06 04:35:03 +07:00
|
|
|
func (s *StandaloneSuite) TestStandaloneWebDriverScenario() {
|
|
|
|
suite.Run(s.T(), NewStandaloneWebDriverSuite())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestOneFactorScenario() {
|
|
|
|
suite.Run(s.T(), NewOneFactorScenario())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestTwoFactorScenario() {
|
|
|
|
suite.Run(s.T(), NewTwoFactorScenario())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestBypassPolicyScenario() {
|
|
|
|
suite.Run(s.T(), NewBypassPolicyScenario())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestBackendProtectionScenario() {
|
|
|
|
suite.Run(s.T(), NewBackendProtectionScenario())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestResetPasswordScenario() {
|
|
|
|
suite.Run(s.T(), NewResetPasswordScenario())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StandaloneSuite) TestAvailableMethodsScenario() {
|
|
|
|
suite.Run(s.T(), NewAvailableMethodsScenario([]string{"ONE-TIME PASSWORD"}))
|
2019-11-02 21:32:58 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestStandaloneSuite(t *testing.T) {
|
2019-11-25 03:27:59 +07:00
|
|
|
suite.Run(t, NewStandaloneSuite())
|
2019-11-02 21:32:58 +07:00
|
|
|
}
|