appauth: Add token and user (with roles) to context

When successfully authenticating a user via apptoken, resolve the user's
roles and add the user and the token returned by the auth service to the
request context. Rely on the account_resolve middleware to add the reva
token to the outgoing request as the other auth middlewares do.
This commit is contained in:
Ralf Haferkamp
2025-04-29 12:04:24 +02:00
parent 95f28baa52
commit 102e92fd73
4 changed files with 33 additions and 10 deletions

View File

@@ -294,6 +294,7 @@ func loadMiddlewares(logger log.Logger, cfg *config.Config,
authenticators = append(authenticators, middleware.AppAuthAuthenticator{
Logger: logger,
RevaGatewaySelector: gatewaySelector,
UserRoleAssigner: roleAssigner,
})
}
authenticators = append(authenticators, middleware.NewOIDCAuthenticator(

View File

@@ -99,8 +99,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
claims := oidc.FromContext(ctx)
user, ok := revactx.ContextGetUser(ctx)
token := ""
// TODO what if an X-Access-Token is set? happens eg for download requests to the /data endpoint in the reva frontend
token, hasToken := revactx.ContextGetToken(ctx)
if claims == nil && !ok {
m.next.ServeHTTP(w, req)
@@ -192,10 +191,11 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
req = req.WithContext(ctx)
m.logger.Debug().Interface("claims", claims).Interface("user", user).Msg("associated claims with user")
} else if user != nil {
} else if user != nil && !hasToken {
// If we already have a token (e.g. the app auth middleware adds the token to the context) there is no need
// to get yet another one here.
var err error
_, token, err = m.userProvider.GetUserByClaims(req.Context(), "username", user.Username)
if errors.Is(err, backend.ErrAccountDisabled) {
m.logger.Debug().Interface("user", user).Msg("Disabled")
w.WriteHeader(http.StatusUnauthorized)

View File

@@ -6,6 +6,7 @@ import (
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/proxy/pkg/userroles"
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
)
@@ -14,6 +15,7 @@ import (
type AppAuthAuthenticator struct {
Logger log.Logger
RevaGatewaySelector pool.Selectable[gateway.GatewayAPIClient]
UserRoleAssigner userroles.UserRoleAssigner
}
// Authenticate implements the authenticator interface to authenticate requests via app auth.
@@ -43,11 +45,20 @@ func (m AppAuthAuthenticator) Authenticate(r *http.Request) (*http.Request, bool
return nil, false
}
if authenticateResponse.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
// TODO: log???
m.Logger.Debug().Str("msg", authenticateResponse.GetStatus().GetMessage()).Str("clientid", username).Msg("app auth failed")
return nil, false
}
r.Header.Set(revactx.TokenHeader, authenticateResponse.GetToken())
user := authenticateResponse.GetUser()
if user, err = m.UserRoleAssigner.ApplyUserRole(r.Context(), user); err != nil {
m.Logger.Error().Err(err).Str("clientid", username).Msg("app auth: failed to load user roles")
return nil, false
}
ctx := revactx.ContextSetUser(r.Context(), user)
ctx = revactx.ContextSetToken(ctx, authenticateResponse.GetToken())
r = r.WithContext(ctx)
return r, true
}

View File

@@ -5,19 +5,24 @@ import (
"net/http/httptest"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
"google.golang.org/grpc"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/opencloud-eu/opencloud/pkg/log"
userRoleMocks "github.com/opencloud-eu/opencloud/services/proxy/pkg/userroles/mocks"
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc"
)
var _ = Describe("Authenticating requests", Label("AppAuthAuthenticator"), func() {
var authenticator Authenticator
BeforeEach(func() {
pool.RemoveSelector("GatewaySelector" + "eu.opencloud.api.gateway")
ra := &userRoleMocks.UserRoleAssigner{}
ra.On("ApplyUserRole", mock.Anything, mock.Anything, mock.Anything).Return(&userv1beta1.User{}, nil)
authenticator = AppAuthAuthenticator{
Logger: log.NewLogger(),
RevaGatewaySelector: pool.GetSelector[gateway.GatewayAPIClient](
@@ -39,6 +44,7 @@ var _ = Describe("Authenticating requests", Label("AppAuthAuthenticator"), func(
}
},
),
UserRoleAssigner: ra,
}
})
@@ -51,7 +57,12 @@ var _ = Describe("Authenticating requests", Label("AppAuthAuthenticator"), func(
Expect(valid).To(Equal(true))
Expect(req2).ToNot(BeNil())
Expect(req2.Header.Get("x-access-token")).To(Equal("reva-token"))
user, ok := revactx.ContextGetUser(req2.Context())
Expect(ok).To(BeTrue())
Expect(user).ToNot(BeNil())
token, ok := revactx.ContextGetToken(req2.Context())
Expect(ok).To(BeTrue())
Expect(token).To(Equal("reva-token"))
})
})