Apache Usergrid 2.x: can you restrict API access by a Data Entity's property value? - usergrid

Say I have the following API, where users can have zero or more registeredIds, which model identifiers by type (with effective dates).
Two examples of registeredIds include:
// Social Security Number
{
"id" : "111-11-1111",
"type" : "SSN",
"validFrom": 315554400000,
"validTo" : null,
"registrationAuthority": "United States Social Security Administration"
},
// Employee ID
{
"id" : "12345678",
"type" : "employee-id",
"validFrom": 1262325600000,
"validTo" : null,
"registrationAuthority": "YoYoDyne"
}
When Anonymous User requests an employee, e.g.,
https://api.usergrid.com/your-org/your-app/users/janedoe
Anonymous User should only get a single registeredId.type with the type value "employee-id." Administrators, however, should see both the "employee-id" and "SSN" registeredId.types.
How would Apache Usergrid apply access control by the registeredId.type? I know I can assign permissions, but this is too restrictive. Can I create some kind of Entity SubType? Or should I handle this through relationships?

Currently, Usergrid does not allow you to set property validation checks. One solution to this problem is to have separate "EmployeeID" entities, have a connection from each User to that their id entity and setup permissions so that only authenticated users can access the EmployeeID entities.

Related

unable to add claim to id or access token based on attributes column of accounts table

After many tests I can't figure out how to add claim to userinfo / id token / access token based on the SCIM 2.0 format for the attributes column inside accounts table.
Curity 6.6.0
Mysql configured as the default datasource also for user management
Mysql attributes query configured in the datasource : SELECT * FROM accounts WHERE username = :subject
User added through the User SCIM endpoint have their data inside the 'attributes' column of the accounts table (seems to be by design when the onyl one DS exists in Curity)
family_name, given_name appears correctly in the id token as the connected user
I'm using BFF Token handler SPA code (nodejs) with the overall flow validated
Step by step :
Create a claim named 'user_type'
select the default-account-manager associates with a claim provider
in the 'select value' combo search and add userType (all attributes of the SCIM 2.0 schema are referenced in the combo)
Add the claim to a custom scope & profile scope
Configure the claim to be in the userInfo & Id Token & access token
Commit
--> No user_type field in any token or userInfo
I have tried with (return attributes.userType) and without any mapping, but no way...
The only working test is the one with a mock : return {userType: 'test'} or return 'test'.
It seems that the attributes query SELECT * FROM accounts WHERE username = :subject does'nt allow to use children fields of the attributes column.
Despite the fact that it seems to work correctly in https://curity.io/resources/learn/claims-from-authenticated-subject/ subject attributes in authentication with code
function transform(attributes) {
//Transform the attributes and return the appropriate value for the claim
if(attributes.emails !== undefined
&& attributes.emails.length > 0
&& attributes.emails[0].value !== null) {
//return {"email" : attributes.email};
return attributes.emails[0].value;
}
return null;
}
Any help will be greatly appreciate to point out what I'm doing wrong
Sounds like you got most of it right, but some details to tweak.
First, to use the attribute query, you can't use an Account Manager claims provider, that one uses the account query for the lookup and is not configurable. Instead, use the Data Source Claims Provider.
Second, the claim config can't query in multiple steps, so you'll need to transform your result.
In the picture below, I'm using a data source provider with your query, and putting the value from my attributes.timezone in the "email" claim.
Note the logger.warn, it's useful to find out what you get back from the datasource.

How to set the Sort Key(Secondary key) in AWS Cognito?

