How keycloak sets up user information from an external identity provider - azure-active-directory

During use, I found that keycloak automatically registers a new user in the local database after obtaining the user information of the external identity provider(Azure AD).Can the user's username be consistent with the user information of the external identity provider(Azure AD) in some way? For example, the username of the newly registered user is automatically set to the user mailbox of the external identity provider(Azure AD)?
ps:keycloak 7.0.1 windows10

use identity privider mapper.
For email the mapper is of type Attribute Importer. Map the user attribute email to http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress.
For username the mapper is of type Username Template Importer. Map the user attribute username to ${ATTRIBUTE.http://schemas.microsoft.com/2012/12/certificatecontext/field/subjectname}.
For surname the mapper is of type Attribute Importer. Map the user attribute lastName to http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname.
For given name the mapper is of type Attribute Importer. Map the user attribute firstName to http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname.

Related

How to deal with External authentication for already existing local user or new user

I using ASP.Net Core 3 Identity with Identity Server 4 for authentication ...
On the AspNetIdentity template the External Authentication Controller Callback method calls the AutoProvisionUserAsync method which has the following code:
var email = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Email)?.Value ??
claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value;
if (email != null) {
filtered.Add(new Claim(JwtClaimTypes.Email, email));
}
var user = new User {
UserName = Guid.NewGuid().ToString(),
};
var identityResult = await _userManager.CreateAsync(user);
Basically it creates a user with a Guid as Username ...
In my database I am using Email as Username ... Is there any reason to use a Guid?
I suppose most External authentication services (Google, Facebook, etc) provides an Email.
So my idea would be:
Check if there is an User in the database already with that email.
If no User exists create one with the email obtained from the External authentication service.
Also add the external authentication to the User in the database;
If there is a User with the email in the database check if it has that External Login.
If the user does not have the external login register and add it.
Does this make sense?
Check if there is an User in the database already with that email.
On callback, first call is to FindUserFromExternalProviderAsync, it search users using nameIdentifier, then if not found there is call to AutoProvisionUserAsync
Basically it creates a user with a Guid as Username ...
In my database I am using Email as Username ... Is there any reason to use a Guid?
The ApplicationUser's base class is IdentityUser, IdentityUser has a prop for ID and one for email by design. thats why most of libraries take advantage of having GUID as ID in addition of email for extensibility. You can use the email for ID if you like to.

Delphi IPWorks LDAP PASSWD_CANT_CHANGE

