How to change user_type of a user in Azure AD with terraform - azure-active-directory

Im using this resource : https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/user#user_type
`resource "azuread_user" "example" {
user_principal_name = "jdoe#hashicorp.com"
display_name = "J. Doe"
mail_nickname = "jdoe"
password = "SecretP#sswd99!"
}`
How to specify user_type to be Guest and not Member as its by default
I tried to put the user_type = "Guest" but its not accepted. this is the eror
with azuread_user.example,your text
│ 16: user_type = "Guest"
│
│ Can't configure a value for "user_type": its value will be decided automatically based on the result
│ of applying this configuration.

I tried to reproduce the same in my environment.
The user created using azuread_user is by default a member.
And user created through invitation is by default a guest user.
***User created in azure through invitation.***User type applied as guest automatically.
Only Global administrator or a user with User administrator role can change the created user type .
Only Global administrator can invite users as members.
Other wise the user type attribute will be applied according to what is mentioned as above .In this case the user type is applied as per way of creation.
First create the user and then try to update its property User Type, only after creating the user with default properties using globalAdministrator rights

Related

How to mimic `Get-AzureADUser` in C#

I am working on an Azure AD B2C application and the B2C policy stores the MFA secret-key in the extension_mfaTotpSecretKey property of the user. This works and when I run Get-AzureADUser -ObjectId '<object-id>' | ConvertTo-Json, then it shows:
{
"ExtensionProperty": {
"odata.metadata": "https://graph.windows.net/<tenant-id>/$metadata#directoryObjects/#Element",
"odata.type": "Microsoft.DirectoryServices.User",
"createdDateTime": "2/4/2022 2:13:22 PM",
"employeeId": null,
"onPremisesDistinguishedName": null,
"userIdentities": "[]",
"extension_7eb927869ae04818b3aa16db92645c09_mfaTotpSecretKey": "32YZJFPXXOMHT237M64IVW63645GXQLV"
},
"DeletionTimestamp": null,
...
}
During the migration process from the old directory to the new Azure B2C directory, I also want to transfer the existing TOTP key so users don't need to reregister their TOTP key. I have spent all day to get this to work, but no luck and I really don't know what's left.
I have created an app registration in the tenant with Directory.ReadWrite.All rights, but when I read the user, then the extension is empty:
var creds = new ClientSecretCredential("<tenant-id>", "<client-id>", "<client-secret>", new TokenCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud });
var graphClient = new GraphServiceClient(creds, new[] { "https://graph.microsoft.com/.default" });
var user = await graphClient.Users["<object-id>"].Request().Select(u => new {u.Id, u.Extensions}).Expand(u => new { u.Extensions}).GetAsync();
If I can't read the value, then I probably can't write it. I tried using OpenTypeExtension, but I am under the impression that this is a completely different property.
I can't find any documentation that tells me how I can run Get-AzureADUser using Graph API v2 in C#.
It seems that there three possible ways to extend properties in Azure AD for an object:
AzureAD Graph extension attributes
Azure AD Open extensions
Azure AD Schema extensions
Azure B2C uses AzureAD Graph extension attributes and these should be fetched directly on the user object like this:
var graphClient = new GraphServiceClient(...);
var user = await graphClient.Users["<object-id>"].Request().Select("extension_7eb927869ae04818b3aa16db92645c09_mfaTotpSecretKey").GetAsync();
var mfaTotpSecretKey = user.AdditionalData["extension_7eb927869ae04818b3aa16db92645c09_mfaTotpSecretKey"]?.ToString();
When the user is created, then these properties can be added to the AdditionalData property of the user.
Note that Azure B2C uses the persistent claim name extension_mfaTotpSecretKey, but this is translated to extension_<client-id-without-hyphens>_mfaTotpSecretKey, where <client-id> is the client-id of the B2C extensions app (with all hyphens removed).
Extension attributes are not included by default if you use the v1 endpoint of the Microsoft Graph. You must explicitly ask for them via a $select, as per #Ramon answer. When you use a $select statement, you'll get back only the specified attributes plus the id, so pay attention and specify all the fields you need. Moreover, the SDK is misleading since you'll find the extension attributes under the AdditionalData field, not in the Extensions field.
When you are going to migrate the users to a new tenant, keep in mind that the extension attribute name will change since the middle part is the b2c-extensions appId without the dashes.
i.e.
on Tenant 1: extension_xxx_myAttribute
on Tenant 2: extension_yyy_myAttribute
When you'll try to write the extension attribute on Tenant 2 via Microsoft Graph it must already exist. If you never run your custom policies on the new tenant you can create the attribute via Microsoft Graph as well with a simple POST operation:
POST https://graph.microsoft.com/v1.0/applications/<b2c-extensions-app-objectId/extensionProperties
{
"name": "attributeName",
"dataType":"string/int/etc.",
"targetObjects": ["User"]
}
You'll get the full extension attribute name in the response (i.e. extension_xxx_attributeName)
HTH, F.
https://learn.microsoft.com/en-us/graph/api/application-list-extensionproperty?view=graph-rest-1.0&tabs=csharp
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var extensionProperties = await graphClient.Applications["{application-id}"].ExtensionProperties
.Request()
.GetAsync();

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).

