How do I get an OID claim in ASPCore from Azure B2C - asp.net-core

Why do I want this?
I'm trying to get a unique identifier from my user which I can connect to database records. There are reasons I don't want to use the Email as the identifier. I read that SUB claim isn't supported with B2C, and to use OID in it's place.
Steps I've Taken
So, I've set up that both of my policies return Object ID on Azure B2C:
I'm using individual SignIn and SignUp policies at the moment, and I get all of the claims back, including the email claim which I specified I wanted to be returned. I cannot however find a claim related to OID or SUB.
User.Claims
Nets me the following results:
The single breadcrumb of hope that I have found is this claim:
Type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
Value: Not supported currently. Use oid claim.
Questions
Have I missed some additional step that you need to perform to retrieve this particular claim?
Has anyone had any success retrieving an OID or SUB from Azure B2C?

Well, this is embarrassing, I must have looked over this line about 30 times and not noticed...
I was retrieving the OID token, it's claim type was:
http://schemas.microsoft.com/identity/claims/objectidentifier
As can be clearly seen in my provided screenshots. I'll leave this question up as, the schema may throw someone else off.

I struggled with this for a little while and this post helped me.
To update things with some code, the below will obtain the object identifier value (unique user id in Azure)
User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value
Thanks for pointing out the differences in the schema/types!

If you are using the Microsoft.Identity.Web package there is now a ClaimsPrincipalExtensions class that provides an extension method, so that you can simply use:
// using Microsoft.Identity.Web;
User.GetObjectId();
This uses the oid or http://schemas.microsoft.com/identity/claims/objectidentifier claim.

Since the links above are broken and this is something that I really struggled to find a working example of, here is a code fragment of what I ended up using;
using System.IdentityModel.Tokens.Jwt;
...
string oid;
string pTokenInput = Request.Headers["x-ms-token-aad-id-token"].ToString();
var lJWTHandler = new JwtSecurityTokenHandler();
if (lJWTHandler.CanReadToken(pTokenInput)
{
var lToken = lJWTHandler.ReadJwtToken(pTokenInput);
if (lToken.Payload.ContainsKey("oid"))
oid = lToken.Payload["oid"].ToString();
}
Hopefully, this will help someone else...

It seems that you do not necessarily need object-identifier here.
When debugging, I see that the value of object-identifier is mapped to nameidentifier
Which is accessible with the built-in constant NameIdentifier:
var identity = authState.User.Identity as System.Security.Claims.ClaimsIdentity;
var userId = identity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier).Value;

Related

discord.js - Has role give permission

