Is it possible to user custom authentication in keystone.js without a keystone user model? - passport.js

I have a (I hope) quick question regarding Authorization in Keystone: it seems like the "User" object is a core dependency in the framework. I'd like to side-step it completely but there doesn't seem to be a way to get the application functional without it.
I've run a basic bypass here:
keystone.init({
//...
'auth': (req, res, next)=>{
if(Roles.has(Roles.Admin, Roles.Keyston)){
next();
} else {
throw "403"; //Terminate
}
},
'user model': 'User',
//...
})
Which results in:
Sorry, an error occurred loading the page (500)
snip\KS2\node_modules\keystone\templates\layout\base.jade:80
> 79| a(href='/keystone/' + User.path + '/' + user.id)= User.getDocumentName(user)
80| | .
81|
82| //- Common
item.get is not a function
As a result it expects the user object to exist on the request (even though I'm using my own authentication method). If I disable authentication completely it seems fine and I can protect the route with some middleware, but this seems like fairly buggy behavior.
Is the "User" object actually a dependency in the framework or is it basically there for convinience? Removing the model
//'user model' : 'User'
crashes Keystone
Sorry, an error occurred loading the page (500) Unknown keystone list undefined).
I'm fairly certain the former error is related to the "User Object" on the request being set to something silly and thus the Jade template blows up. Is it possible to decouple this User object from the framework? If it isn't is it possible to set this object so that I can continue using passport.js for primary authentication?
I'm particularly interested in this topic as I'd like to implement Role Based Authentication in the Keystone.js administration module and without more information on how this works/ideas for workarounds I don't have a jumping off point.
(**EDIT The error exists even with auth set to false)
Sorry, an error occurred loading the page (500)
...snip\KS2\node_modules\keystone\templates\layout\base.jade:78
76| if User && user
77| | Signed in as
> 78| a(href='/keystone/' + User.path + '/' + user.id)= User.getDocumentName(user)
79| | .
80|
81| //- Common
item.get is not a function
Exits even with auth: false as I have a "user" object that is turning up null and crashing the template.
EDIT #2
I've created a patch that solved the crash when user authentication is turned off, it doesn't really answer the question but it makes the application usable once again without depending on Keystone.js for authentication (which was a CRITICAL requirement for this CMS).

I'm still looking for help on this but here's how I bypassed it for the time being. It looks like the application is headed in a whole new direction for the administration console.
I'm issuing a pull request against that fork (which I believe is the package on npm currently).
You can view my fork here:
https://github.com/danielbchapman/keystone/commit/d28dae031252fc2512598ef8496f336f27c1bbc0
//Git Patch for tag v3.22
From d28dae031252fc2512598ef8496f336f27c1bbc0 Mon Sep 17 00:00:00 2001
From: "Daniel B. Chapman"
Date: Tue, 30 Aug 2016 09:25:50 -0600
Subject: [PATCH] Added a local auth variable that mirrors the
keystone.get('auth') configuration setting so that applications that use a
custom User object (like Passport.js) do not trigger a crash in the
adiministration page due to the 'signed in as' functionality.
---
lib/core/render.js | 1 +
templates/layout/base.jade | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/core/render.js b/lib/core/render.js
index 5d80453..2b03b7f 100644
--- a/lib/core/render.js
+++ b/lib/core/render.js
## -59,6 +59,7 ## function render(req, res, view, ext) {
moment: moment,
numeral: numeral,
env: keystone.get('env'),
+ auth: keystone.get('auth'),
brand: keystone.get('brand'),
appversion : keystone.get('appversion'),
nav: keystone.nav,
diff --git a/templates/layout/base.jade b/templates/layout/base.jade
index 1caee5e..95639c6 100644
--- a/templates/layout/base.jade
+++ b/templates/layout/base.jade
## -73,7 +73,7 ## html
#footer: .container
p #{brand} #{appversion}
| Powered by KeystoneJS version #{version}.
- if User && user
+ if User && user && auth
| Signed in as
a(href='/keystone/' + User.path + '/' + user.id)= User.getDocumentName(user)
| .
--
1.9.5.msysgit.0

Related

Lighthouse GraphQL - How to return current_user in mutation resolver?

