feat: add cli command to generate app token for user

This commit is contained in:
Thomas Müller
2024-05-07 08:27:26 +02:00
committed by jkoberg
parent 1eb66eb18c
commit 4fa7ea0b20
8 changed files with 137 additions and 2 deletions

View File

@@ -0,0 +1,109 @@
package command
import (
"context"
"fmt"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/auth/scope"
applicationsv1beta1 "github.com/cs3org/go-cs3apis/cs3/auth/applications/v1beta1"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
"github.com/owncloud/ocis/v2/services/auth-app/pkg/config"
"github.com/owncloud/ocis/v2/services/auth-app/pkg/config/parser"
"github.com/urfave/cli/v2"
"google.golang.org/grpc/metadata"
"time"
)
// Create is the entrypoint for the app auth create command
func Create(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "create",
Usage: "create an app auth token for a user",
Category: "maintenance",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "user-name",
Value: "",
Usage: "the user name",
Required: true,
},
&cli.IntFlag{
Name: "expiration",
Value: 72,
Usage: "expiration of the app password in hours",
Required: false,
},
},
Before: func(_ *cli.Context) error {
return configlog.ReturnError(parser.ParseConfig(cfg))
},
Action: func(c *cli.Context) error {
traceProvider, err := tracing.GetServiceTraceProvider(cfg.Tracing, cfg.Service.Name)
if err != nil {
return err
}
gatewaySelector, err := pool.GatewaySelector(
cfg.Reva.Address,
append(
cfg.Reva.GetRevaOptions(),
pool.WithRegistry(registry.GetRegistry()),
pool.WithTracerProvider(traceProvider),
)...)
if err != nil {
return err
}
next, err := gatewaySelector.Next()
if err != nil {
return err
}
userID := c.String("user-name")
ctx := context.Background()
authRes, err := next.Authenticate(ctx, &gatewayv1beta1.AuthenticateRequest{
Type: "machine",
ClientId: "username:" + userID,
ClientSecret: cfg.Commons.MachineAuthAPIKey,
})
if err != nil {
return err
}
granteeCtx := ctxpkg.ContextSetUser(context.Background(), &userpb.User{Id: authRes.GetUser().GetId()})
granteeCtx = metadata.AppendToOutgoingContext(granteeCtx, ctxpkg.TokenHeader, authRes.GetToken())
exp := c.Int("expiration")
expiryDuration := time.Duration(exp) * time.Hour
scopes, err := scope.AddOwnerScope(map[string]*authpb.Scope{})
if err != nil {
return err
}
appPassword, err := next.GenerateAppPassword(granteeCtx, &applicationsv1beta1.GenerateAppPasswordRequest{
TokenScope: scopes,
Label: "Generated via CLI",
Expiration: &typesv1beta1.Timestamp{
Seconds: uint64(time.Now().Add(expiryDuration).Unix()),
},
})
if err != nil {
return err
}
fmt.Printf("App password created for %s", authRes.GetUser().GetUsername())
fmt.Println()
fmt.Printf(" password: %s", appPassword.GetAppPassword().GetPassword())
fmt.Println()
return nil
},
}
}

View File

@@ -15,6 +15,7 @@ func GetCommands(cfg *config.Config) cli.Commands {
Server(cfg),
// interaction with this service
Create(cfg),
// infos about this service
Health(cfg),

View File

@@ -1,11 +1,16 @@
package revaconfig
import (
"path/filepath"
"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
"github.com/owncloud/ocis/v2/services/auth-app/pkg/config"
)
// AuthAppConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func AuthAppConfigFromStruct(cfg *config.Config) map[string]interface{} {
appAuthJSON := filepath.Join(defaults.BaseDataPath(), "appauth.json")
rcfg := map[string]interface{}{
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
@@ -30,6 +35,14 @@ func AuthAppConfigFromStruct(cfg *config.Config) map[string]interface{} {
},
},
},
"applicationauth": map[string]interface{}{
"driver": "json",
"drivers": map[string]interface{}{
"json": map[string]interface{}{
"file": appAuthJSON,
},
},
},
},
"interceptors": map[string]interface{}{
"prometheus": map[string]interface{}{

View File

@@ -35,6 +35,7 @@ type Config struct {
GroupsEndpoint string `yaml:"-"`
PermissionsEndpoint string `yaml:"-"`
SharingEndpoint string `yaml:"-"`
AuthAppEndpoint string `yaml:"-"`
AuthBasicEndpoint string `yaml:"-"`
AuthBearerEndpoint string `yaml:"-"`
AuthMachineEndpoint string `yaml:"-"`

View File

@@ -52,6 +52,7 @@ func DefaultConfig() *config.Config {
FrontendPublicURL: "https://localhost:9200",
AppRegistryEndpoint: "com.owncloud.api.app-registry",
AuthAppEndpoint: "com.owncloud.api.auth-app",
AuthBasicEndpoint: "com.owncloud.api.auth-basic",
AuthMachineEndpoint: "com.owncloud.api.auth-machine",
AuthServiceEndpoint: "com.owncloud.api.auth-service",

View File

@@ -37,6 +37,7 @@ func GatewayConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]i
// TODO build services dynamically
"services": map[string]interface{}{
"gateway": map[string]interface{}{
"applicationauthsvc": cfg.AuthAppEndpoint,
// registries are located on the gateway
"authregistrysvc": cfg.Reva.Address,
"storageregistrysvc": cfg.Reva.Address,
@@ -89,6 +90,7 @@ func GatewayConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]i
"drivers": map[string]interface{}{
"static": map[string]interface{}{
"rules": map[string]interface{}{
"appauth": cfg.AuthAppEndpoint,
"basic": cfg.AuthBasicEndpoint,
"machine": cfg.AuthMachineEndpoint,
"publicshares": cfg.StoragePublicLinkEndpoint,

View File

@@ -364,7 +364,7 @@ func loadMiddlewares(logger log.Logger, cfg *config.Config, userInfoCache, signi
middleware.CredentialsByUserAgent(cfg.AuthMiddleware.CredentialsByUserAgent),
middleware.Logger(logger),
middleware.OIDCIss(cfg.OIDC.Issuer),
middleware.EnableBasicAuth(cfg.EnableBasicAuth),
middleware.EnableBasicAuth(true),
middleware.TraceProvider(traceProvider),
),
middleware.AccountResolver(

View File

@@ -4,6 +4,8 @@ import (
"net/http"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
revactx "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
)
@@ -31,6 +33,7 @@ func (m AppAuthAuthenticator) Authenticate(r *http.Request) (*http.Request, bool
if err != nil {
return nil, false
}
authenticateResponse, err := next.Authenticate(r.Context(), &gateway.AuthenticateRequest{
Type: "appauth",
ClientId: username,
@@ -39,7 +42,12 @@ func (m AppAuthAuthenticator) Authenticate(r *http.Request) (*http.Request, bool
if err != nil {
return nil, false
}
r.Header.Add(_headerRevaAccessToken, authenticateResponse.GetToken())
if authenticateResponse.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
// TODO: log???
return nil, false
}
r.Header.Set(revactx.TokenHeader, authenticateResponse.GetToken())
return r, true
}