My roles are something like SEND_SMS_100, SEND_SMS_200 or more in general SEND_SMS_X where X is an integer. It's the maximum number of small text message that an user can send over a month. An user should have at max one of this role. I'm looking for:
ensure SEND_SMS_X is granted
extract X integer
AFAIK this will not support regular expression based search:
$this->get('security.context')->isGranted($roleName);
I think this is bad design - this shouldn't be something that is controlled by roles.
You should probably have a $smsPerMonth property on your user entity so you can call getSmsPerMonth() instead of using many different roles to figure out how many SMS messages a user can send.
Related
I have a situation where a user can create a doc and then share it with a group of other users. They could share it to multiple different groups. I don't know how to set a rule for this.
Here is the database structure:
So in the group you have a list of docs that have been shared to it. My app loads the group that a user is in, then wants to load all the docs in the documents array. I need a way server side to say that this is OK. Up until now only the owner of the doc can read it.
I put a field in each doc that contains ids for each group its shared to. I think I want to say "check if the user is a member of any groups in the sharedToGroups" list but I can't work out how to do that unless I maintain another list somewhere say in the userProfile doc that has a list of circles the user is a member of. Even then I'd be trying to compare 2 lists and I'm not sure I can do that client side.
It would be nice to be able to get the group Id somehow from where the request is being issued from and just see if that is in the sharedToGroups array.
Any help or comments on how this can be achieved would be greatly appreciated, maybe it needs a different db structure.
You can try an approach of this sort:
I am not sure if this will help you but off the top of my head maybe you could enable permissions on firestore for the group document. As in, in the rules, for the group set up a function that validates the user with the user ID stored in the document with the ID attached in the auth via the firebase auth
Therefore, rather than trying to restrict access per document, restrict access per group.
I'm going to answer my own question. Not sure if its the correct protocol here (not a professional programmer or experienced Stack Overflower) but it might help someone.
I ended up adding a field in the user_profiles document that has a list of each group they are in. This list needs to be maintained as I create and add / remove people from groups along with the members list in the group itself.
The benefit of this is that I can use the users id from the request object to get that document from the data base in the security rule. I then have a 'sharedToGroup' array in the doc I'm trying to access and a "inGroups" array in the user_profile that I can access also. Then I use the hasAny operator to compare the two arrays and allow access if the sharedToGroup array has any values from the inGroups array.
My rule becomes:
match /_group/{groupId}{
allow create: if isSignedIn();
allow read: if isOwner()
|| resource.data.sharedToGroup.hasAny(get(/databases/$(database)/documents/user_profiles/$(request.auth.uid)).data['inGroups']);
allow write: if isOwner();
}
Only thing left to do is to secure the user_profiles doc to make sure not even the user can write to it since I don't want someone manually adding groups into their array.
I hope this might help someone someday - like I said I'm a not a pro here so take it with a grain of salt.
When users sign up in my app (with accounts-ui) I ask for three mandatory fields: username, email and pwd. I'm looking for a way to allow users to sign In with only two fields: Email and password (not username/email and pwd as default) but always asking for username in sign up (Usernames could be duplicates between users).
There is a way to do that with accounts-ui? The reason is pretty obvious, as facebook do, I need to allow the creation of different accounts with the same name, but not with the same email.
As workaround I have installed a package to add the additional field to sign Up (selaias:accounts-entry) and customize the sign in / sign up forms but the additional field (username) is shown below the password which looks awkward. I wonder if meteor accounts should have a natural option to do the explained at begin.
Option 1
Pass passwordSignupFields:'EMAIL_ONLY' to Accounts.ui.config
Option 2
Part 1: Pass a custom validation method to Accounts.validateNewUser so duplicate usernames are allowed.
Part 2:
the additional field (username) is shown below the password which looks awkward.
Hide it with a CSS hack
I am using forms authentication and need to get a list of users that have a certain role and have a certain value in a certain profile property. The way I am doing this is to call Membership.GetAllUsers and then looping through them and checking the roles and profile. Is there a better way to do this in 1 call so that I don't have to get all users back and iterate?
Thanks,
Sachin
You may use GetUsersInRole() method.
string []users=System.Web.Security.Roles.GetUsersInRole("role");
You might want to replace Membership.GetAllUsers with Roles.GetUsersInRole(string roleName) - at least you'll have less entries to check for your custom field value.
The MSDN documentation isn't precise on this point.
It says in one place: "Gets a collection of membership users where the user name contains the specified user name to match."
Later it says, "FindUsersByName returns a list of membership users where the user name matches the supplied usernameToMatch for the configured applicationName."
The SQLMembershipProvider supports wildcards, but the documentation doesn't say whether I must also do so with my custom membership provider.
Edit: I'm really asking more about the intent of the Membership Provider rather than what I should do in my specific situation.
The FindUsersByName function will do a match on the string you pass in.
If you want it to do a partial match then you need to add '%' on the end of the string you're searching for.
This sentence in the documentation explains it:
The SqlMembershipProvider performs its search using a LIKE clause against the usernameToMatch parameter. Any wildcards that are supported by SQL Server in LIKE clauses can be used in the usernameToMatch parameter value.
SO
"Gets a collection of membership users where the user name contains the specified user name to match."
is the accurate sentence if you do a search for "DAV*" you should get "Dave", "David, "Davis", etc.
Let's make it more restrictive (find exact match) to be sure that user 'joe' has no access to data of the user 'joel' :)
Anyway, do you really need to find a user given only part of it's name?
EDIT:
Now checked again the MSDN method you linked to, and it's name is FindUsersByName (users, not user) so the method is able to return more than one user. It this case I assume you should implement the code to return all matches.
If the method would be FindUserByName, then it is the opposite answer (you have the method GetUser for this)
I have an .aspx form with 20 fields that must be disable based on a users role and a status of a order record. Currently the application has 5 roles and 3 status, so I have 300 different possible conditions that I have to account for.
My first thought is to store each permutation in a table, then set the fields when the page loads by looping through the fields. Is there a better way? Please note, I am using .Net 2.0 and NOT MVC.
I'd probably store the details of each field, and then the roles and status that can edit them, and do it that way.
What are the rules for the system? Basically, are there really 300 possible conditions? Or is that really certain fields are only editable for certain status, and then only certain roles can edit those fields? Or is it that certain fields are available for certain roles as well?
If it's more of the former I'd probably have something like this:
Three primary tables (makes it easy to extend if you add a field, role or status):
Fields
Roles
Status
Then two link tables:
Field.Id and Role.Id
Field.Id and Status.Id
Then for any given order and user you can then find which Fields are editable for the order's current status, and the users role, and as you work through the fields set the access rights appropriately - however you set the controls - either dynamically generating them based on the collection you get back, or statically on the page.
If you have an issue where the Role can override the Status, you could also store a boolean in the Field/Role table, indicating whether the Field should be avaiable regardless of status.
Like another responder, we also use a Business Object framework called CSLA. CSLA implements field-level security checks by requiring class developers to do security checks in the property get/set calls. A typical property implementation looks like this:
Private mFirstName As String = ""
Public Property FirstName() As String
<System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _
Get
CanReadProperty("FirstName", True)
Return mFirstName
End Get
<System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _
Set(ByVal value As String)
CanWriteProperty("FirstName", True)
If value Is Nothing Then value = ""
If Not mFirstName.Equals(value) Then
mFirstName = value
PropertyHasChanged("FirstName")
End If
End Set
End Property
Notice the calls to CanReadProperty and CanWriteProperty. The second parameter specifies that the method should throw an exception if the user is not authorized to perform the specific read/write operation.
The implementation of the CanReadProperty and CanWriteProperty are provided by the framework's base class but should be reproducible without adopting the entire CSLA framework. The implementations check an AuthorizationRules data structure which defines who is allowed/denied Read/Write access based on roles. Often, the AuthorizationRules structure is populated during object creation.
Exposing the same CanReadProperty and CanWriteProperty methods to your presentation-tier allows you to enable/disable UI elements based on the current user's access rights. For example:
FirstNameTextBox.ReadOnly = Not CanWriteProperty("FirstName", false)
Hopefully this information will provide you with a good starting point for developing your own implementation. If you're interested in learning more about CSLA then check out Expert C# 2008 Business Objects.
I suggest to use third party framework to achieve this. We use CSLA framework in our projects. It allow us to set authorization at field level.