Still upto working. Authentication sort of working

This commit is contained in:
tanshu 2015-06-12 18:23:37 +05:30
parent 9aaeb0987f
commit 8ed028115a
23 changed files with 28841 additions and 186 deletions

View File

@ -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()

24
soter/renderers.py Normal file
View File

@ -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)

23
soter/security.py Normal file
View File

@ -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)]

View File

@ -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;
});
});
}]);
})();

View File

@ -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;
}]
};

View File

@ -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}
});
}]
});

View File

@ -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;
}]
};

View File

@ -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}
});
}
})();

View File

@ -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;
}
})();

View File

@ -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});
});
}];
});
}
})();

View File

@ -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>

View File

@ -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
}
}
}
})();

View File

@ -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}
});
}]
});
}
})();

28133
soter/static/assets/js/angular.js vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
soter/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -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>

View File

@ -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)

View File

100
soter/views/auth/role.py Normal file
View File

@ -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

159
soter/views/auth/user.py Normal file
View File

@ -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)

59
soter/views/session.py Normal file
View File

@ -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