Merge pull request #2528 from ishank011/reva-auth-tokens

Use reva's Authenticate method instead of spawning token managers
This commit is contained in:
David Christofas
2021-09-22 12:20:29 -04:00
committed by GitHub
22 changed files with 182 additions and 97 deletions
+11
View File
@@ -0,0 +1,11 @@
Enhancement: Use reva's Authenticate method instead of spawning token managers
When using the CS3 proxy backend, we previously obtained the user from reva's
userprovider service and minted the token ourselves. This required maintaining
a shared JWT secret between ocis and reva, as well duplication of logic. This
PR delegates this logic by using the `Authenticate` method provided by the reva
gateway service to obtain this token, making it an arbitrary, indestructible
entry. Currently, the changes have been made to the proxy service but will be
extended to others as well.
https://github.com/owncloud/ocis/pull/2528
+1
View File
@@ -64,6 +64,7 @@ type Config struct {
AccountBackend string
RevaAddress string
StorageUsersDriver string
MachineAuthAPIKey string
IdentityManagement IdentityManagement
Context context.Context
+7
View File
@@ -165,6 +165,13 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVars: []string{"OCS_REVA_GATEWAY_ADDR"},
Destination: &cfg.RevaAddress,
},
&cli.StringFlag{
Name: "machine-auth-api-key",
Value: flags.OverrideDefaultString(cfg.MachineAuthAPIKey, "change-me-please"),
Usage: "the API key to be used for the machine auth driver in reva",
EnvVars: []string{"OCS_MACHINE_AUTH_API_KEY", "OCIS_MACHINE_AUTH_API_KEY"},
Destination: &cfg.MachineAuthAPIKey,
},
&cli.StringFlag{
Name: "idm-address",
Value: flags.OverrideDefaultString(cfg.IdentityManagement.Address, "https://localhost:9200"),
+1 -1
View File
@@ -165,7 +165,7 @@ func (o Ocs) getCS3Backend() backend.UserBackend {
if err != nil {
o.logger.Fatal().Msgf("could not get reva client at address %s", o.config.RevaAddress)
}
return backend.NewCS3UserBackend(revaClient, nil, revaClient, o.logger)
return backend.NewCS3UserBackend(nil, revaClient, o.config.MachineAuthAPIKey, o.logger)
}
func (o Ocs) getGroupsService() accounts.GroupsService {
+1 -1
View File
@@ -736,7 +736,7 @@ func (o Ocs) fetchAccountByUsername(ctx context.Context, name string) (*accounts
func (o Ocs) fetchAccountFromCS3Backend(ctx context.Context, name string) (*accounts.Account, error) {
backend := o.getCS3Backend()
u, err := backend.GetUserByClaims(ctx, "username", name, false)
u, _, err := backend.GetUserByClaims(ctx, "username", name, false)
if err != nil {
return nil, err
}
+11 -1
View File
@@ -9,6 +9,7 @@ import (
"time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/cs3org/reva/pkg/token/manager/jwt"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/justinas/alice"
"github.com/micro/cli/v2"
@@ -148,14 +149,23 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic
var userProvider backend.UserBackend
switch cfg.AccountBackend {
case "accounts":
tokenManager, err := jwt.New(map[string]interface{}{
"secret": cfg.TokenManager.JWTSecret,
"expires": int64(24 * 60 * 60),
})
if err != nil {
l.Error().Err(err).
Msg("Failed to create token manager")
}
userProvider = backend.NewAccountsServiceUserBackend(
acc.NewAccountsService("com.owncloud.api.accounts", grpc.DefaultClient),
rolesClient,
cfg.OIDC.Issuer,
tokenManager,
l,
)
case "cs3":
userProvider = backend.NewCS3UserBackend(revaClient, rolesClient, revaClient, l)
userProvider = backend.NewCS3UserBackend(rolesClient, revaClient, cfg.MachineAuthAPIKey, l)
default:
l.Fatal().Msgf("Invalid accounts backend type '%s'", cfg.AccountBackend)
}
+3 -2
View File
@@ -121,8 +121,9 @@ type Config struct {
Reva Reva
PreSignedURL PreSignedURL
AccountBackend string
UserOIDCClaim string
UserCS3Claim string
UserOIDCClaim string
UserCS3Claim string
MachineAuthAPIKey string
AutoprovisionAccounts bool
EnableBasicAuth bool
InsecureBackends bool
+8
View File
@@ -291,6 +291,14 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
Destination: &cfg.AccountBackend,
},
&cli.StringFlag{
Name: "machine-auth-api-key",
Value: flags.OverrideDefaultString(cfg.MachineAuthAPIKey, "change-me-please"),
Usage: "the API key to be used for the machine auth driver in reva",
EnvVars: []string{"PROXY_MACHINE_AUTH_API_KEY", "OCIS_MACHINE_AUTH_API_KEY"},
Destination: &cfg.MachineAuthAPIKey,
},
// Reva Middlewares Config
&cli.StringSliceFlag{
Name: "proxy-user-agent-lock-in",
+2 -26
View File
@@ -4,12 +4,9 @@ import (
"errors"
"net/http"
"github.com/cs3org/reva/pkg/auth/scope"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
revactx "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/oidc"
)
@@ -21,18 +18,9 @@ func AccountResolver(optionSetters ...Option) func(next http.Handler) http.Handl
logger := options.Logger
return func(next http.Handler) http.Handler {
tokenManager, err := jwt.New(map[string]interface{}{
"secret": options.TokenManagerConfig.JWTSecret,
"expires": int64(60),
})
if err != nil {
logger.Fatal().Err(err).Msg("Could not initialize token-manager")
}
return &accountResolver{
next: next,
logger: logger,
tokenManager: tokenManager,
userProvider: options.UserProvider,
userOIDCClaim: options.UserOIDCClaim,
userCS3Claim: options.UserCS3Claim,
@@ -44,7 +32,6 @@ func AccountResolver(optionSetters ...Option) func(next http.Handler) http.Handl
type accountResolver struct {
next http.Handler
logger log.Logger
tokenManager token.Manager
userProvider backend.UserBackend
autoProvisionAccounts bool
userOIDCClaim string
@@ -56,6 +43,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
claims := oidc.FromContext(ctx)
u, 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
if claims == nil && !ok {
@@ -74,7 +62,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
u, err = m.userProvider.GetUserByClaims(req.Context(), m.userCS3Claim, value, true)
u, token, err = m.userProvider.GetUserByClaims(req.Context(), m.userCS3Claim, value, true)
if errors.Is(err, backend.ErrAccountNotFound) {
m.logger.Debug().Str("claim", m.userOIDCClaim).Str("value", value).Msg("User by claim not found")
@@ -108,18 +96,6 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
m.logger.Debug().Interface("claims", claims).Interface("user", u).Msg("associated claims with user")
}
s, err := scope.AddOwnerScope(nil)
if err != nil {
m.logger.Error().Err(err).Msg("could not get owner scope")
return
}
token, err := m.tokenManager.MintToken(ctx, u, s)
if err != nil {
m.logger.Error().Err(err).Msg("could not mint token")
w.WriteHeader(http.StatusInternalServerError)
return
}
req.Header.Set(revactx.TokenHeader, token)
m.next.ServeHTTP(w, req)
+15 -2
View File
@@ -7,7 +7,9 @@ import (
"testing"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/auth/scope"
revactx "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/token/manager/jwt"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/oidc"
"github.com/owncloud/ocis/proxy/pkg/config"
@@ -106,9 +108,20 @@ func TestInternalServerErrorOnMissingMailAndUsername(t *testing.T) {
}
func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr error, oidcclaim, cs3claim string) http.Handler {
tokenManager, _ := jwt.New(map[string]interface{}{
"secret": "change-me",
"expires": int64(60),
})
token := ""
if userBackendResult != nil {
s, _ := scope.AddOwnerScope(nil)
token, _ = tokenManager.MintToken(context.Background(), userBackendResult, s)
}
mock := &test.UserBackendMock{
GetUserByClaimsFunc: func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, error) {
return userBackendResult, userBackendErr
GetUserByClaimsFunc: func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, string, error) {
return userBackendResult, token, userBackendErr
},
}
+1 -1
View File
@@ -41,7 +41,7 @@ func BasicAuth(optionSetters ...Option) func(next http.Handler) http.Handler {
removeSuperfluousAuthenticate(w)
login, password, _ := req.BasicAuth()
user, err := h.userProvider.Authenticate(req.Context(), login, password)
user, _, err := h.userProvider.Authenticate(req.Context(), login, password)
// touch is a user agent locking guard, when touched changes to true it indicates the User-Agent on the
// request is configured to support only one challenge, it it remains untouched, there are no considera-
-11
View File
@@ -8,8 +8,6 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
revactx "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
"github.com/owncloud/ocis/ocis-pkg/log"
"google.golang.org/grpc/metadata"
)
@@ -20,17 +18,9 @@ func CreateHome(optionSetters ...Option) func(next http.Handler) http.Handler {
logger := options.Logger
return func(next http.Handler) http.Handler {
tokenManager, err := jwt.New(map[string]interface{}{
"secret": options.TokenManagerConfig.JWTSecret,
})
if err != nil {
logger.Fatal().Err(err).Msgf("Could not initialize token-manager")
}
return &createHome{
next: next,
logger: logger,
tokenManager: tokenManager,
revaGatewayClient: options.RevaGatewayClient,
}
}
@@ -39,7 +29,6 @@ func CreateHome(optionSetters ...Option) func(next http.Handler) http.Handler {
type createHome struct {
next http.Handler
logger log.Logger
tokenManager token.Manager
revaGatewayClient gateway.GatewayAPIClient
}
+2 -2
View File
@@ -45,9 +45,9 @@ type Options struct {
// PreSignedURLConfig to configure the middleware
PreSignedURLConfig config.PreSignedURL
// UserOIDCClaim to read from the oidc claims
UserOIDCClaim string
UserOIDCClaim string
// UserCS3Claim to use when looking up a user in the CS3 API
UserCS3Claim string
UserCS3Claim string
// AutoprovisionAccounts when an accountResolver does not exist.
AutoprovisionAccounts bool
// EnableBasicAuth to allow basic auth
+1 -1
View File
@@ -48,7 +48,7 @@ func (m signedURLAuth) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
user, err := m.userProvider.GetUserByClaims(req.Context(), "username", req.URL.Query().Get("OC-Credential"), true)
user, _, err := m.userProvider.GetUserByClaims(req.Context(), "username", req.URL.Query().Get("OC-Credential"), true)
if err != nil {
m.logger.Error().Err(err).Msg("Could not get user by claim")
w.WriteHeader(http.StatusInternalServerError)
+44 -17
View File
@@ -8,6 +8,8 @@ import (
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/pkg/auth/scope"
"github.com/cs3org/reva/pkg/token"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/oidc"
@@ -15,11 +17,12 @@ import (
)
// NewAccountsServiceUserBackend creates a user-provider which fetches users from the ocis accounts-service
func NewAccountsServiceUserBackend(ac accounts.AccountsService, rs settings.RoleService, oidcISS string, logger log.Logger) UserBackend {
func NewAccountsServiceUserBackend(ac accounts.AccountsService, rs settings.RoleService, oidcISS string, tokenManager token.Manager, logger log.Logger) UserBackend {
return &accountsServiceBackend{
accountsClient: ac,
settingsRoleService: rs,
OIDCIss: oidcISS,
tokenManager: tokenManager,
logger: logger,
}
}
@@ -29,9 +32,10 @@ type accountsServiceBackend struct {
settingsRoleService settings.RoleService
OIDCIss string
logger log.Logger
tokenManager token.Manager
}
func (a accountsServiceBackend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, error) {
func (a accountsServiceBackend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error) {
var account *accounts.Account
var status int
var query string
@@ -44,38 +48,41 @@ func (a accountsServiceBackend) GetUserByClaims(ctx context.Context, claim, valu
case "id":
query = fmt.Sprintf("id eq '%s'", strings.ReplaceAll(value, "'", "''"))
default:
return nil, fmt.Errorf("invalid user by claim lookup must be 'mail', 'username' or 'id")
return nil, "", fmt.Errorf("invalid user by claim lookup must be 'mail', 'username' or 'id")
}
account, status = a.getAccount(ctx, query)
if status == http.StatusNotFound {
return nil, ErrAccountNotFound
return nil, "", ErrAccountNotFound
}
if status != 0 || account == nil {
return nil, fmt.Errorf("could not get account, got status: %d", status)
return nil, "", fmt.Errorf("could not get account, got status: %d", status)
}
if !account.AccountEnabled {
return nil, ErrAccountDisabled
return nil, "", ErrAccountDisabled
}
user := a.accountToUser(account)
if !withRoles {
return user, nil
if withRoles {
if err := injectRoles(ctx, user, a.settingsRoleService); err != nil {
a.logger.Warn().Err(err).Msgf("Could not load roles... continuing without")
}
}
if err := injectRoles(ctx, user, a.settingsRoleService); err != nil {
a.logger.Warn().Err(err).Msgf("Could not load roles... continuing without")
token, err := a.generateToken(ctx, user)
if err != nil {
return nil, "", err
}
return user, nil
return user, token, nil
}
// Authenticate authenticates against the accounts services and returns the user on success
func (a *accountsServiceBackend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, error) {
func (a *accountsServiceBackend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error) {
query := fmt.Sprintf(
"login eq '%s' and password eq '%s'",
strings.ReplaceAll(username, "'", "''"),
@@ -84,23 +91,28 @@ func (a *accountsServiceBackend) Authenticate(ctx context.Context, username stri
account, status := a.getAccount(ctx, query)
if status != 0 {
return nil, fmt.Errorf("could not authenticate with username, password for user %s. Status: %d", username, status)
return nil, "", fmt.Errorf("could not authenticate with username, password for user %s. Status: %d", username, status)
}
user := a.accountToUser(account)
token, err := a.generateToken(ctx, user)
if err != nil {
return nil, "", err
}
if err := injectRoles(ctx, user, a.settingsRoleService); err != nil {
a.logger.Warn().Err(err).Msgf("Could not load roles... continuing without")
}
return user, nil
return user, token, nil
}
func (a accountsServiceBackend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error) {
req := &accounts.CreateAccountRequest{
Account: &accounts.Account{
CreationType: "LocalAccount",
AccountEnabled: true,
CreationType: "LocalAccount",
AccountEnabled: true,
},
}
var ok bool
@@ -144,7 +156,7 @@ func (a *accountsServiceBackend) accountToUser(account *accounts.Account) *cs3.U
Id: &cs3.UserId{
OpaqueId: account.Id,
Idp: a.OIDCIss,
Type: cs3.UserType_USER_TYPE_PRIMARY, // TODO: once we have support for other user types, this needs to be inferred
Type: cs3.UserType_USER_TYPE_PRIMARY, // TODO: once we have support for other user types, this needs to be inferred
},
Username: account.OnPremisesSamAccountName,
DisplayName: account.DisplayName,
@@ -185,6 +197,21 @@ func (a *accountsServiceBackend) getAccount(ctx context.Context, query string) (
return
}
func (a *accountsServiceBackend) generateToken(ctx context.Context, u *cs3.User) (string, error) {
s, err := scope.AddOwnerScope(nil)
if err != nil {
a.logger.Error().Err(err).Msg("could not get owner scope")
return "", err
}
token, err := a.tokenManager.MintToken(ctx, u, s)
if err != nil {
a.logger.Error().Err(err).Msg("could not mint token")
return "", err
}
return token, nil
}
func expandGroups(account *accounts.Account) []string {
groups := make([]string, len(account.MemberOf))
for i := range account.MemberOf {
+12 -7
View File
@@ -6,6 +6,7 @@ import (
"github.com/asim/go-micro/v3/client"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/token/manager/jwt"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/oidc"
@@ -51,7 +52,7 @@ func TestGetUserByClaimsFound(t *testing.T) {
for k := range tests {
t.Run(tests[k].id, func(t *testing.T) {
u, err := accBackend.GetUserByClaims(context.Background(), tests[k].claim, tests[k].value, true)
u, _, err := accBackend.GetUserByClaims(context.Background(), tests[k].claim, tests[k].value, true)
assert.NoError(t, err)
assert.NotNil(t, u)
@@ -64,7 +65,7 @@ func TestGetUserByClaimsFound(t *testing.T) {
func TestGetUserByClaimsNotFound(t *testing.T) {
accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles)
u, err := accBackend.GetUserByClaims(context.Background(), "mail", "foo@example.com", true)
u, _, err := accBackend.GetUserByClaims(context.Background(), "mail", "foo@example.com", true)
assert.Error(t, err)
assert.Nil(t, u)
@@ -73,7 +74,7 @@ func TestGetUserByClaimsNotFound(t *testing.T) {
func TestGetUserByClaimsInvalidClaim(t *testing.T) {
accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles)
u, err := accBackend.GetUserByClaims(context.Background(), "invalidClaimName", "efwfwfwfe", true)
u, _, err := accBackend.GetUserByClaims(context.Background(), "invalidClaimName", "efwfwfwfe", true)
assert.Nil(t, u)
assert.Error(t, err)
@@ -81,7 +82,7 @@ func TestGetUserByClaimsInvalidClaim(t *testing.T) {
func TestGetUserByClaimsDisabledAccount(t *testing.T) {
accBackend := newAccountsBackend([]*accounts.Account{{AccountEnabled: false}}, expectedRoles)
u, err := accBackend.GetUserByClaims(context.Background(), "mail", "foo@example.com", true)
u, _, err := accBackend.GetUserByClaims(context.Background(), "mail", "foo@example.com", true)
assert.Nil(t, u)
assert.Error(t, err)
@@ -90,7 +91,7 @@ func TestGetUserByClaimsDisabledAccount(t *testing.T) {
func TestAuthenticate(t *testing.T) {
accBackend := newAccountsBackend(mockAccResp, expectedRoles)
u, err := accBackend.Authenticate(context.Background(), "foo", "secret")
u, _, err := accBackend.Authenticate(context.Background(), "foo", "secret")
assert.NoError(t, err)
assert.NotNil(t, u)
@@ -99,7 +100,7 @@ func TestAuthenticate(t *testing.T) {
func TestAuthenticateFailed(t *testing.T) {
accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles)
u, err := accBackend.Authenticate(context.Background(), "foo", "secret")
u, _, err := accBackend.Authenticate(context.Background(), "foo", "secret")
assert.Nil(t, u)
assert.Error(t, err)
@@ -151,7 +152,11 @@ func assertUserMatchesAccount(t *testing.T, exp *accounts.Account, act *userv1be
func newAccountsBackend(mockAccounts []*accounts.Account, mockRoles []*settings.UserRoleAssignment) UserBackend {
accSvc, roleSvc := getAccountService(mockAccounts, nil), getRoleService(mockRoles, nil)
accBackend := NewAccountsServiceUserBackend(accSvc, roleSvc, "https://idp.example.org", log.NewLogger())
tokenManager, _ := jwt.New(map[string]interface{}{
"secret": "change-me",
"expires": int64(24 * 60 * 60),
})
accBackend := NewAccountsServiceUserBackend(accSvc, roleSvc, "https://idp.example.org", tokenManager, log.NewLogger())
zerolog.SetGlobalLevel(zerolog.Disabled)
return accBackend
}
+2 -2
View File
@@ -23,8 +23,8 @@ var (
// UserBackend allows the proxy to retrieve users from different user-backends (accounts-service, CS3)
type UserBackend interface {
GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, error)
Authenticate(ctx context.Context, username string, password string) (*cs3.User, error)
GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error)
Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error)
CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error)
GetUserGroups(ctx context.Context, userID string)
}
+22 -16
View File
@@ -14,42 +14,48 @@ import (
)
type cs3backend struct {
userProvider cs3.UserAPIClient
settingsRoleService settings.RoleService
authProvider RevaAuthenticator
machineAuthAPIKey string
logger log.Logger
}
// NewCS3UserBackend creates a user-provider which fetches users from a CS3 UserBackend
func NewCS3UserBackend(up cs3.UserAPIClient, rs settings.RoleService, ap RevaAuthenticator, logger log.Logger) UserBackend {
func NewCS3UserBackend(rs settings.RoleService, ap RevaAuthenticator, machineAuthAPIKey string, logger log.Logger) UserBackend {
return &cs3backend{
userProvider: up,
settingsRoleService: rs,
authProvider: ap,
machineAuthAPIKey: machineAuthAPIKey,
logger: logger,
}
}
func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, error) {
res, err := c.userProvider.GetUserByClaim(ctx, &cs3.GetUserByClaimRequest{
Claim: claim,
Value: value,
func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error) {
// We only support authentication via username for now
if claim != "username" {
return nil, "", fmt.Errorf("claim: %s not supported", claim)
}
res, err := c.authProvider.Authenticate(ctx, &gateway.AuthenticateRequest{
Type: "machine",
ClientId: value,
ClientSecret: c.machineAuthAPIKey,
})
switch {
case err != nil:
return nil, fmt.Errorf("could not get user by claim %v with value %v: %w", claim, value, err)
return nil, "", fmt.Errorf("could not get user by claim %v with value %v: %w", claim, value, err)
case res.Status.Code != rpcv1beta1.Code_CODE_OK:
if res.Status.Code == rpcv1beta1.Code_CODE_NOT_FOUND {
return nil, ErrAccountNotFound
return nil, "", ErrAccountNotFound
}
return nil, fmt.Errorf("could not get user by claim %v with value %v : %w ", claim, value, err)
return nil, "", fmt.Errorf("could not get user by claim %v with value %v : %w ", claim, value, err)
}
user := res.User
if !withRoles {
return user, nil
return user, res.Token, nil
}
var roleIDs []string
@@ -82,10 +88,10 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, w
user.Opaque.Map["roles"] = enc
}
return res.User, nil
return user, res.Token, nil
}
func (c *cs3backend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, error) {
func (c *cs3backend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error) {
res, err := c.authProvider.Authenticate(ctx, &gateway.AuthenticateRequest{
Type: "basic",
ClientId: username,
@@ -94,12 +100,12 @@ func (c *cs3backend) Authenticate(ctx context.Context, username string, password
switch {
case err != nil:
return nil, fmt.Errorf("could not authenticate with username and password user: %s, %w", username, err)
return nil, "", fmt.Errorf("could not authenticate with username and password user: %s, %w", username, err)
case res.Status.Code != rpcv1beta1.Code_CODE_OK:
return nil, fmt.Errorf("could not authenticate with username and password user: %s, got code: %d", username, res.Status.Code)
return nil, "", fmt.Errorf("could not authenticate with username and password user: %s, got code: %d", username, res.Status.Code)
}
return res.User, nil
return res.User, res.Token, nil
}
func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error) {
+7 -6
View File
@@ -5,9 +5,10 @@ package test
import (
"context"
"github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
"sync"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
)
// Ensure, that UserBackendMock does implement UserBackend.
@@ -40,13 +41,13 @@ var _ backend.UserBackend = &UserBackendMock{}
// }
type UserBackendMock struct {
// AuthenticateFunc mocks the Authenticate method.
AuthenticateFunc func(ctx context.Context, username string, password string) (*userv1beta1.User, error)
AuthenticateFunc func(ctx context.Context, username string, password string) (*userv1beta1.User, string, error)
// CreateUserFromClaimsFunc mocks the CreateUserFromClaims method.
CreateUserFromClaimsFunc func(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error)
// GetUserByClaimsFunc mocks the GetUserByClaims method.
GetUserByClaimsFunc func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, error)
GetUserByClaimsFunc func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, string, error)
// GetUserGroupsFunc mocks the GetUserGroups method.
GetUserGroupsFunc func(ctx context.Context, userID string)
@@ -95,7 +96,7 @@ type UserBackendMock struct {
}
// Authenticate calls AuthenticateFunc.
func (mock *UserBackendMock) Authenticate(ctx context.Context, username string, password string) (*userv1beta1.User, error) {
func (mock *UserBackendMock) Authenticate(ctx context.Context, username string, password string) (*userv1beta1.User, string, error) {
if mock.AuthenticateFunc == nil {
panic("UserBackendMock.AuthenticateFunc: method is nil but UserBackend.Authenticate was just called")
}
@@ -169,7 +170,7 @@ func (mock *UserBackendMock) CreateUserFromClaimsCalls() []struct {
}
// GetUserByClaims calls GetUserByClaimsFunc.
func (mock *UserBackendMock) GetUserByClaims(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, error) {
func (mock *UserBackendMock) GetUserByClaims(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, string, error) {
if mock.GetUserByClaimsFunc == nil {
panic("UserBackendMock.GetUserByClaimsFunc: method is nil but UserBackend.GetUserByClaims was just called")
}
+4 -1
View File
@@ -101,7 +101,7 @@ func authBearerConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]i
// TODO build services dynamically
"services": map[string]interface{}{
"authprovider": map[string]interface{}{
"auth_manager": "oidc",
"auth_manager": cfg.Reva.AuthBearerConfig.Driver,
"auth_managers": map[string]interface{}{
"oidc": map[string]interface{}{
"issuer": cfg.Reva.OIDC.Issuer,
@@ -111,6 +111,9 @@ func authBearerConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]i
"gid_claim": cfg.Reva.OIDC.GIDClaim,
"gatewaysvc": cfg.Reva.Gateway.Endpoint,
},
"machine": map[string]interface{}{
"api_key": cfg.Reva.AuthBearerConfig.MachineAuthAPIKey,
},
},
},
},
+8
View File
@@ -119,6 +119,13 @@ type Users struct {
UserGroupsCacheExpiration int
}
// AuthBearerConfig defines the available configuration for the bearer auth drivers.
type AuthBearerConfig struct {
Port
Driver string
MachineAuthAPIKey string
}
// Groups defines the available groups configuration.
type Groups struct {
Port
@@ -423,6 +430,7 @@ type Reva struct {
Users Users
Groups Groups
AuthProvider Users
AuthBearerConfig AuthBearerConfig
AuthBasic Port
AuthBearer Port
Sharing Sharing
+19
View File
@@ -19,6 +19,15 @@ func AuthBearerWithConfig(cfg *config.Config) []cli.Flag {
Destination: &cfg.Reva.AuthBearer.DebugAddr,
},
// Driver
&cli.StringFlag{
Name: "auth-driver",
Value: flags.OverrideDefaultString(cfg.Reva.AuthBearerConfig.Driver, "oidc"),
Usage: "bearer auth driver: 'oidc' or 'machine'",
EnvVars: []string{"STORAGE_AUTH_BEARER_DRIVER"},
Destination: &cfg.Reva.AuthBearerConfig.Driver,
},
// OIDC
&cli.StringFlag{
@@ -63,6 +72,16 @@ func AuthBearerWithConfig(cfg *config.Config) []cli.Flag {
Destination: &cfg.Reva.OIDC.GIDClaim,
},
// Machine Auth
&cli.StringFlag{
Name: "machine-auth-api-key",
Value: flags.OverrideDefaultString(cfg.Reva.AuthBearerConfig.MachineAuthAPIKey, "change-me-please"),
Usage: "the API key to be used for the machine auth driver in reva",
EnvVars: []string{"STORAGE_AUTH_BEARER_MACHINE_AUTH_API_KEY", "OCIS_MACHINE_AUTH_API_KEY"},
Destination: &cfg.Reva.AuthBearerConfig.MachineAuthAPIKey,
},
// Services
// AuthBearer