How to implement IAuthorizationServiceEventHandler in Orchard CMS? - authentication

I have difficulties with the implementation of IAuthorizationServiceEventHandler in Orchard CMS.
The issue here is that i want to check for specific permissions (permissions defined by my module) but the parameters of the handler methods (type Orchard.Security.CheckAccessContext) do not provide the feature name of the permission being checked.
Why is that so or is this a bug?
Surely i can name my permission like MyModuleName.PermissionName or use another type of name encoding but i think this is not practical as we already have the feature name linked to the permission in the DB for example.

Hmm, after reconsidering my approach and watching the call stack the issue is no more an issue.
My question was based on the thinking that i need to compare aContext.Permission.Name provided by e.g. IAuthorizationServiceEventHandler.Complete() with the permission names of my module.
But since the instance aContext.Permission provided by by e.g. IAuthorizationServiceEventHandler.Complete() is the instance passed to the related IAuthorizationService.TryCheckAccess() call i can do a simple comparison like
if (aContext.Permission == MyModule.Permission.PermissionA) { ... }
and it works because both instances have the same pointer address.

Related

How to organize endpoints when using FeathersJS's seemingly restrictive api methods?

I'm trying to figure out if FeathersJS suits my needs. I have looked at several examples and use cases. FeathersJS uses a set of request methods : find, get, create, update, patch and delete. No other methods let alone custom methods can be implemented and used, as confirmed on this other SO post..
Let's imagine this application where users can save their app settings. Careless of following method conventions, I would create an endpoint describing the action that is performed by the user. In this case, we could have, for instance: /saveSettings. Knowing there won't be any setting-finding, -creation, -updating (only some -patching) or -deleting. I might also need a /getSettings route.
My question is: can every action be reduced down to these request methods? To me, these actions are strongly bound to a specific collection/model. Sometimes, we need to create actions that are not bound to a single collection and could potentially interact with more than one collection/model.
For this example, I'm guessing it would be translated in FeathersJS with a service named Setting which would hold two methods: get() and a patch().
If that is the correct approach, it looks to me as if this solution is more server-oriented than client-oriented in the sense that we have to know, client-side, what underlying collection is going to get changed or affected. It feels like we are losing some level of freedom by not having some kind of routing between endpoints and services (like we have in vanilla ExpressJS).
Here's another example: I have a game character that can skill-up. When the user decides to skill-up a particular skill, a request is sent to the server. This endpoint can look like POST: /skillUp What would it be in FeathersJS? by implementing SkillUpService#create?
I hope you get the issue I'm trying to highlight here. Do you have some ideas to share or recommendations on how to organize the API in this particular framework?
I'm not an expert of featherJs, but if you build your database and models with a good logic,
these methods are all you need :
for the settings example, saveSettings corresponds to setting.patch({options}) so to the route settings/:id?options (method PATCH) since the user already has some default settings (created whith the user). getSetting would correspond to setting.find(query)
To create the user AND the settings, I guess you have a method to call setting.create({defaultOptions}) when the user CREATE route is called. This would be the right way.
for the skillUp route, depends on the conception of your database, but I guess it would be something like a table that gives you the level/skills/character, so you need a service for this specific table and to call skillLevel.patch({character, level})
In addition to the correct answer that #gui3 has already given, it is probably worth pointing out that Feathers is intentionally restricting in order to help you create RESTful APIs which focus on resources (data) and a known set of methods you can execute on them.
Aside from the answer you linked, this is also explained in more detail in the FAQ and an introduction to REST API design and why Feathers does what it does can be found in this article: Design patterns for modern web APIs. These are best practises that helped scale the internet (specifically the HTTP protocol) to what it is today and can work really well for creating APIs. If you still want to use the routes you are suggesting (which a not RESTful) then Feathers is not the right tool for the job.
One strategy you may want to consider is using a request parameter in a POST body such as { "action": "type" } and use a switch statement to conditionally perform the desired action. An example of this strategy is discussed in this tutorial.

Check original language of repository objects at creation?

