Merge branch 'improving-auth' of OpenServer/OpenAuth_server into master

This commit is contained in:
Fabian Stamm 2020-03-25 22:39:56 +00:00
commit 043aca26da
5 changed files with 195 additions and 52 deletions

View File

@ -12,81 +12,100 @@ PermissionRoute.route("/")
/**
* @api {get} /admin/permission
* @apiName AdminGetPermissions
*
*
* @apiParam client Optionally filter by client _id
*
*
* @apiGroup admin_permission
* @apiPermission admin
*
*
* @apiSuccess {Object[]} permissions
* @apiSuccess {String} permissions._id The ID
* @apiSuccess {String} permissions.name Permission name
* @apiSuccess {String} permissions.description A description, that makes it clear to the user, what this Permission allows to do
* @apiSuccess {String} permissions.client The ID of the owning client
*/
.get(promiseMiddleware(async (req, res) => {
let query = {};
if (req.query.client) {
query = { client: new ObjectID(req.query.client) }
}
let permission = await Permission.find(query);
res.json(permission);
}))
.get(
promiseMiddleware(async (req, res) => {
let query = {};
if (req.query.client) {
query = { client: new ObjectID(req.query.client) };
}
let permissions = await Permission.find(query);
res.json(permissions);
})
)
/**
* @api {post} /admin/permission
* @apiName AdminAddPermission
*
*
* @apiParam client The ID of the owning client
* @apiParam name Permission name
* @apiParam description A description, that makes it clear to the user, what this Permission allows to do
*
*
* @apiGroup admin_permission
* @apiPermission admin
*
*
* @apiSuccess {Object[]} permissions
* @apiSuccess {String} permissions._id The ID
* @apiSuccess {String} permissions.name Permission name
* @apiSuccess {String} permissions.description A description, that makes it clear to the user, what this Permission allows to do
* @apiSuccess {String} permissions.client The ID of the owning client
* @apiSuccess {String} permissions.grant_type The type of the permission. "user" | "client" granted
*/
.post(verify({
client: {
type: Types.STRING
},
name: {
type: Types.STRING
},
description: {
type: Types.STRING
}
}, true), promiseMiddleware(async (req, res) => {
let client = await Client.findById(req.body.client);
if (!client) {
throw new RequestError("Client not found", HttpStatusCode.BAD_REQUEST);
}
let permission = Permission.new({
description: req.body.description,
name: req.body.name,
client: client._id
});
await Permission.save(permission);
res.json(permission);
}))
.post(
verify(
{
client: {
type: Types.STRING
},
name: {
type: Types.STRING
},
description: {
type: Types.STRING
},
type: {
type: Types.ENUM,
values: ["user", "client"]
}
},
true
),
promiseMiddleware(async (req, res) => {
let client = await Client.findById(req.body.client);
if (!client) {
throw new RequestError(
"Client not found",
HttpStatusCode.BAD_REQUEST
);
}
let permission = Permission.new({
description: req.body.description,
name: req.body.name,
client: client._id,
grant_type: req.body.type
});
await Permission.save(permission);
res.json(permission);
})
)
/**
* @api {delete} /admin/permission
* @apiName AdminDeletePermission
*
*
* @apiParam id The permission ID
*
*
* @apiGroup admin_permission
* @apiPermission admin
*
*
* @apiSuccess {Boolean} success
*/
.delete(promiseMiddleware(async (req, res) => {
let { id } = req.query;
await Permission.delete(id);
res.json({ success: true });
}));
.delete(
promiseMiddleware(async (req, res) => {
let { id } = req.query;
await Permission.delete(id);
res.json({ success: true });
})
);
export default PermissionRoute;
export default PermissionRoute;

View File

@ -6,6 +6,7 @@ import { createJWT } from "../../keys";
import Client from "../../models/client";
import RequestError, { HttpStatusCode } from "../../helper/request_error";
import config from "../../config";
import Mail from "../../models/mail";
const ClientRouter = Router();
@ -45,10 +46,15 @@ ClientRouter.get("/user", Stacker(GetClientAuthMiddleware(false), GetUserMiddlew
}));
ClientRouter.get("/account", Stacker(GetClientApiAuthMiddleware(), async (req: Request, res) => {
let mails = await Promise.all(req.user.mails.map(id => Mail.findById(id)));
let mail = mails.find(e => e.primary) || mails[0];
res.json({
user: {
username: req.user.username,
name: req.user.name,
email: mail
}
})
}));

View File