cakephp authenticate user with repeated entries in the Database table (manual authentication?)

I'm creating an authentication system for a group of websites. The problem is that I have to use a pre-existing Database, which has a users table already full of entries, and that one user can have several accounts. Basically, a user has one account per website he has access to (it's not the best way to do this, but I can't change it). Each account is represented by an entry in the users table, with login, password, name... and the important field: website_id. This field tells the system what website that account has access to.
The big problem is that some users with more than one account have the exact same login/password information for all of them. For example, one user has 3 accounts:
account1: login = charly / pwd = 1234 / name = Charles ... website_id = 1
account2: login = charly / pwd = 1234 / name = Charles ... website_id = 2
account3: login = charly / pwd = 1234 / name = Charles ... website_id = 3
So if he goes to the website that has id = 2 and uses those credentials, he's granted access. If he goes to the website that has id = 4, he's denied access.
My problem is that since CakePHP does the login automatically, when a user tries to login, CakePHP checks only the first entry in the Database that matches the login/password submited in the form. So if a user is currently in the website with website_id = 3 and tries to login, Cake finds the first entry (account1), compares its website_id (1 in this case) to the current website's id (3), and since they're different, the access is not granted, but it should. _Please note that the comparison of the website_id vs the account's website_id is already being made manually in the login() function_.
This how the login() function looks like now:
function login() {
$userInfo = $this->Auth->user();
if ( isset($userInfo) ) {
if ($userInfo['User']['website_id'] == $this->website_id) {
//Users gets access to a website that he has an account for
}
else {
//User is denied access because his account is not registered for the current website
$this->Session->destroy();
$this->Session->setFlash(__('You don't have access to this website', true));
$this->redirect($this->Auth->logout());
}
}
}
What I would like is to be able to manually authorize the access to the current website by using the login/password submitted by the user to manually search in the users table, and if I find a match in one of the user accounts, grant the access, or otherwise deny access. To sum up, avoid all the automagic of Auth's component.
If the Auth component's login method fails, control is transferred back to the custom login action (e.g. UsersController::login()). I've used this to authenticate using either username or email address, but it could be easily adapted for this purpose. Same idea, different criteria. I offered what I think is a reasonably thorough response (with code) to a similar question. It may help you as well.

app on GAE | Restricted Google account authentications | listed google accounts not all |

I am quite new to this Google app engine. I am learning things every day.
I am have a forum on google app engine.
But I want is to be having private or restricted parts.
Some features should be locked for certain google account users, which are in some sort of access control list.
I plain words I can say, only those user who are in list of access can see the forum rest will be redirect to the "contact to admin" page.
As I am new I wanna know that is it something possible.
if yes, how can I achieve it ?
Thanks,
Alok
If you are using the built-in Users API, you can check users.is_current_user_admin() as an access control mechanism. Administrators can be managed via the dashboard.
If you need more granular, application-specific authorization logic, generally you would create a User model in the datastore that references the built-in UserProperty and also holds a list of roles or whatever else you need to check authorization.
To follow up Drew's reply, I use a similar system in my app, so my server code has something like the following class definition (simplified here for clarity)
class myUser(db.Model):
user = db.UserProperty(required=True)
rights = db.StringProperty(required=True, choices=set(["public", "private"]))
created = db.DateTimeProperty(auto_now_add=True)
lastaccess = db.DateTimeProperty(auto_now=True)
and then I have code like this where I handle queries
def checkUserRights(user):
q = db.GqlQuery("SELECT * from myUser WHERE user = :1", user)
u = q.get()
if not u:
# create a new 'public access' user if we haven't seen this person before
u = myUser(user=user, rights="public")
# always update the user record after the source is fetched (updates the lastaccess field)
db.put( u )
return u.rights
rights = checkUser(users.get_current_user())
if isPrivateArea and rights == "private":
....
This way I create a user for EVERY visitor, and then I have an admin interface to change the rights of selected users - you may decide, for example, to not create a record for every visitor
def checkUserRights(user):
q = db.GqlQuery("SELECT * from myUser WHERE user = :1", user)
u = q.get()
if not u:
# grant default public rights to anyone...
return "public"
# always update the user record after the source is fetched (updates the lastaccess field)
db.put( u )
return u.rights
This is, of course, on a page where the app.yaml specifies "login: required"

Resources