1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

feat(api): relocate authorizations outside of JWT (#3079)

* feat(api): relocate authorizations outside of JWT

* fix(api): update user authorization after enabling the RBAC extension

* feat(api): add PortainerEndpointList operation in the default portainer authorizations

* feat(auth): retrieve authorization from API instead of JWT

* refactor(auth): move permissions retrieval to function

* refactor(api): document authorizations methods
This commit is contained in:
Anthony Lapenna 2019-09-10 10:58:26 +12:00 committed by GitHub
parent 7ebb3e62dd
commit 7d76bc89e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 472 additions and 303 deletions

View file

@ -98,25 +98,9 @@ func (handler *Handler) authenticateLDAPAndCreateUser(w http.ResponseWriter, use
}
user := &portainer.User{
Username: username,
Role: portainer.StandardUserRole,
PortainerAuthorizations: map[portainer.Authorization]bool{
portainer.OperationPortainerDockerHubInspect: true,
portainer.OperationPortainerEndpointGroupList: true,
portainer.OperationPortainerEndpointList: true,
portainer.OperationPortainerEndpointInspect: true,
portainer.OperationPortainerEndpointExtensionAdd: true,
portainer.OperationPortainerEndpointExtensionRemove: true,
portainer.OperationPortainerExtensionList: true,
portainer.OperationPortainerMOTD: true,
portainer.OperationPortainerRegistryList: true,
portainer.OperationPortainerRegistryInspect: true,
portainer.OperationPortainerTeamList: true,
portainer.OperationPortainerTemplateList: true,
portainer.OperationPortainerTemplateInspect: true,
portainer.OperationPortainerUserList: true,
portainer.OperationPortainerUserMemberships: true,
},
Username: username,
Role: portainer.StandardUserRole,
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
}
err = handler.UserService.CreateUser(user)
@ -134,59 +118,14 @@ func (handler *Handler) authenticateLDAPAndCreateUser(w http.ResponseWriter, use
func (handler *Handler) writeToken(w http.ResponseWriter, user *portainer.User) *httperror.HandlerError {
tokenData := &portainer.TokenData{
ID: user.ID,
Username: user.Username,
Role: user.Role,
PortainerAuthorizations: user.PortainerAuthorizations,
ID: user.ID,
Username: user.Username,
Role: user.Role,
}
_, err := handler.ExtensionService.Extension(portainer.RBACExtension)
if err == portainer.ErrObjectNotFound {
return handler.persistAndWriteToken(w, tokenData)
} else if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a extension with the specified identifier inside the database", err}
}
endpointAuthorizations, err := handler.getAuthorizations(user)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve authorizations associated to the user", err}
}
tokenData.EndpointAuthorizations = endpointAuthorizations
return handler.persistAndWriteToken(w, tokenData)
}
func (handler *Handler) getAuthorizations(user *portainer.User) (portainer.EndpointAuthorizations, error) {
endpointAuthorizations := portainer.EndpointAuthorizations{}
if user.Role == portainer.AdministratorRole {
return endpointAuthorizations, nil
}
userMemberships, err := handler.TeamMembershipService.TeamMembershipsByUserID(user.ID)
if err != nil {
return endpointAuthorizations, err
}
endpoints, err := handler.EndpointService.Endpoints()
if err != nil {
return endpointAuthorizations, err
}
endpointGroups, err := handler.EndpointGroupService.EndpointGroups()
if err != nil {
return endpointAuthorizations, err
}
roles, err := handler.RoleService.Roles()
if err != nil {
return endpointAuthorizations, err
}
endpointAuthorizations = getUserEndpointAuthorizations(user, endpoints, endpointGroups, roles, userMemberships)
return endpointAuthorizations, nil
}
func (handler *Handler) persistAndWriteToken(w http.ResponseWriter, tokenData *portainer.TokenData) *httperror.HandlerError {
token, err := handler.JWTService.GenerateToken(tokenData)
if err != nil {

View file

@ -111,25 +111,9 @@ func (handler *Handler) validateOAuth(w http.ResponseWriter, r *http.Request) *h
if user == nil {
user = &portainer.User{
Username: username,
Role: portainer.StandardUserRole,
PortainerAuthorizations: map[portainer.Authorization]bool{
portainer.OperationPortainerDockerHubInspect: true,
portainer.OperationPortainerEndpointGroupList: true,
portainer.OperationPortainerEndpointList: true,
portainer.OperationPortainerEndpointInspect: true,
portainer.OperationPortainerEndpointExtensionAdd: true,
portainer.OperationPortainerEndpointExtensionRemove: true,
portainer.OperationPortainerExtensionList: true,
portainer.OperationPortainerMOTD: true,
portainer.OperationPortainerRegistryList: true,
portainer.OperationPortainerRegistryInspect: true,
portainer.OperationPortainerTeamList: true,
portainer.OperationPortainerTemplateList: true,
portainer.OperationPortainerTemplateInspect: true,
portainer.OperationPortainerUserList: true,
portainer.OperationPortainerUserMemberships: true,
},
Username: username,
Role: portainer.StandardUserRole,
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
}
err = handler.UserService.CreateUser(user)

View file

@ -1,122 +0,0 @@
package auth
import portainer "github.com/portainer/portainer/api"
func getUserEndpointAuthorizations(user *portainer.User, endpoints []portainer.Endpoint, endpointGroups []portainer.EndpointGroup, roles []portainer.Role, userMemberships []portainer.TeamMembership) portainer.EndpointAuthorizations {
endpointAuthorizations := make(portainer.EndpointAuthorizations)
groupUserAccessPolicies := map[portainer.EndpointGroupID]portainer.UserAccessPolicies{}
groupTeamAccessPolicies := map[portainer.EndpointGroupID]portainer.TeamAccessPolicies{}
for _, endpointGroup := range endpointGroups {
groupUserAccessPolicies[endpointGroup.ID] = endpointGroup.UserAccessPolicies
groupTeamAccessPolicies[endpointGroup.ID] = endpointGroup.TeamAccessPolicies
}
for _, endpoint := range endpoints {
authorizations := getAuthorizationsFromUserEndpointPolicy(user, &endpoint, roles)
if len(authorizations) > 0 {
endpointAuthorizations[endpoint.ID] = authorizations
continue
}
authorizations = getAuthorizationsFromUserEndpointGroupPolicy(user, &endpoint, roles, groupUserAccessPolicies)
if len(authorizations) > 0 {
endpointAuthorizations[endpoint.ID] = authorizations
continue
}
authorizations = getAuthorizationsFromTeamEndpointPolicies(userMemberships, &endpoint, roles)
if len(authorizations) > 0 {
endpointAuthorizations[endpoint.ID] = authorizations
continue
}
endpointAuthorizations[endpoint.ID] = getAuthorizationsFromTeamEndpointGroupPolicies(userMemberships, &endpoint, roles, groupTeamAccessPolicies)
}
return endpointAuthorizations
}
func getAuthorizationsFromUserEndpointPolicy(user *portainer.User, endpoint *portainer.Endpoint, roles []portainer.Role) portainer.Authorizations {
policyRoles := make([]portainer.RoleID, 0)
policy, ok := endpoint.UserAccessPolicies[user.ID]
if ok {
policyRoles = append(policyRoles, policy.RoleID)
}
return getAuthorizationsFromRoles(policyRoles, roles)
}
func getAuthorizationsFromUserEndpointGroupPolicy(user *portainer.User, endpoint *portainer.Endpoint, roles []portainer.Role, groupAccessPolicies map[portainer.EndpointGroupID]portainer.UserAccessPolicies) portainer.Authorizations {
policyRoles := make([]portainer.RoleID, 0)
policy, ok := groupAccessPolicies[endpoint.GroupID][user.ID]
if ok {
policyRoles = append(policyRoles, policy.RoleID)
}
return getAuthorizationsFromRoles(policyRoles, roles)
}
func getAuthorizationsFromTeamEndpointPolicies(memberships []portainer.TeamMembership, endpoint *portainer.Endpoint, roles []portainer.Role) portainer.Authorizations {
policyRoles := make([]portainer.RoleID, 0)
for _, membership := range memberships {
policy, ok := endpoint.TeamAccessPolicies[membership.TeamID]
if ok {
policyRoles = append(policyRoles, policy.RoleID)
}
}
return getAuthorizationsFromRoles(policyRoles, roles)
}
func getAuthorizationsFromTeamEndpointGroupPolicies(memberships []portainer.TeamMembership, endpoint *portainer.Endpoint, roles []portainer.Role, groupAccessPolicies map[portainer.EndpointGroupID]portainer.TeamAccessPolicies) portainer.Authorizations {
policyRoles := make([]portainer.RoleID, 0)
for _, membership := range memberships {
policy, ok := groupAccessPolicies[endpoint.GroupID][membership.TeamID]
if ok {
policyRoles = append(policyRoles, policy.RoleID)
}
}
return getAuthorizationsFromRoles(policyRoles, roles)
}
func getAuthorizationsFromRoles(roleIdentifiers []portainer.RoleID, roles []portainer.Role) portainer.Authorizations {
var roleAuthorizations []portainer.Authorizations
for _, id := range roleIdentifiers {
for _, role := range roles {
if role.ID == id {
roleAuthorizations = append(roleAuthorizations, role.Authorizations)
break
}
}
}
processedAuthorizations := make(portainer.Authorizations)
if len(roleAuthorizations) > 0 {
processedAuthorizations = roleAuthorizations[0]
for idx, authorizations := range roleAuthorizations {
if idx == 0 {
continue
}
processedAuthorizations = mergeAuthorizations(processedAuthorizations, authorizations)
}
}
return processedAuthorizations
}
func mergeAuthorizations(a, b portainer.Authorizations) portainer.Authorizations {
c := make(map[portainer.Authorization]bool)
for k := range b {
if _, ok := a[k]; ok {
c[k] = true
}
}
return c
}

View file

@ -53,12 +53,15 @@ func (handler *Handler) endpointGroupUpdate(w http.ResponseWriter, r *http.Reque
endpointGroup.Tags = payload.Tags
}
updateAuthorizations := false
if payload.UserAccessPolicies != nil {
endpointGroup.UserAccessPolicies = payload.UserAccessPolicies
updateAuthorizations = true
}
if payload.TeamAccessPolicies != nil {
endpointGroup.TeamAccessPolicies = payload.TeamAccessPolicies
updateAuthorizations = true
}
err = handler.EndpointGroupService.UpdateEndpointGroup(endpointGroup.ID, endpointGroup)
@ -66,5 +69,12 @@ func (handler *Handler) endpointGroupUpdate(w http.ResponseWriter, r *http.Reque
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist endpoint group changes inside the database", err}
}
if updateAuthorizations {
err = handler.AuthorizationService.UpdateUserAuthorizationsFromPolicies(&payload.UserAccessPolicies, &payload.TeamAccessPolicies)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to update user authorizations", err}
}
}
return response.JSON(w, endpointGroup)
}

View file

@ -14,6 +14,7 @@ type Handler struct {
*mux.Router
EndpointService portainer.EndpointService
EndpointGroupService portainer.EndpointGroupService
AuthorizationService *portainer.AuthorizationService
}
// NewHandler creates a handler to manage endpoint group operations.

View file

@ -76,12 +76,15 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
endpoint.Tags = payload.Tags
}
updateAuthorizations := false
if payload.UserAccessPolicies != nil {
endpoint.UserAccessPolicies = payload.UserAccessPolicies
updateAuthorizations = true
}
if payload.TeamAccessPolicies != nil {
endpoint.TeamAccessPolicies = payload.TeamAccessPolicies
updateAuthorizations = true
}
if payload.Status != nil {
@ -173,5 +176,12 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist endpoint changes inside the database", err}
}
if updateAuthorizations {
err = handler.AuthorizationService.UpdateUserAuthorizationsFromPolicies(&payload.UserAccessPolicies, &payload.TeamAccessPolicies)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to update user authorizations", err}
}
}
return response.JSON(w, endpoint)
}

