Merge pull request #95 from owncloud/roles-middleware

Add assigned roles to access token
This commit is contained in:
Benedikt Kulmann
2020-08-28 17:09:31 +02:00
committed by GitHub
7 changed files with 558 additions and 35 deletions

View File

@@ -0,0 +1,5 @@
Enhancement: Add roleIDs to the access token
We are using the roleIDs of the authenticated user for permission checks against ocis-settings. We added the roleIDs to the access token to have them available quickly.
https://github.com/owncloud/ocis-proxy/pull/95

18
go.mod
View File

@@ -3,29 +3,29 @@ module github.com/owncloud/ocis-proxy
go 1.13
require (
contrib.go.opencensus.io/exporter/jaeger v0.2.0
contrib.go.opencensus.io/exporter/jaeger v0.2.1
contrib.go.opencensus.io/exporter/ocagent v0.7.0
contrib.go.opencensus.io/exporter/zipkin v0.1.1
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/cs3org/go-cs3apis v0.0.0-20200611124600-7a1be2026543
github.com/cs3org/reva v0.1.0
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd
github.com/cs3org/reva v1.1.0
github.com/justinas/alice v1.2.0
github.com/micro/cli/v2 v2.1.2
github.com/micro/go-micro/v2 v2.6.0
github.com/micro/go-micro/v2 v2.9.1
github.com/oklog/run v1.1.0
github.com/openzipkin/zipkin-go v0.2.2
github.com/owncloud/flaex v0.2.0
github.com/owncloud/ocis-accounts v0.1.2-0.20200618163128-aa8ae58dd95e
github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200811112628-2151a60cc204
github.com/owncloud/ocis-pkg/v2 v2.4.0
github.com/owncloud/ocis-settings v0.3.2-0.20200828130413-0cc0f5bf26fe
github.com/owncloud/ocis-store v0.0.0-20200716140351-f9670592fb7b
github.com/prometheus/client_golang v1.7.0
github.com/prometheus/client_golang v1.7.1
github.com/restic/calens v0.2.0
github.com/spf13/viper v1.7.0
go.opencensus.io v0.22.4
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
google.golang.org/grpc v1.29.1
gopkg.in/square/go-jose.v2 v2.4.0 // indirect
google.golang.org/grpc v1.31.0
)
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0

492
go.sum
View File

File diff suppressed because it is too large Load Diff

View File

