feat: use short tokens as access tokens
The "real" access token will be stored using the short token as key. This short token will be sent to the clients to be used as access token for the WOPI server. This is configurable, and requires a store in order to keep the tokens.
This commit is contained in:
@@ -2,10 +2,13 @@ package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
@@ -15,6 +18,7 @@ import (
|
||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/helpers"
|
||||
"github.com/rs/zerolog"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
@@ -44,7 +48,7 @@ type WopiContext struct {
|
||||
// * The created WopiContext for the request
|
||||
// * A contextual zerologger containing information about the request
|
||||
// and the WopiContext
|
||||
func WopiContextAuthMiddleware(cfg *config.Config, next http.Handler) http.Handler {
|
||||
func WopiContextAuthMiddleware(cfg *config.Config, st microstore.Store, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
@@ -67,6 +71,23 @@ func WopiContextAuthMiddleware(cfg *config.Config, next http.Handler) http.Handl
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.Wopi.ShortTokens {
|
||||
records, err := st.Read(accessToken)
|
||||
if err != nil {
|
||||
wopiLogger.Error().Err(err).Msg("cannot retrieve access token from store")
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if len(records) != 1 {
|
||||
wopiLogger.Error().Int("records", len(records)).Msg("no record found for the token")
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
accessToken = string(records[0].Value)
|
||||
}
|
||||
|
||||
claims := &Claims{}
|
||||
_, err := jwt.ParseWithClaims(accessToken, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
|
||||
@@ -163,7 +184,11 @@ func WopiContextToCtx(ctx context.Context, wopiContext WopiContext) context.Cont
|
||||
// The access token inside the wopiContext is expected to be decrypted.
|
||||
// In order to generate the access token for WOPI, the reva token inside the
|
||||
// wopiContext will be encrypted
|
||||
func GenerateWopiToken(wopiContext WopiContext, cfg *config.Config) (string, int64, error) {
|
||||
func GenerateWopiToken(wopiContext WopiContext, cfg *config.Config, st microstore.Store) (string, int64, error) {
|
||||
if cfg.Wopi.ShortTokens && st == nil {
|
||||
return "", 0, errors.New("Cannot generate a short token without microstore")
|
||||
}
|
||||
|
||||
cryptedReqAccessToken, err := EncryptAES([]byte(cfg.Wopi.Secret), wopiContext.AccessToken)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
@@ -187,6 +212,20 @@ func GenerateWopiToken(wopiContext WopiContext, cfg *config.Config) (string, int
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
accessToken, err := token.SignedString([]byte(cfg.Wopi.Secret))
|
||||
|
||||
if cfg.Wopi.ShortTokens {
|
||||
c := sha256.New()
|
||||
c.Write([]byte(accessToken))
|
||||
shortAccessToken := hex.EncodeToString(c.Sum(nil))
|
||||
|
||||
errWrite := st.Write(µstore.Record{
|
||||
Key: shortAccessToken,
|
||||
Value: []byte(accessToken),
|
||||
Expiry: claims.ExpiresAt.Sub(time.Now()),
|
||||
})
|
||||
|
||||
return shortAccessToken, claims.ExpiresAt.UnixMilli(), errWrite
|
||||
}
|
||||
|
||||
return accessToken, claims.ExpiresAt.UnixMilli(), err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user