View file

@ -37,6 +37,7 @@ type Handler struct {
JobService portainer.JobService
ReverseTunnelService portainer.ReverseTunnelService
SettingsService portainer.SettingsService
AuthorizationService *portainer.AuthorizationService
}
// NewHandler creates a handler to manage endpoint operations.

View file

@ -17,6 +17,7 @@ type Handler struct {
EndpointGroupService portainer.EndpointGroupService
EndpointService portainer.EndpointService
RegistryService portainer.RegistryService
AuthorizationService *portainer.AuthorizationService
}
// NewHandler creates a handler to manage extension operations.

View file

@ -1,6 +1,8 @@
package extensions
import portainer "github.com/portainer/portainer/api"
import (
portainer "github.com/portainer/portainer/api"
)
func updateUserAccessPolicyToReadOnlyRole(policies portainer.UserAccessPolicies, key portainer.UserID) {
tmp := policies[key]
@ -34,6 +36,10 @@ func (handler *Handler) upgradeRBACData() error {
return err
}
err = handler.AuthorizationService.UpdateUserAuthorizationsFromPolicies(&endpointGroup.UserAccessPolicies, &endpointGroup.TeamAccessPolicies)
if err != nil {
return err
}
}
endpoints, err := handler.EndpointService.Endpoints()
@ -54,6 +60,11 @@ func (handler *Handler) upgradeRBACData() error {
if err != nil {
return err
}
err = handler.AuthorizationService.UpdateUserAuthorizationsFromPolicies(&endpoint.UserAccessPolicies, &endpoint.TeamAccessPolicies)
if err != nil {
return err
}
}
return nil
}