I have a situation where I'm writing a custom mutation resolver, and currently have to pass the current_user's ID from my frontend to be able to then perform a ::find on the User model. What would be ideal however, is to be able to use an instance of current_user so that I don't have to rely on passing over an ID to my GraphQL server.
I'm still fairly new to the world of Laravel and GraphQL in general, however I've been reading up on the Lighthouse docs that mention the #auth directive, and other StackOverflow answers that mention using auth('api')->user(), however that returns NULL for me. I should also mention that I'm using the lighthouse-graphql-passport-auth library for dealing with user authentication, if that makes any difference. Does anybody know how to access current_user?
public function __invoke($_, array $args)
{
// $user = \App\Models\User::find($args['id']); <--- not ideal
$user = auth('api')->user(); <--- returns NULL
var_dump($user);
foreach ($user->notifications as $notification) {
$notification->viewed = true;
$notification->save();
}
$notifications = $user->notifications->toArray();
return [
'status' => 'Success',
'notifications' => $notifications
];
}
I found an interesting part in the lighthouse-graphql-passport-auth docs that discuss setting a [global middleware][3] to insert the logged in user into the $context. This was exactly like what I needed, and after adding the line into the middleware section of lighthouse.php config as mentioned in the docs, I was able to use $context->user() to return the currently logged in user.

What is the best way to implement roles and permission in Express REST Api

