How can I Retrieve a UserRole with Valence query - desire2learn

Is there some way that I can retrieve the roleId of the current user context regardless of that user's role permissions within the LMS?
For example, I would like to programatically determine if a user is a 'student', 'teacher', etc. I know this can be done if the authenticated user has access to user roles but obviously a 'student' role would not possess such credentials.
Any insight into this matter would be greatly appreciated!

With many organizations the assigned role of a user's enrolment is considered sensitive information by the organization (for example, imagine the case where the organization wants to set up multiple roles for particular pay grades of instructors), and does not want the roles to be visible outside a small group of administrative users. Accordingly, there may not be a reliable way for a users to determine their own roleIds assigned to them within an organization unit (course, department, faculty, and so forth), let alone the roles assigned to other users.
Our typical recommendation is that client applications focus first on attempting actions that a user should be able to accomplish based on their access in the webUI: in some cases, this could involve a user characterizing their own general role in a context ("Are you a student in this course? An instructor? A Teaching Assistant?") or it could involve simply attempting actions and gracefully taking action based on results ("I'm sorry, you don't have permission to do/see that").
The various API calls that return an Enrollment.OrgUnitUser structure will contain role information for enrollments; notably the MyEnrollments API call does not return such a structure (it's intention was to be a "safe" call that any user could make to fetch back the list of their own enrollments with potentially privileged information redacted).

Related

How to remember the organization a user is logged in for? Switching between organizations

Background:
User and Organization have a many-to-many relationship through Relationship. So a user can be part of multiple organizations.
But a user can only be logged in for 1 organization.
Therefore the user has a screen where he can switch between the organizations he belongs to.
Also, user has a default organization, which is the organization the user initially logs in for. This is implemented using a has-one through relationship.
How to know/remember which organization a user is currently logged in for?
Now I'm a bit in a pickle how to implement how the app should know/remember which organization a user is currently logged in for. I see three options and am hoping for advice which should work best:
An additional column in the User db that stores the id of the organization (or relationship?) for which the user currently is logged in. A helper method logged_in_for could then find the organization based on the value in that column and return the organization the user is logged in for. Implementation using a db column also enables validation so that a user can't set the organization it is logged in for to an organization it is not even part of.
Use a cookie: session[:logged_in_for] that defines/sets the organization the user is currently logged in for. However, 1) I have doubts whether this is secure (not sure why), 2) I think the first option facilitates validation better, 3) I also don't think this would work in combination with the log in "remember me" option?
Implement an additional has-one through relationship that defines the organization a user is logged in for. This is basically an extension of the first option that adds a relationship. Since I already have so many relationships I don't prefer this option. Or is there no way around this addition for the first option?
Is the first option indeed an effective way to know/remember which organization a user is currently logged in for?
It really depends on which experience you're looking to create for the end user. In your cases:
This will allow remembering of organization between logins, which in your application, can be useful or complete non-sense. If indeed it's useful to remember an organization (i.e, the logistics of user choosing an organization after login is non-frequent), then this could create a better user experience.
session is secure, and you can use it like a hash and it would not collide with other features in your app (unless you use the same key). This case is suited for your application when user should always choose an organization after login, and thus it should be session based.
Ref: http://guides.rubyonrails.org/security.html
Like you mentioned, this is non-ideal, as you already know.
You can store the information in sessions hash, but not use cookie store, instead use Active Record store

Getting List of All Instructor Enrollments

I've been using /d2l/api/lp/1.4/enrollments/myenrollments/ to get a list of enrollments for the current user. Now, I want to just get the enrollments where the user is in an instructor role. So, I'm trying to use:
/d2l/api/lp/1.4/enrollments/users/{userId}/orgUnits/?roleId=105
When I use that, I get an empty list of Items back, with or without the roleId specified.
My expectation is that just calling it without the roleId would return the same list as /d2l/api/lp/1.4/enrollments/myenrollments/. But, I always get an empty list, except when I log in as a system administrator. Only in that case do I get anything back.
Does anyone have any suggestions on what I might be doing wrong?
The various my* API calls specifically exist to provide end users to fetch back details about the system that they should know, but segregated from information they shouldn't (that's available through the more general routes for a particular area). Enrollments is a good example of this. And end-user should be able to see their own enrollments, but they should not have generalized access to enrollment records. In particular, the D2L system treats the D2L user role belonging to an enrollment as fairly privileged information, and a side effect of this is that it's not generally visible to end users.
One way that applications and services can cope with achieving goals that the end-user cannot themselves perform is to have set up a "service account" that the app can use to make calls of an administrative nature, to fetch back data that they can use in the business logic around presenting information to end users. In this particular case, you could, for example use the service account to make calls about a user's enrollments, and then present the user with logic that could filter the list of their enrollments by "these are the student ones, and these are the ones where you're a teacher, and a tutor, and so forth".
But you'd also need to carefully consider the implications of this type of activity in balance against the intentions of the client LMS's policies and administration. Even this level of information may be giving away too much to end users, in the eyes of a client LMS administrator.
Using a service account to let an app make administrative level calls must always be done with great care around the issue of information/functional leakage to end users.

Separate Users class [Parse]

