Having issues getting authentication working using static roles access control within models. Things seem to be working when using ACL's with principal types $authenticated and $everyone. So access controls are in place and functioning as expected when logged in and logged out. As ACL's are moved over to static roles authentication fails and a 401 is returned. Loopback built in models for for roles, role-mapping, and user are being used. I've tried using ROLE and USER as principalTypes.
Creating User, Role, and principal with RoleMapping:
User.create({
username: 'admin',
email: 'admin#admin.com',
password: 'password',
active: true
},
function (err, user) {
Role.create({
name: 'Admin'
},
function (err, role) {
if (err) throw err;
console.log('Created role:', role);
//make user an admin
role.principals.create({
principalType: RoleMapping.USER,
//principalType: RoleMapping.ROLE,
principalId: user.id,
active: true
},
function (err, principal) {
if (err) throw err;
console.log('Principal:', principal);
});
});
});
Customer Model:
"name": "Customer",
"base": "PersistedModel",
"strict": false,
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"description": {
"type": "string"
},
"active": {
"type": "boolean"
}
},
"validations": [],
"relations": {
"products": {
.........
},
"users": {
.........
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
WORKS AS EXPECTED
"accessType": "*",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
RETURNS 401 AFTER LOGGING IN AS USER ASSIGNED TO ROLE
"accessType": "*",
"principalType": "ROLE",
"principalId": "Admin",
"permission": "ALLOW"
}
],
"methods": []
User record created:
"_id" : ObjectId("55b7c34d6033a33758038c3b"),
"username" : "admin",
"password" : ....,
"email" : "admin#admin.com",
"active" : true
Role record:
"_id" : ObjectId("55b7c34d6033a33758038c3e"),
"name" : "Admin",
"created" : ISODate("2015-07-28T18:00:45.336Z"),
"modified" : ISODate("2015-07-28T18:00:45.336Z")
RoleMapping Record:
"_id" : ObjectId("55b7c34d6033a33758038c41"),
"principalType" : "USER",
"principalId" : "55b7c34d6033a33758038c3b",
"roleId" : ObjectId("55b7c34d6033a33758038c3e"),
"active" : true
Thanks before hand for any help!
When you define the user in principalId, try try instead:
principalId: user[0].id,
Please note at:
RoleMapping.principalType: USER (mean user, not ROLE)
RoleMapping.principalId: USER_ID (because define RoleMapping.principalType is USER)
acls: [
{ "principalType": "ROLE",
"principalId": "admin",
}
]
I have tested, it's working
Role
—————————
_id: ObjectId(5c70409a98103f1af6ee2b55)
name: “admin”,
description: “Only Admin can write”,
Role Mapping
——————————
_id: ObjectId(5c7040f998103f1af6ee2b57)
principalType: USER
principalId: 5c72b9ef79dcf14443c1aa3b
roleId: ObjectId(5c70409a98103f1af6ee2b55)
User
——————————
_id: ObjectId(5c72b9ef79dcf14443c1aa3b)
firstName: “”,
lastName: “”,
email:””,
Active:””,
emailVerified:
ACL
{
"accessType": "WRITE",
"principalType": "ROLE",
"principalId": "admin",
"permission": "ALLOW"
}
Related
I've written some CDK code to programmatically create a data pipeline that backs up a DynamoDB table into an S3 bucket on a daily basis.
But it keeps running into this error:
amazonaws.datapipeline.taskrunner.TaskExecutionException: Failed to complete EMR transform. at amazonaws.datapipeline.activity.EmrActivity.runActivity(EmrActivity.java:67) at amazonaws.datapipeline.objects.AbstractActivity.run(AbstractActivity.java:16) at amazonaws.datapipeline.taskrunner.TaskPoller.executeRemoteRunner(TaskPoller.java:136) at amazonaws.datapipeline.taskrunner.TaskPoller.executeTask(TaskPoller.java:105) at amazonaws.datapipeline.taskrunner.TaskPoller$1.run(TaskPoller.java:81) at private.com.amazonaws.services.datapipeline.poller.PollWorker.executeWork(PollWorker.java:76) at private.com.amazonaws.services.datapipeline.poller.PollWorker.run(PollWorker.java:53) at java.lang.Thread.run(Thread.java:750) Caused by:
....
fatal error: An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied at amazonaws.datapipeline.activity.mapreduce.HadoopJobRunner.executeCommand(HadoopJobRunner.java:175) at amazonaws.datapipeline.activity.mapreduce.HadoopJobRunner.ex
I'm using the DataPipelineDefaultResourceRole and DataPipelineDefaultRole for this data pipeline which has S3:* permission, so I'm puzzled why this is happening.
On top of that, I'm not sure why logging is not enabled on my EMR cluster which is spun off by this data pipeline although I've specified the logLocation parameter: myLogUri
Any pointers please?
import { CfnPipeline } from "monocdk/aws-datapipeline";
private createDataPipeline(props: InfrastructureStackProps) {
const dataPipelineName = "a-nice-datapipeline8.23";
const pipeline = new CfnPipeline(this, dataPipelineName, {
name: dataPipelineName,
parameterObjects: [
{
id: "myDDBTableName",
attributes: [
{
key: "Description",
stringValue: "Source table"
},
{
key: "Type",
stringValue: "String"
},
{
key: "Default",
stringValue: "Attributes"
}
]
},
{
id: "myOutputS3Location",
attributes: [
{
key: "Description",
stringValue: "Output S3 Location"
},
{
key: "Type",
stringValue: "String"
},
{
key: "Default",
stringValue: "s3://ddb-table-backup/"
}
]
},
{
id: "myDdbReadThroughputRatio",
attributes: [
{
key: "Description",
stringValue: "DynamoDB Read Throughput Ratio"
},
{
key: "Type",
stringValue: "Double"
},
{
key: "Default",
stringValue: "0.15"
}
]
},
{
id: 'myLogUri',
attributes: [
{
key: 'type',
stringValue: 'AWS::S3::ObjectKey',
},
{
key: 'description',
stringValue: 'DataPipeline Log Uri',
},
],
},
{
id: "myDDBRegion",
attributes: [
{
key: "Description",
stringValue: "Region of the DynamoDB Table"
},
{
key: "Type",
stringValue: "String"
},
{
key: "Default",
stringValue: props.region
}
]
}
],
parameterValues: [
{
id: "myDDBTableName",
stringValue: "Attributes"
},
{
id: "myOutputS3Location",
stringValue: "s3://ddb-table-backup/"
},
{
id: "myDdbReadThroughputRatio",
stringValue: "0.15"
},
{
id: 'myLogUri',
stringValue: `s3://data_pipeline_log/`,
},
{
id: "myDDBRegion",
stringValue: props.region
}
],
pipelineObjects: [
{
"id": "EmrClusterForBackup",
"name": "EmrClusterForBackup",
"fields": [
{
"key": "resourceRole",
"stringValue": "DataPipelineDefaultResourceRole"
},
{
"key": "role",
"stringValue": "DataPipelineDefaultRole"
},
{
"key": "coreInstanceCount",
"stringValue": "1"
},
{
"key": "coreInstanceType",
"stringValue": "m4.xlarge"
},
{
"key": "releaseLabel",
"stringValue": "emr-5.29.0"
},
{
"key": "masterInstanceType",
"stringValue": "m4.xlarge"
},
{
"key": "region",
"stringValue": props.region
},
{
"key": "type",
"stringValue": "EmrCluster"
},
{
"key": "terminateAfter",
"stringValue": "2 Hours"
}
]
},
{
"id": "S3BackupLocation",
"name": "S3BackupLocation",
"fields": [
{
"key": "directoryPath",
"stringValue": "s3://ddb-table-backup/"
},
{
"key": "type",
"stringValue": "S3DataNode"
}
]
},
{
"id": "DDBSourceTable",
"name": "DDBSourceTable",
"fields": [
{
"key": "readThroughputPercent",
"stringValue": "0.15"
},
{
"key": "type",
"stringValue": "DynamoDBDataNode"
},
{
"key": "tableName",
"stringValue": "Attributes"
}
]
},
{
"id": "Default",
"name": "Default",
"fields": [
{
"key": "failureAndRerunMode",
"stringValue": "CASCADE"
},
{
"key": "resourceRole",
"stringValue": "DataPipelineDefaultResourceRole"
},
{
"key": "role",
"stringValue": "DataPipelineDefaultRole"
},
{
"key": "scheduleType",
"stringValue": "cron"
},
{
key: 'schedule',
refValue: 'DailySchedule'
},
{
key: 'pipelineLogUri',
stringValue: 's3://data_pipeline_log/',
},
{
"key": "type",
"stringValue": "Default"
}
]
},
{
"name": "Every 1 day",
"id": "DailySchedule",
"fields": [
{
"key": 'type',
"stringValue": 'Schedule'
},
{
"key": 'period',
"stringValue": '1 Day'
},
{
"key": 'startDateTime',
"stringValue": "2021-12-20T00:00:00"
}
]
},
{
"id": "TableBackupActivity",
"name": "TableBackupActivity",
"fields": [
{
"key": "type",
"stringValue": "EmrActivity"
},
{
"key": "output",
"refValue": "S3BackupLocation"
},
{
"key": "input",
"refValue": "DDBSourceTable"
},
{
"key": "maximumRetries",
"stringValue": "2"
},
{
"key": "preStepCommand",
"stringValue": "(sudo yum -y update aws-cli) && (aws s3 rm #{output.directoryPath} --recursive)"
},
{
"key": "step",
"stringValue": "s3://dynamodb-dpl-#{myDDBRegion}/emr-ddb-storage-handler/4.11.0/emr-dynamodb-tools-4.11.0-SNAPSHOT-jar-with-dependencies.jar,org.apache.hadoop.dynamodb.tools.DynamoDBExport,#{output.directoryPath},#{input.tableName},#{input.readThroughputPercent}"
},
{
"key": "runsOn",
"refValue": "EmrClusterForBackup"
},
{
"key": "resizeClusterBeforeRunning",
"stringValue": "false"
}
]
}
],
activate: true
});
return pipeline;
}
I may be avoiding the direct issue at hand here, but I'm curious to know why you are using DataPipeline for this? You would probably be better served using AWS Backup which will allow you to take periodic backups in a manged fashion as well as other features such as expiring backups or sending to cold storage.
On the particular issue at hand, please check that your S3 bucket does not have a resource based policy blocking you: https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html
Also check the EC2 role used for your DP, commonly called AmazonEC2RoleforDataPipelineRole. More info on IAM roles for DP here.
I used "https://localhost:9443/t/carbon.super/scim2/Bulk" to upload bulk users to WSO2IS. How to add organization,email and mobileno to following data set.
Here is my data object.
{
"failOnErrors": 1,
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:BulkRequest"
],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "qwerty1",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"userName": "Alexwso26.com",
"password": "12345678",
"name": {
"givenName": "Alex26 ",
"familyName": "Silva26"
},
"emails": [
{
"type": "home",
"value": "Alex26#g.com",
"primary": true
}
]
}
}
]
}
It is working fine. But email didn't update.
From your user creation payload, it updates the user's home email. If you Navigate to the Management console -> Main menu -> Claims -> List -> "http://wso2.org/claims" -> Emails - Home Email-> Edit and tick Supported by Default, and view that created user's profile. You can see that the given value has been updated.
Change the email attribute like the following payload. Then you can update the Email attribute of the user. Also, the following payload contains the attribute format for mobile number and organization.
{
"failOnErrors": 1,
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:BulkRequest"
],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "qwerty1",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"userName": "Alexwso26.com",
"password": "12345678",
"name": {
"givenName": "Alex26 ",
"familyName": "Silva26"
},
"emails": [
{
"value": "Alex26#g.com",
"primary": true
}
],
"phoneNumbers": [
{
"value": "0771234567",
"type": "mobile"
}
],
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" : {
"organization": "abc"
}
}
}
]
}
Refer to the following documents when forming payload when creating or managing users/groups via SCIM endpoint.
https://anuradha-15.medium.com/how-to-add-scim-extended-attributes-in-wso2-identity-server-71621f62c5d3
https://www.rfc-editor.org/rfc/rfc7643
I am trying to create two user using CFT i am very new to cloudformation how do we define multiple users i have tried below but getting cft error.
{
"Resources": {
"AWSSCRIPTS": {
"Type": "AWS::IAM::User"
},
"AWSSCRIPTSPolicy": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"Description" : "This policy allows to run scripts in new account.",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
},
"Users": [{
"Ref": "AWSSCRIPTS"
}]
}
},
"AWSSCRIPTSKeys": {
"Type": "AWS::IAM::AccessKey",
"Properties": {
"UserName": {
"Ref": "AWSSCRIPTS"
}
}
}
},
"ADDUSER": {
"Type": "AWS::IAM::User"
},
"ADDUSERPolicy": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"Description" : "This policy allows to list IAM Roles for AAD User.",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
},
"Users": [{
"Ref": "ADDUSER"
}]
}
},
"ADDUSERKeys": {
"Type": "AWS::IAM::AccessKey",
"Properties": {
"UserName": {
"Ref": "ADDUSER"
}
}
},
"Outputs": {
"AccessKey": {
"Value": {
"Ref": "AWSSCRIPTS"
},
"Description": "Access Key ID of AWS Scripts"
},
"SecretKey": {
"Value": {
"Fn::GetAtt": [
"AWSSCRIPTSKeys",
"SecretAccessKey"
]
},
"Description": "Secret Key of AWS Scripts User"
},
"AccessKey2": {
"Value": {
"Ref": "ADDUSER"
},
"Description": "Access Key ID of ADD USER"
},
"SecretKey2": {
"Value": {
"Fn::GetAtt": [
"ADDUSERKeys",
"SecretAccessKey"
]
},
"Description": "Secret Key of ADD User"
}
}
}
I am getting below error
Invalid template property or properties [ADDUSERPolicy, ADDUSER, ADDUSERKeys]
Create credentials for the user, depending on the type of access the user requires:
Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user.
AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.
ADDUSER, ADDUSERPolicy and ADDUSERKeys should be in Resources, but they are on the same level:
I am trying to tap into the password reset process on Loopback, so I can send an e-mail with the instructions to the user. I created a custom model called 'user' that extends 'User'. Then I added "User.on('resetPasswordRequest'...", but it never gets executed. Please check the console.log on the user.js
model-config.json
{
...
"user": {
"dataSource": "mysqlDs",
"public": true,
"options": {
"emailVerificationRequired": false
}
},
...
}
user.json
{
"name": "user",
"base": "User",
"idInjection": true,
"properties": {},
"validations": [],
"relations": {},
"acls": [
{
"principalType": "ROLE",
"principalId": "$everyone",
"accessType": "READ",
"permission": "ALLOW"
}
],
"methods": []
}
user.js
module.exports = function(User) {
console.log('It prints this log here.');
User.on('resetPasswordRequest', function(info) {
console.log('But it does not print this log here ever.');
var url = 'http://www.example.com/reset-password';
var html = 'Click here';
loopback.Email.send({
to: info.email,
from: 'mail#example.com',
subject: 'My Subject',
html: html
}, function() {
console.log('> sending password reset email to:', info.email);
if (err) return console.log('> error sending password reset email');
});
});
};
Ok, so #IvanSschwarz was right. Thank you so much! My initial code was correct, but it was missing a small change on the model-config.json: I needed to hide the User model for some reason. So I also took the opportunity and changed my model name from "user" to "member", to follow the loopback good practices guide lines.
...
"User": {
"dataSource": "mysqlDs",
"public": false
},
"member": {
"dataSource": "mysqlDs",
"public": true,
"options": {
"emailVerificationRequired": true
}
},
....
I believe that the other suggestions could potentially work as well, but I wanted to extend the User model through JSON and also leverage the built-in remote method Reset Password from the Users model. So thank you guys!
The solution is explained here:
http://loopback.io/doc/en/lb3/Extending-built-in-models.html#setting-up-a-custom-model
So you will need:
User.setup = function() {
var User = this;
// since setup is called for every extended model
// the extended model will also have the event listener
User.on('resetPasswordRequest', function() {
///Do your stuff here
});
}
Don't you simply miss to define a remote method in order to call your code?
This is what I would do:
user.js
module.exports = function(User) {
console.log('It prints this log here.');
User.resetPasswordRequest = function (info, cb) {
console.log('But it does not print this log here ever.');
var url = 'http://www.example.com/reset-password';
var html = 'Click here';
loopback.Email.send({
to: info.email,
from: 'mail#example.com',
subject: 'My Subject',
html: html
}, function() {
console.log('> sending password reset email to:', info.email);
if (err) {
cb(err, false);
return console.log('> error sending password reset email');
}
cb(err, true):
});
});
User.remoteMethod('resetPasswordRequest', {
description: 'Send a mail to an User to permit him to reset his password',
accepts: {arg: 'info', type: 'object', required: true},
returns: {arg: 'mailSend', type: 'boolean'},
http: {verb: 'post'}
});
};
Then, using the Explorer or calling the API via REST while posting a your info json like:
{
accessToken: xxx,
email: xxx
}
And don't forget to update your ACLs in user.json so you can call the method from remote:
{
"name": "user",
"base": "User",
"idInjection": true,
"properties": {},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
},
{
"accessType": "WRITE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "resetPasswordRequest"
}
],
"methods": []
}
I have generated remote method using
slc loopback:remote-method
I tried to access this method from explorer and it give status 400 with message "phoneNumber is a required arg"
When I tried with postman it gives status 500 with message Internal sever error. I tried sending post data as form, x-www-form-urlencoded encoded, and row, it gives same result.
Server side error:
Unhandled error for request POST /otp/getOTP: TypeError: Cannot read property 'modelName' of null
at convertToBasicRemotingType (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:390:16)
at /Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:544:20
at Array.filter (native)
at Function.SharedMethod.toResult (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:534:21)
at callback (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:249:31)
at Function.Onetimepassword.getOTP (/Users/manish/Documents/workspace-node/carbuk-services/common/models/one-time-password.js:14:4)
at SharedMethod.invoke (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:263:25)
at HttpContext.invoke (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/http-context.js:387:12)
at phaseInvoke (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:644:9)
at runHandler (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/loopback-phase/lib/phase.js:135:5)
at iterate (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/async/lib/async.js:146:13)
at Object.async.eachSeries (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/async/lib/async.js:162:9)
at runHandlers (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/loopback-phase/lib/phase.js:144:13)
at iterate (/Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/async/lib/async.js:146:13)
at /Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/async/lib/async.js:157:25
at /Users/manish/Documents/workspace-node/carbuk-services/node_modules/loopback/node_modules/async/lib/async.js:154:25
model json look like this
{
"name": "OneTimePassword",
"plural": "otp",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"phoneNumber": {
"type": "number",
"required": true
},
"otpNumber": {
"type": "number",
"required": true
},
"resendCounter": {
"type": "number",
"default": "0"
},
"createdDate": {
"type": "date"
} }, "validations": [], "relations": {}, "acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "deleteById"
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "getOTP"
} ], "methods": {
"getOTP": {
"accepts": [
{
"arg": "phoneNumber",
"type": "number",
"required": true,
"description": "phone number",
"http": {
"source": "form"
}
}
],
"returns": [
{
"arg": "oneTimePassword",
"type": null,
"root": true,
"description": "otp"
}
],
"description": "generate otp and send sms",
"http": [
{
"path": "/getOTP",
"verb": "post"
}
]
} } }
model js:
module.exports = function(Onetimepassword) {
/**
* generate otp and send sms
* #param {number} phoneNumber phone number
* #param {Function(Error, )} callback
*/
Onetimepassword.getOTP = function(phoneNumber, callback) {
var oneTimePassword = {};
oneTimePassword.phoneNumber = phoneNumber;
// TODO
// logic will come here
//
callback(null, oneTimePassword);
};
};
Am I missing something?
You have a typo.
in line oneTimePassword.phoneNumber = phoneNumber; you need to set to optNumber
I found the solution.
In model.json, Remote method's return type is null. I changed this to object type "OneTimePassword"
But still I am not able to hit the remote method from explorer. There is a bug issue#440.
Using postman, request work fine