AWS Cognito NotAuthorizedException A client attempted to write unauthorized attribute - amazon-web-services

I'm using AWS Cognito and aws-cpp-sdk for my application. I defined a user pool and an application, then I got app client id and app secret.
I can create user pool object:
Aws::Client::ClientConfiguration clientConfig;
clientConfig.region =
Aws::Region::EU_CENTRAL_1; // "RegionEndpoint.EUCentral1";
clientConfig.scheme = Aws::Http::Scheme::HTTPS;
clientConfig.connectTimeoutMs = 30000;
clientConfig.requestTimeoutMs = 600000;
CognitoIdentityProviderClient client;
client = CognitoIdentityProviderClient(clientConfig);
DescribeUserPoolClientRequest describeUserPoolClientRequest;
describeUserPoolClientRequest.WithUserPoolId(POOL_ID)
.WithClientId(TEST_APP_CLIENT_ID);
DescribeUserPoolClientOutcome describeUserPoolClientOutcome =
client.DescribeUserPoolClient(describeUserPoolClientRequest);
After I defined an user with SignUpRequest, there was an error like this: NotAuthorizedException A client attempted to write unauthorized attribute
This is my signup code:
SignUpRequest signUpRequest;
signUpRequest.SetClientId(describeUserPoolClientOutcome.GetResult()
.GetUserPoolClient()
.GetClientId());
signUpRequest.SetUsername("xxxxx");
signUpRequest.SetPassword("xxxxxx?");
AttributeType email, phone_number, gender, given_name, family_name, picture;
email.WithName("email").WithValue("gacer#ku.edu.tr");
phone_number.WithName("phone_number").WithValue("+xxxxx");
given_name.WithName("given_name").WithValue("xxx");
family_name.WithName("familiy_name").WithValue("xxx");
gender.WithName("gender").WithValue("MALE");
picture.WithName("picture").WithValue(
"http://xxxx");
signUpRequest.AddUserAttributes(email);
signUpRequest.AddUserAttributes(phone_number);
signUpRequest.AddUserAttributes(given_name);
signUpRequest.AddUserAttributes(family_name);
signUpRequest.AddUserAttributes(gender);
signUpRequest.AddUserAttributes(picture);
SignUpOutcome signUpOutcome = client.SignUp(signUpRequest);
What is the problem? How can I solve it?

In the AWS website go to your User Pool -> Apps -> Show Details -> Set attribute read write permissions. Make sure every attribute you are trying to write i in the writeable attributes list and they have a checkmark.

I have same problem but it was resolved by adding custom: in other attributes.
While you are adding custom attributes
you need to add
custom:family_name

Omg! The reason of exception is only writing mistake. The problem is solved by correcting typing error from familiy to family at this line:
family_name.WithName("familiy_name").WithValue("xxx");

Related

Cannot write required AWS Cognito attribute