I am using Delphi 10.3 and IPWorks LDAP component. I can modify most attributes without any issues, such as unicodePwd, givenName, and mail. However, for the userAccountControl attribute of a user, I am unable to set ADS_UF_PASSWD_CANT_CHANGE, of course after successfully binding as an administrator with secure connection and supplying correct DN, because if the connection is not secure, it is impossible to modify the password:
const
ADS_UF_NORMAL_ACCOUNT = 512;
ADS_UF_DONT_EXPIRE_PASSWD = 65536;
ADS_UF_PASSWD_CANT_CHANGE = 64;
ADS_UF_LOCKOUT = 16;
ipaLDAP1.DN := searchResultDN;
ipaLDAP1.AttrCount := 1;
ipaLDAP1.AttrType[0] := 'userAccountControl';
ipaLDAP1.AttrValue[0] := IntToStr(ADS_UF_NORMAL_ACCOUNT + ADS_UF_DONT_EXPIRE_PASSWD + ADS_UF_LOCKOUT + ADS_UF_PASSWD_CANT_CHANGE);
ipaLDAP1.AttrModOp[0] := amoReplace;
ipaLDAP1.Modify();
It is strange that I can not modify ADS_UF_PASSWD_CANT_CHANGE. It doesn't take effect on the user. When I check the user, this attribute is still unchecked. I don't understand why.
userAccountControl is a bitmask, so you should be using the or operator to combine flags, not the + operator.
But, more importantly, according to How to use the UserAccountControl flags to manipulate user account properties:
PASSWD_CANT_CHANGE
Note: You cannot assign this permission by directly modifying the UserAccountControl attribute. For information about how to set the permission programmatically, see the "Property flag descriptions" section.
Where the "Property flag descriptions" section says:
PASSWD_CANT_CHANGE - The user cannot change the password. This is a permission on the user's object. For information about how to programmatically set this permission, visit the following Web site:
Modifying User Cannot Change Password (LDAP Provider)
That page, in turn, says:
The ability of a user to change their own password is a permission that can be grant or denied. To deny this permission, set two ACEs in the security descriptor discretionary access control list (DACL) of the user object with the ADS_ACETYPE_ACCESS_DENIED_OBJECT ace type. One ACE denies the permission to the user and another ACE denies the permission to the Everyone group. Both ACEs are object-specific deny ACEs that specify the GUID of the extended permission for changing passwords. To grant this permission, set the same ACEs with the ADS_ACETYPE_ACCESS_ALLOWED_OBJECT ace type.
The following procedure describes how to modify or add ACEs for this permission.
To modify or add the ACEs for this permission
Bind to the user object.
Obtain the IADsSecurityDescriptor object from the ntSecurityDescriptor property of the user object.
Obtain an IADsAccessControlList interface for the security descriptor from the IADsSecurityDescriptor.DiscretionaryAcl property.
Enumerate the ACEs for the object and search for the ACEs that have the change password GUID ({AB721A53-1E2F-11D0-9819-00AA0040529B}) for the IADsAccessControlEntry.ObjectType property and "Everyone" or "NT AUTHORITY\SELF" for the IADsAccessControlEntry.Trustee property.
Note: The "Everyone" and "NT AUTHORITY\SELF" strings are localized based on the language of the first domain controller in the domain. Because of this, the strings should not be used directly. The account names should be obtained at run time by calling the LookupAccountSid function with the SID for "Everyone" ("S-1-1-0") and "NT AUTHORITY\SELF" ("S-1-5-10") well-known security principals. The GetSidAccountName, GetSidAccountName_Everyone, and GetSidAccountName_Self C++ example functions shown in Reading User Cannot Change Password (LDAP Provider) demonstrate how to do this.
Modify the IADsAccessControlEntry.AceType property of the ACEs that were found to ADS_ACETYPE_ACCESS_DENIED_OBJECT if the user cannot change their password or ADS_ACETYPE_ACCESS_ALLOWED_OBJECT if the user can change their password.
If the "Everyone" ACE is not found, create a new IADsAccessControlEntry object that contains the property values shown in the table below and add the new entry to the ACL with the IADsAccessControlList.AddAce method.
If the "NT AUTHORITY\SELF" ACE is not found, create a new IADsAccessControlEntry object with the same property values shown in the table below except the Trustee property contains the account name for SID "S-1-5-10" ("NT AUTHORITY\SELF"). Add the entry to the ACL with the IADsAccessControlList.AddAce method.
To update the ntSecurityDescriptor property of the object, call the IADs.Put method with the same IADsSecurityDescriptor obtained in Step 2.
Commit the local changes to the server with the IADs.SetInfo method.
If either of the ACEs were created, you must reorder the ACL so that the ACEs are in the correct order. To do this, call the GetNamedSecurityInfo function with the LDAP ADsPath of the object and then the SetNamedSecurityInfo function with the same DACL. This reordering will occur automatically when the ACEs are added.
The following table lists the IADsAccessControlEntry object property values.
AccessMask
ADS_RIGHT_DS_CONTROL_ACCESS
AceType
ADS_ACETYPE_ACCESS_DENIED_OBJECT if the user cannot change their password or ADS_ACETYPE_ACCESS_ALLOWED_OBJECT if the user can change their password.
AceFlags
0
Flags
ADS_FLAG_OBJECT_TYPE_PRESENT
ObjectType
"{AB721A53-1E2F-11D0-9819-00AA0040529B}" which is the change password GUID in string form.
InheritedObjectType
Not used
Trustee
Account name for SID "S-1-1-0" (Everyone).
There is a fairly lengthy code example provided on the same page.

