I have only one account - admin by default. I need to change user permissions to non-admin one. I believe that I have few options available (not great yet can be used)
Create a new endpoint on a server just for testing - to make it possible for non-admin user to update those permissions. This idea seems pretty odd to me to change something like that.
Have multiple users to be able to switch between them for different roles (all in all not that simple for now).
Connect to db within tests and make those changes on db - probably easiest option
Is it OK to create new endpoints for testing e.g. /publish-cypress? Is it OK to populate the database just for tests by running some operations on db?
On my personal opinion you shouldn't create testing endpoint.
What you should be testing is the method that will be called by these routes (Your service), and for front-end you can 'fake' these call to the api.
The simplest way to do that is to use something similar ton interfaces (you might want to look at typescript ;) )
An example to fake these calls in your tests:
I'll go with typescript as it'll be mush easier to understand (less code)
//here you define all calls possible to your api
//dont forget to always pass the gateway by reference so that you can change whenever you want between fake & real
interface MyGateway {
changeUserPermission(userId, permissions);
}
//here do the actual implementation that will be used by your app
class MyApiGateway implements MyGateway {
public changeUserPermission(userId, permissions) {
//here is your real api call with fetch, axios or whatever
fetch('http://example.com/perms')...
}
}
//now you can do another implementation for testing purposes
class MyTestGateway implements MyGateway {
//here you can return hard values or do whatever you want so that your app doesn't depends on you backend
public changeUserPermission(userId, permissions) {
console.log(`Updating ${userId} is ${permissions}`);
}
}
Related
I want to implement authorization layer on my microservices project. I have 3 microservices customer-service, workspace-service and cloud-service. So if a customer want to create a cloud instance he will create on behalf of a workspace which means that the cloud instance will belong to the workspace instead of him and also he may invite other customer to the workspace, and have access to the cloud instance. The data structure may looks like this.
// workspace
{
"workspaceId": "ws-123",
"customers": ["customer-123", "customer-456"]
}
// cloud-instance
{
"cloudId": "cloud-123",
"workspaceId: "ws-123"
}
I want to implement authorization logic that check if a user has access to a particular cloud instance. In order to do that I need to have workspaceId somewhere else in my authentication object. One thing that I can think of is that to put workspaceId in the jwt claims so my jwt may looks like this.
header.{ ..., workspaceId: ["ws-123"] }.signature
but the drawback of this solution is that the workspaceId claim won't be updated until the token has been refresh.
another solution that is to implement a service that query data from workspace-service and use it to validate.
const hasAccess = (customerId, workspaceId_on_cloud_instance) => {
let actual_workspaceId_that_he_has = workspace_service_exposed_api.findWorkspaceByCustomerId(customerId)
return actual_workspaceId_that_he_has == workspaceId_on_cloud_instance
}
but this approach would heavily rely on workspace-service if workspace-service is down then the other service can not handle a request at all since it doesn't have access to workspaceId.
So IMHO I would rather go for the 1st option since I use oauth2.0 and token will be refresh every 30s, but is it bad practice to do that? I wonder if there's better solution.
Having 3 microservices you cannot implement functionality with assumption that one service is down. I have feeling that access token lifespan is also defined based on this restriction - to have up to date data in the token. As I correctly understand, in worst case there is also ~30 sec. delay related to workspaceId update in token payload.
Token claim will change only when you invite or remove person from workspace so this service must work anyway. I would use 2nd solution with longer token lifespan to not generate it so often.
Another solution is to generate new token every time when workspace is changed - you can treat adding/removing to workspace as a business logic that invalidates token, but probably in this case communication to workspace service is also required.
If you are afraid that microservice will be down or you will have problem with communication, maybe you should focus more on app infrastructure or choose a new solution based on monolith application.
And back to question from title - adding any custom claim to token payload is standard approach.
We have recently started using Node.js for our API server instead of Java. Apart from all the good things which Node.js provides, one thing I miss the most is having a proper response object for an API.
Since Javascript being dynamically typed languages, objects can be created on the fly while returning the response. This is in contrast to Java, where I can have a class , an instance of which will be serialized in the response. I can anytime lookup this class to determine what the response of the API will be.
Is there such a design pattern in Node.Js / Javascript. We would like our API's to have strict conformance to such templated object.
You can make them yourself.
If you're using ES6 for example, you can have various error and response modules, and perform your own validation in the class that creates those responses.
For example,
// sample-response.js
class SampleResponse {
constructor(message) {
// validate `message` somehow
this.data = message
}
}
module.exports = {
SampleResponse
}
Then however you're structuring your HTTP interface, you can send back whichever response you'd like (for example, with Express):
res.send(new SampleResponse(message))
Same goes with errors, etc. You're not necessarily limited by a lack of types with JavaScript, you just have to enforce things differently.
If you're not using ES6, you can do something like this:
module.exports = {
SampleResponse: function(message) {
// do some validation
return { data: message }; // or whatever you want
}
};
You can use Flow or TypeScript for you code.
You can use contract testing tools. Depending on the contract for your REST API:
abao for RAML
dredd for api blueprint
SoapUI for Swagger
My choice is to use TypeScript and Abao+RAML.
I have a Torii adapter that is posting my e.g. Facebook and Twitter authorization tokens back to my API to establish sessions. In the open() method of my adapter, I'd like to know the name of the provider to write some logic around how to handle the different types of providers. For example:
// app/torii-adapters/application.js
export default Ember.Object.extend({
open(authorization) {
if (this.provider.name === 'facebook-connect') {
var provider = 'facebook';
// Facebook specific logic
var data = { ... };
}
else if (this.provider.name === 'twitter-oauth2') {
var provider = 'twitter';
// Twitter specific logic
var data = { ... };
}
else {
throw new Error(`Unable to handle unknown provider: ${this.provider.name}`);
}
return POST(`/api/auth/${provider}`, data);
}
}
But, of course, this.provider.name is not correct. Is there a way to get the name of the provider used from inside an adapter method? Thanks in advance.
UPDATE: I think there are a couple ways to do it. The first way would be to set the provider name in localStorage (or sessionStorage) before calling open(), and then use that value in the above logic. For example:
localStorage.setItem('providerName', 'facebook-connect');
this.get('session').open('facebook-connect');
// later ...
const providerName = localStorage.getItem('providerName');
if (providerName === 'facebook-connect') {
// ...
}
Another way is to create separate adapters for the different providers. There is code in Torii to look for e.g. app-name/torii-adapters/facebook-connect.js before falling back on app-name/torii-adapters/application.js. I'll put my provider-specific logic in separate files and that will do the trick. However, I have common logic for storing, fetching, and closing the session, so I'm not sure where to put that now.
UPDATE 2: Torii has trouble finding the different adapters under torii-adapters (e.g. facebook-connect.js, twitter-oauth2.js). I was attempting to create a parent class for all my adapters that would contain the common functionality. Back to the drawing board...
UPDATE 3: As #Brou points out, and as I learned talking to the Torii team, fetching and closing the session can be done—regardless of the provider—in a common application adapter (app-name/torii-adapters/application.js) file. If you need provider-specific session-opening logic, you can have multiple additional adapters (e.g. app-name/torii-adapters/facebook-oauth2.js) that may subclass the application adapter (or not).
Regarding the session lifecycle in Torii: https://github.com/Vestorly/torii/issues/219
Regarding the multiple adapters pattern: https://github.com/Vestorly/torii/issues/221
Regarding the new authenticatedRoute() DSL and auto-sesssion-fetching in Torii 0.6.0: https://github.com/Vestorly/torii/issues/222
UPDATE 4: I've written up my findings and solution on my personal web site. It encapsulates some of the ideas from my original post, from #brou, and other sources. Please let me know in the comments if you have any questions. Thank you.
I'm not an expert, but I've studied simple-auth and torii twice in the last weeks. First, I realized that I needed to level up on too many things at the same time, and ended up delaying my login feature. Today, I'm back on this work for a week.
My question is: What is your specific logic about?
I am also implementing provider-agnostic processing AND later common processing.
This is the process I start implementing:
User authentication.
Basically, calling torii default providers to get that OAuth2 token.
User info retrieval.
Getting canonical information from FB/GG/LI APIs, in order to create as few sessions as possible for a single user across different providers. This is thus API-agnotic.
➜ I'd then do: custom sub-providers calling this._super(), then doing this retrieval.
User session fetching or session updates via my API.
Using the previous canonical user info. This should then be the same for any provider.
➜ I'd then do: a single (application.js) torii adapter.
User session persistence against page refresh.
Theoretically, using simple-auth's session implementation is enough.
Maybe the only difference between our works is that I don't need any authorizer for the moment as my back-end is not yet secured (I still run local).
We can keep in touch about our respective progress: this is my week task, so don't hesitate!
I'm working with ember 1.13.
Hope it helped,
Enjoy coding! 8-)
Introduction
I'm building a private messaging system using sails, but this question can apply to pretty much anything. I'll be using the messaging system as an example to make the question more clear. As a bit of background info, I'm working with the latest sails 0.10 RC.
The problem
Sails allows you to use redis for sessions and pubsub, which allows you to scale over multiple servers. This is all very neat and works brilliantly, but it leaves me with the question of how to publish events to specific connected sockets (clients).
Sometimes you wish to only publish events to participants, as is the case with a private messaging system. Only the author and recipient should be notified of new messages in the thread. How would you accomplish this? I know you can subscribe a client to a specific model instance, notifying the client of changes in said model; I also know it's possible to subscribe a client to a model, notifying them of newly created (saved) model instances. It's the latter, the create verb that's causing me a bit of trouble. I don't want everyone that's using the messaging system to receive updates for new messages in threads they're not in. This would be a privacy issue.
TL;DR
How can I filter which clients receive the create verb event based on the value of a property (author and recipient) on the model in question? Is there any other way to make sure only these clients receive updates for the model?
You have a few options here, but all of them involve not really using the default publishCreate method, which will just blast out the created message to everyone who was subscribed to it via .watch().
The first option is to use associations to link your Message model to the users who should know about it, and then listen for the publishAdd message instead of publishCreate. For example, if there's an association between a Message instance and the User instances who represent the sender and recipient, then the default publishCreate logic will also trigger a publishAdd for the related users, indicating that a new Message has been added to their messages (or whatever you name it) collection.
The second option is to override the default publishCreate for Message, to have it send only to the correct users. For example, if only the recipient should be notified, then in api/models/Message.js you could do:
attributes: {...},
publishCreate: function (values, req, options) {
User.publish(values.recipient, {
verb: "created",
data: values,
id: values.id
}, req);
}
As a slight alternative, you can place your custom code in the model's afterPublishCreate method instead, which the default publishCreate will then call. This has the benefit of maintaining the default code that handles calling publishAdd for associated models; the trick would be just to make sure that no one was subscribed to the model classroom via .watch(), so that the default publishCreate doesn't send out created messages to users who shouldn't see them.
I'm quite new to JayData, so this may sound like a stupid question.
I've read the OData server tutorial here: http://jaydata.org/blog/install-your-own-odata-server-with-nodejs-and-mongodb - it is very impressive that one can set up an OData provider just like that. However the tutorial did not go into details about how to customize the provider.
I'd be interested in seeing how I can set it up with a custom database and how I can add a layer of authentication/authorization to the OData server. What I mean is, not every user may have permissions to every entity and not every user has the permission to add new entities.
How would I handle such use cases with JayData?
Thanks in advance for your answers!
UPDATE:
Here are two posts that will get you started:
How to use the odata-server npm module
How to set up authentication/authorization
The $data.createODataServer method frequently used in the posts is a convenience method that hides the connect/express pipleline from you. To interact with the pipeline examine the method body of $data.createODataServer function found in node_modules/odata-server folder.
Disregard text below
Authentication must be solved with the connect pipeline there are planty of middleware for that.
For authorization EntityContext constructor accepts an authorization function that must be promise aware.
The all-allow authorizator looks like this.
function checkPerm(access, user, entitysets, callback) {
var pHandler = new $data.PromiseHandler();
var clbWrapper = pHandler.createCallback(callback);
var pHandlerResult = pHandler.getPromise();
clbWrapper.success(true); // this grants a joker rw permission to everyone
//consult user, entitySet and acces to decide on success/error
//since you return a promise you can call async stuff (will not be fast though)
return pHandlerResult;
}
I have to consult with one of the team members on the syntax that let you pass this into the build up process - but I can confirm this is doable and is supported. I'll get back with the answer ASAP.
Having authenticated the user you can also use EntityContext Level Events to intercept Read/Update/Create/Delete operations.
$data.EntityContext.extend({
MySet: { type: $data.EntitySet, elementType: Foobar,
beforeDelete: function(items) {
//if delete was in batch you'll get multiple items
//check items here,access this.request.user
return false // deny access
}
});
And there is a declarative way, you can annotate Role names with permissions on entity sets, this requirest that your user object actually has a roles field with an array of role names.
I too have been researching oData recently and as we develop our platform in both node and C# naturally looked at JayStorm. From my understanding of the technical details of JayStorm the whole capability of Connect and Express are available to make this topic possible. We use Restify to provide the private API of our platform and there we have written numerous middleware modules for exactly this case.
We are using JayData for our OData Service layer also, and i have implemnment a very simple basic authentication with it.
Since the JayData is using Express, so we can leverage Express' features. For Basic Auth, the simplest way is:
app.use(c.session({ secret: 'session key' }));
// Authenticator
app.use(c.basicAuth('admin', 'admin'));
app.use("/odata.svc", $data.JayService.OData.Utils.simpleBodyReader());
you also can refer to this article for more detail for authentication with Express: http://blog.modulus.io/nodejs-and-express-basic-authentication
Thanks.
I wrote that blogpost, I work for JayData.
What do you mean by custom database?
We have written a middleware for authentication and authorization but it is not open source. We might release it later.
We have a service called JayStorm, it has a free version, maybe that is good for you.
We probably will release an appliance version of it.