So basically I am trying to make a ticket sort of discord bot using discord.js.
The concept: someone says +help then it DMs a member, who has said +onduty and has a role of something like "Helper".
I need to work out how to detect the role and add them to a set who are "on duty".
I was wondering if anyone can help me with this.
Many thanks.
The way I do stuff like this in my bot (snipet from my example bot's kick command):
// This command should be limited to staff. In this example we just hardcode the role names.
// Please read up on Array.some() to understand this bit:
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some
if(!message.member.roles.some(r=>["STAFF","Helper"].includes(r.name))) {
return message.reply("Sorry, you don't have permissions to use this!");
}
A little bit of the documentation on this:
https://discord.js.org/#/docs/main/stable/class/Message?scrollTo=member
https://discord.js.org/#/docs/main/stable/class/GuildMember?scrollTo=roles
message.member.roles contains a collection of the members roles
we can use .some() to go through them and see if the user has a role
.some(): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some
So to go through all guild members to see if they have helper then, if they also have on duty:
// assuming the Message is in a variable called message
var gm=Array.from(message.guild.members);
for(var member in gm) {
if(gm[member].roles.some(r=>["Helper"].includes(r.name))) {
if(gm[member].roles.some(r=>["on duty"].includes(r.name))) {
gm[member].send(`Help command ran:\nUser: ${message.author.tag}\nContent: ${message.content.replace("+help ","")}`);
}
}
}
if a user runs the command +help <what they need help with> it will send to someone in the guild with the roles helper and on duty:
(using my Discord tag for an example)
What was ran: +help I need some help with something
"Help command ran:
User: Donovan_DMC#1337
Content: I need some help with something"
(without quotes)
as for this
I need to work out how to detect the role and add them to a set who are "on duty".
I assume you mean that when someone with the role helper runs the command +onduty they get the role on duty.
var roleid=message.guild.roles.find("name","on duty").id;
if(message.member.roles.some(r=>["Helper"].includes(r.name))) {
message.member.addRole(roleid);
}
A few documentation links to hopefully help you understand this
message: https://discord.js.org/#/docs/main/stable/class/Message
message.guild: https://discord.js.org/#/docs/main/stable/class/Message?scrollTo=guild
message.guild.roles: https://discord.js.org/#/docs/main/stable/class/Guild?scrollTo=roles
and for removing the role it's almost exactly the same
var roleid=message.guild.roles.find("name","on duty").id;
if(message.member.roles.some(r=>["Helper"].includes(r.name))) {
message.member.removeRole(roleid);
}
In summary a basic bot for this you could have something like this.
^ I've added some extra checks for already having the role, not having it, and made it where the prefix can be changed
I've tested it, and it worked wonderfully.

Firestore Database Rules for User

I'm following a tutorial about firestore but I don't understand firestore rules very well. I'm trying to allow anyone to be able to create in the standard
users/uid/
path but only allow updates if the requester is trying to update
users/theirUserId/
I saw this in the documentation, but it didn't seem to work for me:
allow write: if request.auth.uid == resource.data.author_id;
Can anyone explain the functionality of the above line and/or offer suggestions as to how I can achieve this?
Additionally, is there any way to specify rules for a specific piece of data within a document?
It looks like that your document doesn't contain a author_id field.
The Firebase documentation Writing Conditions for Security Rules use this example:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches the 'author_id' field
// of the document
match /users/{user} {
allow read, write: if request.auth.uid == resource.data.author_id;
}
}
}
It means that a random user will be able to read and write in the users collections only if their authentication ID equals the author_id field of a specific document.
The resource variable refers to the requested document, and resource.data is a map of all of the fields and values stored in the document. For more information on the resource variable, see the reference documentation.
For your second question, I recommend you to have a look on the documentation about resource variable (link in the quote above). It is the same logic as your author_id question.
You can split allow write in to three create, update, delete for specific cases.
In your case
allow create: if request.auth.uid != null;
allow update: if request.auth.uid == resource.data.author_id;
which says any authenticated users can create and only update their on document. and created user must have a field author_id which is their user id.

Authentication in liferay pages

We are having a portlet on a liferay page. We want to put up up a permission on every action method that is performed. For example on page A we have landed an XYZ portlet. Now we want that whenever there is any action performed form this portlet, we want to check that if the user is having a role to perform this action or not.
It wont be a good approach to put up the code in Action method of the portlet cause we are having approximately 20 such pages and portlets.
Can we have some sort of filter or so, so that each action request is checked if the user is having the access to the content or not.
Thank you...
My idea.
Use a filter to intercept all request
You can add a filter to the Liferay Servlet to check every request.
For that you can use a hook-plugin.
Look at this :
http://www.liferay.com/fr/documentation/liferay-portal/6.1/development/-/ai/other-hooks
http://connect-sam.com/2012/06/creating-servlet-filter-hook-in-liferay-6-1-to-restrict-access-based-on-ip-location/
Issue with filter is that you can't access ThemeDisplay or use PortalUtil.getUser(request).
So you must use work around like that :
private User _getUser(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
User user = PortalUtil.getUser(request);
if (user != null) {
return user;
}
String userIdString = (String) session.getAttribute("j_username");
String password = (String) session.getAttribute("j_password");
if ((userIdString != null) && (password != null)) {
long userId = GetterUtil.getLong(userIdString);
user = UserLocalServiceUtil.getUser(userId);
}
return user;
}
Filtering the request
To filter the request you must get :
page id (Layout id in Liferay)
portlet id
portlet lifecycle
One more time using a filter is a pain because you can get the ThemeDisplay. These params are easy to get (with real object instancee) with ThemeDisplay.
So you must get this as parameter in the request.
final String portletId = ParamUtil.get((HttpServletRequest) servletRequest, "p_p_id", "");
final String layoutId = ParamUtil.get((HttpServletRequest) servletRequest, "plid", "");
final String portletLifecycle = ParamUtil.get((HttpServletRequest) servletRequest, "p_p_lifecycle", "");
Lifecycle details :
portletLifecycle is a int and the meaning of value is :
0 : RENDER
1 : ACTION (the one that interests you)
2 : RESOURCE
I think that with this data you can be able to define if user can or cannot make the action.
You can get user roles from the user.
You can get the current page and portlet linked to the request.
And you can know if the request is an action request.
Good luck with Liferay.
You can add freely configurable permissions to Liferay, see the Developer Guide for detailed information. My first guess on this would be that these affect "model resources", e.g. the data that your portlet is dealing with, rather than portlet-resources, e.g. permissions on the individual portlet itself. Think of portlet-permissions as permissions that are defined by Liferay, model-resources as permissions where you can come up with your own vocabulary on the actions, e.g. "UPDATE_ADDRESS" etc.
These permissions will typically be tied to roles, which are granted to users/usergroups/etc.
Based on this variability, it depends on the nature of your permissions if you can write a filter to generically check permissions, or if it depends on more than the individual action call.
If you determine that there is a generic solution, look up PortletFilters, they behave just like ServletFilters. These can easily provide a home for permission checks.
It's quite hard to cover this topic in such a short answer, I hope to have given enough resources for you to continue your quest.
You can abuse some existing portlet permission like "Add to Page" and set it to roles that should call the action.
And by the rendering and action phases validate "has the user necessary permission".
Or you can create new permission and configure it by portlet-configuration. This way is cleaner, but difficulty.

