mirror of https://github.com/portainer/portainer
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 methodspull/3148/head
parent
7ebb3e62dd
commit
7d76bc89e7
|
@ -0,0 +1,266 @@
|
||||||
|
package portainer
|
||||||
|
|
||||||
|
// AuthorizationService represents a service used to
|
||||||
|
// update authorizations associated to a user or team.
|
||||||
|
type AuthorizationService struct {
|
||||||
|
endpointService EndpointService
|
||||||
|
endpointGroupService EndpointGroupService
|
||||||
|
roleService RoleService
|
||||||
|
teamMembershipService TeamMembershipService
|
||||||
|
userService UserService
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizationServiceParameters are the required parameters
|
||||||
|
// used to create a new AuthorizationService.
|
||||||
|
type AuthorizationServiceParameters struct {
|
||||||
|
EndpointService EndpointService
|
||||||
|
EndpointGroupService EndpointGroupService
|
||||||
|
RoleService RoleService
|
||||||
|
TeamMembershipService TeamMembershipService
|
||||||
|
UserService UserService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAuthorizationService returns a point to a new AuthorizationService instance.
|
||||||
|
func NewAuthorizationService(parameters *AuthorizationServiceParameters) *AuthorizationService {
|
||||||
|
return &AuthorizationService{
|
||||||
|
endpointService: parameters.EndpointService,
|
||||||
|
endpointGroupService: parameters.EndpointGroupService,
|
||||||
|
roleService: parameters.RoleService,
|
||||||
|
teamMembershipService: parameters.TeamMembershipService,
|
||||||
|
userService: parameters.UserService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPortainerAuthorizations returns the default Portainer authorizations used by non-admin users.
|
||||||
|
func DefaultPortainerAuthorizations() Authorizations {
|
||||||
|
return map[Authorization]bool{
|
||||||
|
OperationPortainerDockerHubInspect: true,
|
||||||
|
OperationPortainerEndpointGroupList: true,
|
||||||
|
OperationPortainerEndpointList: true,
|
||||||
|
OperationPortainerEndpointInspect: true,
|
||||||
|
OperationPortainerEndpointExtensionAdd: true,
|
||||||
|
OperationPortainerEndpointExtensionRemove: true,
|
||||||
|
OperationPortainerExtensionList: true,
|
||||||
|
OperationPortainerMOTD: true,
|
||||||
|
OperationPortainerRegistryList: true,
|
||||||
|
OperationPortainerRegistryInspect: true,
|
||||||
|
OperationPortainerTeamList: true,
|
||||||
|
OperationPortainerTemplateList: true,
|
||||||
|
OperationPortainerTemplateInspect: true,
|
||||||
|
OperationPortainerUserList: true,
|
||||||
|
OperationPortainerUserInspect: true,
|
||||||
|
OperationPortainerUserMemberships: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserAuthorizationsFromPolicies will update users authorizations based on the specified access policies.
|
||||||
|
func (service *AuthorizationService) UpdateUserAuthorizationsFromPolicies(userPolicies *UserAccessPolicies, teamPolicies *TeamAccessPolicies) error {
|
||||||
|
|
||||||
|
for userID, policy := range *userPolicies {
|
||||||
|
if policy.RoleID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.UpdateUserAuthorizations(userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for teamID, policy := range *teamPolicies {
|
||||||
|
if policy.RoleID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.updateUserAuthorizationsInTeam(teamID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *AuthorizationService) updateUserAuthorizationsInTeam(teamID TeamID) error {
|
||||||
|
|
||||||
|
memberships, err := service.teamMembershipService.TeamMembershipsByTeamID(teamID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, membership := range memberships {
|
||||||
|
err := service.UpdateUserAuthorizations(membership.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserAuthorizations will trigger an update of the authorizations for the specified user.
|
||||||
|
func (service *AuthorizationService) UpdateUserAuthorizations(userID UserID) error {
|
||||||
|
user, err := service.userService.User(userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpointAuthorizations, err := service.getAuthorizations(user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user.EndpointAuthorizations = endpointAuthorizations
|
||||||
|
|
||||||
|
return service.userService.UpdateUser(userID, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *AuthorizationService) getAuthorizations(user *User) (EndpointAuthorizations, error) {
|
||||||
|
endpointAuthorizations := EndpointAuthorizations{}
|
||||||
|
if user.Role == AdministratorRole {
|
||||||
|
return endpointAuthorizations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userMemberships, err := service.teamMembershipService.TeamMembershipsByUserID(user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return endpointAuthorizations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints, err := service.endpointService.Endpoints()
|
||||||
|
if err != nil {
|
||||||
|
return endpointAuthorizations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpointGroups, err := service.endpointGroupService.EndpointGroups()
|
||||||
|
if err != nil {
|
||||||
|
return endpointAuthorizations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
roles, err := service.roleService.Roles()
|
||||||
|
if err != nil {
|
||||||
|
return endpointAuthorizations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpointAuthorizations = getUserEndpointAuthorizations(user, endpoints, endpointGroups, roles, userMemberships)
|
||||||
|
|
||||||
|
return endpointAuthorizations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserEndpointAuthorizations(user *User, endpoints []Endpoint, endpointGroups []EndpointGroup, roles []Role, userMemberships []TeamMembership) EndpointAuthorizations {
|
||||||
|
endpointAuthorizations := make(EndpointAuthorizations)
|
||||||
|
|
||||||
|
groupUserAccessPolicies := map[EndpointGroupID]UserAccessPolicies{}
|
||||||
|
groupTeamAccessPolicies := map[EndpointGroupID]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 *User, endpoint *Endpoint, roles []Role) Authorizations {
|
||||||
|
policyRoles := make([]RoleID, 0)
|
||||||
|
|
||||||
|
policy, ok := endpoint.UserAccessPolicies[user.ID]
|
||||||
|
if ok {
|
||||||
|
policyRoles = append(policyRoles, policy.RoleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAuthorizationsFromRoles(policyRoles, roles)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAuthorizationsFromUserEndpointGroupPolicy(user *User, endpoint *Endpoint, roles []Role, groupAccessPolicies map[EndpointGroupID]UserAccessPolicies) Authorizations {
|
||||||
|
policyRoles := make([]RoleID, 0)
|
||||||
|
|
||||||
|
policy, ok := groupAccessPolicies[endpoint.GroupID][user.ID]
|
||||||
|
if ok {
|
||||||
|
policyRoles = append(policyRoles, policy.RoleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAuthorizationsFromRoles(policyRoles, roles)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAuthorizationsFromTeamEndpointPolicies(memberships []TeamMembership, endpoint *Endpoint, roles []Role) Authorizations {
|
||||||
|
policyRoles := make([]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 []TeamMembership, endpoint *Endpoint, roles []Role, groupAccessPolicies map[EndpointGroupID]TeamAccessPolicies) Authorizations {
|
||||||
|
policyRoles := make([]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 []RoleID, roles []Role) Authorizations {
|
||||||
|
var roleAuthorizations []Authorizations
|
||||||
|
for _, id := range roleIdentifiers {
|
||||||
|
for _, role := range roles {
|
||||||
|
if role.ID == id {
|
||||||
|
roleAuthorizations = append(roleAuthorizations, role.Authorizations)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processedAuthorizations := make(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 Authorizations) Authorizations {
|
||||||
|
c := make(map[Authorization]bool)
|
||||||
|
|
||||||
|
for k := range b {
|
||||||
|
if _, ok := a[k]; ok {
|
||||||
|
c[k] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
|
@ -124,8 +124,10 @@ func (store *Store) MigrateData() error {
|
||||||
ExtensionService: store.ExtensionService,
|
ExtensionService: store.ExtensionService,
|
||||||
RegistryService: store.RegistryService,
|
RegistryService: store.RegistryService,
|
||||||
ResourceControlService: store.ResourceControlService,
|
ResourceControlService: store.ResourceControlService,
|
||||||
|
RoleService: store.RoleService,
|
||||||
SettingsService: store.SettingsService,
|
SettingsService: store.SettingsService,
|
||||||
StackService: store.StackService,
|
StackService: store.StackService,
|
||||||
|
TeamMembershipService: store.TeamMembershipService,
|
||||||
TemplateService: store.TemplateService,
|
TemplateService: store.TemplateService,
|
||||||
UserService: store.UserService,
|
UserService: store.UserService,
|
||||||
VersionService: store.VersionService,
|
VersionService: store.VersionService,
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package migrator
|
||||||
|
|
||||||
|
import portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
func (m *Migrator) updateUsersToDBVersion20() error {
|
||||||
|
legacyUsers, err := m.userService.Users()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
authorizationServiceParameters := &portainer.AuthorizationServiceParameters{
|
||||||
|
EndpointService: m.endpointService,
|
||||||
|
EndpointGroupService: m.endpointGroupService,
|
||||||
|
RoleService: m.roleService,
|
||||||
|
TeamMembershipService: m.teamMembershipService,
|
||||||
|
UserService: m.userService,
|
||||||
|
}
|
||||||
|
|
||||||
|
authorizationService := portainer.NewAuthorizationService(authorizationServiceParameters)
|
||||||
|
|
||||||
|
for _, user := range legacyUsers {
|
||||||
|
err := authorizationService.UpdateUserAuthorizations(user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -8,8 +8,10 @@ import (
|
||||||
"github.com/portainer/portainer/api/bolt/extension"
|
"github.com/portainer/portainer/api/bolt/extension"
|
||||||
"github.com/portainer/portainer/api/bolt/registry"
|
"github.com/portainer/portainer/api/bolt/registry"
|
||||||
"github.com/portainer/portainer/api/bolt/resourcecontrol"
|
"github.com/portainer/portainer/api/bolt/resourcecontrol"
|
||||||
|
"github.com/portainer/portainer/api/bolt/role"
|
||||||
"github.com/portainer/portainer/api/bolt/settings"
|
"github.com/portainer/portainer/api/bolt/settings"
|
||||||
"github.com/portainer/portainer/api/bolt/stack"
|
"github.com/portainer/portainer/api/bolt/stack"
|
||||||
|
"github.com/portainer/portainer/api/bolt/teammembership"
|
||||||
"github.com/portainer/portainer/api/bolt/template"
|
"github.com/portainer/portainer/api/bolt/template"
|
||||||
"github.com/portainer/portainer/api/bolt/user"
|
"github.com/portainer/portainer/api/bolt/user"
|
||||||
"github.com/portainer/portainer/api/bolt/version"
|
"github.com/portainer/portainer/api/bolt/version"
|
||||||
|
@ -25,8 +27,10 @@ type (
|
||||||
extensionService *extension.Service
|
extensionService *extension.Service
|
||||||
registryService *registry.Service
|
registryService *registry.Service
|
||||||
resourceControlService *resourcecontrol.Service
|
resourceControlService *resourcecontrol.Service
|
||||||
|
roleService *role.Service
|
||||||
settingsService *settings.Service
|
settingsService *settings.Service
|
||||||
stackService *stack.Service
|
stackService *stack.Service
|
||||||
|
teamMembershipService *teammembership.Service
|
||||||
templateService *template.Service
|
templateService *template.Service
|
||||||
userService *user.Service
|
userService *user.Service
|
||||||
versionService *version.Service
|
versionService *version.Service
|
||||||
|
@ -42,8 +46,10 @@ type (
|
||||||
ExtensionService *extension.Service
|
ExtensionService *extension.Service
|
||||||
RegistryService *registry.Service
|
RegistryService *registry.Service
|
||||||
ResourceControlService *resourcecontrol.Service
|
ResourceControlService *resourcecontrol.Service
|
||||||
|
RoleService *role.Service
|
||||||
SettingsService *settings.Service
|
SettingsService *settings.Service
|
||||||
StackService *stack.Service
|
StackService *stack.Service
|
||||||
|
TeamMembershipService *teammembership.Service
|
||||||
TemplateService *template.Service
|
TemplateService *template.Service
|
||||||
UserService *user.Service
|
UserService *user.Service
|
||||||
VersionService *version.Service
|
VersionService *version.Service
|
||||||
|
@ -61,7 +67,9 @@ func NewMigrator(parameters *Parameters) *Migrator {
|
||||||
extensionService: parameters.ExtensionService,
|
extensionService: parameters.ExtensionService,
|
||||||
registryService: parameters.RegistryService,
|
registryService: parameters.RegistryService,
|
||||||
resourceControlService: parameters.ResourceControlService,
|
resourceControlService: parameters.ResourceControlService,
|
||||||
|
roleService: parameters.RoleService,
|
||||||
settingsService: parameters.SettingsService,
|
settingsService: parameters.SettingsService,
|
||||||
|
teamMembershipService: parameters.TeamMembershipService,
|
||||||
templateService: parameters.TemplateService,
|
templateService: parameters.TemplateService,
|
||||||
stackService: parameters.StackService,
|
stackService: parameters.StackService,
|
||||||
userService: parameters.UserService,
|
userService: parameters.UserService,
|
||||||
|
@ -257,5 +265,13 @@ func (m *Migrator) Migrate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Portainer 1.22.x
|
||||||
|
if m.currentDBVersion < 20 {
|
||||||
|
err := m.updateUsersToDBVersion20()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return m.versionService.StoreDBVersion(portainer.DBVersion)
|
return m.versionService.StoreDBVersion(portainer.DBVersion)
|
||||||
}
|
}
|
||||||
|
|
|
@ -638,23 +638,7 @@ func main() {
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
Role: portainer.AdministratorRole,
|
Role: portainer.AdministratorRole,
|
||||||
Password: adminPasswordHash,
|
Password: adminPasswordHash,
|
||||||
PortainerAuthorizations: map[portainer.Authorization]bool{
|
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := store.UserService.CreateUser(user)
|
err := store.UserService.CreateUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -100,23 +100,7 @@ func (handler *Handler) authenticateLDAPAndCreateUser(w http.ResponseWriter, use
|
||||||
user := &portainer.User{
|
user := &portainer.User{
|
||||||
Username: username,
|
Username: username,
|
||||||
Role: portainer.StandardUserRole,
|
Role: portainer.StandardUserRole,
|
||||||
PortainerAuthorizations: map[portainer.Authorization]bool{
|
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.UserService.CreateUser(user)
|
err = handler.UserService.CreateUser(user)
|
||||||
|
@ -137,56 +121,11 @@ func (handler *Handler) writeToken(w http.ResponseWriter, user *portainer.User)
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
Role: user.Role,
|
Role: user.Role,
|
||||||
PortainerAuthorizations: user.PortainerAuthorizations,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, 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)
|
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 {
|
func (handler *Handler) persistAndWriteToken(w http.ResponseWriter, tokenData *portainer.TokenData) *httperror.HandlerError {
|
||||||
token, err := handler.JWTService.GenerateToken(tokenData)
|
token, err := handler.JWTService.GenerateToken(tokenData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -113,23 +113,7 @@ func (handler *Handler) validateOAuth(w http.ResponseWriter, r *http.Request) *h
|
||||||
user = &portainer.User{
|
user = &portainer.User{
|
||||||
Username: username,
|
Username: username,
|
||||||
Role: portainer.StandardUserRole,
|
Role: portainer.StandardUserRole,
|
||||||
PortainerAuthorizations: map[portainer.Authorization]bool{
|
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.UserService.CreateUser(user)
|
err = handler.UserService.CreateUser(user)
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -53,12 +53,15 @@ func (handler *Handler) endpointGroupUpdate(w http.ResponseWriter, r *http.Reque
|
||||||
endpointGroup.Tags = payload.Tags
|
endpointGroup.Tags = payload.Tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateAuthorizations := false
|
||||||
if payload.UserAccessPolicies != nil {
|
if payload.UserAccessPolicies != nil {
|
||||||
endpointGroup.UserAccessPolicies = payload.UserAccessPolicies
|
endpointGroup.UserAccessPolicies = payload.UserAccessPolicies
|
||||||
|
updateAuthorizations = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.TeamAccessPolicies != nil {
|
if payload.TeamAccessPolicies != nil {
|
||||||
endpointGroup.TeamAccessPolicies = payload.TeamAccessPolicies
|
endpointGroup.TeamAccessPolicies = payload.TeamAccessPolicies
|
||||||
|
updateAuthorizations = true
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.EndpointGroupService.UpdateEndpointGroup(endpointGroup.ID, endpointGroup)
|
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}
|
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)
|
return response.JSON(w, endpointGroup)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ type Handler struct {
|
||||||
*mux.Router
|
*mux.Router
|
||||||
EndpointService portainer.EndpointService
|
EndpointService portainer.EndpointService
|
||||||
EndpointGroupService portainer.EndpointGroupService
|
EndpointGroupService portainer.EndpointGroupService
|
||||||
|
AuthorizationService *portainer.AuthorizationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandler creates a handler to manage endpoint group operations.
|
// NewHandler creates a handler to manage endpoint group operations.
|
||||||
|
|
|
@ -76,12 +76,15 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
|
||||||
endpoint.Tags = payload.Tags
|
endpoint.Tags = payload.Tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateAuthorizations := false
|
||||||
if payload.UserAccessPolicies != nil {
|
if payload.UserAccessPolicies != nil {
|
||||||
endpoint.UserAccessPolicies = payload.UserAccessPolicies
|
endpoint.UserAccessPolicies = payload.UserAccessPolicies
|
||||||
|
updateAuthorizations = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.TeamAccessPolicies != nil {
|
if payload.TeamAccessPolicies != nil {
|
||||||
endpoint.TeamAccessPolicies = payload.TeamAccessPolicies
|
endpoint.TeamAccessPolicies = payload.TeamAccessPolicies
|
||||||
|
updateAuthorizations = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.Status != nil {
|
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}
|
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)
|
return response.JSON(w, endpoint)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ type Handler struct {
|
||||||
JobService portainer.JobService
|
JobService portainer.JobService
|
||||||
ReverseTunnelService portainer.ReverseTunnelService
|
ReverseTunnelService portainer.ReverseTunnelService
|
||||||
SettingsService portainer.SettingsService
|
SettingsService portainer.SettingsService
|
||||||
|
AuthorizationService *portainer.AuthorizationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandler creates a handler to manage endpoint operations.
|
// NewHandler creates a handler to manage endpoint operations.
|
||||||
|
|
|
@ -17,6 +17,7 @@ type Handler struct {
|
||||||
EndpointGroupService portainer.EndpointGroupService
|
EndpointGroupService portainer.EndpointGroupService
|
||||||
EndpointService portainer.EndpointService
|
EndpointService portainer.EndpointService
|
||||||
RegistryService portainer.RegistryService
|
RegistryService portainer.RegistryService
|
||||||
|
AuthorizationService *portainer.AuthorizationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandler creates a handler to manage extension operations.
|
// NewHandler creates a handler to manage extension operations.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package extensions
|
package extensions
|
||||||
|
|
||||||
import portainer "github.com/portainer/portainer/api"
|
import (
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
func updateUserAccessPolicyToReadOnlyRole(policies portainer.UserAccessPolicies, key portainer.UserID) {
|
func updateUserAccessPolicyToReadOnlyRole(policies portainer.UserAccessPolicies, key portainer.UserID) {
|
||||||
tmp := policies[key]
|
tmp := policies[key]
|
||||||
|
@ -34,6 +36,10 @@ func (handler *Handler) upgradeRBACData() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = handler.AuthorizationService.UpdateUserAuthorizationsFromPolicies(&endpointGroup.UserAccessPolicies, &endpointGroup.TeamAccessPolicies)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints, err := handler.EndpointService.Endpoints()
|
endpoints, err := handler.EndpointService.Endpoints()
|
||||||
|
@ -54,6 +60,11 @@ func (handler *Handler) upgradeRBACData() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = handler.AuthorizationService.UpdateUserAuthorizationsFromPolicies(&endpoint.UserAccessPolicies, &endpoint.TeamAccessPolicies)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,23 +45,7 @@ func (handler *Handler) adminInit(w http.ResponseWriter, r *http.Request) *httpe
|
||||||
user := &portainer.User{
|
user := &portainer.User{
|
||||||
Username: payload.Username,
|
Username: payload.Username,
|
||||||
Role: portainer.AdministratorRole,
|
Role: portainer.AdministratorRole,
|
||||||
PortainerAuthorizations: map[portainer.Authorization]bool{
|
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Password, err = handler.CryptoService.Hash(payload.Password)
|
user.Password, err = handler.CryptoService.Hash(payload.Password)
|
||||||
|
|
|
@ -60,23 +60,7 @@ func (handler *Handler) userCreate(w http.ResponseWriter, r *http.Request) *http
|
||||||
user = &portainer.User{
|
user = &portainer.User{
|
||||||
Username: payload.Username,
|
Username: payload.Username,
|
||||||
Role: portainer.UserRole(payload.Role),
|
Role: portainer.UserRole(payload.Role),
|
||||||
PortainerAuthorizations: map[portainer.Authorization]bool{
|
PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(),
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
settings, err := handler.SettingsService.Settings()
|
settings, err := handler.SettingsService.Settings()
|
||||||
|
|
|
@ -3,6 +3,8 @@ package users
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/portainer/portainer/api/http/security"
|
||||||
|
|
||||||
httperror "github.com/portainer/libhttp/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/libhttp/request"
|
"github.com/portainer/libhttp/request"
|
||||||
"github.com/portainer/libhttp/response"
|
"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}
|
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))
|
user, err := handler.UserService.User(portainer.UserID(userID))
|
||||||
if err == portainer.ErrObjectNotFound {
|
if err == portainer.ErrObjectNotFound {
|
||||||
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err}
|
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err}
|
||||||
|
|
|
@ -19,6 +19,7 @@ type (
|
||||||
dockerTransport *http.Transport
|
dockerTransport *http.Transport
|
||||||
enableSignature bool
|
enableSignature bool
|
||||||
ResourceControlService portainer.ResourceControlService
|
ResourceControlService portainer.ResourceControlService
|
||||||
|
UserService portainer.UserService
|
||||||
TeamMembershipService portainer.TeamMembershipService
|
TeamMembershipService portainer.TeamMembershipService
|
||||||
RegistryService portainer.RegistryService
|
RegistryService portainer.RegistryService
|
||||||
DockerHubService portainer.DockerHubService
|
DockerHubService portainer.DockerHubService
|
||||||
|
@ -498,7 +499,12 @@ func (p *proxyTransport) createOperationContext(request *http.Request) (*restric
|
||||||
if tokenData.Role != portainer.AdministratorRole {
|
if tokenData.Role != portainer.AdministratorRole {
|
||||||
operationContext.isAdmin = false
|
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 {
|
if ok {
|
||||||
operationContext.endpointResourceAccess = true
|
operationContext.endpointResourceAccess = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ const AzureAPIBaseURL = "https://management.azure.com"
|
||||||
// proxyFactory is a factory to create reverse proxies to Docker endpoints
|
// proxyFactory is a factory to create reverse proxies to Docker endpoints
|
||||||
type proxyFactory struct {
|
type proxyFactory struct {
|
||||||
ResourceControlService portainer.ResourceControlService
|
ResourceControlService portainer.ResourceControlService
|
||||||
|
UserService portainer.UserService
|
||||||
TeamMembershipService portainer.TeamMembershipService
|
TeamMembershipService portainer.TeamMembershipService
|
||||||
SettingsService portainer.SettingsService
|
SettingsService portainer.SettingsService
|
||||||
RegistryService portainer.RegistryService
|
RegistryService portainer.RegistryService
|
||||||
|
@ -70,6 +71,7 @@ func (factory *proxyFactory) createDockerReverseProxy(u *url.URL, endpoint *port
|
||||||
transport := &proxyTransport{
|
transport := &proxyTransport{
|
||||||
enableSignature: enableSignature,
|
enableSignature: enableSignature,
|
||||||
ResourceControlService: factory.ResourceControlService,
|
ResourceControlService: factory.ResourceControlService,
|
||||||
|
UserService: factory.UserService,
|
||||||
TeamMembershipService: factory.TeamMembershipService,
|
TeamMembershipService: factory.TeamMembershipService,
|
||||||
SettingsService: factory.SettingsService,
|
SettingsService: factory.SettingsService,
|
||||||
RegistryService: factory.RegistryService,
|
RegistryService: factory.RegistryService,
|
||||||
|
|
|
@ -13,6 +13,7 @@ func (factory *proxyFactory) newLocalProxy(path string, endpoint *portainer.Endp
|
||||||
transport := &proxyTransport{
|
transport := &proxyTransport{
|
||||||
enableSignature: false,
|
enableSignature: false,
|
||||||
ResourceControlService: factory.ResourceControlService,
|
ResourceControlService: factory.ResourceControlService,
|
||||||
|
UserService: factory.UserService,
|
||||||
TeamMembershipService: factory.TeamMembershipService,
|
TeamMembershipService: factory.TeamMembershipService,
|
||||||
SettingsService: factory.SettingsService,
|
SettingsService: factory.SettingsService,
|
||||||
RegistryService: factory.RegistryService,
|
RegistryService: factory.RegistryService,
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Microsoft/go-winio"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ func (factory *proxyFactory) newLocalProxy(path string, endpoint *portainer.Endp
|
||||||
transport := &proxyTransport{
|
transport := &proxyTransport{
|
||||||
enableSignature: false,
|
enableSignature: false,
|
||||||
ResourceControlService: factory.ResourceControlService,
|
ResourceControlService: factory.ResourceControlService,
|
||||||
|
UserService: factory.UserService,
|
||||||
TeamMembershipService: factory.TeamMembershipService,
|
TeamMembershipService: factory.TeamMembershipService,
|
||||||
SettingsService: factory.SettingsService,
|
SettingsService: factory.SettingsService,
|
||||||
RegistryService: factory.RegistryService,
|
RegistryService: factory.RegistryService,
|
||||||
|
|
|
@ -31,6 +31,7 @@ type (
|
||||||
// ManagerParams represents the required parameters to create a new Manager instance.
|
// ManagerParams represents the required parameters to create a new Manager instance.
|
||||||
ManagerParams struct {
|
ManagerParams struct {
|
||||||
ResourceControlService portainer.ResourceControlService
|
ResourceControlService portainer.ResourceControlService
|
||||||
|
UserService portainer.UserService
|
||||||
TeamMembershipService portainer.TeamMembershipService
|
TeamMembershipService portainer.TeamMembershipService
|
||||||
SettingsService portainer.SettingsService
|
SettingsService portainer.SettingsService
|
||||||
RegistryService portainer.RegistryService
|
RegistryService portainer.RegistryService
|
||||||
|
@ -48,6 +49,7 @@ func NewManager(parameters *ManagerParams) *Manager {
|
||||||
legacyExtensionProxies: cmap.New(),
|
legacyExtensionProxies: cmap.New(),
|
||||||
proxyFactory: &proxyFactory{
|
proxyFactory: &proxyFactory{
|
||||||
ResourceControlService: parameters.ResourceControlService,
|
ResourceControlService: parameters.ResourceControlService,
|
||||||
|
UserService: parameters.UserService,
|
||||||
TeamMembershipService: parameters.TeamMembershipService,
|
TeamMembershipService: parameters.TeamMembershipService,
|
||||||
SettingsService: parameters.SettingsService,
|
SettingsService: parameters.SettingsService,
|
||||||
RegistryService: parameters.RegistryService,
|
RegistryService: parameters.RegistryService,
|
||||||
|
|
|
@ -142,10 +142,15 @@ func (bouncer *RequestBouncer) checkEndpointOperationAuthorization(r *http.Reque
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user, err := bouncer.userService.User(tokenData.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
apiOperation := &portainer.APIOperationAuthorizationRequest{
|
apiOperation := &portainer.APIOperationAuthorizationRequest{
|
||||||
Path: r.URL.String(),
|
Path: r.URL.String(),
|
||||||
Method: r.Method,
|
Method: r.Method,
|
||||||
Authorizations: tokenData.EndpointAuthorizations[endpoint.ID],
|
Authorizations: user.EndpointAuthorizations[endpoint.ID],
|
||||||
}
|
}
|
||||||
|
|
||||||
bouncer.rbacExtensionClient.setLicenseKey(extension.License.LicenseKey)
|
bouncer.rbacExtensionClient.setLicenseKey(extension.License.LicenseKey)
|
||||||
|
@ -208,10 +213,19 @@ func (bouncer *RequestBouncer) mwCheckPortainerAuthorizations(next http.Handler)
|
||||||
return
|
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{
|
apiOperation := &portainer.APIOperationAuthorizationRequest{
|
||||||
Path: r.URL.String(),
|
Path: r.URL.String(),
|
||||||
Method: r.Method,
|
Method: r.Method,
|
||||||
Authorizations: tokenData.PortainerAuthorizations,
|
Authorizations: user.PortainerAuthorizations,
|
||||||
}
|
}
|
||||||
|
|
||||||
bouncer.rbacExtensionClient.setLicenseKey(extension.License.LicenseKey)
|
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)
|
httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -84,6 +84,7 @@ type Server struct {
|
||||||
func (server *Server) Start() error {
|
func (server *Server) Start() error {
|
||||||
proxyManagerParameters := &proxy.ManagerParams{
|
proxyManagerParameters := &proxy.ManagerParams{
|
||||||
ResourceControlService: server.ResourceControlService,
|
ResourceControlService: server.ResourceControlService,
|
||||||
|
UserService: server.UserService,
|
||||||
TeamMembershipService: server.TeamMembershipService,
|
TeamMembershipService: server.TeamMembershipService,
|
||||||
SettingsService: server.SettingsService,
|
SettingsService: server.SettingsService,
|
||||||
RegistryService: server.RegistryService,
|
RegistryService: server.RegistryService,
|
||||||
|
@ -93,6 +94,15 @@ func (server *Server) Start() error {
|
||||||
}
|
}
|
||||||
proxyManager := proxy.NewManager(proxyManagerParameters)
|
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{
|
requestBouncerParameters := &security.RequestBouncerParams{
|
||||||
JWTService: server.JWTService,
|
JWTService: server.JWTService,
|
||||||
UserService: server.UserService,
|
UserService: server.UserService,
|
||||||
|
@ -136,10 +146,12 @@ func (server *Server) Start() error {
|
||||||
endpointHandler.JobService = server.JobService
|
endpointHandler.JobService = server.JobService
|
||||||
endpointHandler.ReverseTunnelService = server.ReverseTunnelService
|
endpointHandler.ReverseTunnelService = server.ReverseTunnelService
|
||||||
endpointHandler.SettingsService = server.SettingsService
|
endpointHandler.SettingsService = server.SettingsService
|
||||||
|
endpointHandler.AuthorizationService = authorizationService
|
||||||
|
|
||||||
var endpointGroupHandler = endpointgroups.NewHandler(requestBouncer)
|
var endpointGroupHandler = endpointgroups.NewHandler(requestBouncer)
|
||||||
endpointGroupHandler.EndpointGroupService = server.EndpointGroupService
|
endpointGroupHandler.EndpointGroupService = server.EndpointGroupService
|
||||||
endpointGroupHandler.EndpointService = server.EndpointService
|
endpointGroupHandler.EndpointService = server.EndpointService
|
||||||
|
endpointGroupHandler.AuthorizationService = authorizationService
|
||||||
|
|
||||||
var endpointProxyHandler = endpointproxy.NewHandler(requestBouncer)
|
var endpointProxyHandler = endpointproxy.NewHandler(requestBouncer)
|
||||||
endpointProxyHandler.EndpointService = server.EndpointService
|
endpointProxyHandler.EndpointService = server.EndpointService
|
||||||
|
@ -157,6 +169,7 @@ func (server *Server) Start() error {
|
||||||
extensionHandler.EndpointGroupService = server.EndpointGroupService
|
extensionHandler.EndpointGroupService = server.EndpointGroupService
|
||||||
extensionHandler.EndpointService = server.EndpointService
|
extensionHandler.EndpointService = server.EndpointService
|
||||||
extensionHandler.RegistryService = server.RegistryService
|
extensionHandler.RegistryService = server.RegistryService
|
||||||
|
extensionHandler.AuthorizationService = authorizationService
|
||||||
|
|
||||||
var registryHandler = registries.NewHandler(requestBouncer)
|
var registryHandler = registries.NewHandler(requestBouncer)
|
||||||
registryHandler.RegistryService = server.RegistryService
|
registryHandler.RegistryService = server.RegistryService
|
||||||
|
|
|
@ -19,8 +19,6 @@ type claims struct {
|
||||||
UserID int `json:"id"`
|
UserID int `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Role int `json:"role"`
|
Role int `json:"role"`
|
||||||
EndpointAuthorizations portainer.EndpointAuthorizations `json:"endpointAuthorizations"`
|
|
||||||
PortainerAuthorizations portainer.Authorizations `json:"portainerAuthorizations"`
|
|
||||||
jwt.StandardClaims
|
jwt.StandardClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +38,10 @@ func NewService() (*Service, error) {
|
||||||
func (service *Service) GenerateToken(data *portainer.TokenData) (string, error) {
|
func (service *Service) GenerateToken(data *portainer.TokenData) (string, error) {
|
||||||
expireToken := time.Now().Add(time.Hour * 8).Unix()
|
expireToken := time.Now().Add(time.Hour * 8).Unix()
|
||||||
cl := claims{
|
cl := claims{
|
||||||
int(data.ID),
|
UserID: int(data.ID),
|
||||||
data.Username,
|
Username: data.Username,
|
||||||
int(data.Role),
|
Role: int(data.Role),
|
||||||
data.EndpointAuthorizations,
|
StandardClaims: jwt.StandardClaims{
|
||||||
data.PortainerAuthorizations,
|
|
||||||
jwt.StandardClaims{
|
|
||||||
ExpiresAt: expireToken,
|
ExpiresAt: expireToken,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -74,8 +70,6 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData,
|
||||||
ID: portainer.UserID(cl.UserID),
|
ID: portainer.UserID(cl.UserID),
|
||||||
Username: cl.Username,
|
Username: cl.Username,
|
||||||
Role: portainer.UserRole(cl.Role),
|
Role: portainer.UserRole(cl.Role),
|
||||||
EndpointAuthorizations: cl.EndpointAuthorizations,
|
|
||||||
PortainerAuthorizations: cl.PortainerAuthorizations,
|
|
||||||
}
|
}
|
||||||
return tokenData, nil
|
return tokenData, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,7 @@ type (
|
||||||
Password string `json:"Password,omitempty"`
|
Password string `json:"Password,omitempty"`
|
||||||
Role UserRole `json:"Role"`
|
Role UserRole `json:"Role"`
|
||||||
PortainerAuthorizations Authorizations `json:"PortainerAuthorizations"`
|
PortainerAuthorizations Authorizations `json:"PortainerAuthorizations"`
|
||||||
|
EndpointAuthorizations EndpointAuthorizations `json:"EndpointAuthorizations"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserID represents a user identifier
|
// UserID represents a user identifier
|
||||||
|
@ -163,8 +164,6 @@ type (
|
||||||
ID UserID
|
ID UserID
|
||||||
Username string
|
Username string
|
||||||
Role UserRole
|
Role UserRole
|
||||||
EndpointAuthorizations EndpointAuthorizations
|
|
||||||
PortainerAuthorizations Authorizations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StackID represents a stack identifier (it must be composed of Name + "_" + SwarmID to create a unique identifier)
|
// StackID represents a stack identifier (it must be composed of Name + "_" + SwarmID to create a unique identifier)
|
||||||
|
@ -904,7 +903,7 @@ const (
|
||||||
// APIVersion is the version number of the Portainer API
|
// APIVersion is the version number of the Portainer API
|
||||||
APIVersion = "1.22.0"
|
APIVersion = "1.22.0"
|
||||||
// DBVersion is the version number of the Portainer database
|
// DBVersion is the version number of the Portainer database
|
||||||
DBVersion = 19
|
DBVersion = 20
|
||||||
// AssetsServerURL represents the URL of the Portainer asset server
|
// AssetsServerURL represents the URL of the Portainer asset server
|
||||||
AssetsServerURL = "https://portainer-io-assets.sfo2.digitaloceanspaces.com"
|
AssetsServerURL = "https://portainer-io-assets.sfo2.digitaloceanspaces.com"
|
||||||
// MessageOfTheDayURL represents the URL where Portainer MOTD message can be retrieved
|
// MessageOfTheDayURL represents the URL where Portainer MOTD message can be retrieved
|
||||||
|
|
|
@ -2,6 +2,8 @@ export function UserViewModel(data) {
|
||||||
this.Id = data.Id;
|
this.Id = data.Id;
|
||||||
this.Username = data.Username;
|
this.Username = data.Username;
|
||||||
this.Role = data.Role;
|
this.Role = data.Role;
|
||||||
|
this.EndpointAuthorizations = data.EndpointAuthorizations;
|
||||||
|
this.PortainerAuthorizations = data.PortainerAuthorizations;
|
||||||
if (data.Role === 1) {
|
if (data.Role === 1) {
|
||||||
this.RoleName = 'administrator';
|
this.RoleName = 'administrator';
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
angular.module('portainer.app')
|
angular.module('portainer.app')
|
||||||
.factory('Authentication', [
|
.factory('Authentication', [
|
||||||
'Auth', 'OAuth', 'jwtHelper', 'LocalStorage', 'StateManager', 'EndpointProvider',
|
'Auth', 'OAuth', 'jwtHelper', 'LocalStorage', 'StateManager', 'EndpointProvider', 'UserService',
|
||||||
function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider) {
|
function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider, UserService) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var service = {};
|
var service = {};
|
||||||
|
@ -15,6 +15,7 @@ function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManage
|
||||||
service.getUserDetails = getUserDetails;
|
service.getUserDetails = getUserDetails;
|
||||||
service.isAdmin = isAdmin;
|
service.isAdmin = isAdmin;
|
||||||
service.hasAuthorizations = hasAuthorizations;
|
service.hasAuthorizations = hasAuthorizations;
|
||||||
|
service.retrievePermissions = retrievePermissions;
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
var jwt = LocalStorage.getJWT();
|
var jwt = LocalStorage.getJWT();
|
||||||
|
@ -53,14 +54,20 @@ function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManage
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function retrievePermissions() {
|
||||||
|
return UserService.user(user.ID)
|
||||||
|
.then((data) => {
|
||||||
|
user.endpointAuthorizations = data.EndpointAuthorizations;
|
||||||
|
user.portainerAuthorizations = data.PortainerAuthorizations;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function setUser(jwt) {
|
function setUser(jwt) {
|
||||||
LocalStorage.storeJWT(jwt);
|
LocalStorage.storeJWT(jwt);
|
||||||
var tokenPayload = jwtHelper.decodeToken(jwt);
|
var tokenPayload = jwtHelper.decodeToken(jwt);
|
||||||
user.username = tokenPayload.username;
|
user.username = tokenPayload.username;
|
||||||
user.ID = tokenPayload.id;
|
user.ID = tokenPayload.id;
|
||||||
user.role = tokenPayload.role;
|
user.role = tokenPayload.role;
|
||||||
user.endpointAuthorizations = tokenPayload.endpointAuthorizations;
|
|
||||||
user.portainerAuthorizations = tokenPayload.portainerAuthorizations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAdmin() {
|
function isAdmin() {
|
||||||
|
|
|
@ -29,12 +29,21 @@ function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, Us
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function permissionsError() {
|
||||||
|
$scope.state.permissionsError = true;
|
||||||
|
Authentication.logout();
|
||||||
|
$scope.state.AuthenticationError = 'Unable to retrieve permissions.'
|
||||||
|
$scope.state.loginInProgress = false;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
$scope.authenticateUser = function() {
|
$scope.authenticateUser = function() {
|
||||||
var username = $scope.formValues.Username;
|
var username = $scope.formValues.Username;
|
||||||
var password = $scope.formValues.Password;
|
var password = $scope.formValues.Password;
|
||||||
$scope.state.loginInProgress = true;
|
$scope.state.loginInProgress = true;
|
||||||
|
|
||||||
Authentication.login(username, password)
|
Authentication.login(username, password)
|
||||||
|
.then(() => Authentication.retrievePermissions().catch(permissionsError))
|
||||||
.then(function success() {
|
.then(function success() {
|
||||||
return retrieveAndSaveEnabledExtensions();
|
return retrieveAndSaveEnabledExtensions();
|
||||||
})
|
})
|
||||||
|
@ -42,6 +51,9 @@ function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, Us
|
||||||
checkForEndpoints();
|
checkForEndpoints();
|
||||||
})
|
})
|
||||||
.catch(function error() {
|
.catch(function error() {
|
||||||
|
if ($scope.state.permissionsError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SettingsService.publicSettings()
|
SettingsService.publicSettings()
|
||||||
.then(function success(settings) {
|
.then(function success(settings) {
|
||||||
if (settings.AuthenticationMethod === 1) {
|
if (settings.AuthenticationMethod === 1) {
|
||||||
|
@ -166,6 +178,7 @@ function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, Us
|
||||||
|
|
||||||
function oAuthLogin(code) {
|
function oAuthLogin(code) {
|
||||||
return Authentication.OAuthLogin(code)
|
return Authentication.OAuthLogin(code)
|
||||||
|
.then(() => Authentication.retrievePermissions().catch(permissionsError))
|
||||||
.then(function success() {
|
.then(function success() {
|
||||||
return retrieveAndSaveEnabledExtensions();
|
return retrieveAndSaveEnabledExtensions();
|
||||||
})
|
})
|
||||||
|
@ -173,6 +186,9 @@ function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, Us
|
||||||
URLHelper.cleanParameters();
|
URLHelper.cleanParameters();
|
||||||
})
|
})
|
||||||
.catch(function error() {
|
.catch(function error() {
|
||||||
|
if ($scope.state.permissionsError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$scope.state.AuthenticationError = 'Unable to login via OAuth';
|
$scope.state.AuthenticationError = 'Unable to login via OAuth';
|
||||||
$scope.state.isInOAuthProcess = false;
|
$scope.state.isInOAuthProcess = false;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue