Flutter AWS Auth: How to get custom user attribute? - amazon-web-services

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

Related

How to protect admin area from users by role in laravel 5.6?

I was looking for simple Laravel 5.6+ version roles and users solution.
I want to have one users table. So I added user_type in my table as string in
$table->enum('role', ['admin', 'user']);
Which files should I create or update to protect everything under /admin route. And do not let to use admins routes for users?
You should create a middleware that is active in all /admin routes. In this middleware you should check if the user that is logged in (Auth::user()) has the "admin"-role.
Auth::user() references the User-model.
So in the User-model you can create a function like isAdmin():
public function isAdmin()
{
return $this->role === 'admin'
}
In the Middleware (or wherever you want it) you can just write
if(Auth::user()->isAdmin()) {
// do something if user is admin
} else {
// do something if user is not admin
}
Since it is in the User-model you can also write $user->isAdmin() for regular user models.

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"]);
}

AWS Cognito NotAuthorizedException A client attempted to write unauthorized attribute

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");

Using SitecoreUser.Profile with Forms Authentication

We use sitecore to manage our registered users (extranet domain) and when creating new virtual users we give it an email using the Profile.Email property and then call the Profile.Save() method.
Another property somewhere else reads the userProfile.Email, everything is fine at the beginning.
Plus we use Forms authentication with the remember me feature.
The problem is when we close the browser and reopen it Sitecore.Context.User contains info about the actual user who clicked remember me but the User.Profile always has the Email null.
I tried Reload() and initialize() they don't work. I also tried getting the user again via the username (User.FromName()) but the returned user object also doesn't have the Profile Email.
What is being done wrong?
There is one very important remark in Security API Cookbook. It is related to Sitecore 6 but as far as I know it should work with Sitecore 8 as there was no important changes in Security model. It worked for Sitecore 7.
Important You must log in a virtual user only after you assign Roles and Profile properties to them. The Roles and Profile properties that are assigned after logging in are lost upon subsequent request.
Sitecore.Security.Accounts.User user =
Sitecore.Security.Authentication.AuthenticationManager.BuildVirtualUser(#"domain\user"
, true);
if (user != null)
{
string domainRole = #"domain\role";
if (Sitecore.Security.Accounts.Role.Exists(domainRole))
{
user.Roles.Add(Role.FromName(domainRole));
}
user.Profile.Email = "user#domain.com";
user.Profile[“Custom Property”] = “Custom Value”;
user.Profile.Save();
Sitecore.Security.Authentication.AuthenticationManager.LoginVirtualUser(user);
}

Rest Replay Attacks / Security

let me describe a simple scenario:
There is a rest resource represented by this URI: /api/messages/{userid}. After the user is logged in, a request is dispatched passing to this URI "userid" (logged user). This way, as soon as the user logs in, he gets his own messages based on his ID.
If user is not logged yet, the URI is not visible (there is a authentication filter).
The problem is: if a already logged user discover this uri, he can submit a request passing another ID what will lead to a security problem because he will be able to get messages from another user (simply passing any random ID).
Can you propose any security model to prevent this security flaw ? (what I believe its more likely a cross-cutting concern).
Thanks, in advance!
Just off the top of my head, have the endpoint either (a) only return those messages visible by the logged-in user, or (b) only return messages if the logged-in user is the same as the userId in the URI. Which one depends on your business rules.
In the endpoint you can check for the user and then see if that user id matches the pathparam
finding the userid from the user name is as easy as selecting the id using the user name from a database
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import ... blablabla;
#GET
#Path("messages/{userid}")
public Response getMessages( #PathParam("userid") int userId, #Context SecurityContext context ) {
String username = context.getUserPrincipal().getName();
int id = getIdFromName(username); // define this yourself
if(userId==id) {
// output the message list
List<Message> msgs = getDemMessagesGURL(); // define this yourself
return Response.ok(new GenericEntity<List<T>>(msgs) {}).build();
} else {
// output Forbidden(403)
return Response.status(403).build();
}
}
and with oauth you can use a servlet filter to set the user principal based on the oauth signiture