In our company, repository objects must be created with original language EN.
Is there a way to check the logon language in case of creating a new object in the ABAP repository?
Desired behaviour:
SE80 - Create program/class/data element/table/....
==> user exit/badi checks the logon language. When it is not 'EN', the creation will be refused.
regards,
Umar Abdullah
I know there is a exit for this but I haven't remember exact name. You can use general purpose for finding exit. Go to SE24 and open CL_EXITHANDLER class, find GET_INSTANCE method and add break point. Then start creating item, it will pause on debugger multiple times, try to find suitable one.
As #mkysoft suggested, you may implement a check in the BAdI CTS_REQUEST_CHECK, method CHECK_BEFORE_ADD_OBJECTS, which is invoked when the object is about to be attached to a transport request. Raise the exception CANCEL to make the attachment fail (and so the object is not created too).
EDIT: sorry, ignore my answer, "this method is NOT released for Customer usage" as said in note 2150125 - Method CHECK_BEFORE_ADD_OBJECTS not triggered
DISCLAIMER: THE METHOD DESCRIBED HERE IS ABSOLUTELY NOT RECOMMENDED.
As correctly pointed out by the other members there is no standard and customer-exposed method to achieve your requirement, but if you absolutely must enable this check during creation you can use the below method. As well as the previously offered to you, it also involves modification of SAP standard.
There is a system BAdi CTS_TADIR_SUBSCREEN that is located inside enhancement point CTS_ES_TADIR_POPUP. They are SAP internal and not released for customer usage, so do this at your own risk.
Implementation procedure:
Step 0. First thing you need to change is a SAP internal usage flag, for which you need Object Access key which can be obtained from SAP or from SAP partner that made the implementation in your org. In virgin state this BAdi throws the error if you try to implement it
So hereinafter we assume that you already ticked off this checkbox in BAdi settings
Step 1.
In order to implement the BAdi one need to implement enhancement spot prior to that. This is the most complicated part, because despite we disabled internality flag the SAP-namespaced enhancements must be stored only in SAP-namespaced objects. By SAP namespace I mean non-Z, non-Y and non-T (Test). This means to implement this enhancement, besides modifying the enhancement definition, one need to create, for example, CTS_ES_TADIR named enh.impl., and save it to non-Z package, which you also need to create. Your enhancement implementations selector should look somehow like this
On the above screen only the second will work, all the rest Z will not.
Every non-Z object need Object Access Key, remember? Too bad. But just to show the proof-of-concept, I will proceed.
Step 2. After you created the enh. implementation in SAP-namespace it will propose you to create the BAdi implementation. The same principle applies here: only SAP-namespaced container for SAP-namespaced objects, hence CTS_TADIR_SUBSCREEN should have implementing class for example CL_TADIR_SUBSCREEN. During the creation of enhancement you will see many warnings
but finally you should have something like this, where all system-named objects are created and the enhancement/BAdi is activated.
Step 3. In order to get the BAdi working we need to enable this subscreen processing
during the playing with enhancement I found out that BAdi class is not being triggered standalone, without screen events not enhanced, so to make it work you need to touch a screen enhancement for screen 100
If you do not wanna modify screen elements logic, just put the dummy enhancement in SHOW_TADIR dialog module in the end of the include LSTRDO18
PROCESS BEFORE OUTPUT.
MODULE SHOW_TADIR. "<-- create the dummy enhancement here
CALL SUBSCREEN subs_info INCLUDING gv_badi_prog gv_badi_dynnr.
for example declaration statement like I did
Step 4. Activate your created BAdi class and put the necessary logic there. I wasn't able to trigger method GET_DATA_FROM_SCREEN, but PUT_DATA_TO_SCREEN worked fine
If we put this simple processing for your requirement
METHOD cts_if_tadir_subscreen~get_data_from_screen.
IF object_data-l_mstlang <> 'E'.
MESSAGE 'Objects in non-English languages are not allowed!' TYPE 'A'.
ENDIF.
ENDMETHOD.
it will not allow creating objects in languages other than English.
The check in method get_data_from_screen is being done before showing the screen so language is determined from system logon settings. If to play more with this BAdi, I suppose the method GET_DATA_FROM_SCREEN can also be enabled, which will make it possible to check user input, i.e. the case when the user gonna change the default language.

