mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-14 21:59:05 +02:00
feat: add ability to force email verification (#1837)
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
||||
@@ -34,6 +35,58 @@ type authorizationPARTestCase struct {
|
||||
malformed bool
|
||||
}
|
||||
|
||||
// fakeSessionAuthenticator signs every request in as a regular user, optionally one who still has to verify their email
|
||||
type fakeSessionAuthenticator struct {
|
||||
unverified bool
|
||||
}
|
||||
|
||||
func (fakeSessionAuthenticator) Kind() authz.PrincipalKind { return authz.KindSession }
|
||||
|
||||
func (fakeSessionAuthenticator) Present(*gin.Context) bool { return true }
|
||||
|
||||
func (a fakeSessionAuthenticator) Authenticate(*gin.Context) (*authz.Principal, error) {
|
||||
principal := &authz.Principal{Kind: authz.KindSession, UserID: "test-user", Scopes: authz.UserScopes(false, authz.KindSession)}
|
||||
if a.unverified {
|
||||
principal.RestrictUnverified()
|
||||
}
|
||||
return principal, nil
|
||||
}
|
||||
|
||||
// A browser that the authorization middleware refuses at the authorize endpoint must land on the interaction error page instead of a JSON error
|
||||
func TestAuthorizationHandlerRedirectsAuthorizationErrors(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
handler := &authorizationHandler{}
|
||||
|
||||
serve := func(t *testing.T, authenticator authz.Authenticator) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
|
||||
router := gin.New()
|
||||
authz.NewMiddleware(authenticator).Router(router.Group("/")).Use(handler.redirectAuthorizationErrors).Optional().
|
||||
GET("/authorize", authz.AccountAuthorize, func(c *gin.Context) { c.Status(http.StatusNoContent) })
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(recorder, httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/authorize", nil))
|
||||
return recorder
|
||||
}
|
||||
|
||||
t.Run("redirects a user who still has to verify their email", func(t *testing.T) {
|
||||
recorder := serve(t, fakeSessionAuthenticator{unverified: true})
|
||||
|
||||
require.Equal(t, http.StatusFound, recorder.Code)
|
||||
location, err := url.Parse(recorder.Header().Get("Location"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "/interaction/error", location.Path)
|
||||
require.Equal(t, "You must verify your email address before you can access this service.", location.Query().Get("error"))
|
||||
})
|
||||
|
||||
t.Run("leaves an authorized request to the authorize handler", func(t *testing.T) {
|
||||
recorder := serve(t, fakeSessionAuthenticator{})
|
||||
|
||||
require.Equal(t, http.StatusNoContent, recorder.Code)
|
||||
require.Empty(t, recorder.Header().Get("Location"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationHandlerRequiresPAR(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
const fakeURI = parRequestURIPrefix + "missing"
|
||||
@@ -91,7 +144,7 @@ func testAuthorizationHandlerPAR(t *testing.T, clientType string, tt authorizati
|
||||
BaseURL: baseURL, TokenBaseURL: baseURL, Secret: []byte("test-secret"),
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
service := newAuthorizationService(db, newInteractionSessionService(db), newClaimsService(db, nil, baseURL, nil), nil, nil, nil)
|
||||
service := newAuthorizationService(db, newInteractionSessionService(db), newClaimsService(db, nil, baseURL, nil, appconfig.StaticResolver{}), nil, nil, nil)
|
||||
handler := newAuthorizationHandler(provider, service)
|
||||
params := url.Values{
|
||||
"client_id": {clientID},
|
||||
|
||||
Reference in New Issue
Block a user