Can commands be intercepted based on their type? - permissions

In Axon, Command Interceptors seem to intercept any and every command. For permission checking, I need to base my decision on the type of command to see whether it is allowed in the current context.
#Override
public BiFunction<Integer, CommandMessage<?>, CommandMessage<?>> handle(List<? extends CommandMessage<?>> messages) {
return (index, command) -> {
// Check permissions
return command;
};
}
Usually I would prefer to register an interceptor per command type and handle the permission checks in dedicated objects. How would I do it with Axon? Will I need to have a load of instanceof if-statements in a single interceptor? Does anyone have a good example of permission checking with Axon?

At this point (Axon 4.0) the framework does not allow you the option to register DispatchInterceptors per command payload type directly. So what you're suggesting to do, the if-blocks/switch-statements, is the best thing you could do at this point.
Although I am not certain how fine grained your permission checks are, what you could do is have some form of permission annotation on the commands, with a specific value/enum you need to set on it. That way you do not have to tie in your payload type into the dispatcher directly, but could just check if the annotation exists and if so, check it's value for the kind of permission check which should be performed on it.
That would very likely result in a far smaller if-block/switch-statement than checking per payload type.

Related

A custom action that reads the file and stores a value in session obj. Is there a way to use it as a property while invoking othr custom action

<CustomAction I'd=readValue binaryKey = custom.dll
DllEntryy = readfilevalue Execute= deferred Return =
check/>
// // In a .cs file code to read the file having method
// readfilevalue.
// I am setting
Customsession.writesessionvalue(key, value);
// In another .wxs file invoking executables
<Custom Action = someExe After= someOtherExe>
<!CDATA[ key < someValue]>
<Custom>
// Can I get the key value in this Custom tag? If no then
// how can I get the value please suggest.
No, there is very limited information flow between deferred actions (#Execute="deferred") and the shared Windows Installer session. That flow includes sending a few properties to the action (including CustomActionData), and receiving progress information and a success or failure from it, but will not carry arbitrary data like you describe.
Your options, as I see them:
Make the first custom action immediate so it can take part in the planning. This won't work if the action requires elevated privileges, or access to something put in place by another deferred action, but is otherwise the most "correct" way to do this. Note that if the data itself can be read by existing search patterns (like RegistrySearch), that's even better than an immediate custom action.
Merge the two actions, so there isn't any need for such a flow of information.
Use unsupported hacks, like sharing a file location outside of Windows Installer that both actions can access. Then you can send information through that. Note that cleanup of this can be hard to get correct, and that its unsupported nature may result in other problems in esoteric scenarios. (The link about obtaining context information alludes to why.)

Consolidating Code Access Security

Is it possible to consolidate code access security attribute (even if it means imperative method) so I can have something like this in my code?
void WriteToFileAndAccessNetwork()
{
EnterPermission(Perm.File | Perm.Network);
// Do file IO
// Do computation
// Do network operation
LeavePermission(Perm.File | Perm.Network);
}
My program will start with all permissions, but main function will start with zero permission.
I will Assert permission only when I need it in the functions that really need them. I am looking for a easy programmatic construct.
The problem I have is, the FileIOPermission.Assert() I make in EnterPermission() remains valid only within EnterPermission function call. As soon as I exit EnterPermission I lose the permission.
Any other ideas?
I dont want to have a long list of declarative attributes above every method and make my code unreadable.

Deep level access control in DataMapper ORM

Introduction
I'm currently building an access control system in my DataMapper ORM installation (with CodeIgniter 2.*). I have the initial injection of the User's rights (Root/Anonymous layers too) working perfectly. When a User logs in the DataMapper calls that are done in the system will automatically be marked with the Userrights the User has.
So until this point it works perfectly, but now I'm a bit in a bind. The problem is that I need some way to catch and filter each method-call on the Object that is instantiated.
I have two special calls so I can disable the Userrights-checks too. This is particularly handy at the exact moment I want to login a User and need to do initial checks;
DataMapper::disable_userrights();
$this->_user = new User($this->session->userdata('_user_id'));
$this->_userrights = ($this->_user ? $this->_user->userrights(TRUE) : NULL);
DataMapper::enable_userrights();
The above makes sure I can do the initial User (and it's Userrights) injection. Inside the DataMapper library I use the $CI =& get_instance(); to access the _ globals I use. The general rule in this installment I'm building is that $this->_ is reserved for a "globals" system that always gets loaded (or can sometimes be NULL/FALSE) so I can easily access information that's almost always required on each page/call.
Details
Ok, so image the above my logged-in User has the Userrights: Create/Read/Update on the User Entity. So now if I call a simple:
$test = new User();
$test->get_where('name', 'Allendar');
The $_rights Array inside the DataMapper instance will know that the current logged-in User is allowed to perform certain tasks on "this" instance;
protected $_rights = array(
'Create' => TRUE,
'Read' => TRUE,
'Update' => TRUE,
'Delete' => FALSE,
);
The issue
Now comes my problem. I want to control these Userrights by validating them over each action that is performed. I have the following ideas;
Super redundant; make a global validation method that is executed at the start of each other method in the DataMapper Class.
Problem 1: I have to spam the whole DataMapper Class with the same calls
Problem 2: I have no control over DataMapper extension methods
Problem 3: How to detect relational includes? They should be validated too
Low level binding on certain Core DataMapper calls where I can clearly detect what kind of action is executed on the database (C/R/U/D).
So I'm aiming for Option 2 (and 1.) Problem 2), as it will also solve 1.) Problem 2.
The problem is that DataMapper is so massive and it's pretty complex to discern what actually happens when on it's deepest calling level. Furthermore it looks like all methods are very scattered and hardly ever use each other ($this->get() is often not used to do an eventual call to get a dataset).
So my goal is:
User (logged-in, Anonymous, Root) makes a DataMapper istance
$user_test = new User;
User wants to get $user-test (Read)
$user_test->get(1);
DataMapper will validate the actual call that is done at the database
IF it is only SELECT; OK
IF something else than SELECT (or JOINs to other Model that the User doesn't have access to that/those Models, it will fail with a clear error message)
IF JOINed Models also validate; OK
Return the actual instance;
IF OK: continue DataMapper's normal workflow
IF not OK: inform the User and return the normal empty DataMapper instance of that Model
Furthermore, for this system I think I will need to add some customization for the raw_sql (etc.) SQL calls so that I have to inject the rights manually related to that SQL statement or only allow the Root User to do those things.
Recap
I'm curious if someone ever attempted something like this in DataMapper or has some hints how I can use/intercept those lowest level calls in DataMapper.
If I can get some clearance on the deepest level of DataMapper's actual final query-call I can probably get a long way myself too.
I would like to suggest not to do this in Datamapper itself (mainly due to the complexity of the code, as you have already noticed yourself).
Instead, use a base model, and have that extend Datamapper. Then add the code to the base model required for your ACL checks, and then overload every Datamapper method that needs an ACL check. Have it call your ACL, deal with an access denied, and if access is granted, simply return the result of parent::method();.
Instead of extending Datamapper, your application models should then extend this base model, so they will inherit the ACL features.

State-machine workflow in youtrack - restrict state changes for certain roles

I have created a simple state-machine workflow in youtrack to reflect our process. It uses three State values (Submitted, In Progress, Fixed) and allows to move through them sequentially.
Is it possible to restrict certain state changes for specific roles? For example role Reporter should only be able to create issue and move from 'Fixed' to 'In Progress' if something is wrong.
UPDATE:
An even better way to do this task is the following right inside the Statemachine:
initial state Submitted {
on Approve[always] do {
assert loggedInUser.hasRole("Project Admin"): "Only Project Admins can Approve tasks.";
} transit to Open
}
OLD ANSWER:
Straighforward way (inside the Statemachine itself):
initial state Submitted {
on Approve[loggedInUser.hasRole("Project Admin")] do {<define statements>} transit to Open
}
Althought it will work, it will fail silently, so user will not know why does it not work.
A much better approach will look like the following (for this you will have to create Stateless Rule):
when State.oldValue == {Submitted} && State.becomes({Open}) {
assert loggedInUser.hasRole("Project Admin"): "Only Project Admins can Approve tasks.";
}
In this case user will get an error message that you specify.
Remember to delete the condition in the Statemachine, since it is checked earlier and you will not have any error messages as assertion will not run at all.
A pretty old question, but I'll try to answer.
You can specify a guard expression that will be invoked upon transition to/from a specific state. In this expression you can validate user permissions.

How to get tcmid of currently logged user in Tridion?

private void Subscribe()
{
EventSystem.Subscribe<User, LoadEventArgs>(GetInfo, EventPhases.Initiated);
}
public void GetInfo(User user, LoadEventArgs args, EventPhases phase)
{
TcmUri id = user.Id;
string name = user.Title;
Console.WriteLine(id.ToString());
Console.WriteLine(name);
}
I wrote above code and add the assembly in config file in Tridion server but no console window is coming on login of a user
The event you were initially subscribing to is the processed phase of any identifiable object with any of its actions, that will trigger basically on every transaction happening in the SDL Tridion CMS, so it won't give you any indication of when a user logs in (it's basically everything which happens all the time).
Probably one of the first things which is happening after a user logs in, is that its user info and application data is read. So what you should try is something along the lines of:
private void Subscribe()
{
EventSystem.Subscribe<User, LoadEventArgs>(GetInfo, EventPhases.Initiated);
}
public void GetInfo(User user, LoadEventArgs args, EventPhases phase)
{
TcmUri id = user.Id;
string name = user.Title;
}
But do keep in mind that this will also be triggered by other actions, things like viewing history, checking publish transactions and possibly a lot more. I don't know how you can distinguish this action to be part of a user login, since there isn't an event triggered specifically for that.
You might want to check out if you can find anything specific for a login in the LoadEventArgs for instance in its ContextVariables, EventStack, FormerLoadState or LoadFlags.
Edit:
Please note that the Event System is running inside the SDL Tridion core, so you won't ever see a console window popup from anywhere. If you want to log information, you can include the following using statement:
using Tridion.Logging;
After adding a reference to the Tridion.Logging.dll which you can find in your ..\Tridion\bin\client directory. Then you can use the following logging statement in your code:
Logger.Write("message", "name", LoggingCategory.General, TraceEventType.Information);
Which you will find back in your Tridion Event log (provided you have set the logging level to show information messages too).
But probably the best option here is to just debug your event system, so you can directly inspect your object when the event is triggered. Here you can find a nice blog article about how to setup debugging of your event system.
If you want to get the TCM URI of the current user, you can do so in a number of ways.
I would recommend one of these:
Using the Core Service, call GetCurrentUser and read the Id property.
Using TOM.NET, read the User.Id property of the current Session.
It looks like you want #2 in this case as your code is in the event system.