I need kind of expert opinion to implement Roles and Permission in Express js. I'm planning to develop Restful Api using Express js but didn't get sufficient information to implement Roles and Permission although there are tons of option are available for authentication and authorization.
Create Tables
First you need to create your tables that will hold the associations between roles, permissions, and resources:
Create a roles table ('Admin', 'User', 'Guest')
Create a resources table ('Users', 'Projects', 'Programs')
Create a permissions table ('Create', 'Read','Write','Delete','Deny')
Create a junction table with all three tables as sources
You may not need that kind of granularity for the permissions table, but some people like it. For example, you don't really need 'Deny', since you just check for Read != true.
Now when you want the permissions of a role on a resource, you just look up role_id and resource_id and check for which permissions are set to true.
Create Middleware
Since you're using express, middleware will be easy to add. For example, let's say you have a router called users:
users.post('/', getAuth, handleUserPost)
Assuming you have a token of some sort on the request that identifies the user making the post, and attaching the user instance to the request object you can do this:
getAuth = function (req, res, next) {
if(req.user) {
db.getPerms({role_id: req.user.role_id, resource_id: req.resource.id})
.then(function(perms){
var allow = false;
//you can do this mapping of methods to permissions before the db call and just get the specific permission you want.
perms.forEach(function(perm){
if (req.method == "POST" && perms.create) allow = true;
else if (req.method == "GET" && perms.read) allow = true;
else if (req.method == "PUT" && perms.write) allow = true;
else if (req.method == "DELETE" && perm.delete) allow = true;
})
if (allow) next();
else res.status(403).send({error: 'access denied'});
})//handle your reject and catch here
} else res.status(400).send({error: 'invalid token'})
}
That code was roughed in just for this example, so I wouldn't go copy and pasting it, but it should give you the right idea.
Role rights in Node.js
Part 1:What is role and rights?
Role rights implementation is important part of any software.Role is a position of responsibility and every responsibility enjoys some rights given to them.There may be some common rights between few roles and some rights may strictly belong to specific role.
Rights are Urls that a role is authorised to access.It is thus necessary to create collection in db storing information of rights to a role.
We have role collection schema as
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const RoleSchema = new Schema({
roleId:{
type:String,
unique:true,
required:[true,"Role Id required"]
},
type:{
type:String,
unique:true,
required:[true,"Role type is required"]
},
rights:[{
name: String,
path: String,
url: String
}]
});
module.exports = Role = mongoose.model('role',RoleSchema);
Now remember every role that is supose to exist is in Role collection and of above schema type.
In schema rights array of object we see the object has keys:
name(for name of url like "set-username")
path(for base path hit "/users/")
url(requested url or complete path "/users/set-username")
Thus if a user with role user has right to change username then he can hit url
/users/set-username.However a wanderer will not be able to access this url.A higher role like admin & superadmin should logically have access to all lower role rights(urls).
Role in real application are:-
Wanderer (Someone who is just visiting our site.He should be able to access all public routes.Simple Urls/Public urls accessible to all thus need not to make a seprate role for this as it is not any authenticated right.)
Guest (Someone who has registered but not verified say email not verified).
User (Someone who has his verified email)
Admin (Made a Admin by SuperAdmin after verifying.he enjoy most of rights)
Superadmin (Master of application.He enjoy some more sophisticated rights.More rights then admin)
Till Now we have understood what excatly is right and how it is mapped to a role.
Part 1.5:Registerd Urls/Config Urls
Here we have a file called registeredUrls.js which is like:
module.exports = {
simple:{
"/":[""],
'/users/':["login","register"],
},
auth:{
//admin
'/admin/': ['load-users' , 'set-new-password','delete-user'],
'/teacher/':["add-teacher","delete-teacher","edit-teacher"],
'/student/':["add-student","delete-student","edit-student","test-result"],
//user
'/test/':["view-test","submit-test"],
'/profile/': ['change-username', 'update-profile-data', 'set-new-password', 'upload-pic', 'update-social-links'],
'/teacher/':['load-teacher'],
'/student/':['load-student']
}
}
Similarly confgUrls.js
const configUrls= {
'/roles/': ['get-rights', 'create', 'update-rights', 'load', 'delete', 'assign']
}
module.exports = configUrls;
Part 2:Creating SuperAdmin
This is most essential part of application.Whenever server starts for first time or restart/reboot this step occurs.In config/init.js follow procedure:
Load All simple urls(public) and Auth Urls(admin & users) & super-admin-specific urls into superAdminRights[].
Then run a function to create a user with role superadmin if doesn't exist.
Get a Role of type:"superadmin" if found:replace its rights with new rights(superAdminRights).else:create Role of type :"superadmin" and then fill its rights(superAdminRights).
At end of this function call we are always sure that we have a superadmin in application with all its sophisticated urls/rights initialised.
Part 3:Super-Admin-Specific-Urls
These are rights that are enjoyed by super admin only and must be maintained in seprate file in parallel to registerd url file.These include url rights which map routes used only by superadmin.
Here we have routes to create role,load roles,get-rights for a roleId,update-rights for roleId/role type, assign-role to a user,delete a role.
For each user in code we need to change their role from guest to user(say after email verification).Or guest/user to admin by superadmin using assign-role url.Then updating admin rights using route update-rights.
The process ensure that every role has A collection Document and filled rights there.
Part 4:Authenticator Middleware
This heart of our RBACS logic.Here we use a middleware which follow process:
1. Fill all authentication required urls in a [AUTH_URLS] with auth-urls(registeredUrls.js) & super-admin-specific-urls(confgUrls.js) and simple url in different [SIMPLE_URLS].
2. Then check if (AUTH_URLS.indexOf(request.url) > -1){3rd step} else if (SIMPLE_URLS.indexOf(request.url)>-1){then it is public url so simple allow next()} else { response unknown url}
3. In this step we know that url being requested in AUTH_URLS thus required token check for authorization token header if found then extract token from it then{4th step}.if no authorization header found response "required token"/"unknown".
4. Token found, now verify that this token has a valid session.If yes {5th step} else token session not found login again.
5. validate jwt token verifying it if verified{6.step} else response "not valid jwt token".
6.till now correct url requested & token session exist & jwt valid token.Now using role-type information from session(stored in session is basic info of user and token) find in Role for this user session role-type thus we have its rights[].Now see if the request.url is included in rights[].if found {7th step} else {reponse "role not found/unknown user"}.
7. if found then {has access to this url next() } else { response "access denided"}

Disable staging logging for certain items in Kentico

