2
$\begingroup$

I tried the following:

VerifyUserPermission[]:=If[!MemberQ[
    {"allowed users",...},
    $Username
],Print["Access Denied!"];Abort[]];


Test[x_,y_]:=Module[{
},
    Print["PreVerification"];
    VerifyUserPermission[];
    Print["PostVerification"];
    x+y
];

I tried using Return instead of Abort but that doesn't return from the outer function which is calling it.

Test[x,y]

Also there is a danger user can Block the Abort function from outside even if VerifyUserPermission is hidden. What is the way to achieve this?

$\endgroup$
4
  • $\begingroup$ Why can't VerifyUserPermission[...] return True or False depending if verified or not, then the caller decides what to do based on this? I do not understand what is the main issue here. $\endgroup$
    – Nasser
    Commented Jul 10 at 1:14
  • $\begingroup$ I don't want to handle the boolean in the outer function. I want the outer function execution to stop by the inner function. In this way, I can sprinkle this function anywhere in the paclet and perform verification in different places without modifying the code of main functions. $\endgroup$
    – user13892
    Commented Jul 10 at 1:20
  • $\begingroup$ Don't worry about the Block if there is no easy answer. How to use Return in the inner function and apply it to the outer function from the inner function? or Abort is the only option I have? $\endgroup$
    – user13892
    Commented Jul 10 at 1:24
  • $\begingroup$ Maybe you can live with "Quit". Using "Quit" in the inner function will terminate the kernel but not the front end. $\endgroup$ Commented Jul 10 at 7:25

1 Answer 1

1
$\begingroup$

I don't want to handle the boolean in the outer function. I want the outer function execution to stop by the inner function. In this way, I can sprinkle this function anywhere in the paclet and perform verification in different places without modifying the code of main functions.

When you "sprinkle" the auth function in, you'll be modifying the code of the other functions. A better way would be to keep the domain functions clean of any authentication and apply authentication to them in a way that they remain completely ignorant. If you add an "inner function", then they are still being disrupted.

So, you might want to try something along these lines. Create a function that can be applied to another symbol before the other symbol is allowed to operate on its arguments.

RequireAuth[method_, userdata_][func_] :=
  If[method[userdata], func, AuthFailure[func, method, userdata]]

I'm just thinking ahead here and generalizing a bit, but you could forgo method and userdata and just implicitly do the check you were already doing. Let's test it.

RequireAuth[True &, {"name", "password"}][Sin][0]
(* 0 *)

RequireAuth[False &, {"name", "password"}][Sin][0]
(* AuthFailure[Sin, False &, {"name", "password"}][0] *)

I'm hinting that one authentication method might be username + password, but the userdata for these tests is just ignored.

Now, I used that AuthFailure expression as a placeholder, but we'd actually like it to do something useful, so let's give it some behavior.

AuthFailure[func_, method_, userdata_][args___] := 
  Failure[
    "AuthenticationFailure", 
    <|"MessageTemplate" -> "Authentication failed (`Method`) for user `UserData` at `Function` with arguments `Arguments`", 
      "MessageParameters" -> <|"Method" -> method, "UserData" -> userdata, "Function" -> func, "Arguments" -> {args}|>|>]

Now if you re-evaluate our tests, you'll see a Failure object for one of them. For testing purposes, we might want some helpers.

TestAuthPass[___] := True;
TestAuthFail[___] := False;

And we can write our tests like this:

RequireAuth[TestAuthPass, {"name", "password"}][Sin][0]

RequireAuth[TestAuthFail, {"name", "password"}][Sin][0]

Now, wherever you're using a domain-specific function (say Abc) that you want to guard with authentication, you just replace that symbol with RequireAuth[...auth stuff...][Abc]. Of course, there are programmatic ways to do that also.

This is really intended to demonstrate a general strategy. Without knowing any more context, I don't really expect my exact implementation here to work perfectly for you.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.