I created a user pool in AWS's Cognito, specified given_name and family_name as required user attributes. I also added an app and checked the permissions :
If - using the Cognito Identidy SDK - I try to register a user and omit the attributes, I get: "Attributes did not conform to the schema: given_name: The attribute is required family_name: The attribute is required" which is expected.
If I include the attributes:
const firstNameAttribute = new CognitoUserAttribute({ Name: 'first_name', Value: firstName });
const lastNameAttribute = new CognitoUserAttribute({ Name: 'last_name', Value: lastName });
cognitoUserPool.signUp(username, password, [firstNameAttribute], [lastNameAttribute], callback);
The server returns
{
"__type":"NotAuthorizedException",
"message":"A client attempted to write unauthorized attribute"
}
How can I fix this and let users set their name during registration?
The app in which the users would try register sent the wrong field names :(
You have to check Write permission is allowed in app client.
Location:
Amazon Cognito > User Pools > {User Pool} > App Integration > App
Client > Attribute read and write permissions > Edit

Flutter AWS Auth: How to get custom user attribute?

How do I get in Flutter, the cognito custom user attribute for user?
await Amplify.Auth.fetchUserAttributes();
returns only user attributes but not the custom defined ones.
(I have added the attribute to the schema and I am sure it's there, in the AWS UI it's there.)
The fetchUserAttributes function returns a list of AuthUserAttributes including the custom ones you've defined. When you have that list you can iterate through it, and get the attributes you want.
const res = await Amplify.Auth.fetchUserAttributes();
for (var attr in res) {
if (attr.userAttributeKey == CognitoUserAttributeKey.custom('customAttr') {
customAttr = attr.value;
}
}
If the custom attribute isn't there, make sure the user have that attribute.
The issue was that these custom attributes, after they are created, they are not by default readable or writable.
For further explanations, check https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-attribute-permissions-and-scopes
Go to cognito - app clients - details - and very bottom to change permissions

Google API user creation with service account

I'm trying to create a user using Googles Directory API and a service account. However I'm getting the error
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://admin.googleapis.com/admin/directory/v1/users?alt=json returned "Not Authorized to access this resource/api". Details: "Not Authorized to access this resource/api">
I've created a service account on the Google Console and allowed Domain wide delegation. It also says the Admin SDK API is enabled for my project. However I can't seem to create a user. The documentation is confusing me slightly. Here is my implementation
def create_googleuser(content, randpass):
''' This function creates a Google Apps account for a user passing webhook contents and password as arguments '''
# Get User info from Webhook and store them in variables
firstname = get_firstname(content)
secondname = get_secondname(content)
emailaddress = firstname + "." + secondname + "#example.com"
# Connect to google API
userscope = ['https://www.googleapis.com/auth/admin.directory.user']
service_account_credentials = ('serviceaccountcredentials.json')
credentials = service_account.Credentials.from_service_account_file(service_account_credentials, scopes=userscope)
userservice = googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials)
# Create a user dictionary with user details
userinfo = {"primaryEmail": emailaddress,"name":{"givenName":firstname,"familyName":secondname},"password":randpass}
print (emailaddress)
# Create user through googleAPI
userservice.users().insert(body = userinfo).execute()
I'm thinking that my implementation is wrong rather than the permissions as the serviceaccountcredentials.json should have the correct permissions. Any suggestions?
There are two possibilities for getting this error.
If the API method requires an impersonated user to be used.
If the impersonated user has not the relevant service enabled.
Solution for case 1:
Follow the documentation to impersonate a user account.
Solution for case 2:
In the Admin console, open user information and check that the user is not suspended.
Open the "Apps" panel and check that the relevant service is "On".
May be caused by a user not having a license which allows access to the service (Cloud Identity instead of Google Workspace), or a user being in an organizational unit which has the service disabled.
Also this link might be helpful.
Thanks for the input. You were both correct to a point. Basically there were two issues. The service account user needs to be delegated domain administrator privileges that require domain admin actions, domain wide delegation isn't enough. Also the domain scope needed to be broader in the Admin console and the scope definition within the code. There is github issue open which helped here:
https://github.com/googleapis/google-api-nodejs-client/issues/1884
My working code looks like this
def create_googleuser(content, randpass):
''' This function creates a Google Apps account for a user passing webhook contents and password as arguments '''
# Get User info from Webhook and store them in variables
username = get_username(content)
firstname = get_firstname(content)
secondname = get_secondname(content)
emailaddress = firstname + "." + secondname + "#example.com"
# Connect to google API
userscope = ['https://www.googleapis.com/auth/admin.directory.user', 'https://www.googleapis.com/auth/admin.directory.user.security']
service_account_credentials = ('serviceaccountcredentials.json')
credentials = service_account.Credentials.from_service_account_file(service_account_credentials, scopes=userscope)
delegated_credentials = credentials.with_subject('domain.admin#example.com')
userservice = googleapiclient.discovery.build('admin', 'directory_v1', credentials=delegated_credentials)
# Create a user dictionary with user details
userinfo = {"primaryEmail": emailaddress,"name":{"givenName":firstname,"familyName":secondname},"password":randpass}
# Create user through googleAPI
userservice.users().insert(body = userinfo).execute()

Store UserTokens generated by ASP.Net Core identity for external login provider

I am using Facebook as external login of ASP.Net Core identity.
I would like, even if the user logged in with Facebook, the user to fill his profile on the website.
For that I use the ExternalLoginCallback method, from which I would like to get data from Facebook such as date of birth, location (country), ...
One issue is if the user unchecked some of the permissions, the default call to Facebook fails:
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
return RedirectToAction(nameof(Login));
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
I would also need to do some additional checks on user data, which would require calling directly the Graph API.
My blocking points:
- In the ExternalLoginCallback method, I would need to separate the 'country' and 'birthday' to avoid the Facebook API to return an error in case of the user didn't grant the permission
- For that I would need the the user access_token (and for additional calls in the method), I don't see how to get it even if it is used by the Facebook Identity framework
- Once the profile created, I would like to get access to this access_token, which should be stored in the UserTokens table (I guess?), but I can't find it there, the table is empty. (my DbContext is a class extending IdentityDbContext<AppUser, AppRole, long>, don't know if it has an impact)
I have found this answer https://stackoverflow.com/a/42670559/4881677 which may help, but not sufficient.
Any help? :)
In order to store the user Facebook token, it requires to specify it in the options (not stored by default).
var fo = new FacebookOptions();
fo.SaveTokens = true;
From there we can call the graph method permissions to get the available permissions: https://graph.facebook.com/me/permissions?access_token={token}
Then it can be read with something like this:
foreach (var perm in data)
{
perms.Add((string)perm["permission"], (string)perm["status"]);
}

Sitecore Virtual User Login Experience Profile

I need to validate user credentials from external service, therefore I'm using the VirtualUser authentication.
BuildVirtualUser, checking for the roles to set to him, saving the user Profile and then login with that name.
I'm facing a problem, that everyday that i login, with the same credentials Sitecore creates a new user in Experience Profile.
What i need to change in my code to assure that, with virtual user login, Sitecore gets the old experience profile of the user?
I was thinking in creating the user in sitecore with same generic password. Instead of using the virtual user, and authenticate directly with sitecore. Is that correct?
Here's my code:
Sitecore.Security.Accounts.User user = Sitecore.Security.Authentication.AuthenticationManager.BuildVirtualUser(sitecoreUser, true);
string roleName = #"newRole\User";
Sitecore.Security.Accounts.Role demoRole = Sitecore.Security.Accounts.Role.FromName(roleName);
if (Sitecore.Security.Accounts.Role.Exists(roleName) && !demoRole.IsMember(user, true, false))
{
user.Roles.Add(Sitecore.Security.Accounts.Role.FromName(roleName));
}
user.Profile.Name = name;
user.Profile.Email = email;
user.Profile.FullName = fullname;
user.Profile.Save();
Sitecore.Security.Authentication.AuthenticationManager.Login(user.Name);
Tracker.Initialize();
Code looks fine, but you miss one important thing: to identify your user/contact.
You need to add next line of code:
Tracker.Current.Session.Identify(email);
Please check next link to find more information about how to identify contacts:
https://doc.sitecore.net/sitecore_experience_platform/setting_up__maintaining/xdb/contacts/identifying_contacts