Is there any way I can trigger a policy on a specific request method (e.g. DELETE) rather than on specific routes?
I'd imagine something like this:
module.exports.policies = {
'DELETE *': 'isAdmin'
}
My goal here is to expose the blueprint api to admins only, so that I can keep it in production, as it's a very useful tool for allowing third party scripts to add extra functionality.
I'm on Sails 1.0 right now.
One way to do that might be to add the check for the request method to the actual admin policy, however that doesn't quite seem like the best solution to me.
You can override the blueprint for all models for a particular method. You can do this for DELETE by creating a file destroy.js in /api/blueprints/ and then adding your code for what you want to do when a DELETE comes through:
module.exports = function(req,res, next) {
if(ACLService.hasPermission(req.user.acl, 'admin')) {
//Ok to allow delete here
} else {
return res.unauthorized();
}
};
This is how I've done it in the past, but looking at the docs for the just released SailsJS 1.0:
https://sailsjs.com/documentation/reference/blueprint-api
You may need to add this hook for overriding blueprints in 1.0
https://www.npmjs.com/package/sails-hook-custom-blueprints
Here is one method that you can use, I am not claiming that it is the right way, but you can consider it:
You can write your own hook. How to do this: https://sailsjs.com/documentation/concepts/extending-sails/hooks/project-hooks
Basically here is the solution with a hook:
1 Create a hooks folder under your api folder.
2 In the hooks folder create another folder - the name will be the name of your hook (say my-hook).
3 In api/hooks/my-hook create a file index.js and in it put the following code:
module.exports = function myHook(sails) {
return {
routes: {
before: {
'/*': function (req, res, next) {
if (req.method.toUpperCase() === 'DELETE') {
return sails.hooks.policies.middleware.isadmin(req, res, next); // note - your policy function name must be called here with all lowercase, otherwise it will not work.
}
return next();
}
}
}
};
};
Then in your isAdmin.js policy you can check if your user is an admin and if not:
return res.forbidden();
if it is admin:
return next();
Related
I'm trying to create SSO in my Nest.js application using Okta as Identity Provider and passport-saml library. I read documentation of Nest authentication and passport-saml. I have no problems with understanding of examples, but I really need to use SAML strategy with different configuration which depend on request body value of POST api/auth/saml. In other words, I have one strategy, but with different entryPoint, issuer, cert params for my custom LoginSSOStrategy class which extends PassportStrategy class of Nest.js. Any ideas how can I handle this?
I'm not quite sure if this is a good approach, but if you want, you can make the class request scoped and inject the request via the constructor, then have access to the request object and be able to work with a new instance of your passport strategy each request. You can use the request to pass req.whatever to the super() class's constructor.
#Injectable({ scope: Scope.REQUEST })
export class LoginSSOStrategy exends PassportStrategy(Strategy) {
constructor(#Inject(REQUEST) request: Request, ...) {
super({/* options matching to request.field */});
}
validate(/* validate params*/) {
/* validate functionality */
}
}
This seems like something you'll want to do a lot of testing around and making sure it works with concurrent requests, but overall it could work, in theory at least.
I think this issue is similar to this GitHub issue. Due to the global nature of Passport.js and the fact that Nest is unable to determine which routes use a Passport passport strategy it is not possible to create a request scoped Passport strategy by using #Injectable({ scope: Scope.REQUEST }).
Recently, I had to implement a Azure Active Directory login with a dynamic redirect URL based on some data from the incoming request. Depending on the Strategy you use, you might be able to overwrite some options when calling the authenticate method of a Passport Strategy by using the (undocumented) extraAuthReqQueryParams property.
One way to know wether or not you're able to overwrite some options is to check the documentation, if you're feeling lucky you could look in the source code of the Passport strategy you're using. After reading about the undocumented feature and seeing these lines in the source code of the Azure AD Passport strategy (in particular lines #1355 and #1374) I was able to change the value I previously specified in the redirectUrl property by using the redirect_uri property (note the slight difference here).
#Injectable()
export class AzureOIDCStrategy extends PassportStrategy(OIDCStrategy,'AzureOIDC') {
constructor() {
super({
// Even though it is overwritten in the 'authenticate' method the Passport Strategy expects this to be set to a valid URL.
redirectUrl: `https://your-backend-domain.com/auth/azure/callback`,
// This ensures we have access to the request in the `authenticate` method
passReqToCallback: true,
});
}
authenticate(req: Request, options: Record<string, any>): void {
return super.authenticate(req, {
// `options` may contain more options for the `authenticate` method in Passport.
...options,
extraAuthReqQueryParams: {
// This overwrites the `redirectUrl` specified in the constructor
redirect_uri: `https://${req.headers.host}/auth/callback`,
},
});
}
}
I hope you will be able to apply this 'strategy' to update the entryPoint, issuer and cert params.
In an Express app you could do something like this:
app.get('/login',
(req, res, next) =>
passport.authenticate('azure-ad', {
extraAuthReqQueryParams: {
redirect_uri: `https://${req.headers.host}/auth/callback`,
},
})(req, res, next)
);
I've got some troubles when start working with Next.js
Here is the deal. I have multiple filters, depends on them I make up URL. All of this URL's for one page.
It can be like:
/
/one
/one/two
/one/two/three
This nested is required. How can I create one handler for catch any of these URL's?
I use Express like this, but it doesn't help.
server.get('/*', async (req, res, next) => {
try {
app.render(req, res, '/')
} catch (e) {
next(e)
}
})
Thanks!
Use Dynamic routing like that :
pages/[one]/[two]/[three].js
cf:
Multiple dynamic route segments work the same way.
For example, pages/post/[pid]/[comment].js would match /post/1/a-comment. Its query object would be: { pid: '1', comment: 'a-comment' }.
https://nextjs.org/docs#dynamic-routing
Hope it's help.
New feature introduced in Next.js 9.5
Solution: Rewrites
See also: Redirects & Headers:
Announcing comment: https://github.com/vercel/next.js/discussions/9081#discussioncomment-48301
Besides that I am aware of some wildcard matching that nests paths deep in the default routing, but I feel Rewrites is a better solution in most use cases.
use npm next-routes in order to use path patterns (regex) to bind multiple urls to a page
How do you access application configuration settings inside a middleware function with express? For example say I have the following contrived example which is defined it's own module and I want to branch based on the results of a application configuration.
function fail(req, res, next) {
if (app.config.fail === true) {
res.json({'err': 'failed'});
}
return next();
}
What is correct way to handle this with express?
Well, if you wanna access app inside a middleware you can do that with req.app. As explained here
I hope this is what you were looking for!
In Meteor.js, how do one generally give different users (say depending on a field role in the users collection, which can have values like admin, users, testers) different versions of the site (both clientside and serverside)?
First, I am using Iron Router for my routing. At some point I may drop it and write my own, at least for this project, as I am not using half of the features, but for now this is what I have.
For roles I am using the alanning:roles package. Again, I could probably write my own, but it does what I need it too for now, so I am happy with it.
Next I have a custom package I wrote. In it I set up a template for signin and signout, with routes etc. I also provide a utility class that provides a function called authenticationRequired. This function will check if the current user is logged in, and if roles are passed in that they have those roles. The code looks like this:
AccountUtils.authenticationRequired = function(router, roles) {
if (!router) {
throw new Meteor.Error(500, 'Router is a required parameter');
}
if (!Meteor.loggingIn()) {
var currUser = Meteor.user();
if (currUser) {
if (roles) {
if (!Roles.userIsInRole(currUser, roles)) {
console.log('User was not in the required roles: %j, %j', currUser.roles, roles);
//throw new Meteor.Error(403, 'Access Denied');
Router.go('notAuthorized');
}
}
} else {
console.log('User not found');
Router.go(AccountUtils.settings.signinRoute);
}
}
}
Now, in my Router router I do something like:
this.route('admin', {
path: '/admin',
onBeforeAction: function() { AccountUtils.authenticationRequired(this, ['ADMIN']); }
});
There are a few moving parts around all of this, but that's the jest of it. In the onBeforeAction of the route, check if the user has the required role. If not, send them to the notAuthorize page. If they are, let them through. I am still missing a few pieces that I haven't worked out yet in this code, but it works for the most part.
Hope that gives you a jumping-off point.
I'm just getting started with express.js and am failing to understand how one defines discrete "pages" (in the traditional sense) that one can link to internally.
I'm using Jade as a template engine and I see how it pulls the various components together and references them in the app.js (which is what is initially invoked by npm) so that, in effect is my "index". Would be great to see a tutorial on what one does to then build out pageA, pageB, pageC so that they can be linked to via <a href="pageA.html"> (or the Jade equivalent).
I'm assuming this is possible, right?
Express.js itself does not offer URL generation, only a built-in router.
You would need to use an additional package to perform URL generation, or build it yourself. Maybe you find something fitting in this question's answers: URL generation for routes in express
If you do not care about route generation and want to "hard code" the URLs, you would need to add a route for each static page, like this:
// routes.js
app.get("/pageA.html", function(req, res, next) { res.render("static/page_a", { templateLocals: "here" }) };
app.get("/pageB.html", function(req, res, next) { res.render("static/page_b") };
Or, if you have many of those pages, you could use a controller for this:
// static_page_controller.js
module.exports = function(pageTemplate) {
return function(req, res, next) {
return res.render("static/" + pageTemplate);
}
}
And use it like this:
// routes.js
var staticController = require("./static_page_controller");
app.get("/pageA.html", staticController("page_a"));