List allowed methods while connecting via RFC?

I can connect as user "foo" with password "bar" via SAP-RFC from my machine to the SAP server.
Is introspection possible via SAP-RFC?nI would like to know which methods user "foo" is allowed to execute. I am using PyRFC, but AFAIK this should not matter for this question.
According to user Suncatcher it is not available out of the box.
My SAP knowledge is limited up to now. But wouldn't it be possible to loop like this pseudo code? (This code should run (as ABAP) inside in SAP and could be exposed via RFC)
user = 'foo'
allowed_methods = [] # empty list
for func in get_all_functions_which_are_exported_via_rfc():
if not check_if_user_has_permission_to_call_rfc_function(func, user):
# not allowed
continue
# user is allowed
allowed_methods.append(func)
return allowed_methods
I would like to know which methods user "foo" is allowed to execute.
There is no such entity as method in terms of SAP authorization concept, so you cannot list allowed methods.
You only can get list of assigned roles for your user from the table AGR_USERS (if you have permissions to read it :), and then try to determine which function modules, tcodes, programs you are allowed to call. As we a speaking about RFC, I assume you are interested in function modules.
But the detection of all available RFC-enabled FMs requires separate and not very simple development.
So the answer is NO. You cannot list them out-of-the-box.

Configuration for PowerShell module created via .NET framework

What's the best practice when you have dependencies that you want to be able to configure when creating a PowerShell module in C#?
My specific scenario is that the PowerShell module I am creating via C# code will use a WCF service. Hence, the service's URL must be something that the clients can configure.
Is there a standard approach on this? Or will this be something that must be custom implemented?
A somewhat standard way to do this is to allow a value to be provided as a parameter or default to reading special variable via PSCmdlet's GetVariableValue. This is what the built-in Send-MailMessage cmdlet does. It reads the variable PSEmailServer if no server is provided.
I might not be understanding your question. So I'll posit a few scenarios:
You PS module will always use the same WCF endpoint. In that case you could hardcode the URL in the module
You have a limited number of endpoints to choose from, and there's some algorithm or best practice to associate an endpoint with a particular user, such as the closest geographically, based on the dept or division the user is in, etc.
It's completely up to the end user's preference to choose a URL.
For case #2, I suggest you implement the algorithm/best practice and save the result someplace - as part of the module install.
For case #3, using an environment variable seems reasonable, or a registry setting, or a file in one of the user's profile directories. Probably more important than where you persist the data though, is the interface you give users to change the setting. For example if you used an environment variable, it would be less friendly to tell the user to go to Control Panel, System, Advanced, Environment, User variable, New..., than to provide a simple PS function to change the URL. In fact I'd say providing a cmdlet/function to perform configuration is the closest to a "standard" I can think of.

property qualified-name in method getContentReader

I first apologize for my poor english level and maybe for the stupidity of my question ;)
I am on an alfresco project to learn how it works.
I have to browse programatically my content repository and gather datas all along. In order to do that I guessed I had to use a ContentReader (I get from my ContentService) but the method getReader wants a nodeRef and a propertyQualifiedName.
I am ok with the nodeRef, I get what it's needed for.
But the propertyQualifiedName puzzles me, I barely get what it is but I frankly don't get how it is used.
Reading some alfresco forum threads I get more and more scared that I dont even get how a reader works, I somewhere saw that a reader can read only one node and only one time per instance.
If anyone knows a bit about the Java API for Alfresco Content Repository use I am all hears !
Cheers all !
ContentReader is a wrapper class for the content of a given property of a node. So, in order to get an instance of ContentReader you'll have to give the node from which you the property from and the property qualified name.
As for the qualified name, every node property is identified by the conjunction of two string values:
The property namespace. Usually an uri like "http://www.alfresco.org/model/content/1.0"
The property local name. Usually a simple string like "created".
These two values put together constitute the property qualified name. There are constants defined for most standard properties of the alfresco model in the org.alfresco.model.ContentModel interface. For example, to get the creator of a node you would do something like:
contentService.getReader(myNode, ContentModel.PROP_CREATOR).getContentString();