View file

@ -43,25 +43,9 @@ func (handler *Handler) adminInit(w http.ResponseWriter, r *http.Request) *httpe
}
user := &portainer.User{
Username: payload.Username,
Role: portainer.AdministratorRole,
PortainerAuthorizations: map[portainer.Authorization]bool{
portainer.OperationPortainerDockerHubInspect: true,
portainer.OperationPortainerEndpointGroupList: true,
portainer.OperationPortainerEndpointList: true,
portainer.OperationPortainerEndpointInspect: true,
portainer.OperationPortainerEndpointExtensionAdd: true,
portainer.OperationPortainerEndpointExtensionRemove: true,
portainer.OperationPortainerExtensionList: true,
portainer.OperationPortainerMOTD: true,
portainer.OperationPortainerRegistryList: true,
portainer.OperationPortainerRegistryInspect: true,
portainer.OperationPortainerTeamList: true,
portainer.OperationPortainerTemplateList: true,
portainer.OperationPortainerTemplateInspect: true,
portainer.OperationPortainerUserList: true,
portainer.OperationPortainerUserMemberships: true,
},
Username: payload.Username,
Role: portainer.AdministratorRole,
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
}
user.Password, err = handler.CryptoService.Hash(payload.Password)

View file

@ -58,25 +58,9 @@ func (handler *Handler) userCreate(w http.ResponseWriter, r *http.Request) *http
}
user = &portainer.User{
Username: payload.Username,
Role: portainer.UserRole(payload.Role),
PortainerAuthorizations: map[portainer.Authorization]bool{
portainer.OperationPortainerDockerHubInspect: true,
portainer.OperationPortainerEndpointGroupList: true,
portainer.OperationPortainerEndpointList: true,
portainer.OperationPortainerEndpointInspect: true,
portainer.OperationPortainerEndpointExtensionAdd: true,
portainer.OperationPortainerEndpointExtensionRemove: true,
portainer.OperationPortainerExtensionList: true,
portainer.OperationPortainerMOTD: true,
portainer.OperationPortainerRegistryList: true,
portainer.OperationPortainerRegistryInspect: true,
portainer.OperationPortainerTeamList: true,
portainer.OperationPortainerTemplateList: true,
portainer.OperationPortainerTemplateInspect: true,
portainer.OperationPortainerUserList: true,
portainer.OperationPortainerUserMemberships: true,
},
Username: payload.Username,
Role: portainer.UserRole(payload.Role),
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
}
settings, err := handler.SettingsService.Settings()

