I am new to loopback and I am not able to extend User Base model properly. Though in explorer it shows that it is extended but all API's give a 401 error. ex. In normal get call for /users I get..
{
"error": {
"name": "Error",
"status": 401,
"message": "Authorization Required",
"statusCode": 401,
"code": "AUTHORIZATION_REQUIRED",
"stack": "Error: Authorization Required"
}
}
I went thru all the links and questions but none of they are working for me. I have properly put public:true in model-config for User Model extended model and written acls etc. but none of them works. I have also raised an issue on git for strongloop: https://github.com/strongloop/loopback/issues/1809 . Any leads would be awesome. Thanks.
User.json is as below:
{
"name": "user",
"plural": "users",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"mongodb": {
"collection": "User"
},
"properties": {
"name": {
"type": "string",
"required": true
},
"email": {
"type": "string",
"required": true
},
"password": {
"type": "string",
"required": true
},
"phone": {
"type": "string"
}
},
"validations": [],
"relations": {
"question": {
"type": "hasMany",
"model": "question",
"foreignKey": ""
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "admin",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": {}
}
Some notes meriting consideration though:
1)You are defining email, password,.. properties, although they are already defined exactly the same way in the parent User model; please see: https://github.com/strongloop/loopback/blob/master/common/models/user.json;
2)For ACLs you are missing accesstypes, they are not right, but they do not break anything...For more info about ACL please see: https://docs.strongloop.com/display/public/LB/Define+access+controls
3)Also when you login please make sure to use user that you have created(a POST request) and it is in database already.
Thanks!
Seems like you've not logged into the application.
Anyway by default most of the functions are not accessible by the settings in user parent class. (This totally is a turn-off)
run the code in the login section
{
"username":"abc",
"password":"xyz"
}
This action will return the token id.
Enter this id in the top most right corner of the page and click the set token button.
Now you're able to use some of the user function.
Create a model inheriting user
:~/nodejs/lab/user-api$ slc loopback:model
? Enter the model name: customer
? Select the data-source to attach customer to: db (memory)
? Select model's base class: User
? Expose customer via the REST API? Yes
? Custom plural form (used to build REST URL): customers
Let's add some customer properties now.
Enter an empty property name when done.
? Property name: phone
invoke loopback:property
? Property type: string
? Required? No
Let's add another customer property.
Enter an empty property name when done.
? Property name:
Granting ACL Access:
slc loopback:acl
? Select the model to apply the ACL entry to: customer
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role: All users
? Select the permission to apply: Explicitly grant access
Granting ACL Access once again:
slc loopback:acl
? Select the model to apply the ACL entry to: customer
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role: All users
? Select the permission to apply: Explicitly grant access
When we're granting access two times it takes precedence over DENY in the base class. You'll get a result next time.
A sample class with the ACLs. You can try it in a loopback project, it'll work :)
{
"name": "customer",
"plural": "customers",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"phone": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}
Please accept answer if it works. It will. Cheers!
Related
As per the documentation, I should be able to get a list of users with a custom schema as long as the field in the schema has a value of ALL_DOMAIN_USERS in the readAccessType property. That is the exact set up I have in the admin console; Moreover, when I perform a get request to the schema get endpoint for the schema in question, I get confirmation that the schema fields are set to ALL_DOMAIN_USERS in the readAccessType property.
The problem is when I perform a users list request, I don't get the custom schema in the response. The request is the following:
GET /admin/directory/v1/users?customer=my_customer&projection=full&query=franc&viewType=domain_public
HTTP/1.1
Host: www.googleapis.com
Content-length: 0
Authorization: Bearer fakeTokena0AfH6SMD6jF2DwJbgiDZ
The response I get back is the following:
{
"nextPageToken": "tokenData",
"kind": "admin#directory#users",
"etag": "etagData",
"users": [
{
"externalIds": [
{
"type": "organization",
"value": "value"
}
],
"organizations": [
{
"department": "department",
"customType": "",
"name": "Name",
"title": "Title"
}
],
"kind": "admin#directory#user",
"name": {
"fullName": "Full Name",
"givenName": "Full",
"familyName": "Name"
},
"phones": [
{
"type": "work",
"value": "(999)999-9999"
}
],
"thumbnailPhotoUrl": "https://photolinkurl",
"primaryEmail": "user#domain.com",
"relations": [
{
"type": "manager",
"value": "user#domain.com"
}
],
"emails": [
{
"primary": true,
"address": "user#domain.com"
}
],
"etag": "etagData",
"thumbnailPhotoEtag": "photoEtagData",
"id": "xxxxxxxxxxxxxxxxxx",
"addresses": [
{
"locality": "Locality",
"region": "XX",
"formatted": "999 Some St Some State 99999",
"primary": true,
"streetAddress": "999 Some St",
"postalCode": "99999",
"type": "work"
}
]
}
]
}
However, if I perform the same request with a super admin user, I get an extra property in the response:
"customSchemas": {
"Dir": {
"fieldOne": false,
"fieldTwo": "value",
"fieldThree": value
}
}
My understanding is that I should get the custom schema with a non admin user as long as the custom schema fields are set to be visible by all domain users. This is not happening. I opened a support ticket with G Suite but the guy that provided "support", send me in this direction. I believe this is a bug or maybe I overlooked something.
I contacted G Suite support and in fact, this issue is a domain specific problem.
It took several weeks for the issue to be addressed by the support engineers at Google but it was finally resolved. The behaviour is the intended one now.
I have created a model MyUser based on the User model as follows:
{
"name": "MyUser",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"ownerRelations": true,
"emailVerificationRequired": true,
"hidden": [
"email",
"emailVerified"
],
"properties": {
"firstName": {
"type": "string",
"required": true
},
"lastName": {
"type": "string",
"required": true
},
"email": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"accessTokens": {
"type": "hasMany",
"model": "CustomAccessToken",
"polymorphic": {
"foreignKey": "userId",
"discriminator": "principalType"
},
"options": {
"disableInclude": true
}
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "create"
}
],
"methods": {}
}
It works perfectly on my local server. But when I host it on aws ec2, only the first time user is created. Next time even if I give different email id, I get email verification error as follows:
The 'MyUser' instance is not valid. Details:emailEmail already exists (value: undefined).
Now if I delete the 1st record and try to create user, it works. So, only 1st record is getting inserted and post that for any unique email also, I am getting validation error. I am not sure why this is happening.
I was able to figure out the problem. I have kept email as a hidden field. loopback has "prohibitHiddenPropertiesInQuery": true by default which does not allow hidden properties in query. As a result, during user validation, email was ignored in the query in loopback-juggler/lib/validation.js. Upon setting prohibitHiddenPropertiesInQuery to false, it works.
However, I am still not sure why it was working in development mode on my local server. prohibitHiddenPropertiesInQuery is by default true, so it should not have worked in development mode also. If anyone have any answer to this, please do let me know.
I have created an Artist model with User as its based model. I was trying to update the artist model through the Loopback explorer but i have an error:
"message": "ValidationError: The Artist instance is not valid. Details: password
can't be blank (value: undefined); email can't be blank (value:
undefined)."
I have already registered a sample info and i have it in my artist db in MongoDB. i am not sure why i need to put something in the email and password field when i was only trying to update an existing data?
here is my artist JSON:
{
"name": "Artist",
"base": "User",
"idInjection": false,
"options": {
"validateUpsert": true,
"strictObjectIDCoercion": true
},
"properties": {
"firstName": {
"type": "string"
},
"middleName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"telephoneNumber": {
"type": "string"
},
"country": {
"type": "string"
},
"city": {
"type": "string"
},
"genre": {
"type": "string"
},
"description": {
"type": "string"
},
"pricing": {
"type": "string"
},
"profilePicture": {
"type": "string"
}
},
"validations": [],
"acls": [
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW",
"property": "create"
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": [
"updateAttributes",
"deleteById"
]
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": {}
}
Am i missing something here?
Because your entity is inherited from a User model, it needs to have the 'password' and 'email' attributes set when using POST or PUT methods (so the whole object is created/updated) - as they are used to log the user in.
If you simply want to update your Artist whithout passing the whole datas, use PATCH. (Then 'password' and 'email' won't be mandatory anymore).
If you don't need to use the Loopback's login system, do not inherit your entity from the User model. (Or is there another reason for you to do so?)
I have a user which own a house (several of users can own the house), the house can have several of furnitures.
CustomUser.json relation:
"houses": {
"type": "hasAndBelongsToMany",
"model": "House",
"foreignKey": "houseId"
}
House.json relations:
"furnitures": {
"type": "hasAndBelongsToMany",
"model": "Furniture",
"foreignKey": ""
},
"customUsers": {
"type": "hasAndBelongsToMany",
"model": "CustomUser",
"foreignKey": ""
}
My ACL is simple and looks like this for both House and Furniture:
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "admin",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}
]
Now, accessing houses for the users works fine, but the users won't get their furnitures listed since they belong to a house (the house is the owner). How do I fix this the easiest way possible? Best would be to somehow define that User owns furnitures through the house? The furnitures must belong to the house, though (since multiple users can have a house).
So I got past this through another module called "loopback-component-access-groups" which lets you define groups. In this particular case I made the House-model a group which the users and furnitures have access to. A user can have different roles so I just set that the user (which have the role "member") can access the furnitures which are in the same group (house). This solution works for me, but I am not entirely sure if further objects inherits that they belong to a house if they are related to a furniture.
Writing my own role resolver made this quite flexible, in the role resolver I had to make logic to find the original parent and also make sure there were no dead relationships (since LB doesn't have support for cascade yet).
I recommend starting with this to get going:
https://loopback.io/doc/en/lb3/Defining-and-using-roles.html
I have typed in at the commandline: slc loopback:acl
and disabled all security for the User model.
Going into strongloop explorer, doing a simple GET Users request gives me a 401 authorization required error.
Any ideas how to open up the User object? Is this a known bug?
Thank you
You can extend your user model and set permissions for your custom model like this:
{
"name": "CustomUser",
"base": "User",
"idInjection": true,
"properties": {},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$unauthenticated",
"permission": "ALLOW"
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}
],
"methods": []
}
However I would NEVER recommend you doing this.
If you really want to disable the endpoints on the User model, you can do this.
Go to your model.config.json and add "public": false to the User field like so:
...
"User": {
"public": false,
"dataSource": "db"
},
...