Can't add 'otherMails' with Graph-Tester

I am trying to add another email address to a User.
PATCH https://graph.microsoft.com/v1.0/users/user#domain.de
Body:
{
"givenName":"Meier",
"surname":"Meeier",
"otherMails":["emaissssl#domain.de"]
}
Response: Success - Statuscode 204
The result is givenName changed to Meier, surname changed to Meeier, but the email doesn't get added to otherMails[].
A related question is, can I change the primary address of the User?
Edit: I get the same behavior, if i also include the current address:
{
"givenName": "Meier",
"surname": "Meeier",
"otherMails": ["user#domain.de", "emaissssl#domain.de"]
}
You need spesific permissions in AAD to update otherMails. From the documentation:
Updating another user's businessPhones, mobilePhone, or otherMails property is only allowed on users who are non-administrators or assigned one of the following roles: Directory Readers, Guest Inviter, Message Center Reader, and Reports Reader. For more details, see Helpdesk (Password) Administrator in Azure AD available roles. This is the case for apps granted either the User.ReadWrite.All or Directory.ReadWrite.All delegated or application permissions.
The wording is a little poor but basically, if the User record you are updating is an Administrator or assigned any of the mentioned roles (Directory Readers, Guest Inviter, Message Center Reader, or Reports Reader), it will ignore the change request.
As for changing the primary email address, that isn't possible. The primary email address is automatically constructed based on the mailNickname and the default domain for the tenant (mailNickname#default.dom).

Symfony Fos user Bundle

I am quiet new to symfony 2 frmaework and I have been trying to find a inbuilt function or a fos container service that contains information about groups or role of a currently logged in user.I have used groups of FOS user bundle and each of user is assigned to only one group and role is defined to group.
Thanks in advance.
In the symfony session object you will have the current logged in user, and because the group is mapped to the user entity you can just access to the group with a getter here is a twig example
{{ app.security.getToken().getUser().getGroup() }}
To get the group roles you just call the Geter getRoles (), it returns the user roles and his group roles in the same array.

is FB's db (Oracle?) of "available username" in 'real-time' or gets updated dayly/wekly or never?

Scenario:
there is FB user with Facebook (FB) ID and personal profile.
that FB ID also has one Page.
Now that ID wants to assign an available username "Myusername" to its Page (not assigning that available "Myusername" to ID itself).
Error occurred and available "MyUsername" got assigned to ID .
In order to correct that, and to release "MyUsername" to the availability status,
ID's username "MyUsername" is changed to "NewReplacingUseername" .
However, when then trying to assign "MyUsername" (expected to be now AGAIN availabe) to the ID's Page, FB returns "Username not availabe".
However,
https://graph.facebook.com/MyUsername
returns
{
"error": {
"message": "(#803) Some of the aliases you requested do not exist: MyUsername",
"type": "OAuthException"
}
}
which should mean that "MyUsername" IS available !
Any help ?
========================
#OffBySome
thanks for pointing to that FAQ.
But that FAQ use terminology
"securing" a username
and
"diffrent account".
But this is NOT "different" account.
Page belong to the same ID account to which username was initially (arroneously) given but later that username to ID itself was replaced with NewUserName in order to free original Username to be given to the Page of same account to which ID belongs to.
As for "securing" , it is not anymore "secured" as it was replaced with NewUsername.
I need tech confirmation: Does FB store FOREVER any 'username' ever typed, even in error,
even if an account, who typed it in the first place, REPLACED it with something different, i.e. it is not used anymore / it is abandon ?
And, once again, this is within SAME account !
You cannot transfer a user name. Once it has been assigned it cannot be re-assigned so that is why you are getting that error message. This is documented on their FAQ:
Can I transfer my username to another account? Once you have secured a
username, it is not possible to transfer it to a different account on
Facebook. Also, when an account is removed from the site, its username
will be unavailable. Facebook does this for security reasons, namely
to prevent username squatting.

Resources