I'm using Cognito User Pool for my iOS App User Registration. In general, when Registering a user with Cognito I'm using the email as userID. And also I'm collecting other info like Phone number, Business Name and etc. In this case when I try to register with the same email id with a Different Business name it will show an alert like User already Exist.
In my new Work case, I want to save/register the same email with a different Business name. How can I achieve it?
for example, if we are using a DynamoDB table we have the Partition key and Sort key. By using those we set the email as the Partition key and the Business Name as the Sort key and we can achieve uniqueness.
can we implement the same using Cognito? Does Cognito support the Partition key and Sort key concept?
Is there any way to achieve this by using Cognito?
Please help me with this issue.
Let start from this link :
Configuring User Pool Attributes
You can have changeable standard attributes as far as they are not required. You can add custom attributes as well but they are un-changeable.
Well, let's move on another case on some projects I have a need to storing a user federated identity id (i.e ap-northeast-1:3c2f5c30-0dc8-4d74-91a8-bf5c688abcde) into a cognito user pool attribute. I should store it on a custom attribute (i.e custom:identity_id) because of it will never change in the future.
Back to your case, as it will be dynamic values where users has ability to change their organization list so you can utilize an unused standard attributes for. For example, I will use "zoneinfo" although it looks strange to use unassociated attribute because there is no one with the name "organization". However at least users can pull their organization from their token once logged-in as like :
"zoneinfo": "[org1, org2, org3, etc]"
But it can't full accomodate your case as it should be stored after user registration. While if you set the "zoneinfo" on required registration, it must be unchangeable then. To solve this problem, you can utilize the cognito user pool Post-Confirmation trigger to run some logic to init a standard attribute with empty organization list (i.e "zoneinfo": "[]") adminUpdateUserAttributes. That so users can modify this attribute then because of it is not required attribute.
Sample of adminUpdateUserAttributes :
async function updateOrgAttr() {
try {
var params = {
UserAttributes: [ /* required */
{
Name: 'zoneinfo', /* required */
Value: '[]'
}
],
UserPoolId: 'ap-northeast-1_xxxxxxxx', /* required */
Username: event.userName /* event.userName is an item of post-confirmation trigger event source */
};
let cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
await cognitoidentityserviceprovider.adminUpdateUserAttributes(params).promise()
} catch(e) {
throw e
}
}

does serverless databases like faunadb support role based auth?

i'm new to serverless architecture in general, and i'm studying migrating my current php/mysql rest api to serverless arch.
my main concern is access control.
in certain app, i allow users to access content based on role, and groups they are assigned to "
example
role: user groups: [1,2,3] can only access content with group_id: 1 || 2 || 3
is it possible to do such access control in serverless databases like faunadb ?
It is possible to do such access control with FaunaDB and much more with the ABAC system (https://docs.fauna.com/fauna/current/security/abac.html)
Roles:
In essence you have Roles and these roles provide permissions
CreateRole({
name: "access_todos",
privileges: [{
resource: Collection("todos"),
actions: {
create: true,
update: true,
delete: true,
write: true
}
}]
})
(you might notice that this of course gives access to all groups which is not what you want, we'll get to that)
Roles can be assigned to different things:
Keys: simply make a key with that role and that key can only access the groups collection
Functions: a User Defined Function (like a stored procedure) can assume a role.
Entities in a collection or part of a collection: any entity (e.g. Users, ShareLinks, Accounts) could be assigned a role by adding a 'membership.
Roles Membership (assign roles to a database entity):
You assign a role to database entities by using the membership field.
In this case, all accounts in your database will have these privileges. You can also use a function here to filter out a certain type of account etc..
CreateRole({
name: "access_todos",
membership: [{ resource: Collection("accounts") }],
privileges: [{
resource: Collection("todos"),
actions: {
create: true,
update: true,
delete: true,
write: true
}
}]
})
Assume the identity of that entity, (get a key for that database entity):
Then that leaves us with the question: "how do we assume the identity of a user?".
We use login for that. First you create an account with a password:
Create(
Class("account"),
{
data: { email: "alice#example.com" }
credentials: { password: "secret password" },
}));
The important part is the credentials.password field which is a special field for FaunaDB. It will be encrypted and when a database entity has such a password you can use Login to assume the identity of the entity:
Login(
Index("accounts_by_email"), "alice#example.com"),
{ password: "secret password" })
Login will provide you a token and that token will now have all the rights that this account has. Or in other words all the privileges of the roles for which this database entity of the collection 'accounts' is member (and membership is defined on the role with the membership key)
The power of Role predicates and the 'Identity()' function
Ok but how do we get more fine-grained access?
Roles can have lambda predicates instead of booleans. That means in your case you could store the array of groups on the user (or vice versa) and link the account to the user.
privileges: [
{
resource: Collection("Groups"),
actions: {
read: Query(
Lambda("groupReference",
// Write your logic
)
)
}
}
]
In such a query, the lambda parameter is the reference of the entity you try to access (e.g. a group)
One question remains.. how do we check whether the user linked to an account has access to the groups? Well we use 'Identity()' for that which is an FQL function that returns the reference of the currently logged in database entity.
Note: by default you get read/write access to the entity you are logged into. Hence you do not want to store the group ids on the account since a user could in theory change these. This is why I split account and user in my explanation. We will probably change this in a future FQL version since this appears to be confusing/cumbersome.
A few good resources:
- ABAC docs: https://docs.fauna.com/fauna/current/security/abac.html
- ABAC with GraphQL: https://medium.com/fauna/abac-graphql-6e3273945b1c
- Authentication docs: https://app.fauna.com/tutorials/authentication#creating-users
We are building a complete example as we speak which I expect to appear on our blog in the coming weeks.

