mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 13:55:21 +02:00
feat(uac): add multi user management and UAC (#647)
This commit is contained in:
parent
f28f223624
commit
80d50378c5
91 changed files with 3973 additions and 866 deletions
|
@ -1,14 +1,16 @@
|
|||
angular.module('portainer.services')
|
||||
.factory('Authentication', ['$q', 'Auth', 'jwtHelper', 'LocalStorage', 'StateManager', function AuthenticationFactory($q, Auth, jwtHelper, LocalStorage, StateManager) {
|
||||
.factory('Authentication', ['$q', 'Auth', 'jwtHelper', 'LocalStorage', 'StateManager', 'EndpointProvider', function AuthenticationFactory($q, Auth, jwtHelper, LocalStorage, StateManager, EndpointProvider) {
|
||||
'use strict';
|
||||
|
||||
var credentials = {};
|
||||
var user = {};
|
||||
return {
|
||||
init: function() {
|
||||
var jwt = LocalStorage.getJWT();
|
||||
if (jwt) {
|
||||
var tokenPayload = jwtHelper.decodeToken(jwt);
|
||||
credentials.username = tokenPayload.username;
|
||||
user.username = tokenPayload.username;
|
||||
user.ID = tokenPayload.id;
|
||||
user.role = tokenPayload.role;
|
||||
}
|
||||
},
|
||||
login: function(username, password) {
|
||||
|
@ -16,7 +18,10 @@ angular.module('portainer.services')
|
|||
Auth.login({username: username, password: password}).$promise
|
||||
.then(function(data) {
|
||||
LocalStorage.storeJWT(data.jwt);
|
||||
credentials.username = username;
|
||||
var tokenPayload = jwtHelper.decodeToken(data.jwt);
|
||||
user.username = username;
|
||||
user.ID = tokenPayload.id;
|
||||
user.role = tokenPayload.role;
|
||||
resolve();
|
||||
}, function() {
|
||||
reject();
|
||||
|
@ -25,14 +30,15 @@ angular.module('portainer.services')
|
|||
},
|
||||
logout: function() {
|
||||
StateManager.clean();
|
||||
EndpointProvider.clean();
|
||||
LocalStorage.clean();
|
||||
},
|
||||
isAuthenticated: function() {
|
||||
var jwt = LocalStorage.getJWT();
|
||||
return jwt && !jwtHelper.isTokenExpired(jwt);
|
||||
},
|
||||
getCredentials: function() {
|
||||
return credentials;
|
||||
getUserDetails: function() {
|
||||
return user;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
|
23
app/services/endpointProvider.js
Normal file
23
app/services/endpointProvider.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
angular.module('portainer.services')
|
||||
.factory('EndpointProvider', ['LocalStorage', function EndpointProviderFactory(LocalStorage) {
|
||||
'use strict';
|
||||
var endpoint = {};
|
||||
var service = {};
|
||||
service.initialize = function() {
|
||||
var endpointID = LocalStorage.getEndpointID();
|
||||
if (endpointID) {
|
||||
endpoint.ID = endpointID;
|
||||
}
|
||||
};
|
||||
service.clean = function() {
|
||||
endpoint = {};
|
||||
};
|
||||
service.endpointID = function() {
|
||||
return endpoint.ID;
|
||||
};
|
||||
service.setEndpointID = function(id) {
|
||||
endpoint.ID = id;
|
||||
LocalStorage.storeEndpointID(id);
|
||||
};
|
||||
return service;
|
||||
}]);
|
|
@ -1,84 +1,92 @@
|
|||
angular.module('portainer.services')
|
||||
.factory('EndpointService', ['$q', 'Endpoints', 'FileUploadService', function EndpointServiceFactory($q, Endpoints, FileUploadService) {
|
||||
'use strict';
|
||||
return {
|
||||
getActive: function() {
|
||||
return Endpoints.getActiveEndpoint().$promise;
|
||||
},
|
||||
setActive: function(endpointID) {
|
||||
return Endpoints.setActiveEndpoint({id: endpointID}).$promise;
|
||||
},
|
||||
endpoint: function(endpointID) {
|
||||
return Endpoints.get({id: endpointID}).$promise;
|
||||
},
|
||||
endpoints: function() {
|
||||
return Endpoints.query({}).$promise;
|
||||
},
|
||||
updateEndpoint: function(ID, name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, type) {
|
||||
var endpoint = {
|
||||
id: ID,
|
||||
Name: name,
|
||||
URL: type === 'local' ? ("unix://" + URL) : ("tcp://" + URL),
|
||||
TLS: TLS
|
||||
};
|
||||
var deferred = $q.defer();
|
||||
Endpoints.update({}, endpoint, function success(data) {
|
||||
FileUploadService.uploadTLSFilesForEndpoint(ID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
||||
var service = {};
|
||||
|
||||
service.endpoint = function(endpointID) {
|
||||
return Endpoints.get({id: endpointID}).$promise;
|
||||
};
|
||||
|
||||
service.endpoints = function() {
|
||||
return Endpoints.query({}).$promise;
|
||||
};
|
||||
|
||||
service.updateAuthorizedUsers = function(id, authorizedUserIDs) {
|
||||
return Endpoints.updateAccess({id: id}, {authorizedUsers: authorizedUserIDs}).$promise;
|
||||
};
|
||||
|
||||
service.updateEndpoint = function(id, endpointParams) {
|
||||
var query = {
|
||||
name: endpointParams.name,
|
||||
TLS: endpointParams.TLS,
|
||||
authorizedUsers: endpointParams.authorizedUsers
|
||||
};
|
||||
if (endpointParams.type && endpointParams.URL) {
|
||||
query.URL = endpointParams.type === 'local' ? ("unix://" + endpointParams.URL) : ("tcp://" + endpointParams.URL);
|
||||
}
|
||||
var deferred = $q.defer();
|
||||
Endpoints.update({id: id}, query).$promise
|
||||
.then(function success() {
|
||||
return FileUploadService.uploadTLSFilesForEndpoint(id, endpointParams.TLSCAFile, endpointParams.TLSCertFile, endpointParams.TLSKeyFile);
|
||||
})
|
||||
.then(function success(data) {
|
||||
deferred.notify({upload: false});
|
||||
deferred.resolve(data);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.notify({upload: false});
|
||||
deferred.reject({msg: 'Unable to update endpoint', err: err});
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.deleteEndpoint = function(endpointID) {
|
||||
return Endpoints.remove({id: endpointID}).$promise;
|
||||
};
|
||||
|
||||
service.createLocalEndpoint = function(name, URL, TLS, active) {
|
||||
var endpoint = {
|
||||
Name: "local",
|
||||
URL: "unix:///var/run/docker.sock",
|
||||
TLS: false
|
||||
};
|
||||
return Endpoints.create({}, endpoint).$promise;
|
||||
};
|
||||
|
||||
service.createRemoteEndpoint = function(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, active) {
|
||||
var endpoint = {
|
||||
Name: name,
|
||||
URL: 'tcp://' + URL,
|
||||
TLS: TLS
|
||||
};
|
||||
var deferred = $q.defer();
|
||||
Endpoints.create({active: active}, endpoint, function success(data) {
|
||||
var endpointID = data.Id;
|
||||
if (TLS) {
|
||||
deferred.notify({upload: true});
|
||||
FileUploadService.uploadTLSFilesForEndpoint(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
||||
deferred.notify({upload: false});
|
||||
deferred.resolve(data);
|
||||
if (active) {
|
||||
Endpoints.setActiveEndpoint({}, {id: endpointID}, function success(data) {
|
||||
deferred.resolve(data);
|
||||
}, function error(err) {
|
||||
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(data);
|
||||
}
|
||||
}, function error(err) {
|
||||
deferred.notify({upload: false});
|
||||
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
|
||||
});
|
||||
}, function error(err) {
|
||||
deferred.reject({msg: 'Unable to update endpoint', err: err});
|
||||
});
|
||||
return deferred.promise;
|
||||
},
|
||||
deleteEndpoint: function(endpointID) {
|
||||
return Endpoints.remove({id: endpointID}).$promise;
|
||||
},
|
||||
createLocalEndpoint: function(name, URL, TLS, active) {
|
||||
var endpoint = {
|
||||
Name: "local",
|
||||
URL: "unix:///var/run/docker.sock",
|
||||
TLS: false
|
||||
};
|
||||
return Endpoints.create({active: active}, endpoint).$promise;
|
||||
},
|
||||
createRemoteEndpoint: function(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, active) {
|
||||
var endpoint = {
|
||||
Name: name,
|
||||
URL: 'tcp://' + URL,
|
||||
TLS: TLS
|
||||
};
|
||||
var deferred = $q.defer();
|
||||
Endpoints.create({active: active}, endpoint, function success(data) {
|
||||
var endpointID = data.Id;
|
||||
if (TLS) {
|
||||
deferred.notify({upload: true});
|
||||
FileUploadService.uploadTLSFilesForEndpoint(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
||||
deferred.notify({upload: false});
|
||||
if (active) {
|
||||
Endpoints.setActiveEndpoint({}, {id: endpointID}, function success(data) {
|
||||
deferred.resolve(data);
|
||||
}, function error(err) {
|
||||
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(data);
|
||||
}
|
||||
}, function error(err) {
|
||||
deferred.notify({upload: false});
|
||||
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(data);
|
||||
}
|
||||
}, function error(err) {
|
||||
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
} else {
|
||||
deferred.resolve(data);
|
||||
}
|
||||
}, function error(err) {
|
||||
deferred.reject({msg: 'Unable to create endpoint', err: err});
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
}]);
|
||||
|
|
|
@ -19,15 +19,15 @@ angular.module('portainer.services')
|
|||
var deferred = $q.defer();
|
||||
var queue = [];
|
||||
|
||||
if (TLSCAFile !== null) {
|
||||
if (TLSCAFile) {
|
||||
var uploadTLSCA = uploadFile('api/upload/tls/' + endpointID + '/ca', TLSCAFile);
|
||||
queue.push(uploadTLSCA);
|
||||
}
|
||||
if (TLSCertFile !== null) {
|
||||
if (TLSCertFile) {
|
||||
var uploadTLSCert = uploadFile('api/upload/tls/' + endpointID + '/cert', TLSCertFile);
|
||||
queue.push(uploadTLSCert);
|
||||
}
|
||||
if (TLSKeyFile !== null) {
|
||||
if (TLSKeyFile) {
|
||||
var uploadTLSKey = uploadFile('api/upload/tls/' + endpointID + '/key', TLSKeyFile);
|
||||
queue.push(uploadTLSKey);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,12 @@ angular.module('portainer.services')
|
|||
.factory('LocalStorage', ['localStorageService', function LocalStorageFactory(localStorageService) {
|
||||
'use strict';
|
||||
return {
|
||||
storeEndpointID: function(id) {
|
||||
localStorageService.set('ENDPOINT_ID', id);
|
||||
},
|
||||
getEndpointID: function() {
|
||||
return localStorageService.get('ENDPOINT_ID');
|
||||
},
|
||||
storeEndpointState: function(state) {
|
||||
localStorageService.set('ENDPOINT_STATE', state);
|
||||
},
|
||||
|
|
|
@ -2,6 +2,7 @@ angular.module('portainer.services')
|
|||
.factory('ModalService', [function ModalServiceFactory() {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
service.confirm = function(options){
|
||||
var box = bootbox.confirm({
|
||||
title: options.title,
|
||||
|
@ -9,11 +10,11 @@ angular.module('portainer.services')
|
|||
buttons: {
|
||||
confirm: {
|
||||
label: options.buttons.confirm.label,
|
||||
className: 'btn-danger'
|
||||
className: options.buttons.confirm.className
|
||||
},
|
||||
cancel: {
|
||||
label: options.buttons.cancel.label
|
||||
}
|
||||
cancel: {
|
||||
label: options.buttons.cancel && options.buttons.cancel.label ? options.buttons.cancel.label : 'Cancel'
|
||||
}
|
||||
},
|
||||
callback: options.callback
|
||||
});
|
||||
|
@ -24,5 +25,62 @@ angular.module('portainer.services')
|
|||
}
|
||||
});
|
||||
};
|
||||
|
||||
service.confirmOwnershipChange = function(callback, msg) {
|
||||
service.confirm({
|
||||
title: 'Are you sure ?',
|
||||
message: msg,
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Change ownership',
|
||||
className: 'btn-primary'
|
||||
}
|
||||
},
|
||||
callback: callback,
|
||||
});
|
||||
};
|
||||
|
||||
service.confirmContainerOwnershipChange = function(callback) {
|
||||
var msg = 'You can change the ownership of a container one way only. You will not be able to make this container private again. <b>Changing ownership on this container will also change the ownership on any attached volume.</b>';
|
||||
service.confirmOwnershipChange(callback, msg);
|
||||
};
|
||||
|
||||
service.confirmServiceOwnershipChange = function(callback) {
|
||||
var msg = 'You can change the ownership of a service one way only. You will not be able to make this service private again. <b>Changing ownership on this service will also change the ownership on any attached volume.</b>';
|
||||
service.confirmOwnershipChange(callback, msg);
|
||||
};
|
||||
|
||||
service.confirmVolumeOwnershipChange = function(callback) {
|
||||
var msg = 'You can change the ownership of a volume one way only. You will not be able to make this volume private again.';
|
||||
service.confirmOwnershipChange(callback, msg);
|
||||
};
|
||||
|
||||
service.confirmImageForceRemoval = function(callback) {
|
||||
service.confirm({
|
||||
title: "Are you sure?",
|
||||
message: "Forcing the removal of the image will remove the image even if it has multiple tags or if it is used by stopped containers.",
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Remove the image',
|
||||
className: 'btn-danger'
|
||||
}
|
||||
},
|
||||
callback: callback,
|
||||
});
|
||||
};
|
||||
|
||||
service.confirmDeletion = function(message, callback) {
|
||||
service.confirm({
|
||||
title: 'Are you sure ?',
|
||||
message: message,
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Delete',
|
||||
className: 'btn-danger'
|
||||
}
|
||||
},
|
||||
callback: callback,
|
||||
});
|
||||
};
|
||||
return service;
|
||||
}]);
|
||||
|
|
31
app/services/resourceControlService.js
Normal file
31
app/services/resourceControlService.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
angular.module('portainer.services')
|
||||
.factory('ResourceControlService', ['$q', 'ResourceControl', function ResourceControlServiceFactory($q, ResourceControl) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
service.setContainerResourceControl = function(userID, resourceID) {
|
||||
return ResourceControl.create({ userId: userID, resourceType: 'container' }, { ResourceID: resourceID }).$promise;
|
||||
};
|
||||
|
||||
service.removeContainerResourceControl = function(userID, resourceID) {
|
||||
return ResourceControl.remove({ userId: userID, resourceId: resourceID, resourceType: 'container' }).$promise;
|
||||
};
|
||||
|
||||
service.setServiceResourceControl = function(userID, resourceID) {
|
||||
return ResourceControl.create({ userId: userID, resourceType: 'service' }, { ResourceID: resourceID }).$promise;
|
||||
};
|
||||
|
||||
service.removeServiceResourceControl = function(userID, resourceID) {
|
||||
return ResourceControl.remove({ userId: userID, resourceId: resourceID, resourceType: 'service' }).$promise;
|
||||
};
|
||||
|
||||
service.setVolumeResourceControl = function(userID, resourceID) {
|
||||
return ResourceControl.create({ userId: userID, resourceType: 'volume' }, { ResourceID: resourceID }).$promise;
|
||||
};
|
||||
|
||||
service.removeVolumeResourceControl = function(userID, resourceID) {
|
||||
return ResourceControl.remove({ userId: userID, resourceId: resourceID, resourceType: 'volume' }).$promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
}]);
|
48
app/services/userService.js
Normal file
48
app/services/userService.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
angular.module('portainer.services')
|
||||
.factory('UserService', ['$q', 'Users', function UserServiceFactory($q, Users) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
service.users = function() {
|
||||
return Users.query({}).$promise;
|
||||
};
|
||||
|
||||
service.user = function(id) {
|
||||
return Users.get({id: id}).$promise;
|
||||
};
|
||||
|
||||
service.createUser = function(username, password, role) {
|
||||
return Users.create({}, {username: username, password: password, role: role}).$promise;
|
||||
};
|
||||
|
||||
service.deleteUser = function(id) {
|
||||
return Users.remove({id: id}).$promise;
|
||||
};
|
||||
|
||||
service.updateUser = function(id, password, role) {
|
||||
var query = {
|
||||
password: password,
|
||||
role: role
|
||||
};
|
||||
return Users.update({id: id}, query).$promise;
|
||||
};
|
||||
|
||||
service.updateUserPassword = function(id, currentPassword, newPassword) {
|
||||
var deferred = $q.defer();
|
||||
Users.checkPassword({id: id}, {password: currentPassword}).$promise
|
||||
.then(function success(data) {
|
||||
if (!data.valid) {
|
||||
deferred.reject({invalidPassword: true});
|
||||
}
|
||||
return service.updateUser(id, newPassword, undefined);
|
||||
})
|
||||
.then(function success(data) {
|
||||
deferred.resolve();
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({msg: 'Unable to update user password', err: err});
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
}]);
|
Loading…
Add table
Add a link
Reference in a new issue