Transforming a claim using multiple match RegEx - adfs

I'm working on connecting our on prem AD with AWS by following this article. We have our AD Groups that are to be translated into AWS groups written in the format AWS#Account#Role#AccountNumber in AD. In ADFS, I am writing a custom claim that is to take that particular claim and convert it to the arn that requires the role and account number that is defined in teh AD Group name. I was hoping to use a RegExReplace with a match type of ((?i)([-_a-z0-9]+) which should accurately give me multiple matches back from the incoming token.
My question is, is there a way that I can use the multiple matches generated there to generate one string ("arn:aws:iam::saml-provider/ADFS,arn:aws:iam::role/")that leverages the multiple matches to generate the AWS format I need?
I dont normally work with ADFS but this is something I was tasked to figure out and any help would be greatly appreciated.

In my Roles rule (executes after the gathering of AD Groups rule), I updated my claims rule language transform to:
c:[Type=="http://temp/variable",
Value=~"(?i)(^AWS)#([-_a-z0-9]+)#([-_a-z0-9]+)#([-_a-z0-9]+)"] =>
issue(Type="https://aws.amazon.com/SAML/Attributes/Role",
Value=RegExReplace(c.Value,
"(?i)(^AWS)#(?<accountname>[-_a-z0-9]+)#(?<role>[-_a-z0-9]+)#(?<accountnumber>[-a-z0-9]+)",
"arn:aws:iam:${accountnumber}:saml-provider/ADFS,arn:aws:iam:${accountnumber}:role/${role}))
This basically says, for any AD Group that was added the to the temp variable and matches this regex, issue a claim of this type. In the RegExReplace, I assigned variable names to the grouping matches and then accessed those matches using the ${} syntax. This did the trick and now I see the list of roles in the arn format.

Related

Firebase: How to handle users with same displayNames when they sign up with Google Provider?

I have an app where people can sign up for user accounts. They can use their Google account or sign up using email/password. I am storing the user's displayName in Firestore so I can reference it throughout the app as their username.
However, there is a problem:
Let's say "John Doe" signs up for a user account on my app and he uses his Google account named johndoe#gmail.com. His Google account's display name is also "John Doe". However, a few days later, another with the same name "John Doe" signs up for a user account, and although his Google account email may be different (let's say, johndoe2#gmail.com), his display name is still the same. Now, I have 2 users in my app with the same display name "John Doe". This causes an issue when I am trying to create user name routes such as: https://myapp.com/JohnDoe and handling user profile lookups.
What is the recommended way to allow users to use their Google accounts if there are other users that may have the same display names? The catch is I don't want to store UIDs in the URL as I want it to be clean with just the displayName.
The catch is I don't want to store UIDs in the URL as I want it to be clean with just the displayName.
It might be clean, as long as the number of characters within the displayName is reasonable. In your example, "John Doe", contains only 8 characters, including the whitespace character between the names, which is fine. But I've seen so many examples of names that are larger than 28, the number of characters that exist in a UID. Since the displayName property is set within the Google account and it can be changed only by the user, you're having three solutions left.
The first one would be to create your own mechanism for setting specific user names into your application. These user names can be set especially by the users. It can be the same as the names in the Google account or not. However, when someone chooses "JohnDoe" and a second user wants to set the same user name, it won't be possible, since a "JohnDoe" is already present. So before setting a new user name, you should always check if that one is already present. You can do that because it's something that you control. When using Firestore, this can be simply done by using:
db.collection("users").whereEqualTo("userName", "JohnDoe");
Or when using the Realtime Database:
db.child("users").orderByChild("userName").equalTo("JohnDoe");
Now, the first "John Doe" will have a profile that looks like this:
https://myapp.com/JohnDoe
While the second one might have something like this:
https://myapp.com/John_Doe
See the underscore? This kind of mechanism is very widely used. Facebook, Instagram, Twitter, eBay, Reddit, and many more do that:
https://www.facebook.com/JohnDoe/
https://www.instagram.com/JohnDoe/
https://twitter.com/JohnDoe/
https://www.ebay.com/usr/JohnDoe/
https://www.reddit.com/user/JohnDoe/
The second one would be to ignore the user names and use only the UIDs that come from the authentication process. Case in which, your URL will look like this:
https://myapp.com/TwentyEightCharactersLong
That's not unusual, since other big apps use it:
https://www.imdb.com/user/$userId/
The third one would be to create a combination between the UID and the user name. The best example would be Stackoverflow:
https://stackoverflow.com/users/$userId/$userName/
// ^ ^
Or LinkedIn:
https://www.linkedin.com/in/$userName-$userId/
// ^ ^
Doesn't matter which solution will you apply, you'll always have unique URLs. But it's up to you to choose which one of these solutions seems more clear to you.
It's quite common to see URLs suffixed with some random number or combination of alphanumeric characters like john-doe-1 and so on. That being said you would have to implement logic for this yourself maybe using Firebase Auth Triggers for Cloud Functions which will run whenever a new user is created and you can add an URL for their name.
You could also add some random string like /users/john-doe-qwerty and maybe add a paid feature that allows user to set their own URLs (if applicable for your application) i.e. vanity URLs.
I recently had this issue too, after playing around with 2 separate Google Play accounts, I found that the user.UserId is static and unique, and while the user.DisplayName can be changed, display names are unique.
Therefore, you should be safe storing data under UserId and then grabbing their current display name on login. Alternatively, to match your wants, you can save the data under the display name but you might want to track their user identification code in case they change their display name (if you wish to accommodate that)

Firestore Security Rules Shared Document by Group

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.

Riak and index - how to check the index a particular bucket has?

I am very much new to riak and I am currently using it with an API. So, let me explain my scenario.
There is an account - say example#riaktest.com created under accounts bucket.
So, on doing
localhost:8098/buckets/accounts/keys?keys=true it returns {{"keys":["example#riaktest.com"]}}
So, i basically have one 'key' with other data fields inside.
Now, I have a functionality that a user can join a particular group. Lets say, 'group1'.
He logs in, joins group1. I give the snowflake generated ID of the account as the index.
Question is:
How do I see a particular key's list of index?
localhost:8098/riak/group/group1 will give me the values and the main account it is tied to.

How to search all groups by specified authority?

For example I have userA which is belong to groupA. How I could search all groups by specified authority?
This code find just all groups what I have
QNAME:"sys:system/sys:authorities/*"
So I want to filter out somehow.
There are services for that, if using java use the AuthorityService: http://dev.alfresco.com/resource/docs/java/repository/org/alfresco/service/cmr/security/AuthorityService.html
In javascript the People API could be sufficient: http://wiki.alfresco.com/wiki/4.0_JavaScript_API#People_API

MVC3 routes - replace id with object name

I'm looking for a fast & elegant way of converting my object IDs with descriptive names, so that my autogenerated routes look like:
/products/oak-table-25x25-3-1
instead of
/products/5bd8c59c-fc37-40c3-bf79-dd30e79b55a5
In this sample:
uid = "5bd8c59c-fc37-40c3-bf79-dd30e79b55a5"
name = "Oak table (25x25) 3/1"
I don't even know how that feature could be named, so that I might google for it.
The problem that I see so far is the uniqueness of that "url-object-name", for example if I have two oak tables 25x35 in the db, and their names differ too little to be uniquely url-named but enough to fool the unique constraint in the db.
I'm thinking of writing that function for name-transform in SQL as an UDF, then adding a calculated field that returns it, then unique-constraining that field.
Is there some more mainstream way of achieving that?
One method is that employed by stackoverflow.com which in your case would be:
/products/5bd8c59c-fc37-40c3-bf79-dd30e79b55a5/oak-table-25x25-3-1
This ensures uniqueness, however the length of the UUID may be a deterrent. You may consider adding a sequential int or bigint identity value to the products table in addition to the uniqueidentifier field. This however would require an additional index on that column for lookup, though a similar index would be required for a Url having only a descritive string. Yet another method would be to use a hash value, seeded by date for instance, which you can compose with the descriptive name. It is simpler to rely on a sequential ID value generated by a database, but if you envision use NoSQL storage mechanisms in the future you may consider using an externally generated hash value to append.
Identity should have 2 properties: it should be unique and unchangable. If you can guarantee, that /products/oak-table-25x25-3-1 will never change to /products/oak-table-25x25-3-1-1 (remember, user can have bookmarks, that shouldn't return 404 statuscode)- you can use name as url parameter and get record by this parameter.
If you can't guarantee uniqueness or want to select record more faster - use next:
/products/123/oak-table-25x25-3-1 - get record by id (123)
/products/123/blablabla - should redirect to first, because blabla no exists or have anoher id
/products/123 - should redirect to first
And try to use more short identities - remember, that at web 2.0 url is a part of UI, and UI should be friendly.
MVC routing (actions) will handle spaces and slashes in a name. It will encode them as %20, and then decode them correctly.
Thus your URL would be /products/oak%20table%2025x25-3%2F1
I have done something very similar in an eCommerce platform I am working on.
The idea is that the URL without the unique ID is better for SEO but we didn't want the unique ID to be the product name that can change often.
The solution was to implement .NET MVC "URL slug only" functionality. The product manager creates "slugs" for every product that are unique and are assigned to products. These link to the product but the product ID and name can be changed whenever.
This allows:
domain.com/oak-table-25x25-3-1
to point to:
/products/5bd8c59c-fc37-40c3-bf79-dd30e79b55a5
(The same functionality can be used on categories too so domain.com/tables can point to domain.com/category/5b38c79c-f837-42c3-bh79-dd405479b15b5)
I have documented how I did this at:
http://makit.net/post/3380143142/dotnet-slug-only-urls

Resources