permissions enforcement

This commit is contained in:
Davide Alberani 2017-01-16 21:06:10 +01:00
parent 7be6ab388a
commit 9f8e7e762b
5 changed files with 176 additions and 27 deletions

21
ibt2.py
View file

@ -370,10 +370,14 @@ class UsersHandler(CollectionHandler):
@gen.coroutine @gen.coroutine
def get(self, id_=None, **kwargs): def get(self, id_=None, **kwargs):
if id_: if id_:
if str(self.current_user_info.get('_id')) != id_ and not self.current_user_info.get('isAdmin'):
return self.build_error(status=401, message='insufficient permissions: must be the owner or admin')
output = self.db.getOne(self.collection, {'_id': id_}) output = self.db.getOne(self.collection, {'_id': id_})
if 'password' in output: if 'password' in output:
del output['password'] del output['password']
else: else:
if not self.current_user_info.get('isAdmin'):
return self.build_error(status=401, message='insufficient permissions: must be an admin')
output = {self.collection: self.db.query(self.collection, self.arguments)} output = {self.collection: self.db.query(self.collection, self.arguments)}
for user in output['users']: for user in output['users']:
if 'password' in user: if 'password' in user:
@ -410,19 +414,16 @@ class UsersHandler(CollectionHandler):
self._clean_dict(data) self._clean_dict(data)
if id_ is None: if id_ is None:
return self.build_error(status=404, message='unable to access the resource') return self.build_error(status=404, message='unable to access the resource')
old_pwd = data.get('old_password')
new_pwd = data.get('new_password')
if old_pwd is not None:
del data['old_password']
if new_pwd is not None:
del data['new_password']
authorized, user = self.user_authorized(data['username'], old_pwd)
if not (authorized and self.current_user == data['username']):
raise InputException('not authorized to change password')
data['password'] = utils.hash_password(new_pwd)
if '_id' in data: if '_id' in data:
# Avoid overriding _id # Avoid overriding _id
del data['_id'] del data['_id']
if 'username' in data:
del data['username']
if 'password' in data:
if data['password']:
data['password'] = utils.hash_password(data['password'])
else:
del data['password']
if str(self.current_user_info.get('_id')) != id_ and not self.current_user_info.get('isAdmin'): if str(self.current_user_info.get('_id')) != id_ and not self.current_user_info.get('isAdmin'):
return self.build_error(status=401, message='insufficient permissions: must be the owner or admin') return self.build_error(status=401, message='insufficient permissions: must be the owner or admin')
merged, doc = self.db.update(self.collection, {'_id': id_}, data) merged, doc = self.db.update(self.collection, {'_id': id_}, data)

View file