@ -0,0 +1,98 @@
import { Request, Response } from "express";
import Stacker from "../middlewares/stacker";
import {
ClientAuthMiddleware,
GetClientAuthMiddleware
} from "../middlewares/client";
import Permission from "../../models/permissions";
import User from "../../models/user";
import RequestError, { HttpStatusCode } from "../../helper/request_error";
import Grant from "../../models/grants";
import { ObjectID } from "mongodb";
export const GetPermissions = Stacker(
GetClientAuthMiddleware(true),
async (req: Request, res: Response) => {
const { user, permission } = req.query;
let permissions: { id: string; name: string; description: string }[];
let users: string[];
if (user) {
const grant = await Grant.findOne({
client: req.client._id,
user: user
});
permissions = await Promise.all(
grant.permissions.map(perm => Permission.findById(perm))
).then(res =>
res
.filter(e => e.grant_type === "client")
.map(e => {
return {
id: e._id.toHexString(),
name: e.name,
description: e.description
};
})
);
}
if (permission) {
const grants = await Grant.find({
client: req.client._id,
permissions: new ObjectID(permission)
});
users = grants.map(grant => grant.user.toHexString());
}
res.json({ permissions, users });
}
);
export const PostPermissions = Stacker(
GetClientAuthMiddleware(true),
async (req: Request, res: Response) => {
const { permission, uid } = req.body;
const user = await User.findOne({ uid });
if (!user) {
throw new RequestError("User not found!", HttpStatusCode.BAD_REQUEST);
}
const permissionDoc = await Permission.findById(permission);
if (!permissionDoc || !permissionDoc.client.equals(req.client._id)) {
throw new RequestError(
"Permission not found!",
HttpStatusCode.BAD_REQUEST
);
}
let grant = await Grant.findOne({
client: req.client._id,
user: req.user._id
});
if (!grant) {
grant = Grant.new({
client: req.client._id,
user: req.user._id,
permissions: []
});
}
//TODO: Fix clients getting user data without consent, when a grant is created and no additional permissions are requested, since for now, it is only checked for grant existance to make client access user data
if (grant.permissions.indexOf(permission) < 0)
grant.permissions.push(permission);
await Grant.save(grant);
res.json({
success: true
});
}
);

View File

@ -10,6 +10,7 @@ import { randomBytes } from "crypto";
// import { ObjectID } from "bson";
import Grant, { IGrant } from "../../models/grants";
import GetAuthPage from "../../views/authorize";
import { ObjectID } from "mongodb";
// const AuthRoute = Stacker(GetUserMiddleware(true), async (req: Request, res: Response) => {
// let { response_type, client_id, redirect_uri, scope, state, nored } = req.query;
@ -123,8 +124,15 @@ const GetAuthRoute = (view = false) =>
let proms: PromiseLike<void>[] = [];
if (scopes) {
for (let perm of scopes.filter(e => e !== "read_user")) {
let oid = undefined;
try {
oid = new ObjectID(perm);
} catch (err) {
Logging.error(err);
continue;
}
proms.push(
Permission.findById(perm).then(p => {
Permission.findById(oid).then(p => {
if (!p) return Promise.reject(new Error());
permissions.push(p);
})

View File

@ -7,8 +7,10 @@
<meta name="viewport" content="width=device-width,initial-scale=1" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/popper.js@1.12.6/dist/umd/popper.js" type="text/javascript"></script>
<script src="https://unpkg.com/bootstrap-material-design@4.1.1/dist/js/bootstrap-material-design.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/bootstrap-material-design@4.1.1/dist/js/bootstrap-material-design.js"
type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"
type="text/javascript"></script>
<script>
$(document).ready(() => $('body').bootstrapMaterialDesign())
</script>
@ -251,6 +253,7 @@
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col" style="width: 10ch">Type</th>
<th scope="col" style="width: 2.5rem"></th>
</tr>
</thead>
@ -260,6 +263,7 @@
<td>\{{ _id }}</td>
<td>\{{ name }}</td>
<td>\{{ description }}</td>
<td>\{{ grant_type }}</td>
<td style="padding: 0.25em">
<button style="border: 0; background-color: rgba(0, 0, 0, 0); padding: 0; text-align: center;" onclick="deletePermission('\{{_id}}')">
<i class="material-icons" style="font-size: 2rem; display: inline">
@ -280,8 +284,16 @@
<input type="text" class="form-control" id="name_input" name=name value="">
</div>
<div class="form-group">
<label for=name class="bmd-label-floating">Description</label>
<input type="text" class="form-control" id=name name=description value="">
<label for=description class="bmd-label-floating">Description</label>
<input type="text" class="form-control" id=description name=description value="">
</div>
<div class="form-group">
<label for=type class="bmd-label-floating">Type</label>
<select type="text" class="form-control" id=type name=type>
<option value="user">User granted</option>
<option value="client">Client granted</option>
</select>
</div>
<span class="form-group bmd-form-group">
<!-- needed to match padding for floating labels -->
@ -292,4 +304,4 @@
</body>
</html>
</html>