I am confused about the attached image scenario… I need to disable staging logging for users that have a role of externalrole. So, i need to disable logging for 3 items in this case.
This means that i need to make 3 checks. I need help with check #1 and #2.
1: if the user is external user then do not log. I need help with checking for the second part, IsExternal = true here.
2: if the external user is added to the site, then do not log. What would be the check in this case?
3: if the role is external then do not log. This check is good.
Code snippet:
var obj = e.Settings.InfoObj;
if (
(obj.ObjectTye == PredefinedObjectType.USER && (Check IsExternal ??????)) ||
(check that external user did not get added to the website – how to make this check????) ||
(obj.ObjectType == PredefinedObjectType.ROLE && obj.ObjectCodeName.StartsWith("externalrole"))
)
{
e.Settings.LogStaging = false;
}
You have the object you are already using - var obj = e.Settings.InfoObj;
So, from the "e" object you can get the user ID (e.Settings.InfoObj.ObjectID) and according to the ID you can get the information whether the user is external and whether it belongs to a site, using standard API where you will get the user info by the user ID, then you can check if it is external and also use the CMS.CMSHelper.CurrentUserInfo.IsInSite(string siteName) method to check whether the user is assigned to the site or not
if (obj.ObjectTye == PredefinedObjectType.USER)
{
UserInfo updateUser = UserInfoProvider.GetUserInfo(e.Settings.InfoObj.ObjectID);
if ((updateUser.IsExternal) || (updateUser.IsInSite("sitename")) || (updateUser.IsInRole("roleName"))
{
....
}

How to use sharepoint access to membership information on office365

Sorry, my English is weak, only use diagrams to describe my problem.
In the following figure, as shown, I want to log in using microsoftonline.com (as A) which account settings on my own server (as B). In my server (as B) which can obtain microsoftonline.com (as A) the account information.
How to achieve?
PS:I was able to get to the token social api implementation of access when an unauthorized error.
Looking for help and guidance of the experts. Thank you first.
http://i.stack.imgur.com/8yOEw.png
keep trying after their own, and finally solve this problem, to the point code to facilitate the needs of others it.
developed using csom
important : rUri need to fill true, otherwise an error will occur 400...
string authCode = Request.QueryString["code"];
string error = Request.QueryString["error"];
if (authCode == "" || "access_denied" == error)
{
Response.Write("I'm sorry you do not have the right to access this site, please contact the system administrator authorization");
Response.End();
}
Uri rUri = new Uri("You fill out an application API Redirect address as https://***/RedirectAccept.aspx");
string o365Site = "You need an authorized user's site collection as https://***.sharepoint.com/";
using (ClientContext context = TokenHelper.GetClientContextWithAuthorizationCode(
o365Site,
"00000003-0000-0ff1-ce00-000000000000",
authCode,
TokenHelper.GetRealmFromTargetUrl(new Uri(o365Site)),
rUri)) {
//
Web web = context.Web;
//
context.Load(web.CurrentUser);
context.ExecuteQuery();
Response.Write("context.Web.CurrentUser.LoginName" + " : " + context.Web.CurrentUser.LoginName + "<br/>");
......

Couchdb and Sofa Help

I'm new to Couchdb just a few week back I git clone the couchdb app called sofa [what and app] . Over the week It was going great but suddenly today I stumble upon something.
Here what I meant
when I browse the Sofa app and try to create a Post without the title
it prompt with and alert box "The document could not be saved: The database could not be created, the file already exists." which was weird as looking at the source I found that the require (in validate_doc_update.js return its custom json error) something like in this format {"forbidden" : message }) with forbidden as key
v.forbidden = function(message) {
throw({forbidden : message})
};
v.require = function() {
for (var i=0; i < arguments.length; i++) {
var field = arguments[i];
message = "The '"+field+"' field is required.";
if (typeof newDoc[field] == "undefined") v.forbidden(message);
};
};
in validate_doc_update.js
if (newDoc.type == 'post') {
if (!v.isAuthor()) {
v.unauthorized("Only authors may edit posts.");
}
v.require("created_at", "author", "body", "format", "title");
inspecting the response state that the json returned was found to be different from the json had it would have been return by the above require function in validate_doc_update.js
here is the json
{"error":"file_exists","reason":"The database could not be created, the file already exists."}
This make be believe that the validation in validation_doc_update.js only execute during updating of document
to Prove this point I try to update a document without the title, expecting that it would return the error but surprisingly the document just got saved
so Here are my Question regarding all the Point I mention above
Does validate_doc_update.js "validate" work only during updation of document
if YES
then
how can I manage to succeed in updating a post without the error [Weird bypassing the Validation Completely] . + How can execute validation on create of a document
if NO
then
What is the Error {"error":"file_exists","reason":"The database could not be created, the file already exists."} that is prevent a document to be saved
Can anyone please share light on all the questions listed here
Yes, the validate_doc_update functions are run only when updating documents (include creation and deletion).
The function you show here will allow a document without a title as long as its type is not "post". If you could include the actual request you attempted, I could confirm it.
Finally, the ""The database could not be created" is because you are attempting to create the database (by doing PUT /dbname/ instead of PUT /dbname/docid, I would guess) when it already exists. Again, if you would include the actual request, I could confirm that too.

Resources