View file

@ -3,6 +3,8 @@ package users
import (
"net/http"
"github.com/portainer/portainer/api/http/security"
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
@ -16,6 +18,15 @@ func (handler *Handler) userInspect(w http.ResponseWriter, r *http.Request) *htt
return &httperror.HandlerError{http.StatusBadRequest, "Invalid user identifier route variable", err}
}
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
}
if !securityContext.IsAdmin && securityContext.UserID != portainer.UserID(userID) {
return &httperror.HandlerError{http.StatusForbidden, "Permission denied inspect user", portainer.ErrResourceAccessDenied}
}
user, err := handler.UserService.User(portainer.UserID(userID))
if err == portainer.ErrObjectNotFound {
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err}

View file

@ -19,6 +19,7 @@ type (
dockerTransport *http.Transport
enableSignature bool
ResourceControlService portainer.ResourceControlService
UserService portainer.UserService
TeamMembershipService portainer.TeamMembershipService
RegistryService portainer.RegistryService
DockerHubService portainer.DockerHubService
@ -498,7 +499,12 @@ func (p *proxyTransport) createOperationContext(request *http.Request) (*restric
if tokenData.Role != portainer.AdministratorRole {
operationContext.isAdmin = false
_, ok := tokenData.EndpointAuthorizations[p.endpointIdentifier][portainer.EndpointResourcesAccess]
user, err := p.UserService.User(operationContext.userID)
if err != nil {
return nil, err
}
_, ok := user.EndpointAuthorizations[p.endpointIdentifier][portainer.EndpointResourcesAccess]
if ok {
operationContext.endpointResourceAccess = true
}

View file

@ -16,6 +16,7 @@ const AzureAPIBaseURL = "https://management.azure.com"
// proxyFactory is a factory to create reverse proxies to Docker endpoints
type proxyFactory struct {
ResourceControlService portainer.ResourceControlService
UserService portainer.UserService
TeamMembershipService portainer.TeamMembershipService
SettingsService portainer.SettingsService
RegistryService portainer.RegistryService
@ -70,6 +71,7 @@ func (factory *proxyFactory) createDockerReverseProxy(u *url.URL, endpoint *port
transport := &proxyTransport{
enableSignature: enableSignature,
ResourceControlService: factory.ResourceControlService,
UserService: factory.UserService,
TeamMembershipService: factory.TeamMembershipService,
SettingsService: factory.SettingsService,
RegistryService: factory.RegistryService,

View file

@ -13,6 +13,7 @@ func (factory *proxyFactory) newLocalProxy(path string, endpoint *portainer.Endp
transport := &proxyTransport{
enableSignature: false,
ResourceControlService: factory.ResourceControlService,
UserService: factory.UserService,
TeamMembershipService: factory.TeamMembershipService,
SettingsService: factory.SettingsService,
RegistryService: factory.RegistryService,

View file

@ -3,10 +3,11 @@
package proxy
import (
"github.com/Microsoft/go-winio"
"net"
"net/http"
"github.com/Microsoft/go-winio"
portainer "github.com/portainer/portainer/api"
)
@ -15,6 +16,7 @@ func (factory *proxyFactory) newLocalProxy(path string, endpoint *portainer.Endp
transport := &proxyTransport{
enableSignature: false,
ResourceControlService: factory.ResourceControlService,
UserService: factory.UserService,
TeamMembershipService: factory.TeamMembershipService,
SettingsService: factory.SettingsService,
RegistryService: factory.RegistryService,

View file

@ -31,6 +31,7 @@ type (
// ManagerParams represents the required parameters to create a new Manager instance.
ManagerParams struct {
ResourceControlService portainer.ResourceControlService
UserService portainer.UserService
TeamMembershipService portainer.TeamMembershipService
SettingsService portainer.SettingsService
RegistryService portainer.RegistryService
@ -48,6 +49,7 @@ func NewManager(parameters *ManagerParams) *Manager {
legacyExtensionProxies: cmap.New(),
proxyFactory: &proxyFactory{
ResourceControlService: parameters.ResourceControlService,
UserService: parameters.UserService,
TeamMembershipService: parameters.TeamMembershipService,
SettingsService: parameters.SettingsService,
RegistryService: parameters.RegistryService,

View file

@ -142,10 +142,15 @@ func (bouncer *RequestBouncer) checkEndpointOperationAuthorization(r *http.Reque
return err
}
user, err := bouncer.userService.User(tokenData.ID)
if err != nil {
return err
}
apiOperation := &portainer.APIOperationAuthorizationRequest{
Path: r.URL.String(),
Method: r.Method,
Authorizations: tokenData.EndpointAuthorizations[endpoint.ID],
Authorizations: user.EndpointAuthorizations[endpoint.ID],
}
bouncer.rbacExtensionClient.setLicenseKey(extension.License.LicenseKey)
@ -208,10 +213,19 @@ func (bouncer *RequestBouncer) mwCheckPortainerAuthorizations(next http.Handler)
return
}
user, err := bouncer.userService.User(tokenData.ID)
if err != nil && err == portainer.ErrObjectNotFound {
httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized)
return
} else if err != nil {
httperror.WriteError(w, http.StatusInternalServerError, "Unable to retrieve user details from the database", err)
return
}
apiOperation := &portainer.APIOperationAuthorizationRequest{
Path: r.URL.String(),
Method: r.Method,
Authorizations: tokenData.PortainerAuthorizations,
Authorizations: user.PortainerAuthorizations,
}
bouncer.rbacExtensionClient.setLicenseKey(extension.License.LicenseKey)
@ -281,7 +295,7 @@ func (bouncer *RequestBouncer) mwCheckAuthentication(next http.Handler) http.Han
httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized)
return
} else if err != nil {
httperror.WriteError(w, http.StatusInternalServerError, "Unable to retrieve users from the database", err)
httperror.WriteError(w, http.StatusInternalServerError, "Unable to retrieve user details from the database", err)
return
}
} else {

View file

@ -84,6 +84,7 @@ type Server struct {
func (server *Server) Start() error {
proxyManagerParameters := &proxy.ManagerParams{
ResourceControlService: server.ResourceControlService,
UserService: server.UserService,
TeamMembershipService: server.TeamMembershipService,
SettingsService: server.SettingsService,
RegistryService: server.RegistryService,
@ -93,6 +94,15 @@ func (server *Server) Start() error {
}
proxyManager := proxy.NewManager(proxyManagerParameters)
authorizationServiceParameters := &portainer.AuthorizationServiceParameters{
EndpointService: server.EndpointService,
EndpointGroupService: server.EndpointGroupService,
RoleService: server.RoleService,
TeamMembershipService: server.TeamMembershipService,
UserService: server.UserService,
}
authorizationService := portainer.NewAuthorizationService(authorizationServiceParameters)
requestBouncerParameters := &security.RequestBouncerParams{
JWTService: server.JWTService,
UserService: server.UserService,
@ -136,10 +146,12 @@ func (server *Server) Start() error {
endpointHandler.JobService = server.JobService
endpointHandler.ReverseTunnelService = server.ReverseTunnelService
endpointHandler.SettingsService = server.SettingsService
endpointHandler.AuthorizationService = authorizationService
var endpointGroupHandler = endpointgroups.NewHandler(requestBouncer)
endpointGroupHandler.EndpointGroupService = server.EndpointGroupService
endpointGroupHandler.EndpointService = server.EndpointService
endpointGroupHandler.AuthorizationService = authorizationService
var endpointProxyHandler = endpointproxy.NewHandler(requestBouncer)
endpointProxyHandler.EndpointService = server.EndpointService
@ -157,6 +169,7 @@ func (server *Server) Start() error {
extensionHandler.EndpointGroupService = server.EndpointGroupService
extensionHandler.EndpointService = server.EndpointService
extensionHandler.RegistryService = server.RegistryService
extensionHandler.AuthorizationService = authorizationService
var registryHandler = registries.NewHandler(requestBouncer)
registryHandler.RegistryService = server.RegistryService