New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make sure DDP._CurrentInvocation is never set inside publish functions #8031
Conversation
I added tests. |
Is this just to make sure the expectation that I'm just a bit confused as I was under the impression that a server-method called from another server-method would maintain the Edit: finished sentence. |
This.
Because calling a method from a publish function is a server-initiated method call. And at least it should be consistent. But to be backwards compatible, we probably cannot change this (like, it would break a lot of my code, this is also how I discovered, because things are throwing an error every time a restart happens, because connection was not expected to exist, because this was to determine which arguments a method needs based on where is it called from). So we should just make it consistent. |
Ok, got it. Not saying that I disagree, but the wording on the
(emphasis mine) |
I agree. But calling a server method from publish function should always have connection |
I don't see why that Are you trying to solve a problem? Is this because of trying to detect where a server method was called from? |
I do not really care either way, but we should be consistent. Currently, methods called from a publish function do not have I think it is important that this is consistent also because of the security. I think how most people use this these days is (including me) to check if So this pull request now just handle the inconsistency while keeping it how it was before and backwards compatible. If we want to change that methods called from a publish function keep |
Ok, now this is starting to become clear to me. I still didn't quite understand that this was the inconsistency. You're saying the first time a publish is run
Agree! I do this too (though I don't do method calls from my publications).
I think I understand now. |
That should not be changed at all. As you see, I changed only behavior inside the |
I understand. I was asking what happens right now in that scenario. I honestly don't know as I don't do this anywhere. It seems to me that it would make sense to match that behavior. |
I think we should not over-engineer this. This now is just a fix of an inconsistency. I think this is what is a bug. If we want to change how all this works, this should be a larger discussion. So this here is to fix a real bug which happens in production. Changing how |
There is no over-engineering happening here. I'm asking a question: What happens right now when a Meteor Method calls another Meteor Method when the first was called from the client? I ask because I think it changes the proper solution for this. You are trying to fix an inconsistency and there has to be a "correct" way: Either the nested method always has So to help answer this question, I'm asking what happens in the case of a "Method => Method". It seems the answer should be the same as "Publish => Method". That's my belief, at least. |
I thought that we discussed this already in this thread and I think we are going into circles. In "Method => Method" And what I am saying is that changing so that publish functions have |
Also, this fixes a problem in behavior nobody is relaying on (that |
If there is a misunderstanding here, I digress and apologize, but this is the first time you directly answered. It was not clear to me. I started off saying I was under the impression (that is to say, not certain) and referenced the documentation. I asked two more times, to both you replied with something that still didn't seem like the answer. If someone asks the same question a third time, it is reasonable that something is still not clear. If you think you answered, I didn't understand.
By making this statement aren't you making the assumption that publication restarts are rare? I don't know if that's the case. Publications might get restarted frequently or as many times as they are started in many applications. I would need data from users to make this conclusion. I think either way, there is a breaking change for someone.
My contribution on this issue is a discussion and my opinion. I'm not going to tackle it or change your PR. I want consistency too. I'm happy to discuss further, but I think yes, we're going in circles now. Someone else will probably have to weigh in on this. |
Publications restarts because of the login while you are subscribed is definitely rarer than "as many times as they are started in many applications". In any case, I am not claiming or assuming anything about how often restart happens. I am saying that it seems that nobody until now cared to investigate or report why server-side method which uses information from
I am proposing that we should not change behavior, because this is how it is currently.
You are proposing to make a backwards incompatible change, so I am asking why? What I am reporting is a bug in current behavior and a fix for it. What you are proposing is a backwards incompatible change and a feature change. What I am saying is that we should merge a bug fix. And then if somebody wants to tackle a feature change they can open a ticket, pull request, or whatever. I do not need that feature, but I need the bug fixed. If you do not need that feature either, then let's maybe just agree on fixing the bug? |
Can we get some additional eyes on this? |
As of this week I quite like having access to That said, I'm having to run a modified |
@mitar I've re-read this thread in its entirety and my feelings haven't changed: providing more context, in the form of I still don't accept your argument that my change is "breaking" and yours isn't – something you have stated multiple times now. Your proposal breaks backwards compatibility for some and mine breaks it for others (that's why this is identified above as a "consistency" issue). If someone is relying the I'm inclined to believe that this isn't a popular problem given the lack of overall input and lack of reported issues on this but I think this is still important to merge – edge cases like this can be nasty to debug. The fix seems like it should take the more secure route and match the documentation which specifically states that |
There is no way that anyone is relaying on this fact that in rerun connection is available. I spent a day debugging this until I realized what is happening. This is not documented and not intuitive at all (that something would be available only in such edge case). I am saying that you are discussing hypothetical situation: somebody relaying on this edge case, while I am explaining you the real situation: me having issues because of this edge case. You have not convinced me that there is anyone who is relaying on this edge case.
I do not see how this would happen. Why would you secure privileged access only during publish rerun, but not during normal run?
Exactly, this is really tricky to debug.
Feel free to implement it differently. I do not know how. I know how to fix this. But I do not know how to assure that this is always passed along correctly, without
Documentation is not saying anything that the server-side initiated method from the publish function should share the initial connection data. |
@mitar @abernix I think at this point the only way to settle this is with a friendly game of rock-paper-scissors, since I think you're both right! (oh, and I'm Canadian so I have to say this to help avoid conflict First a quick recap:
Given the above, and to move out of stalemate, maybe we should consider addressing this in 2 steps then? Step 1 is to fix the immediate bug as outlined in this PR (since it's a fairly quick fix and easy win). Step 2 is to open a new issue to track the issue mentioned by @abernix, which when addressed will ultimately be the better fix (but will take more time to implement), and can replace the fix outlined in this PR. Would that work? Otherwise, if we're looking for the best possible solution to this being implemented once and only once, then addressing the issues brought up by @abernix makes sense, before merging this PR. Anyways, just adding some 3rd party feedback. Thanks! |
Lack of
Of course they're not relying on it, but a difference would be observed in an edge case (whether your implementation or mine). With your change, privileges would be relaxed – in my proposal, they would be tightened. Surely you agree that if a random edge case results due to this change that it would be preferred that the publication get less access and not more?
Your real-situation edge case was once a hypothetical.
You're right. It doesn't specifically say anything about publish to method, but it does say:
I maintain the presence of
You are seemingly the only person that is having this problem. I think the problem should be fixed securely and you can adjust your code accordingly. |
@hwillson My core issue is that the above fix seems to relax security in an edge case and therefore I cannot support it. |
But nobody is relaying on a security in edge case, if the main case does not work? How is this possible? |
@abernix Right, good point; I really like the idea of |
@mitar if we take @abernix's approach, would your code still work (with some modification presumably) or would it be literally unfixable? If it's possible to make client => publish => method match client => method => method and it's not going to totally break things for you I think that's the better and more secure option. Probably nobody is relying on the edge-case as you say, but it's still better to increase security (or at least reduce the possibility of an edge-case security mishap) if possible. Plus as I mentioned before I'm relying on And finally this may be a dumb question but I'm not even sure why a Meteor method would need to be called from another method or publish function vs just calling a plain JS function? Happy to be enlightened though! |
I do like this proposal. I would like that this is fixed (I am getting errors regularly because of this). And then whoever wants to change to so that connection is available always, can do that. With a good notice in changelog.
Publish functions already do not have this set, only during a rare moment when they are rerun after a login of the user (when publish functions are restarted). If you need something like
Just because they were defined in this way. Otherwise I would have to define them as a symbol and export it or something. But if they are already registered as a method, I can just call it. It is just a question how you want to organize your code.
No, they are already relaxed in main case as well. Currently, if you call a method from publish function, you do not have access to connection. So you had to do security in some other way. Otherwise your method already had full access. Only in the edge case you gain access to connection. So you are saying that there is somebody who is calling a server method from publish function and do not care about its being trusted (because there is no connection), but then during rerun now they start worrying because they do not know that if it is trusted or not? Really strange logic you have here. Please write me a publish function example which would work like this. So on purpose make an example function which fails in the way you are saying security would fail if we merge this pull request. I would really like to see how is this possible. |
So, what is the next step here? Who will implement an alternative? Or will we keep a buggy version around? |
I made publish-context package. I was not really thinking about this pull request when making it, but now I think this is the correct way to do it. When called from inside Meteor publish function, Then a simple function like this: function userId() {
const currentInvocation = DDP._CurrentInvocation.get();
if (currentInvocation) return currentInvocation.userId;
const currentContext = DDP._CurrentPublish.get();
if (currentContext) return currentContext.userId;
throw new Error("userId() not invoked from a method or publish function.");
} Gives you user ID if you are inside meteor method or publish function, if you want your ACL checks to be the same across all codebase (and even inside nested functions). This is what this package does. Similarly, you can get access to So, I again think that the correct thing is to merge this pull request as it is. Publish function is not method invocation. But we could move into the core BTW, I think also that |
From what I understand of this issue the problem is that when a Then when the same This does not reflect the behaviour of when a I think the "best" and I believe the most secure way of solving this issue is to make sure that This would probably have to be properly documented as it might "break" some people's applications that are doing method security based on the currently "broken" behaviour. The If we can come to a decision on this issue I would try and create a PR to solve this. |
I think we should really simply introduce public context ddp variable. Because then when you cal any function, one will be able to get to the current publish context. I think we should make I think this is much better approach than giving access to this global variable only inside methods. |
If we fix |
So This is why I went for a new variable. Also, my I think it would be simply cleaner to have two variables with clear semantics, and make them public and documented. |
From what I understand, having When a Maybe I misunderstood the point you were trying to make and I'm missing something? |
What I am saying is that Example, if we set So I think it is much better that we expose this as it is, do not try to be too smart about it. Make one variable always expose the publish context, if it is, and another always expose the method context, if it is. We could make it so that a context is both, but then callers would have to expect that, and this might be a breaking change. Maybe we could have also both things: two variables, and then a new helper function (public one) which returns a current context from one or the other. |
Ok, so I believe that might be a different issue all together. What I'm suggesting isn't going to change the |
But what will be the value of
No, And this is why this pull request exists. Because I think it is bad that |
I think we should make |
You are actually correct. I just tested this and it's only when the publications are re-run because a user logged in, but not in following subscribe calls to the publications. Maybe |
Ok so I've look at this once more now. If we just accept this patch we will fix the current inconsistency of a In all other cases a I'm totally fine with this and I don't see this as being "loose" on security as all of a sudden If you have a method that only run whenever So in this issue @mitar is and always have been correct as far as I can tell. However this issue have revealed a different issue all together and this is where I believe the confusion has arisen. As a developer I would expect that Today this is not the case because in all the normal cases a One solution to this problem is to make sure that @mitar however brought up a case for having a separate publish context set on From what I can tell though, this will not directly solve the problem of If we go down this route I would suggest that we introduce Sorry for the wall of text but I just wanted to try and clear this issue up as I would really like to see a fix for these 2 issues. |
Yes. I think this might get be a consensus we can all agree on. It will also satisfy points brought by @abernix. I would then suggest that we:
In this way the behavior which is arguably useful as pointed out by @abernix, having |
Closing in favor of #8629 which is a more complete solution for this issue and already contains all of the commits for this thanks to it being rebased on this. Will be great to see this finally land and agreeable to all parties! |
_setUserId
is normally called from a Meteor method withDDP._CurrentInvocation
set. ButDDP._CurrentInvocation
is not expected to be set inside a publish function, so we have to temporary unset it.Otherwise, this can lead to a problem that if a publish function is calling server-side Meteor methods, their
this.connection
property is set when publish function is restarted here, but the property should not be set.