Add users to UserMulti field type using Client Object Model

I'm bit of a SharePoint noobie so please bear with me.
I need to be able to create a new list item in one our custom list using the client object model. I have been following the example described on the MSDN site and for the most part this has worked.
We have a list that contains several fields including a UserMulti field type. I am having problems adding users to this field. So far I have tried the following but this somehow always seems to default to the system account rather than the user specified in the field.
...
listItem["ProjectMembers"] = "1;#domain\\johndoe";
listItem.Update();
_clientContext.ExecuteQuery();
Do I need to do some type of lookup first? Any help is appreciated. Thanks.
It took a little while but I figured it out in the end. Below are two approaches you can take
Assign a Principal to the list item
var principal = _rootWeb.EnsureUser("domain\\johndoe") as Principal;
listItem["ProjectMembers"] = principal;
listItem.Update();
_clientContext.ExecuteQuery();
Assign an list of FieldUserValue if you need to assign more than one user to the field.
string[] users = { "domain\\johndoe", "domain\\peterpan" };
var projectMembers = users
.Select(loginName => FieldUserValue.FromUser(loginName))
.ToList();
listItem["ProjectMembers"] = projectMembers;
listItem.Update();
_clientContext.ExecuteQuery();
I'm sure there's better ways of doing things and you could combine the two to ensure that the users are valid before adding them to the list, but this is working so far. Hope this help someone else.
Microsoft has a wiki article, "SharePoint: A Complete Guide to Getting and Setting Fields using C#" that can help. http://social.technet.microsoft.com/wiki/contents/articles/21801.sharepoint-a-complete-guide-to-getting-and-setting-fields-using-c.aspx#Set_and_Get_a_Multi-Person_Field
It includes this sample code.
var lotsofpeople = new SPFieldUserValueCollection(web, item["lotsofpeoplefield"].ToString());
var personA = web.EnsureUser("contoso\\fred");
var personAValue = new SPFieldUserValue(web, personA.ID, personA.LoginName);
var personB = web.EnsureUser("contoso\\barnie");
var personBValue = new SPFieldUserValue(web, personB.ID, personB.LoginName);
lotsofpeople.Add(personAValue);
lotsofpeople.Add(personBValue);
item["lotsofpeoplefield"] = lotsofpeople;
item.Update();

What is used to login in LDAP mail server?

If I added data on LDAP in this way:
$ldapserver = "mail";
$ds = ldap_connect($ldapserver);
$r = ldap_bind($ds, $ldaprootun, $ldaprootpw);
add = ldap_add($ds, "cn=$full_name,ou=$domain,o=mygroup.com", $infonew);
Then does that mean that when I log in to my account I will use:
`cn="mynameHere",ou="domainIused",o=mygroup.com`
as my username? Or just my uid?
My account cannot login but I'm sure that it exists in LDAP.
Answers are very much appreciated. =)
Typically in LDAP applications you only ned to login with your UID, not your full X.500 name.
Try calling ldap_bind() with your creds and see what it returns?
Usually, the user provides a simple name. Then the app searches the LDAP source for some attribute that has that value. Then you bind or password compare in your code, as that full DN.
You can use uid which is Unique ID, which is required to be unique. I.e. If you find more than one instance of it, that is an error.
You can try CN, but that can often be multi valued depending on your LDAP implementations schema.
If you know you are going against eDirectory, then uid is fine, or CN just do something if it is multi valued.
If you know you are going against Active Directory, you can assume sAMAccountName is unique since the system enforces uniqueness. userPrinicpalName ought to be unique, but nothing actually enforces it.
You can always use mail, which is the email address pretty uniformly.