@ -5,12 +5,22 @@
<md-input-container md-inline v-if="edit"> <md-input-container md-inline v-if="edit">
<md-input @keyup.enter.native="updateAttendee()" v-model="attendee.name" ref="updateAttendeeName" /> <md-input @keyup.enter.native="updateAttendee()" v-model="attendee.name" ref="updateAttendeeName" />
</md-input-container> </md-input-container>
<md-button class="md-icon-button md-list-action" @click="editAttendee()">
<md-icon>edit</md-icon> <md-menu v-if="isAuthorized(attendee.created_by)" md-align-trigger>
</md-button> <md-button class="md-icon-button" md-menu-trigger>
<md-button class="md-icon-button md-list-action" @click="deleteAttendee()"> <md-icon>more_vert</md-icon>
<md-icon>cancel</md-icon> </md-button>
</md-button> <md-menu-content>
<md-menu-item @click="editAttendee()">
<span>edit</span>
<md-icon>edit</md-icon>
</md-menu-item>
<md-menu-item @click="deleteAttendee()">
<span>delete</span>
<md-icon>cancel</md-icon>
</md-menu-item>
</md-menu-content>
</md-menu>
</md-list-item> </md-list-item>
</template> </template>
<script> <script>
@ -24,11 +34,21 @@ export default {
} }
}, },
computed: {
loggedInUser() {
return this.$store.state.loggedInUser;
}
},
beforeCreate: function() { beforeCreate: function() {
this.attendeesUrl = this.$resource('attendees{/id}'); this.attendeesUrl = this.$resource('attendees{/id}');
}, },
methods: { methods: {
isAuthorized(ownerID) {
return this.$store.state.loggedInUser.isAdmin || (this.$store.state.loggedInUser._id && this.$store.state.loggedInUser._id == ownerID);
},
editAttendee() { editAttendee() {
this.edit = true; this.edit = true;
// FIXME: it's so wrong it hurts, but any other attempt to set the focus // FIXME: it's so wrong it hurts, but any other attempt to set the focus

View file

@ -1,6 +1,24 @@
<template> <template>
<div id="user"> <div id="user">
User {{loggedInUser}} <md-card>
<md-card-header>
<span class="md-title">User: {{ user.username }}</span>
</md-card-header>
<md-card-content>
<md-input-container>
<label>Email</label>
<md-input v-model="user.email" />
</md-input-container>
<div class="md-body-2">Change password</div>
<md-input-container id="password-input" md-has-password>
<label>New password</label>
<md-input v-model="password" type="password" />
</md-input-container>
<md-button class="md-raised md-primary" @click="save()">Save</md-button>
</md-card-content>
</md-card>
</div> </div>
</template> </template>
<script> <script>
@ -8,32 +26,52 @@
export default { export default {
data () { data () {
return { return {
user: {},
password: null
} }
}, },
computed: { computed: {
count() {
return this.$store.state.count;
},
loggedInUser() { loggedInUser() {
console.log(this.$store.state.loggedInUser);
return this.$store.state.loggedInUser; return this.$store.state.loggedInUser;
} }
}, },
beforeCreate: function() { beforeCreate: function() {
this.userUrl = this.$resource('users'); this.usersUrl = this.$resource('users{/id}');
}, },
mounted: function() { mounted: function() {
this.getUser(this.$route.params.id);
}, },
methods: { methods: {
}, getUser(id) {
this.usersUrl.get({id: id}).then((response) => {
components: { return response.json();
}, (response) => {
alert('getUsers: unable to get resource');
}).then((data) => {
this.user = data || {};
});
},
save() {
var user_data = {password: this.password, email: this.user.email};
this.usersUrl.update({id: this.user._id}, user_data).then((response) => {
return response.json();
}, (response) => {
alert('save: unable to get resource');
}).then((data) => {
this.user = data;
});
}
} }
} }
</script> </script>
<style> <style>
#user {
padding: 10px;
}
</style> </style>

88
src/Users.vue Normal file
View file

@ -0,0 +1,88 @@
<template>
<div id="users">
<md-card>
<md-card-header>
<span class="md-title">Users</span>
</md-card-header>
<md-card-content>
<md-table>
<md-table-header>
<md-table-row>
<md-table-head>Username</md-table-head>
<md-table-head>Email</md-table-head>
</md-table-row>
</md-table-header>
<md-table-body>
<md-table-row v-for="(user, index) in users" :key="user._id">
<md-table-cell>
<router-link :to="userLink(user._id)" class="md-raised md-primary">
{{user.username}}
</router-link>
</md-table-cell>
<md-table-cell>
{{user.email}}
</md-table-cell>
</md-table-row>
</md-table-body>
</md-table>
</md-card-content>
</md-card>
</div>
</template>
<script>
export default {
data () {
return {
users: []
}
},
computed: {
loggedInUser() {
return this.$store.state.loggedInUser;
}
},
beforeCreate: function() {
this.usersUrl = this.$resource('users{/id}');
},
mounted: function() {
this.getUsers();
},
methods: {
userLink(id) {
return '/user/' + id;
},
getUsers() {
this.usersUrl.get().then((response) => {
return response.json();
}, (response) => {
alert('getUsers: unable to get resource');
}).then((data) => {
this.users = data.users || [];
});
},
deleteUser(userId) {
this.usersUrl.update({id: userId}).then((response) => {
return response.json();
}, (response) => {
alert('deleteUser: unable to get resource');
}).then((data) => {
console.log('AAAAAAAAAAAAAAAAAAAAAAAAAAAA');
});
}
}
}
</script>
<style>
#users {
padding: 10px;
}
</style>

View file

@ -12,6 +12,7 @@ import jQuery from 'jquery';
import store_data from './store.js'; import store_data from './store.js';
import App from './App'; import App from './App';
import User from './User'; import User from './User';
import Users from './Users';
import Toolbar from './Toolbar'; import Toolbar from './Toolbar';
Vue.use(Vuex); Vue.use(Vuex);
@ -20,10 +21,11 @@ Vue.use(VueResource);
Vue.use(VueMaterial); Vue.use(VueMaterial);
var routes = [ var routes = [
{path: '/', name: 'root', component: App}, {path: '/', name: 'home', component: App},
{path: '/day/', name: 'days', component: App}, {path: '/day/', name: 'days', component: App},
{path: '/day/:day', name: 'day', component: App}, {path: '/day/:day', name: 'day', component: App},
{path: '/user/:user', name: 'user', component: User} {path: '/user/', name: 'users', component: Users},
{path: '/user/:id', name: 'user', component: User}
]; ];
const store = new Vuex.Store(store_data); const store = new Vuex.Store(store_data);
@ -46,5 +48,5 @@ var vue = new Vue({
store: store, store: store,
template: '<div id="app"><Toolbar /><router-view class="view"></router-view></div>', template: '<div id="app"><Toolbar /><router-view class="view"></router-view></div>',
router: router, router: router,
components: { App, Toolbar, User } components: { App, Toolbar, Users, User }
}); });