Still upto working. Authentication sort of working
This commit is contained in:
parent
9aaeb0987f
commit
8ed028115a
|
@ -1,6 +1,11 @@
|
|||
from pyramid.authentication import AuthTktAuthenticationPolicy
|
||||
from pyramid.authorization import ACLAuthorizationPolicy
|
||||
from pyramid.config import Configurator
|
||||
from pyramid.session import SignedCookieSessionFactory
|
||||
from sqlalchemy import engine_from_config
|
||||
from soter.models import initialize_sql
|
||||
from soter.renderers import json_renderer
|
||||
from soter.security import rolefinder
|
||||
|
||||
|
||||
def main(global_config, **settings):
|
||||
|
@ -9,16 +14,32 @@ def main(global_config, **settings):
|
|||
engine = engine_from_config(settings, 'sqlalchemy.')
|
||||
initialize_sql(engine)
|
||||
|
||||
config = Configurator(settings=settings)
|
||||
session_factory = SignedCookieSessionFactory('soter')
|
||||
authentication_policy = AuthTktAuthenticationPolicy('brewman', timeout=900, reissue_time=90, callback=rolefinder)
|
||||
authorization_policy = ACLAuthorizationPolicy()
|
||||
|
||||
|
||||
config = Configurator(settings=settings,
|
||||
session_factory=session_factory,
|
||||
authentication_policy=authentication_policy,
|
||||
authorization_policy=authorization_policy)
|
||||
|
||||
config.add_renderer(name='json', factory=json_renderer)
|
||||
|
||||
config.add_static_view('app', 'soter:static/app', cache_max_age=3600)
|
||||
config.add_static_view('assets', 'soter:static/assets', cache_max_age=3600)
|
||||
config.add_route('favicon', '/favicon.ico')
|
||||
config.add_route('home', '/')
|
||||
config.add_route('v1_auth', '/v1/Auth')
|
||||
config.add_route('v1_login', '/v1/login')
|
||||
config.add_route('login', '/login')
|
||||
config.add_route('logout', '/logout')
|
||||
|
||||
|
||||
add_route(config,'picture', '/picture')
|
||||
add_route(config,'album', '/album')
|
||||
add_route(config,'user', '/user')
|
||||
add_route(config,'group', '/group')
|
||||
add_route(config,'role', '/role')
|
||||
config.scan()
|
||||
return config.make_wsgi_app()
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
from decimal import Decimal
|
||||
import uuid
|
||||
from pyramid.renderers import JSON
|
||||
|
||||
|
||||
class DecimalAsFloatHack(float):
|
||||
def __init__(self, d):
|
||||
self.d = d
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.d)
|
||||
|
||||
|
||||
def decimal_adaptor(obj, request):
|
||||
return DecimalAsFloatHack(obj)
|
||||
|
||||
|
||||
def uuid_adaptor(obj, request):
|
||||
return str(obj)
|
||||
|
||||
json_renderer = JSON()
|
||||
|
||||
json_renderer.add_adapter(Decimal, decimal_adaptor)
|
||||
json_renderer.add_adapter(uuid.UUID, uuid_adaptor)
|
|
@ -0,0 +1,23 @@
|
|||
import uuid
|
||||
from soter.models.auth import User
|
||||
|
||||
|
||||
def rolefinder(user_id, request):
|
||||
if request is not None and 'perms' in request.session:
|
||||
perms = request.session['perms']
|
||||
else:
|
||||
perms = []
|
||||
user = User.by_id(user_id)
|
||||
for item in user.roles:
|
||||
for perm in item.permissions:
|
||||
perms.append(perm.name)
|
||||
perms = f7(perms)
|
||||
if request is not None:
|
||||
request.session['perms'] = perms
|
||||
return perms
|
||||
|
||||
|
||||
def f7(seq):
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
return [x for x in seq if x not in seen and not seen_add(x)]
|
|
@ -1,80 +1,107 @@
|
|||
'use strict';
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var soter = angular.module('soter', ['ngRoute', 'chieffancypants.loadingBar'])
|
||||
.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
|
||||
$routeProvider.
|
||||
when('/', {templateUrl: '/app/home/view.html'}).
|
||||
when('/login', {templateUrl: '/app/shared/login.html', controller: 'LoginCtrl'}).
|
||||
when('/logout', {templateUrl: '/app/home/view.html', controller: 'LogoutCtrl'}).
|
||||
var soter = angular.module('soter', ['ngRoute', 'ngResource', 'chieffancypants.loadingBar'])
|
||||
.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
|
||||
$routeProvider.
|
||||
when('/', {templateUrl: '/app/home/view.html'}).
|
||||
when('/login', {templateUrl: '/app/shared/login.html', controller: 'LoginController'}).
|
||||
when('/logout', {templateUrl: '/app/home/view.html', controller: 'LogoutController'}).
|
||||
|
||||
//when('/album', {templateUrl: '/app/album/view.html', controller: 'AlbumController', resolve: AlbumCtrl.resolve}).
|
||||
//when('/album/:id', {templateUrl: '/app/album/view.html', controller: 'AlbumController', resolve: AlbumCtrl.resolve}).
|
||||
//when('/album', {templateUrl: '/app/album/view.html', controller: 'AlbumController', resolve: AlbumCtrl.resolve}).
|
||||
//when('/album/:id', {templateUrl: '/app/album/view.html', controller: 'AlbumController', resolve: AlbumCtrl.resolve}).
|
||||
|
||||
//when('/picture', {templateUrl: '/app/picture/view.html', controller: 'PictureController', resolve: PictureCtrl.resolve, reloadOnSearch:false}).
|
||||
//when('/picture/:id', {templateUrl: '/app/picture/view.html', controller: 'PictureController', resolve: PictureCtrl.resolve, reloadOnSearch:false}).
|
||||
//when('/picture', {templateUrl: '/app/picture/view.html', controller: 'PictureController', resolve: PictureCtrl.resolve, reloadOnSearch:false}).
|
||||
//when('/picture/:id', {templateUrl: '/app/picture/view.html', controller: 'PictureController', resolve: PictureCtrl.resolve, reloadOnSearch:false}).
|
||||
|
||||
when('/users', {templateUrl: '/app/user/list.html', controller: 'UserListController', resolve: UserListCtrlResolve}).
|
||||
when('/user', {templateUrl: '/app/user/view.html', controller: 'UserController', resolve: UserCtrlResolve}).
|
||||
when('/user/:id', {templateUrl: '/app/user/view.html', controller: 'UserController', resolve: UserCtrlResolve}).
|
||||
when('/users', {
|
||||
templateUrl: '/app/user/list.html',
|
||||
controller: 'UserListController',
|
||||
resolve: UserListCtrlResolve
|
||||
}).
|
||||
when('/user', {
|
||||
templateUrl: '/app/user/view.html',
|
||||
controller: 'UserController',
|
||||
resolve: UserCtrlResolve
|
||||
}).
|
||||
when('/user/:id', {
|
||||
templateUrl: '/app/user/view.html',
|
||||
controller: 'UserController',
|
||||
resolve: UserCtrlResolve
|
||||
}).
|
||||
|
||||
when('/groups', {templateUrl: '/app/group/list.html', controller: 'GroupListController', resolve: GroupListCtrlResolve}).
|
||||
when('/group', {templateUrl: '/app/group/view.html', controller: 'GroupController', resolve: GroupCtrlResolve}).
|
||||
when('/group/:id', {templateUrl: '/app/group/view.html', controller: 'GroupController', resolve: GroupCtrlResolve}).
|
||||
when('/roles', {
|
||||
templateUrl: '/app/role/list.html',
|
||||
controller: 'RoleListController',
|
||||
resolve: RoleListCtrlResolve
|
||||
}).
|
||||
when('/role', {
|
||||
templateUrl: '/app/role/view.html',
|
||||
controller: 'RoleController',
|
||||
resolve: RoleCtrlResolve
|
||||
}).
|
||||
when('/role/:id', {
|
||||
templateUrl: '/app/role/view.html',
|
||||
controller: 'RoleController',
|
||||
resolve: RoleCtrlResolve
|
||||
}).
|
||||
|
||||
//when('/settings', {templateUrl: '/partial/settings.html', controller: 'SettingsController', resolve: SettingsCtrl.resolve}).
|
||||
//when('/settings', {templateUrl: '/partial/settings.html', controller: 'SettingsController', resolve: SettingsCtrl.resolve}).
|
||||
|
||||
otherwise({templateUrl: '/app/shared/404.html'});
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
}])
|
||||
.config(['$httpProvider', function ($httpProvider) {
|
||||
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
}])
|
||||
.config(['$httpProvider', function ($httpProvider) {
|
||||
$httpProvider.interceptors.push('responseInterceptor');
|
||||
}])
|
||||
.factory('responseInterceptor', ['$q', '$rootScope', function ($q, $rootScope) {
|
||||
return {
|
||||
response: function (response) {
|
||||
return response;
|
||||
},
|
||||
responseError: function (response) {
|
||||
var headers = response.headers(),
|
||||
isResourceResponse = headers['content-type'] === "application/json; charset=utf-8",
|
||||
status = response.status;
|
||||
if (status === 401 && !isResourceResponse) {
|
||||
$rootScope.$broadcast('loginRequired');
|
||||
otherwise({templateUrl: '/app/shared/404.html'});
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
}])
|
||||
.config(['$httpProvider', function ($httpProvider) {
|
||||
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
}])
|
||||
.config(['$httpProvider', function ($httpProvider) {
|
||||
$httpProvider.interceptors.push('responseInterceptor');
|
||||
}])
|
||||
.factory('responseInterceptor', ['$q', '$rootScope', function ($q, $rootScope) {
|
||||
return {
|
||||
response: function (response) {
|
||||
return response;
|
||||
},
|
||||
responseError: function (response) {
|
||||
var headers = response.headers(),
|
||||
isResourceResponse = headers['content-type'] === "application/json; charset=utf-8",
|
||||
status = response.status;
|
||||
if (status === 401 && !isResourceResponse) {
|
||||
$rootScope.$broadcast('loginRequired');
|
||||
}
|
||||
// otherwise
|
||||
return $q.reject(response);
|
||||
}
|
||||
// otherwise
|
||||
return $q.reject(response);
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module('soter').controller('BaseCtrl', ['$rootScope', '$scope', 'AuthService', '$location', '$routeParams', function ($rootScope, $scope, AuthService, $location, $routeParams) {
|
||||
$rootScope.$on('loginRequired', function () {
|
||||
if (Session.loggedIn === true) {
|
||||
$location.path('/');
|
||||
} else {
|
||||
var came_from = $routeParams.came_from;
|
||||
if (angular.isUndefined(came_from) && $location.path() !== '/login') {
|
||||
came_from = $location.url();
|
||||
}
|
||||
$location.path('/login').search({came_from: came_from});
|
||||
}
|
||||
});
|
||||
$scope.toasts = [];
|
||||
$scope.clearToast = function (item) {
|
||||
var idx = $scope.toasts.indexOf(item);
|
||||
if (idx !== -1) {
|
||||
$scope.toasts.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on("$routeChangeStart", function (event, next, current) {
|
||||
|
||||
Auth.get(function (u, putResponseHeaders) {
|
||||
$rootScope.auth = u;
|
||||
$rootScope.perms = u.perms;
|
||||
});
|
||||
});
|
||||
}]);
|
||||
|
||||
soter.controller('BaseCtrl', ['$rootScope', '$scope', 'Auth', '$location', '$routeParams', function ($rootScope, $scope, Auth, $location, $routeParams) {
|
||||
$rootScope.$on('loginRequired', function () {
|
||||
if ($rootScope.auth.isAuthenticated) {
|
||||
$location.path('/');
|
||||
} else {
|
||||
var came_from = $routeParams.came_from;
|
||||
if (angular.isUndefined(came_from) && $location.path() !== '/login') {
|
||||
came_from = $location.url();
|
||||
}
|
||||
$location.path('/login').search({came_from: came_from});
|
||||
}
|
||||
});
|
||||
$scope.toasts = [];
|
||||
$scope.clearToast = function (item) {
|
||||
var idx = $scope.toasts.indexOf(item);
|
||||
if (idx !== -1) {
|
||||
$scope.toasts.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on("$routeChangeStart", function (event, next, current) {
|
||||
Auth.get(function (u, putResponseHeaders) {
|
||||
$rootScope.auth = u;
|
||||
$rootScope.perms = u.perms;
|
||||
});
|
||||
});
|
||||
}]);
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter')
|
||||
.controller('GroupListController', GroupListController)
|
||||
.controller('GroupController', GroupController);
|
||||
|
||||
var GroupListCtrl = ['$scope', 'groups', function ($scope, groups) {
|
||||
$scope.info = groups;
|
||||
}];
|
||||
|
||||
var GroupCtrl = ['$scope', '$location', 'group', function ($scope, $location, group) {
|
||||
$scope.group = group;
|
||||
|
||||
$scope.save = function () {
|
||||
$scope.group.$save(function (u, putResponseHeaders) {
|
||||
$scope.toasts.push({Type: 'Success', Message: ''});
|
||||
$location.path('/Groups')
|
||||
}, function (data, status) {
|
||||
$scope.toasts.push({Type: 'Danger', Message: data.data});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.delete = function () {
|
||||
$scope.group.$delete(function (u, putResponseHeaders) {
|
||||
$scope.toasts.push({Type: 'Success', Message: ''});
|
||||
$location.path('/Groups')
|
||||
}, function (data, status) {
|
||||
$scope.toasts.push({Type: 'Danger', Message: data.data});
|
||||
});
|
||||
};
|
||||
$('#txtName').focus();
|
||||
}];
|
||||
|
||||
});
|
||||
|
||||
var GroupCtrlResolve = {
|
||||
group: ['$route', 'Group', function ($route, Group) {
|
||||
var id = $route.current.params.id;
|
||||
return Group.get({id: id}).$promise;
|
||||
}]
|
||||
};
|
||||
|
||||
var GroupListCtrlResolve = {
|
||||
groups: ['Group', function (Group) {
|
||||
return Group.query({}).$promise;
|
||||
}]
|
||||
};
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter').factory('Group', Group);
|
||||
|
||||
var Group = ['$resource', function ($resource) {
|
||||
return $resource('/api/Group/:id',
|
||||
{id: '@GroupID'}, {
|
||||
query: {method: 'GET', params: {list: true}, isArray: true}
|
||||
});
|
||||
}]
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter')
|
||||
.controller('RoleListController', ['$scope', 'roles', RoleListController])
|
||||
.controller('RoleController', ['$scope', '$location', 'role', RoleController]);
|
||||
|
||||
function RoleListController($scope, roles) {
|
||||
$scope.info = roles;
|
||||
}
|
||||
|
||||
function RoleController($scope, $location, role) {
|
||||
$scope.role = role;
|
||||
|
||||
$scope.save = function () {
|
||||
$scope.role.$save(function (u, putResponseHeaders) {
|
||||
$scope.toasts.push({Type: 'Success', Message: ''});
|
||||
$location.path('/Roles')
|
||||
}, function (data, status) {
|
||||
$scope.toasts.push({Type: 'Danger', Message: data.data});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.delete = function () {
|
||||
$scope.role.$delete(function (u, putResponseHeaders) {
|
||||
$scope.toasts.push({Type: 'Success', Message: ''});
|
||||
$location.path('/Roles')
|
||||
}, function (data, status) {
|
||||
$scope.toasts.push({Type: 'Danger', Message: data.data});
|
||||
});
|
||||
};
|
||||
$('#txtName').focus();
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
var RoleCtrlResolve = {
|
||||
role: ['$route', 'Role', function ($route, Role) {
|
||||
var id = $route.current.params.id;
|
||||
return Role.get({id: id}).$promise;
|
||||
}]
|
||||
};
|
||||
|
||||
var RoleListCtrlResolve = {
|
||||
roles: ['Role', function (Role) {
|
||||
return Role.query({}).$promise;
|
||||
}]
|
||||
};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter').factory('Role', ['$resource', Role]);
|
||||
|
||||
function Role($resource) {
|
||||
return $resource('/v1/Role/:id',
|
||||
{id: '@RoleID'}, {
|
||||
query: {method: 'GET', params: {list: true}, isArray: true}
|
||||
});
|
||||
}
|
||||
})();
|
|
@ -1,11 +1,45 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter').factory('Auth', Auth);
|
||||
angular.module('soter')
|
||||
.constant('AUTH_EVENTS', {
|
||||
loginSuccess: 'auth-login-success',
|
||||
loginFailed: 'auth-login-failed',
|
||||
logoutSuccess: 'auth-logout-success',
|
||||
sessionTimeout: 'auth-session-timeout',
|
||||
notAuthenticated: 'auth-not-authenticated',
|
||||
notAuthorized: 'auth-not-authorized'
|
||||
})
|
||||
.factory('AuthService', ['$http', 'Session', AuthService]);
|
||||
function AuthService($http, Session) {
|
||||
var authService = {};
|
||||
|
||||
var Auth = ['$resource', function ($resource) {
|
||||
return $resource('/api/Auth', {}, {
|
||||
login: {method: 'GET', params: {list: true}, isArray: true}
|
||||
});
|
||||
}]
|
||||
});
|
||||
authService.login = function (credentials) {
|
||||
return $http
|
||||
.post('/v1/login', credentials)
|
||||
.success(function (data) {
|
||||
Session.create(0, data.id, data.name, data.permissions);
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
authService.logout = function () {
|
||||
return $http
|
||||
.post('/logout')
|
||||
.success(function (res) {
|
||||
Session.destroy();
|
||||
});
|
||||
};
|
||||
|
||||
authService.isAuthenticated = function () {
|
||||
return !!Session.userId;
|
||||
};
|
||||
|
||||
authService.isAuthorized = function (permission) {
|
||||
return (authService.isAuthenticated() && Session.permissions.indexOf(permission) !== -1);
|
||||
};
|
||||
|
||||
return authService;
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -2,50 +2,39 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('soter')
|
||||
.controller('LoginController', LoginController)
|
||||
.controller('LogoutController', LogoutController);
|
||||
.controller('LoginController', ['$scope', '$rootScope', '$location', '$routeParams', 'AuthService', 'AUTH_EVENTS', 'Session', LoginController])
|
||||
.controller('LogoutController', ['$scope', '$rootScope', '$location', 'AuthService', 'AUTH_EVENTS', 'Session', LogoutController]);
|
||||
|
||||
var LoginController = ['$scope', '$http', '$location', '$routeParams', '$cookieStore', function ($scope, $http, $location, $routeParams, $cookieStore) {
|
||||
$scope.showOTP = false;
|
||||
function LoginController($scope, $rootScope, $location, $routeParams, AuthService, AUTH_EVENTS, Session) {
|
||||
$scope.submit = function () {
|
||||
var data;
|
||||
if ($scope.showOTP) {
|
||||
data = {username: $scope.username, password: $scope.password, otp: $scope.otp, ClientName: $scope.name};
|
||||
} else {
|
||||
data = {username: $scope.username, password: $scope.password};
|
||||
}
|
||||
var data = {username: $scope.username, password: $scope.password};
|
||||
AuthService.login(data).success(function (data) {
|
||||
$rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
|
||||
var came_from = $routeParams.came_from;
|
||||
if (angular.isUndefined(came_from) || came_from === "" || came_from === "/login" || came_from === "/logout") {
|
||||
came_from = "/";
|
||||
}
|
||||
$rootScope.auth = Session.data();
|
||||
$location.url(came_from);
|
||||
|
||||
|
||||
$http.
|
||||
post('/api/login', data).
|
||||
success(function () {
|
||||
var came_from = $routeParams.came_from;
|
||||
if (angular.isUndefined(came_from) || came_from === "" || came_from === "/login" || came_from === "/logout") {
|
||||
came_from = "/";
|
||||
}
|
||||
$location.url(came_from);
|
||||
}).
|
||||
error(function (data, status, headers, config) {
|
||||
if (status === 403 && ['Unknown Client', 'OTP not supplied', 'OTP is wrong'].indexOf(data) !== -1) {
|
||||
$scope.showOTP = true;
|
||||
$scope.clientID = $cookieStore.get('ClientID');
|
||||
$scope.$apply();
|
||||
}
|
||||
}).error(function (data, one, two, three) {
|
||||
$rootScope.$broadcast(AUTH_EVENTS.loginFailed);
|
||||
$scope.toasts.push({Type: 'Danger', Message: data});
|
||||
});
|
||||
});
|
||||
};
|
||||
$('#username').focus();
|
||||
}];
|
||||
}
|
||||
|
||||
var LogoutController = ['$scope', '$http', '$location', function ($scope, $http, $location) {
|
||||
$http.
|
||||
post('/logout').
|
||||
function LogoutController($scope, $rootScope, $location, AuthService, AUTH_EVENTS) {
|
||||
AuthService.logout.
|
||||
success(function () {
|
||||
$rootScope.$broadcast(AUTH_EVENTS.logoutSuccess);
|
||||
$scope.toasts.push({Type: 'Success', Message: 'Logged out'});
|
||||
$rootScope.auth = {};
|
||||
$location.path('/');
|
||||
}).
|
||||
error(function (errorMessage) {
|
||||
$scope.toasts.push({Type: 'Danger', Message: errorMessage});
|
||||
});
|
||||
}];
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<form class="form-horizontal" role="form">
|
||||
<h2>Please sign in</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="username">Username</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" ng-model="username" id="username" required placeholder="Username"
|
||||
autofocus/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="password">Password</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="password" class="form-control" ng-model="password" id="password" required
|
||||
placeholder="Password"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="forgot"></label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<span id="forgot">Forgot <a href="#">Username</a> / <a href="#">Password</a></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button ng-click="submit()" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,32 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter').service('Session', Session);
|
||||
|
||||
function Session() {
|
||||
this.create = function (sessionId, userId, name, permissions) {
|
||||
this.id = sessionId;
|
||||
this.userId = userId;
|
||||
this.name = name;
|
||||
this.permissions = permissions;
|
||||
this.isAuthenticated = true;
|
||||
};
|
||||
this.destroy = function () {
|
||||
this.id = null;
|
||||
this.userId = null;
|
||||
this.name = null;
|
||||
this.permissions = null;
|
||||
this.isAuthenticated = false;
|
||||
};
|
||||
this.data = function () {
|
||||
return {
|
||||
id: this.id,
|
||||
userId: this.userId,
|
||||
name: this.name,
|
||||
permissions: this.permissions,
|
||||
isAuthenticated: this.isAuthenticated
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('soter').factory('User', User);
|
||||
angular.module('soter').factory('User', ['$resource', User]);
|
||||
|
||||
var User = ['$resource', function ($resource) {
|
||||
return $resource('/api/User/:id',
|
||||
function User($resource) {
|
||||
return $resource('/v1/User/:id',
|
||||
{id: '@UserID'}, {
|
||||
query: {method: 'GET', params: {list: true}, isArray: true},
|
||||
names: {method: 'GET', params: {names: true}, isArray: true}
|
||||
});
|
||||
}]
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
|
@ -25,7 +25,7 @@
|
|||
<script src="/assets/js/jquery-2.1.4.min.js"></script>
|
||||
<script src="/assets/js/bootstrap.min.js"></script>
|
||||
|
||||
<script src="/assets/js/angular.min.js"></script>
|
||||
<script src="/assets/js/angular.js"></script>
|
||||
<script src="/assets/js/angular-locale_en-in.js"></script>
|
||||
<script src="/assets/js/angular-animate.min.js"></script>
|
||||
<script src="/assets/js/angular-resource.min.js"></script>
|
||||
|
@ -36,12 +36,14 @@
|
|||
<script src="/app/app.module.js"></script>
|
||||
|
||||
<script src="/app/shared/auth.service.js"></script>
|
||||
<script src="/app/shared/session.service.js"></script>
|
||||
<script src="/app/shared/login.controller.js"></script>
|
||||
|
||||
<script src="/app/user/user.controller.js"></script>
|
||||
<script src="/app/user/user.service.js"></script>
|
||||
|
||||
<script src="/app/group/group.controller.js"></script>
|
||||
<script src="/app/group/group.service.js"></script>
|
||||
<script src="/app/role/role.controller.js"></script>
|
||||
<script src="/app/role/role.service.js"></script>
|
||||
|
||||
<script src="/script/angular_directive.js"></script>
|
||||
<script src="/script/angular_filter.js"></script>
|
||||
|
@ -153,13 +155,12 @@
|
|||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown" ng-show="auth.isAuthenticated"><a href="#" class="dropdown-toggle"
|
||||
data-toggle="dropdown"><i
|
||||
class="glyphicon glyphicon-user"></i> {{auth.Name}} <b class="caret"></b></a>
|
||||
class="glyphicon glyphicon-user"></i> {{auth.name}} <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/logout">Logout {{auth.Name}}</a></li>
|
||||
<li><a href="/User/{{auth.Name}}">Change Password</a></li>
|
||||
<li><a href="/logout">Logout {{auth.name}}</a></li>
|
||||
<li><a href="/User/{{auth.name}}">Change Password</a></li>
|
||||
<li><a href="/Users">Users</a></li>
|
||||
<li><a href="/Groups">Groups</a></li>
|
||||
<li><a href="/Clients">Clients</a></li>
|
||||
<li><a href="/Roles">Roles</a></li>
|
||||
<li><a href="/Settings">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -1,10 +1,31 @@
|
|||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.response import FileResponse, Response
|
||||
from pyramid.view import view_config
|
||||
from webob.exc import HTTPForbidden, HTTPFound
|
||||
|
||||
|
||||
@view_config(route_name='home')
|
||||
@view_config(request_method='GET', route_name='login')
|
||||
def my_view(request):
|
||||
package, resource = 'soter:static/index.html'.split(':', 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(context=HTTPForbidden)
|
||||
def forbidden(request):
|
||||
if 'X-Requested-With' in request.headers and request.headers['X-Requested-With'] == 'XMLHttpRequest':
|
||||
response = Response("Forbidden")
|
||||
response.status_int = 401
|
||||
return response
|
||||
else:
|
||||
return HTTPFound(location=request.route_url('login', _query={'came_from': request.path_qs}))
|
||||
|
||||
|
||||
@view_config(route_name='favicon')
|
||||
def favicon(request):
|
||||
package, resource = 'soter:static/favicon.ico'.split(':', 1)
|
||||
icon = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(icon, request=request)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
import uuid
|
||||
import pkg_resources
|
||||
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
import transaction
|
||||
from soter.models import DBSession
|
||||
from soter.models.auth import Role, Permission
|
||||
from soter.models.validation_exception import ValidationError, TryCatchFunction
|
||||
|
||||
@view_config(route_name='role_list', permission='Users')
|
||||
@view_config(request_method='GET', route_name='role_id', permission='Users')
|
||||
@view_config(request_method='GET', route_name='role', permission='Users')
|
||||
def html(request):
|
||||
package, resource = 'brewman:static/base.html'.split(':', 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(request_method='POST', route_name='api_role', renderer='json', permission='Users')
|
||||
@TryCatchFunction
|
||||
def save(request):
|
||||
role = Role(request.json_body['Name'])
|
||||
DBSession.add(role)
|
||||
add_permissions(role, request.json_body['Permissions'])
|
||||
transaction.commit()
|
||||
return role_info(role.id)
|
||||
|
||||
|
||||
@view_config(request_method='POST', route_name='api_role_id', renderer='json', permission='Users')
|
||||
@TryCatchFunction
|
||||
def update(request):
|
||||
id = request.matchdict.get('id', None)
|
||||
role = Role.by_id(uuid.UUID(id))
|
||||
role.name = request.json_body['Name']
|
||||
add_permissions(role, request.json_body['Permissions'])
|
||||
transaction.commit()
|
||||
return role_info(role.id)
|
||||
|
||||
|
||||
def add_permissions(role, permissions):
|
||||
for permission in permissions:
|
||||
id = uuid.UUID(permission['PermissionID'])
|
||||
gp = [p for p in role.permissions if p.id == id]
|
||||
gp = None if len(gp) == 0 else gp[0]
|
||||
if permission['Enabled'] and gp is None:
|
||||
role.permissions.append(Permission.by_id(id))
|
||||
elif not permission['Enabled'] and gp:
|
||||
role.permissions.remove(gp)
|
||||
|
||||
|
||||
@view_config(request_method='DELETE', route_name='api_role_id', renderer='json', permission='Users')
|
||||
def delete(request):
|
||||
id = request.matchdict.get('id', None)
|
||||
if id is None:
|
||||
response = Response("Role is Null")
|
||||
response.status_int = 500
|
||||
return response
|
||||
else:
|
||||
response = Response("Role deletion not implemented")
|
||||
response.status_int = 500
|
||||
return response
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_role_id', renderer='json', permission='Users')
|
||||
def show_id(request):
|
||||
return role_info(uuid.UUID(request.matchdict.get('id', None)))
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_role', renderer='json', permission='Users')
|
||||
def show_blank(request):
|
||||
return role_info(None)
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_role', renderer='json', request_param='list', permission='Users')
|
||||
def show_list(request):
|
||||
list = Role.list()
|
||||
roles = []
|
||||
for item in list:
|
||||
role = {'Name': item.name, 'Permissions': [], 'Url': request.route_url('role_id', id=item.id)}
|
||||
for permission in item.permissions:
|
||||
role['Permissions'].append(permission.name)
|
||||
roles.append(role)
|
||||
return roles
|
||||
|
||||
|
||||
def role_info(id):
|
||||
if id is None:
|
||||
role = {'Name': '', 'Permissions': []}
|
||||
for item in Permission.list():
|
||||
role['Permissions'].append({'PermissionID': item.id, 'Name': item.name, 'Enabled': False})
|
||||
else:
|
||||
role_object = Role.by_id(id)
|
||||
role = {'RoleID': role_object.id, 'Name': role_object.name, 'Permissions': []}
|
||||
for item in Permission.list():
|
||||
role['Permissions'].append(
|
||||
{'PermissionID': item.id, 'Name': item.name, 'Enabled': True if item in role_object.permissions else False})
|
||||
return role
|
||||
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
import re
|
||||
import uuid
|
||||
import pkg_resources
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.security import authenticated_userid
|
||||
|
||||
from pyramid.view import view_config
|
||||
import transaction
|
||||
from soter import rolefinder
|
||||
from soter.models import DBSession
|
||||
from soter.models.auth import User, Role
|
||||
|
||||
from soter.models.validation_exception import TryCatchFunction, ValidationError
|
||||
|
||||
|
||||
class UserView(object):
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
self.user = authenticated_userid(request)
|
||||
self.permissions = None
|
||||
self.has_permission = False
|
||||
if self.user is not None:
|
||||
self.user = User.by_id(self.user)
|
||||
self.has_permission = 'Users' in rolefinder(self.user.id, request)
|
||||
|
||||
@view_config(route_name='user_list', permission='Users')
|
||||
@view_config(request_method='GET', route_name='user_id', permission='Authenticated')
|
||||
@view_config(request_method='GET', route_name='user', permission='Users')
|
||||
def html(self):
|
||||
package, resource = 'soter:static/base.html'.split(':', 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=self.request)
|
||||
|
||||
|
||||
@view_config(request_method='POST', route_name='api_user', renderer='json', permission='Users')
|
||||
def save(self):
|
||||
return self.save_user()
|
||||
|
||||
|
||||
@TryCatchFunction
|
||||
def save_user(self):
|
||||
user = User(self.request.json_body['Name'], self.request.json_body['Password'],
|
||||
self.request.json_body['LockedOut'])
|
||||
DBSession.add(user)
|
||||
self.add_roles(user, self.request.json_body['Roles'])
|
||||
transaction.commit()
|
||||
return self.user_info(user.id)
|
||||
|
||||
|
||||
@view_config(request_method='POST', route_name='api_user_id', renderer='json', permission='Authenticated')
|
||||
def update(self):
|
||||
id = self.request.matchdict['id']
|
||||
p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$')
|
||||
if p.match(id):
|
||||
user = User.by_id(uuid.UUID(id))
|
||||
else:
|
||||
user = User.by_name(id)
|
||||
return self.update_user(user)
|
||||
|
||||
@TryCatchFunction
|
||||
def update_user(self, user):
|
||||
if user is None:
|
||||
raise ValidationError('User name / id not found')
|
||||
if self.has_permission:
|
||||
user.name = self.request.json_body['Name']
|
||||
user.locked_out = self.request.json_body['LockedOut']
|
||||
self.add_roles(user, self.request.json_body['Roles'])
|
||||
|
||||
if self.request.json_body['Password'] != '' and self.request.json_body['Password'] != user.password:
|
||||
user.password = self.request.json_body['Password']
|
||||
transaction.commit()
|
||||
return self.user_info(user.id)
|
||||
|
||||
|
||||
@view_config(request_method='DELETE', route_name='api_user_id', renderer='json', permission='Users')
|
||||
def delete(self):
|
||||
id = self.request.matchdict.get('id', None)
|
||||
if id is None:
|
||||
response = Response("User is Null")
|
||||
response.status_int = 500
|
||||
return response
|
||||
else:
|
||||
response = Response("User deletion not implemented")
|
||||
response.status_int = 500
|
||||
return response
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_user_id', renderer='json', permission='Authenticated')
|
||||
def show_id(self):
|
||||
id = self.request.matchdict['id']
|
||||
p = re.compile('^[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}$')
|
||||
if p.match(id):
|
||||
id = uuid.UUID(id)
|
||||
return self.user_info(id)
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_user', renderer='json', permission='Users')
|
||||
def show_blank(self):
|
||||
return self.user_info(None)
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_user', renderer='json', request_param='list', permission='Users')
|
||||
def show_list(self):
|
||||
list = User.list()
|
||||
users = []
|
||||
for item in list:
|
||||
user = {'Name': item.name, 'LockedOut': item.locked_out,
|
||||
'Roles': [], 'Url': self.request.route_url('user_id', id=item.name)}
|
||||
for role in item.roles:
|
||||
user['Roles'].append(role.name)
|
||||
users.append(user)
|
||||
return users
|
||||
|
||||
|
||||
@view_config(request_method='GET', route_name='api_user', renderer='json', request_param='names',
|
||||
permission='Authenticated')
|
||||
def show_name(self):
|
||||
list = User.query().filter(User.locked_out == False).order_by(User.name).all()
|
||||
users = [{'Name': item.name} for item in list]
|
||||
# for item in list:
|
||||
# users.append({'Name': item.name})
|
||||
return users
|
||||
|
||||
|
||||
def user_info(self, id):
|
||||
if id is None:
|
||||
account = {'Name': '', 'LockedOut': False, 'Roles': []}
|
||||
for item in Role.list():
|
||||
account['Roles'].append({'RoleID': item.id, 'Name': item.name, 'Enabled': False})
|
||||
return account
|
||||
|
||||
if isinstance(id, uuid.UUID):
|
||||
user = User.by_id(id)
|
||||
else:
|
||||
user = User.by_name(id)
|
||||
|
||||
if self.has_permission:
|
||||
account = {'UserID': user.id, 'Name': user.name, 'Password': '', 'LockedOut': user.locked_out, 'Roles': []}
|
||||
for item in Role.list():
|
||||
account['Roles'].append(
|
||||
{'RoleID': item.id, 'Name': item.name, 'Enabled': True if item in user.roles else False})
|
||||
elif self.user.id == user.id:
|
||||
account = {'UserID': user.id, 'Name': user.name, 'Password': '', 'LockedOut': user.locked_out, 'Roles': []}
|
||||
else:
|
||||
response = Response("User can only update his/her password")
|
||||
response.status_int = 500
|
||||
return response
|
||||
return account
|
||||
|
||||
|
||||
def add_roles(self, user, roles):
|
||||
for role in roles:
|
||||
id = uuid.UUID(role['RoleID'])
|
||||
ug = [g for g in user.roles if g.id == id]
|
||||
ug = None if len(ug) == 0 else ug[0]
|
||||
if role['Enabled'] and ug is None:
|
||||
user.roles.append(Role.by_id(id))
|
||||
elif not role['Enabled'] and ug:
|
||||
user.roles.remove(ug)
|
|
@ -0,0 +1,59 @@
|
|||
from pyramid.security import authenticated_userid, forget, remember
|
||||
from pyramid.view import view_config
|
||||
from webob import Response
|
||||
from webob.exc import HTTPFound
|
||||
|
||||
from soter import rolefinder
|
||||
from soter.models.auth import User, Permission
|
||||
from soter.models.validation_exception import TryCatchFunction
|
||||
|
||||
|
||||
@view_config(route_name='v1_auth', renderer='json')
|
||||
def user_permission(request):
|
||||
user_id = authenticated_userid(request)
|
||||
if user_id is None:
|
||||
auth = {'isAuthenticated': False, 'permissions': {}}
|
||||
elif 'auth' in request.session:
|
||||
auth = request.session['auth']
|
||||
else:
|
||||
user = User.by_id(user_id)
|
||||
auth = {'isAuthenticated': True, 'name': user.name, 'id': user.id}
|
||||
session_perms = rolefinder(user.id, request)
|
||||
perms = {}
|
||||
for item in Permission.list():
|
||||
perms[item.name] = True if item.name in session_perms else False
|
||||
auth['permissions'] = perms
|
||||
request.session['auth'] = auth
|
||||
return auth
|
||||
|
||||
|
||||
@view_config(route_name='logout')
|
||||
def logout(request):
|
||||
request.session.invalidate()
|
||||
headers = forget(request)
|
||||
return HTTPFound(location=request.route_url('home'), headers=headers)
|
||||
|
||||
|
||||
@view_config(request_method='POST', route_name='v1_login', renderer='json')
|
||||
@TryCatchFunction
|
||||
def login(request):
|
||||
username = request.json_body.get('username', None)
|
||||
password = request.json_body.get('password', None)
|
||||
found, user = User.auth(username, password)
|
||||
|
||||
if found:
|
||||
headers = remember(request, str(user.id))
|
||||
request.response.headers = headers
|
||||
request.response.content_type = 'application/json'
|
||||
request.response.charset = 'utf8'
|
||||
auth = {'isAuthenticated': True, 'name': user.name, 'id': user.id}
|
||||
session_perms = rolefinder(user.id, request)
|
||||
perms = {}
|
||||
for item in Permission.list():
|
||||
perms[item.name] = True if item.name in session_perms else False
|
||||
auth['permissions'] = perms
|
||||
return auth
|
||||
else:
|
||||
response = Response("Login failed")
|
||||
response.status_int = 403
|
||||
return response
|
Loading…
Reference in New Issue