@@ -10,16 +10,11 @@ import (
"strings"
"time"
"github.com/coreos/go-oidc"
"github.com/justinas/alice"
"github.com/owncloud/ocis-pkg/v2/log"
"github.com/owncloud/ocis-proxy/pkg/cs3"
"github.com/owncloud/ocis-proxy/pkg/middleware"
"golang.org/x/oauth2"
"contrib.go.opencensus.io/exporter/jaeger"
"contrib.go.opencensus.io/exporter/ocagent"
"contrib.go.opencensus.io/exporter/zipkin"
"github.com/coreos/go-oidc"
"github.com/justinas/alice"
"github.com/micro/cli/v2"
mclient "github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/grpc"
@@ -27,15 +22,20 @@ import (
openzipkin "github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
acc "github.com/owncloud/ocis-accounts/pkg/proto/v0"
"github.com/owncloud/ocis-pkg/v2/log"
"github.com/owncloud/ocis-proxy/pkg/config"
"github.com/owncloud/ocis-proxy/pkg/cs3"
"github.com/owncloud/ocis-proxy/pkg/flagset"
"github.com/owncloud/ocis-proxy/pkg/metrics"
"github.com/owncloud/ocis-proxy/pkg/middleware"
"github.com/owncloud/ocis-proxy/pkg/proxy"
"github.com/owncloud/ocis-proxy/pkg/server/debug"
proxyHTTP "github.com/owncloud/ocis-proxy/pkg/server/http"
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
storepb "github.com/owncloud/ocis-store/pkg/proto/v0"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"golang.org/x/oauth2"
)
// Server is the entrypoint for the server command.
@@ -258,11 +258,13 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic
// TODO this won't work with a registry other than mdns. Look into Micro's client initialization.
// https://github.com/owncloud/ocis-proxy/issues/38
accounts := acc.NewAccountsService("com.owncloud.api.accounts", mclient.DefaultClient)
roles := settings.NewRoleService("com.owncloud.api.settings", mclient.DefaultClient)
uuidMW := middleware.AccountUUID(
middleware.Logger(l),
middleware.TokenManagerConfig(cfg.TokenManager),
middleware.AccountsClient(accounts),
middleware.SettingsRoleService(roles),
)
// the connection will be established in a non blocking fashion

View File

@@ -2,7 +2,9 @@ package middleware
import (
"context"
"encoding/json"
"fmt"
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
"net/http"
"strconv"
"strings"
@@ -146,6 +148,17 @@ func AccountUUID(opts ...Option) func(next http.Handler) http.Handler {
groups[i] = account.MemberOf[i].OnPremisesSamAccountName
}
// fetch active roles from ocis-settings
assignmentResponse, err := opt.SettingsRoleService.ListRoleAssignments(r.Context(), &settings.ListRoleAssignmentsRequest{AccountUuid: account.Id})
roleIDs := make([]string, 0)
if err != nil {
l.Err(err).Str("accountID", account.Id).Msg("failed to fetch role assignments")
} else {
for _, assignment := range assignmentResponse.Assignments {
roleIDs = append(roleIDs, assignment.RoleId)
}
}
l.Debug().Interface("claims", claims).Interface("account", account).Msgf("Associated claims with uuid")
user := &revauser.User{
Id: &revauser.UserId{
@@ -171,6 +184,17 @@ func AccountUUID(opts ...Option) func(next http.Handler) http.Handler {
Value: []byte(strconv.FormatInt(account.GidNumber, 10)),
}
// encode roleIDs as json string
roleIDsJSON, jsonErr := json.Marshal(roleIDs)
if jsonErr != nil {
l.Err(jsonErr).Str("accountID", account.Id).Msg("failed to marshal roleIDs into json")
} else {
user.Opaque.Map["roles"] = &types.OpaqueEntry{
Decoder: "json",
Value: roleIDsJSON,
}
}
token, err := tokenManager.MintToken(r.Context(), user)
if err != nil {

View File

@@ -12,6 +12,7 @@ import (
"github.com/owncloud/ocis-pkg/v2/log"
"github.com/owncloud/ocis-pkg/v2/oidc"
"github.com/owncloud/ocis-proxy/pkg/config"
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
)
// TODO testing the getAccount method should inject a cache
@@ -35,6 +36,7 @@ func TestAccountUUIDMiddleware(t *testing.T) {
Logger(log.NewLogger()),
TokenManagerConfig(config.TokenManager{JWTSecret: "secret"}),
AccountsClient(mockAccountUUIDMiddlewareAccSvc(false, true)),
SettingsRoleService(mockAccountUUIDMiddlewareRolesSvc(false)),
)(next)
r := httptest.NewRequest(http.MethodGet, "http://www.example.com", nil)
@@ -55,6 +57,7 @@ func TestAccountUUIDMiddlewareWithDisabledAccount(t *testing.T) {
Logger(log.NewLogger()),
TokenManagerConfig(config.TokenManager{JWTSecret: "secret"}),
AccountsClient(mockAccountUUIDMiddlewareAccSvc(false, false)),
SettingsRoleService(mockAccountUUIDMiddlewareRolesSvc(false)),
)(next)
r := httptest.NewRequest(http.MethodGet, "http://www.example.com", nil)
@@ -72,16 +75,11 @@ func TestAccountUUIDMiddlewareWithDisabledAccount(t *testing.T) {
}
func mockAccountUUIDMiddlewareAccSvc(retErr, accEnabled bool) proto.AccountsService {
if retErr {
return &proto.MockAccountsService{
ListFunc: func(ctx context.Context, in *proto.ListAccountsRequest, opts ...client.CallOption) (out *proto.ListAccountsResponse, err error) {
return nil, fmt.Errorf("error returned by mockAccountsService LIST")
},
}
}
return &proto.MockAccountsService{
ListFunc: func(ctx context.Context, in *proto.ListAccountsRequest, opts ...client.CallOption) (out *proto.ListAccountsResponse, err error) {
if retErr {
return nil, fmt.Errorf("error returned by mockAccountsService LIST")
}
return &proto.ListAccountsResponse{
Accounts: []*proto.Account{
{
@@ -92,5 +90,17 @@ func mockAccountUUIDMiddlewareAccSvc(retErr, accEnabled bool) proto.AccountsServ
}, nil
},
}
}
func mockAccountUUIDMiddlewareRolesSvc(returnError bool) settings.RoleService {
return &settings.MockRoleService{
ListRoleAssignmentsFunc: func(ctx context.Context, req *settings.ListRoleAssignmentsRequest, opts ...client.CallOption) (res *settings.ListRoleAssignmentsResponse, err error) {
if returnError {
return nil, fmt.Errorf("error returned by mockRoleService.ListRoleAssignments")
}
return &settings.ListRoleAssignmentsResponse{
Assignments: []*settings.UserRoleAssignment{},
}, nil
},
}
}

View File

@@ -1,6 +1,7 @@
package middleware
import (
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
"net/http"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -23,6 +24,8 @@ type Options struct {
HTTPClient *http.Client
// AccountsClient for resolving accounts
AccountsClient acc.AccountsService
// SettingsRoleService for the roles API in settings
SettingsRoleService settings.RoleService
// OIDCProviderFunc to lazily initialize a provider, must be set for the oidcProvider middleware
OIDCProviderFunc func() (OIDCProvider, error)
// OIDCIss is the oidc-issuer
@@ -74,6 +77,13 @@ func AccountsClient(ac acc.AccountsService) Option {
}
}
// SettingsRoleService provides a function to set the role service option.
func SettingsRoleService(rc settings.RoleService) Option {
return func(o *Options) {
o.SettingsRoleService = rc
}
}
// OIDCProviderFunc provides a function to set the the oidc provider function option.
func OIDCProviderFunc(f func() (OIDCProvider, error)) Option {
return func(o *Options) {