userType field - which values are allowed?

Microsoft Graph API's User entity has field "userType". According to documentation there is no any information about this. There is one line: "A string value that can be used to classify user types in your directory, such as “Member” and “Guest”. Supports $filter.". So there is no any limitations :-)
Can be "userType" null? I can't PATCH existing user manually via graph api - graph api return an error. But on production we have some users, which have "userType": null
Which values are valid for "userType"? Can you provide it in documentation or here please?
According to your questions, I suppose you want to know the valid value of the field userType. we can refer to the content of User Entity.
For your first question, we can set the field userType to null, not " " or "null". When we create a user, the default value of this field will be Member if we didn't set it.
We can patch existing user. Based on my test, we can modify it like this:
PATCH https://graph.microsoft.com/v1.0/users/{userid}
{
"displayName": "XXX",
"givenName": "XXXX",
"jobTitle": "Marketing Director",
"userType": "Guest"
}
This will modify the user'userType from Member to Guest.
For your second question, according to the content of User Entity and the article of Azure AD User, the valid value for userType is "Member" and "Guest". Based on my test, it is sure that only these two values can be used.

Extending a member profile with two further layers - asp.net mvc

I have a modeling question related to profiles. Firstly, I have looked into using the SQLTableProvider and using the in built profiling system but didn't feel they were suitable. So, with that said, I have a membership scheme where every person has a profile, then that person can upgrade their profile to either an individual (additional fields) or a company account (additional fields again).
So I thought, use a Profile base class and then inherit from that for the Company account and Individual account. However, when it comes to implementing this in MVC I'm hitting a brick wall.
Since either the company or individual edit pages are effectively updating both the base Profile table and also the individual/company tables from the same page. How would I go about implementing this within the model (which is currently generated via LinqToSQL) and also at the view level?
Apologies if that wasn't very clear, tricky one to explain!
If you are using Linq to SQL, then you already have a model. Linq generates the entities and collections based on your database for you. The generated model is a shallow one, but is pretty solid and workable. The Linq to SQL model can be extended via partial classes allowing you to enhance entities or the context itself for additional functionality.
The controller can work directly against the generated model and pass entities or collections of entities to the view as needed.
I would suggest that, for what you appear to be trying to do, you might consider not using the built-in profile provider system at all. The profile providers in asp.net work well for simple personalization stuff, but it doesn't work well for concrete data like contact info and such. Also keep in mind that the profile provider systems tend to store object data as serialized strings in the database... this makes getting at profile data very difficult from admin tools and such. Performance starts to become a problem VERY fast in any case where you are needing multiple user's profile information (such as with an admin user editor).
For a when you are storing important personal details like the stuff you mentioned, what you are really storing are "account details" not "user profiles". You can extend a membership provider to expose your additional details, but I've generally found it much easier to just roll my own data model and access logic to deal with the additional account information.
My rule of thumb is this: if the information is ONLY needed during a request made by the user to whome the data belongs, then it goes in profiles. If I would need the data for one user to be read during another user's request, or if I would need a "list" of that data for different users, then it doesn't go in asp.net profiles.
Do you mean settings like choosing how many items to view on each page, and choosing some style sheet?
public class Profile
{
int? ItemsPerPage { get; set; }
string PreferredStyleSheet { get; set; }
}
The company selects some values that will work for users unless the users have chosen some other values for themselves. Is that what you have in mind?
In that case: I don't know how to do it together in ASP.NET Profile, but how about the following tables in the database:
TABLE Setting
(
SettingID int NOT NULL,
SettingName varchar(32) NOT NULL,
DefaultValue nvarchar(128) NULL
)
TABLE CompanySetting
(
CompanySettingID int NOT NULL,
RefSettingID int NOT NULL,
RefCompanyID int NOT NULL,
SettingValue nvarchar(128) NOT NULL
)
TABLE UserSetting
(
UserSettingID int NOT NULL,
RefSettingID int NOT NULL,
RefUserId uniqueidentifier NOT NULL,
SettingValue nvarchar(128) NOT NULL
)
And then make some joins for the present user. If the user setting is not given, take the company setting; if the company setting is not given, take the default value.

Resources