I'm building an app that users have to register before they can view the content, I am using Parse for my database needs.
What I need is have a class of Users (Parse.User) for regular users and a class of Users (Parse.User) for admins. The regular users would only be able to access the app, the admins would only be able to access an admin website where they will add the content (products) that will show up in the app.
Is it possible to create 2 different classes of Users with Parse? Or should I create the admin user class manually (not using Parse.User)?
Thanks for the help! I'm pretty new at this databases and user thing haha
What you really want is to create a Role for Administrators. You can assign ACL permissions to this Role and it will be respected throughout Parse. As you add/remove Users from this Role they automatically have the permissions of their current Role(s).
You can read more about Roles in the documentation, there's a whole chapter about it.
I'm fairly certain that you can't create 2 different User classes. (Though I may be wrong.)
But regardless, the easiest way to do this would probably be to keep all the users in the same class and just add an admin boolean key to indicate whether or not the user is an administrator; then log the user in (to access the current user's keys) but only proceed with the actions following a successful app login if the admin value is set to false and, likewise, only proceed with the actions following a successful website login if the admin value is set to true. If the admin value indicates that the user shouldn't be logged in on that platform, don't proceed with the login and instead log the user out.
In my App, a user can take on more than one role. My solution to this is to have a User class and then a pointer for each type of user (could be a regular object pointer, but I use something similar). So there would be an "adminLink" pointing to the Admin role-specific object and a userLink pointing to the user role-specific object. The pointer designates the object containing the attributes relevant to that role (user or admin). Attributes common to all roles are stored in the User object.
"Roles" (capital R) are needed to control access to objects. So for each User, you may need to create a user Role and an Admin Role if the person performs both roles (small r). You have to have a reference for each Role. These can be stored either with the User object in separate attributes or in the role-specific user objects.
-Bob

No result returned using Valence API desire2learn

I'm working on migrating from SOAP to valence API. I'm having some problems with a few calls like getting users (All users, based on role, by userID, etc) and grades (All variations).
I see an empty list returned with no items. There's no error of any kind. When I try to get the data using SOAP, I get the desired data.
I've checked the permissions for "Search for Students", so technically, I should be getting something when I try to get all users or by role id of students. What else am I missing here...
The D2LWS service's authentication mechanism puts the API caller in the position of being a privileged caller. The Valence Learning Framework APIs use a different auth model: the user ID/Key tokens that identify a user get employed by the back-end to restrict the functionality of calls. That is: the authenticated user should have access to the same functionality and data as the user would get through the web UI, and no more.
In this particular case, the calls succeed: they send back all the elements in the result set that your calling user has privileges to see -- none of them.
This is almost certainly an issue with the role privileges afforded to your calling user, and debugging the permissions around calls can be challenging. The Valence project's documentation provides a walkthrough topic on investigating role permissions that might shed let on a possible approach here, especially with respect to the calls to gain access to user records (or properties that appear in user records).
As the walkthrough discusses, there are various aspects to making the general call to /d2l/api/lp/{version}/users/ that bring permissions into play:
If you're trying to filter with a query parameter, does the calling user context have permissions to use the data on which you want to filter
Does the calling user context have permission to see properties affected by User Information Privacy settings
Does the calling user have permission to search for all the user roles they need to, in order find users in the result set
The users call operates on the root organization unit, so the permissions the calling user requires must be set on the organization org unit type.
By contrast, the Grades-related API calls operate not on the root organization unit, but typically on course offerings, sections, or groups. The permissions surrounding the calls there will get checked in the associated org unit types, so the calling user will need the right permissions against those types. Additionally, many of the calls related to course offerings (also sections and groups) require that the calling user be enrolled in the org unit in question (and in some cases, explicitly enrolled, not merely enrolled by cascading enrollment).
If you're sure that your calling user context does give you access to these things (and allows you access to this data through the web UI), and you still see a mismatch like this when you're calling through the API, then you may have uncovered a defect of some kind and you should please ask your organization's support contact, or your account manager, to open a support ticket to report that through Desire2Learn's support desk.

Group permissions for a website using spring security - design query

I am creating a Grails website where users will have access to the resources they create. Till here everything is clear to me. I define ROLE_USER and lock down my controllers and actions using the Config.groovy file.
The issue I am facing is that I have requirement to support group of users such that some resources created by a user can be edited/updated/deleted by other users of the same group. How do I associate a user with a "group" in spring security, what is the design/library I should use here?
What you will need to do is to have your users' roles (the authorizations) come from the database. Once that is the case, you can then easily adjust the roles a user (or set of users) has and create/remove them on the fly. The docs have some pretty good info on how to get the roles to come from the database, so I won't go any more into that here.
Once the dynamic roles are in place, however, you still need to be able to connect roles to the objects that are created. There are essentially two ways you can go about doing this:
Access Control Lists
Custom logic
Depending on the granularity you need and the flexibility you want, one option may be more appealing than another.
Access Control Lists essentially allow you to have a permission mapping between each user and each entity instance. As you can imagine, it's a fair bit of overhead and can perform poorly if you have a large number of entities and users.
Putting together your own logic, on the other hand, is much more flexible because you can set up your own scheme to connect entity instances or entity classes to users and their roles.
I dont think that spring-security provides such functionality out of the box so you will have to do that manually.
For each domain class that you this kind of functionality, store the user name of current logged in user
def authenticateService
def user = authenticateService.principal()
entity.setUser(user?.getUsername())
Then in the update/delete method of the contoller you should check if the role of the current logged in user matches
the role of the user that created the entity. If you have a match you should proceed with the update/delete otherwise throw an exception
/redirect the user to an error page
As role you can use the spring security roles or you can create a property on the user object you have created

Resources