mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
0a970aef8a
This moves the OpenID Connect storage from memory into the SQL storage, making it persistent and allowing it to be used with clustered deployments like the rest of Authelia.
180 lines
5.3 KiB
Go
180 lines
5.3 KiB
Go
package suites
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type OIDCScenario struct {
|
|
*RodSuite
|
|
secret string
|
|
}
|
|
|
|
func NewOIDCScenario() *OIDCScenario {
|
|
return &OIDCScenario{
|
|
RodSuite: new(RodSuite),
|
|
}
|
|
}
|
|
|
|
func (s *OIDCScenario) SetupSuite() {
|
|
browser, err := StartRod()
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
s.RodSession = browser
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer func() {
|
|
cancel()
|
|
s.collectScreenshot(ctx.Err(), s.Page)
|
|
|
|
s.collectCoverage(s.Page)
|
|
s.MustClose()
|
|
}()
|
|
|
|
s.Page = s.doCreateTab(s.T(), HomeBaseURL)
|
|
s.secret = s.doRegisterAndLogin2FA(s.T(), s.Context(ctx), "john", "password", false, AdminBaseURL)
|
|
}
|
|
|
|
func (s *OIDCScenario) TearDownSuite() {
|
|
err := s.RodSession.Stop()
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func (s *OIDCScenario) SetupTest() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer func() {
|
|
cancel()
|
|
s.collectScreenshot(ctx.Err(), s.Page)
|
|
}()
|
|
|
|
s.Page = s.doCreateTab(s.T(), fmt.Sprintf("%s/logout", OIDCBaseURL))
|
|
s.doVisit(s.T(), s.Context(ctx), HomeBaseURL)
|
|
s.verifyIsHome(s.T(), s.Context(ctx))
|
|
}
|
|
|
|
func (s *OIDCScenario) TearDownTest() {
|
|
s.collectCoverage(s.Page)
|
|
s.MustClose()
|
|
}
|
|
|
|
func (s *OIDCScenario) TestShouldAuthorizeAccessToOIDCApp() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer func() {
|
|
cancel()
|
|
s.collectScreenshot(ctx.Err(), s.Page)
|
|
}()
|
|
|
|
s.doVisit(s.T(), s.Context(ctx), OIDCBaseURL)
|
|
s.verifyIsFirstFactorPage(s.T(), s.Context(ctx))
|
|
s.doFillLoginPageAndClick(s.T(), s.Context(ctx), "john", "password", false)
|
|
s.verifyIsSecondFactorPage(s.T(), s.Context(ctx))
|
|
s.doValidateTOTP(s.T(), s.Context(ctx), s.secret)
|
|
|
|
s.waitBodyContains(s.T(), s.Context(ctx), "Not logged yet...")
|
|
|
|
// Search for the 'login' link.
|
|
err := s.Page.MustSearch("Log in").Click("left")
|
|
assert.NoError(s.T(), err)
|
|
|
|
s.verifyIsConsentPage(s.T(), s.Context(ctx))
|
|
err = s.WaitElementLocatedByID(s.T(), s.Context(ctx), "accept-button").Click("left")
|
|
assert.NoError(s.T(), err)
|
|
|
|
// Verify that the app is showing the info related to the user stored in the JWT token.
|
|
|
|
rUUID := regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
|
|
rInteger := regexp.MustCompile(`^\d+$`)
|
|
rBoolean := regexp.MustCompile(`^(true|false)$`)
|
|
rBase64 := regexp.MustCompile(`^[-_A-Za-z0-9+\\/]+([=]{0,3})$`)
|
|
|
|
testCases := []struct {
|
|
desc, elementID, elementText string
|
|
pattern *regexp.Regexp
|
|
}{
|
|
{"welcome", "welcome", "Logged in as john!", nil},
|
|
{"at_hash", "claim-at_hash", "", rBase64},
|
|
{"jti", "claim-jti", "", rUUID},
|
|
{"iat", "claim-iat", "", rInteger},
|
|
{"nbf", "claim-nbf", "", rInteger},
|
|
{"rat", "claim-rat", "", rInteger},
|
|
{"expires", "claim-exp", "", rInteger},
|
|
{"amr", "claim-amr", "pwd, otp, mfa", nil},
|
|
{"acr", "claim-acr", "", nil},
|
|
{"issuer", "claim-iss", "https://login.example.com:8080", nil},
|
|
{"name", "claim-name", "John Doe", nil},
|
|
{"preferred_username", "claim-preferred_username", "john", nil},
|
|
{"groups", "claim-groups", "admins, dev", nil},
|
|
{"email", "claim-email", "john.doe@authelia.com", nil},
|
|
{"email_verified", "claim-email_verified", "", rBoolean},
|
|
}
|
|
|
|
var text string
|
|
|
|
for _, tc := range testCases {
|
|
s.T().Run(fmt.Sprintf("check_claims/%s", tc.desc), func(t *testing.T) {
|
|
text, err = s.WaitElementLocatedByID(t, s.Context(ctx), tc.elementID).Text()
|
|
assert.NoError(t, err)
|
|
if tc.pattern == nil {
|
|
assert.Equal(t, tc.elementText, text)
|
|
} else {
|
|
assert.Regexp(t, tc.pattern, text)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *OIDCScenario) TestShouldDenyConsent() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer func() {
|
|
cancel()
|
|
s.collectScreenshot(ctx.Err(), s.Page)
|
|
}()
|
|
|
|
s.doVisit(s.T(), s.Context(ctx), OIDCBaseURL)
|
|
s.verifyIsFirstFactorPage(s.T(), s.Context(ctx))
|
|
s.doFillLoginPageAndClick(s.T(), s.Context(ctx), "john", "password", false)
|
|
s.verifyIsSecondFactorPage(s.T(), s.Context(ctx))
|
|
s.doValidateTOTP(s.T(), s.Context(ctx), s.secret)
|
|
|
|
s.waitBodyContains(s.T(), s.Context(ctx), "Not logged yet...")
|
|
|
|
// Search for the 'login' link.
|
|
err := s.Page.MustSearch("Log in").Click("left")
|
|
assert.NoError(s.T(), err)
|
|
|
|
s.verifyIsConsentPage(s.T(), s.Context(ctx))
|
|
|
|
err = s.WaitElementLocatedByID(s.T(), s.Context(ctx), "deny-button").Click("left")
|
|
assert.NoError(s.T(), err)
|
|
|
|
s.verifyIsOIDC(s.T(), s.Context(ctx), "access_denied", "https://oidc.example.com:8080/error?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.+Make+sure+that+the+request+you+are+making+is+valid.+Maybe+the+credential+or+request+parameters+you+are+using+are+limited+in+scope+or+otherwise+restricted.&state=random-string-here")
|
|
|
|
errorDescription := "The resource owner or authorization server denied the request. Make sure that the request " +
|
|
"you are making is valid. Maybe the credential or request parameters you are using are limited in scope or " +
|
|
"otherwise restricted."
|
|
|
|
s.verifyIsOIDCErrorPage(s.T(), s.Context(ctx), "access_denied", errorDescription, "",
|
|
"random-string-here")
|
|
}
|
|
|
|
func TestRunOIDCScenario(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping suite test in short mode")
|
|
}
|
|
|
|
suite.Run(t, NewOIDCSuite())
|
|
}
|