I am building a solution, where a single user should be able to access resources from a API spaning multiple accounts using a JWT token.
The setup is quite simple: I have a API exposing resources related to an account, e.g:
[api]/account/{account_id}/orders
However a user should be able to access multiple accounts, but with different permissions for each account (like admin and guest). I however am unsure about how this should best be expressed in the access token, and I have not been able to find an example online addressing this issue.
My current idea would be to have a payload like:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"aud": "[api]",
"accounts": [
{
"account_id": 123,
"roles": ["admin"]
},
{
"account_id": 234,
"roles": ["guest"]
}
]
}
In theory the "roles" property could be replaced on scopes related to the specific account, mimicking then root level scopes. However, if there exist a standard way to achieve this, I would prefer going in that direction?
Related
I want to manage policies for my resources in Keycloak through a UMA compliant endpoint. So I created a resource profile with scopes view_users, invite_users, edit_users.
Then I moved on to creating Policies using the Policy API.
## POST
{
"name": "can_view_users",
"logic": "NEGATIVE",
"decisionStrategy": "AFFIRMATIVE",
"clients": ["uma_postman"],
"scopes": ["view_users"],
"roles": ["uma_postman/lg_admin", "uma_postman/sales", "uma_postman/customer_admin"],
"users": ["37ae8b1e-f1b0-4e72-b6ac-5ad1e49f89d7", "3627cb69-23ed-474d-abec-8f31b230b730"]
}
I can query this(GET http://localhost:8080/auth/realms/ng_whs/authz/protection/uma-policy) and it seems that the policy is created properly.
Now my understanding is that since the decision strategy is AFFIRMATIVE & the logic is NEGATIVE, for any of the above roles - lg_admin, sales, customer_admin or the user with the above ids, I should not be allowed access to the resource.
However, when I query as a user with the above role or id, I still don't get access denied.
Now when I change the logic to POSITIVE for the same policy, the response is still the same. Am I missing something here? Any help would be really appreciated. :)
I was following the instructions from here - keycloak.org/docs/latest/authorization_services/#_service_authorization_uma_policy_api
I have /companies and /users resources. My business logic prevents creating company without first user. Only way I can think of:
POST /companies
{
"name": "Harvey's Broiler",
"user": {
"firstName": "Jojo",
"lastName": "Stomopolous",
"email": "jojostomopolous#harveysbroiler.com",
"password": "password"
}
}
Response:
{
"id": 10001,
"name": "Harvey's Broiler",
"user": {
"id": 10002,
"firstName": "Jojo",
"lastName": "Stomopolous",
"email": "jojostomopolous#harveysbroiler.com"
}
}
Later, they can be reachable as:
GET /companies/10001
Response:
{
"id": 10001,
"name": "Harvey's Broiler"
}
and
GET /users/10002
or
GET /companies/10001/users/10002
Response:
{
"id": 10002,
"firstName": "Jojo",
"lastName": "Stomopolous",
"email": "jojostomopolous#harveysbroiler.com"
}
This is a common question developers encounter when designing APIs.
The first question you should ask yourself is are the Company and User resources same order citizens? By order, I mean are they the same importance, are they both resources you massively operate with and have independent roles and operations in the system you are building? My hunch is the answer is yes. If the answer is no, then the User is only a way of denoting the founder of the Company, and you have no problem, just put the User as an embedded object like you already did.
However, if my hunch is right that you have some business logic around User and Company, I would do just that, keep them separate, under separate endpoints.
If you need a User to create a Company, than implement that logic. If a Company is attempted to be created with a missing User, return an error (HTTP response 400, or something along those lines). Of course, that should be documented for the user. The request is than like this:
POST /companies
{
"name": "Harvey's Broiler",
"user": 1234
}
Mashing the creation of two objects under the same request artifically can only lead to issues. Now you need to return the status for both (a User is created, but Company failed?), return two IDs (what if you also need to add other information, tax details, you get a third ID) and so on.
The only valid reason for creating the User along with the Company is if a User is very often created along with the Company, if not always, and you need to reduce the number of API calls, so you only fire one, but I am not sure that is the case.
If you can't even have a User without a Company, than see if you can revise the requirements or create the User/Company in two steps. First fire a request for a User "placeholder" (let's say the User will not be visible in a list of Users or such, it will not be valid), and after creating Company, the User becomes valid and visible, and other operations become permitted. Until that, there is no User, only a placeholder for it. The same can be logic can be reversed for Company.
And another thing, I will not go into this kind of nesting:
GET /companies/10001/users/10002
First, it is usually hard to program (you get a lot of boilerplate), and it is a possible maintenance nightmare. You can extrapolate the case to:
GET /companies/10001/users/10002/accounts/24314/bank/address
And fetch a bank address for a bank of a user who founded a company. I'm hesitant to implement this kind of approach if I do not have to.
Also, please consider reading about HATEOAS. It might help you if you need this kind of nesting. Actually I will always encourage at least considering the HATEOAS principle when starting a new API.
I'm creating a Google Cloud Storage bucket via the JSON API.
I can create it fine, but when I query the meta data for it I can't see any ACL specified, despite asking for "full" access. Another bucket created via the UI I can see all ACL for.
I need to see the ACL as to update a bucket a required field is the buckets ACL, which I don't quite understand why is needed, but without the same bucket giving its ACL data it means I can't update buckets I create.
I assume that I have full write access to the bucket once I create it, and have tried creating it with and without a predefinedAcl.
Is there anything I am missing on why I can't see the ACL on new buckets?
The creator of the bucket is always an owner of that bucket, and owners of a bucket can always see the bucket's ACL. That said, the ACLs are not part of the default response to a storage.objects.get call. Try passing in the URL query parameter "projection=full", which will cause the ACLs to be included.
The "update" call always sets the absolute, full state of the bucket's metadata, including ACLs and everything else. If you're looking to simply modify some property of the bucket, the "patch" call is probably what you want to use.
The ACL isn't returned because its just not present for the bucket. But to do updates, you can simply pass an empty list to the PATCH method and it will work, even though the acl field is still required:
PUT https://www.googleapis.com/storage/v1/b/blahblahblxxxxlifecycle?key={YOUR_API_KEY}
{
"acl": [
],
"kind": "storage#bucket",
"id": "blahblahblxxxxlifecycle",
"selfLink": "https://www.googleapis.com/storage/v1/b/blahblahblahffflifecycle",
"projectNumber": "1080525199262",
"name": "blahblahblxxxxlifecycle",
"timeCreated": "2016-09-09T21:20:56.490Z",
"updated": "2016-09-09T21:20:56.490Z",
"metageneration": "1",
"location": "US",
"versioning": {
"enabled": true
},
"storageClass": "STANDARD",
"etag": "CAE="
}
Suppose I have a customer that has multiple accounts. Really any data object that has a "1 to many" relationship with another complex object will do.
An example might be:
{ id: 1,
name: "Bob",
accounts: [ { id: 2, name: "Work account" },
{ id: 3, name: "Home account" } }
My question is, when is it appropriate/better to expose the accounts as a sub-resource of the customer, vs. as a separate resource? Or both?
For example, my first intuition would be to have: /customers/1 return the object above. If you wanted to modify one of the accounts, you'd have to POST to /accounts/2.
The other way to go about it (I have seen in some APIs) is to expose another route /customers/1/accounts which would return the array above, and then set up POST/PATCH routes there to allow API users to mutate the array of accounts.
My problem with that approach is that if the array of accounts are actually "included by reference", it's not really clear whether that REST route is modifying the account or if it's merely modifying the linkage between customer and the account.
Is there a best practice here?
This is a good question and is up for discussion (there isn't a "correct" answer). Here are some points you may want to consider:
Having the child account resource embedded in the customer resource will cause more data to always be sent back with the /customers/{id} request.
Having the child account resource non-embedded will require a client to send multiple HTTP requests if it needs both basic customer information and also account information.
You'll want to determine exactly how your security paradigm will work with embedded resources. (i.e. Is it possible to be allowed to get the information of a customer but not be allowed to see the customers accounts?)
Does it ever make sense to have an account without a customer in your domain? Can accounts transfer ownership? If not, then /customers/{id}/accounts/{acct_id} makes more sense.
Implied in the definition of REST, issuing HTTP methods on a URI is modifying a resource identified by the URI, so by default, you're always modifying the account and not the linkage between the customer and account.
If you needed functionality to modify the linkage of accounts, you could invent a resource like, "account link request" (POST /accounts/{id}/linkreqeust or something of that nature). This request could have a state in its own right, where you would have back-end functionality that would evaluate the request and then determine if an account should be linked or detached to/from a customer and then do the attach/detach process.
In summary, there's nothing in REST that prevents you from referencing the same resource with different links (/accounts/{id}; /customers/{id}/accounts/{acct_id}). My preference is if there are no security implications to having the sub-resource, then have it in conjunction with an endpoint to access the sub-resource by itself. If accounts could be tied to multiple users (or have no customers), I would also expose the /accounts/{id} endpoint.
ex. /customers/1:
{
"id": "1",
"name": "John Doe",
"accounts": {
"collection": [
{
"id": "1",
"type": "savings",
"balance": "$400",
"links": {
"self": "/customers/1/accounts/1"
}
},
{
"id": "2",
"type": "checking",
"balance": "$600",
"links": {
"self": "/customers/1/accounts/2",
"detach" : "/customers/1/accounts/2/linkrequest?action=detach"
}
}
],
"links": {
"self": "/customers/1/accounts",
"attach": "customers/1/accounts/linkrequest?action=attach"
}
},
"links": {
"self": "/customers/1"
}
}
As you already suspected, it's all come down to the data representation model in your database. Whether it is an owned relationship (Actual entities list), unowned relationship (what you referred as "included by reference"), or even an implicit 1:N relationship by backlink reference (a customer backlink field on account).
For retrieving the data by GET, the following can be used depending on the representation model:
/customers/1/accounts
/accounts?customer eq 1
Say I have the following two root resources:
.../organizations
.../persons
A GET on .../organizations/id returns all the information about a specific organization, such as the name, location, etc.
A GET on .../persons/id returns all the information about a specific person, such as the name, age, gender, etc.
What is the preferred RESTful way to model the membership of a person in an organization (for retrieval and creation)? I do not only want to model the membership itself, but also add extra properties, such as the date on which the person joined the organization, his/her role in the organization, ...
Some thoughts:
If we provide .../organizations/id/persons/id, what should a GET return? Only the membership data (join data, role, ...) and a link to .../persons/id? The REST API user can use the link to fetch all the information about the person.
Do we provide a possibility to POST to .../persons for creating a person, and another/separate POST to .../organizations/id/persons for creating the membership?
Going further, let's say a person must always be member of at least one organization. In that case, we need one POST for atomically creating the person and the membership at the same time.
How do we model that? Preferably, I would like to keep the root resources .../organizations and .../projects. It doesn't make sense to create a person on .../organizations/id/persons, neither it does make sense to create a membership on .../persons/.
Wouldn't using HAL and its simple format fulfil your needs?
Let's suppose we have defined resources for persons, organizations and memberships
and we are attempting to retrieve information related to a person identified by "42".
Request:
GET /persons/42 HTTP/1.1
Accept: application/hal+json
Response:
HTTP1.1 200 OK
Content-Type: application/hal+json
{
"id": 42,
"name": "Smith",
"firstName": "John",
"organization": {
"id": 1234,
"name": "blah",
"href": "http://myserver/organizations/1234"
},
"membership": {
"id": 5678,
"name": "blih",
"href": "http://myserver/memberships/5678"
},
"_links": {
"self" : {
"href" : "http://myserver/persons/42"
}
}
}
The person resource refers to the parent organization through the "organization"
relation. That relation allows you to easily navigate to the corresponding organization
resource through the corresponding href link.
In the same manner, the membership relations allows to access the corresponding
membership data (once again through the "href" link), if you consider that membership
associates one person to one organization.
Request:
GET /memberships/5678 HTTP/1.1
Accept: application/hal+json
Response:
HTTP1.1 200 OK
Content-Type: application/hal+json
{
"id": 5678,
"name": "blih",
"person": {
"id": 42,
"href": "http://myserver/persons/42"
},
"organization": {
"id": 1234,
"href": "http://myserver/organizations/1234"
},
"_links": {
"self": {
"href": "http://myserver/memberships/5678"
}
}
}
Please note that I'm not saying that the modelisation above is the right one for your
needs (one person can probably belong to several organizations, for example, and you then need an array in the serialization).
My point is that using HAL might help you modelize what you want.
Think of a resource an object that could exist independently without a dependency to another object. This is just a guideline and you can see how it works in terms of your projects and organizations.
The way I see it a membership should be it's independent resource, because it could even exist after the resource person has been deleted, for historical purposes for example.
In that model I would create a resource /memberships, because it's not a property of a person or an organization that would prompt you to add that as a person or organization sub-resource.
I'm not sure if I agree with #hellraiser, perfect would be hard to define even by Roy's standards. I usually try to achieve the higher level of REST as described by Fowler: http://martinfowler.com/articles/richardsonMaturityModel.html
Actually, perfect RESTful API design is unreachable. I've never seen a system that satisfies all REST API theses formulated by Roy Fielding. But you can improve your skills of rest api design from project to project by following best practises.
For the first time, look this article.