I'm doing a proof of concept with connecting to dynamodb, but I appear to be having issues with permissions.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:*"
],
"Resource": [
"arn:aws:dynamodb:us-west-1:172777662485:table/*"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${www.amazon.com:user_id}"
]
}
}
}
]
}
The code:
DynamoDBContext context = new DynamoDBContext(new AmazonDynamoDBClient("...", "...", new AmazonDynamoDBConfig() { RegionEndpoint = RegionEndpoint.USWest1, MaxErrorRetry = 6 }));
var writeContext = context.CreateBatchWrite<Music>();
writeContext.AddPutItem(new Music() { Artist = "Test Artist", SongTitle = "SongTitle" });
writeContext.Execute();
The error I get is:
arn:aws:iam::...:user/DynamoDBTestUser is not authorized to perform: dynamodb:BatchWriteItem on resource: arn:aws:dynamodb:us-west-1:172777662485:table/Music
Does anyone see anything wrong here?
thanks
Your policy appears to be based on some of the samples from this document:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/specifying-conditions.html
However, your code does not appear to be adding a record with a partition key matching the username.
So there are 2 possible solutions, depending on your desired outcome.
Solution 1:
Assuming you simply want to insert records into the table, you can use a policy such as:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:*"
],
"Resource": "*"
}]
}
This policy grants the user fully DynamoDB access to any DynamoDB resource.
Solution 2:
If you want to restrict access to the table limiting the user to read/put records only for them, then you need to ensure your primary key attribute in your Music structure is populated with your IAM user name.
Related
I have an app that processes a bunch of data and generates some results. Currently the app emails the results, but this can be cumbersome and the email can get too big, so I'm looking to have the app store the results to a shared OneDrive folder. The app runs without user interaction.
I've been looking into multiple samples for the Microsoft.Graph sdk. I'v been able to authenticate using an application and the ConfidentialClient workflow, but I'm not sure how to find/access a shared directory in OneDrive. Currently just the root drive request doesn't return any children or anything useful. I could access the shared drive when I used the API to login as my user, but that was using a share link for my user. Do I need to generate a share link somehow for the app or not tied to a user? Or is there some other way to find a shared drive?
Here's the code creating my GraphServiceClient:
public static GraphServiceClient GetAuthenticatedClient()
{
if (graphClient == null)
{
ConfidentialClientApp = ConfidentialClientApplicationBuilder.Create(clientId).WithTenantId(FormBrowser.MsaTenantId).WithClientSecret(FormBrowser.MsaClientSecret).Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(ConfidentialClientApp);
graphClient = new GraphServiceClient(authProvider);
}
return graphClient;
}
Then I've tried some of these different calls just to make sure it is authenticating correctly:
//var shares = await this.graphClient.Shares[encodedUrl].Root.Request().Expand(expandValue).GetAsync();
//ProcessFolder(shares);
var drive = graphClient.Drive.Request().GetAsync();
ProcessFolder(await this.graphClient.Drive.Root.Request().Expand(expandValue).GetAsync());
Here's a sample JSON response from the Drive.Root request:
{
"createdDateTime": "2013-11-07T19:59:00+00:00",
"lastModifiedDateTime": "2019-09-15T02:12:23+00:00",
"name": "root",
"webUrl": "https://<company>.sharepoint.com/Documents",
"fileSystemInfo": {
"createdDateTime": "2013-11-07T19:59:00+00:00",
"lastModifiedDateTime": "2019-09-15T02:12:23+00:00"
},
"folder": {
"childCount": 0
},
"parentReference": {
"driveId": "<stuff>",
"driveType": "documentLibrary"
},
"root": {
},
"size": 0,
"children": [
],
"thumbnails": [
],
"id": "<stuff>",
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#drive/root(thumbnails(),children(thumbnails()))/$entity",
"children#odata.context": "https://graph.microsoft.com/v1.0/$metadata#drive/root/children(thumbnails())",
"thumbnails#odata.context": "https://graph.microsoft.com/v1.0/$metadata#drive/root/thumbnails",
"responseHeaders": {
"Transfer-Encoding": [
"chunked"
],
"Vary": [
"Accept-Encoding"
],
"request-id": [
"<id>"
],
"client-request-id": [
"<id>"
],
"x-ms-ags-diagnostic": [
"{\"ServerInfo\":{\"DataCenter\":\"North Central US\",\"Slice\":\"SliceC\",\"Ring\":\"1\",\"ScaleUnit\":\"000\",\"RoleInstance\":\"<stuff>\",\"ADSiteName\":\"<stuff>\"}}"
],
"OData-Version": [
"4.0"
],
"Duration": [
"259.0577"
],
"Strict-Transport-Security": [
"max-age=31536000"
],
"Cache-Control": [
"private"
],
"Date": [
"Thu, 19 Sep 2019 14:06:27 GMT"
]
},
"statusCode": "OK"
}
So I was able to get there through a round-about way, if someone knows an easier way I'd really appreciate it. Here are the steps I took:
1) Authenticated with my user and loaded the info using the sharing url:
string sharingUrl = "<url>";
string base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sharingUrl));
string encodedUrl = "u!" + base64Value.TrimEnd('=').Replace('/', '_').Replace('+', '-');
var shares = await this.graphClient.Shares[encodedUrl].Root.Request().Expand(expandValue).GetAsync();
Once I got the response for that I noted the "driveId" for the drive. Then when I authenticate using my confidentialclient, I can specify the drive in my request:
await this.graphClient.Drives["<driveId from 1>"].Root.Request().Expand(expandValue).GetAsync()
I'm wondering if there's an easier way to find those driveId's, like from the sharepoint site?
Also, it looks like when I get the sharing link from Sharepoint, if I switch the link from "specific people" to "People in " then I can use the Shares to get the drive items.
I followed this guide in order to create account linking in my app
https://developers.google.com/actions/identity/google-sign-in#json
I'm able to verify the user's jwt decoder and send back a response that the user is authorised. Then, according to the guide, in the next request, I should get the user's profile payload (user.profile.payload in the json structure) but It's missing from the next request. More than that, I get the tokenId for jwt verification again.
I think that what i miss here is in the possibleIntent object but I'm not sure, as I didn't see any documentation for that, because I work with asp.net server. There are SDKs with documentation for java and nodeJS only
this is the request provided for the sign in the contain the tokenId
{
"user": {
"locale": "en-US",
"lastSeen": "2019-07-11T14:18:10Z",
"idToken": "<tokenId>",
"userVerificationStatus": "VERIFIED"
},
"conversation": {
"conversationId": "ABwppHH9uZfcKj6pS6A6wItKC1dOXuZJ5oFYt2Og7cqrElSQYC9bv-aV7iQ5FDYaJPp-fa7tQNhc2yS0fw3QBu-M",
"type": "ACTIVE",
"conversationToken": "e0e78f40-a207-49c2-9050-50c6ed526c24"
},
"inputs": [
{
"intent": "actions.intent.SIGN_IN",
"rawInputs": [
{
"inputType": "KEYBOARD"
}
],
"arguments": [
{
"name": "SIGN_IN",
"extension": {
"#type": "type.googleapis.com/google.actions.v2.SignInValue",
"status": "OK"
}
},
{
"name": "text"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.ACCOUNT_LINKING"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
},
"isInSandbox": true,
"requestType": "SIMULATOR"
}
this is the response that i provide after verifying the user.
I tried it with both intents actions.intent.TEXT and actions.intent.SIGN_IN but with no success. the next request is provided with the user.idToken property again instead of the user.profile (that should contain the payload)
{
"conversationToken": "b09d915e-6df9-496d-acde-b76858cd95b4",
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Hi",
"displayText": "Hi"
}
}
],
"suggestions": []
}
},
"possibleIntents": [
{
"intent": "actions.intent.TEXT",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.v2.SignInValue",
"status": "OK"
}
}
]
}
]
}
The user.profile attribute you're talking about is something that is provided via the actions-on-google library for JavaScript. It isn't in the JSON that you will receive. But...
You don't need it because the basic profile information (name, email, and Google ID) is encoded in the user.idToken. That string, which will be sent to you for every request, is just a JWT token which you can verify and decode. The profile will be in the "payload" section.
I don't know c#, but https://jwt.io/ contains a list of libraries which can decode the JWT string for you so you can read the "payload".
Keep in mind that you don't need to verify the token each time (although if you do it right, this shouldn't be expensive), but that you can decode it to get the information that you're looking for.
If you don't want to decode it, you can decode it when you first verify it, get the information you need, and store that information in the userStorage string (assuming you don't expect it to change).
I have this schema extension:
{
"id": "intnovaction_Docu2EventMetadata",
"description": "Eventos de Docu2",
"targetTypes": [
"event"
],
"status": "Available",
"owner": "d1aaf0fa-549f-4692-8929-22eb90b33099",
"properties": [
{
"name": "ActuacionId",
"type": "String"
},
{
"name": "ExpedienteId",
"type": "String"
}
]
}
I am able to extend event properties using this schema. I can set values for 'ActuacionId' and 'ExpedienteId' on an event and I can get these values through this request: https://graph.microsoft.com/v1.0/me/events?$select=id,intnovaction_Docu2EventMetadata
that returns
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('6d418063-df8b-4f47-921b-1072baf4a949')/events(id,intnovaction_Docu2EventMetadata)",
"value": [
{
"#odata.etag": "W/\"FwgXoe8hSUuEcCnxk8/heAAALdjYcQ==\"",
"id": "AAMkAGE1MDUwMDZkLWRmZDctNGMxMi1hN2ZiLTUwNTBlYTc1NmRkYwBGAAAAAABIbknKwqd9SI8d_mLMOg2XBwAXCBeh7yFJS4RwKfGTz_F4AAAAAAENAAAXCBeh7yFJS4RwKfGTz_F4AAAtI8LHAAA=",
"intnovaction_Docu2EventMetadata": {
"ActuacionId": "1",
"ExpedienteId": "2"
}
}
}
the problem comes when I try to filter for those properties:
https://graph.microsoft.com/v1.0/me/events?$select=id,intnovaction_Docu2EventMetadata&$filter=intnovaction_Docu2EventMetadata/ActuacionId eq '1'
Then I am receiving this error response
{
"error": {
"code": "RequestBroker-ParseUri",
"message": "Could not find a property named 'e2_3be22c6901b942889d07616b14e79402_intnovaction_Docu2EventMetadata' on type 'Microsoft.OutlookServices.Event'.",
"innerError": {
"request-id": "4137b6f4-1c8d-4c1e-84fd-02e8ccaab860",
"date": "2017-10-02T19:25:28"
}
}
}
Is it not possible to filter events by schema properties?
It looks like we missed something in our documentation. It's not currently possible to filter on schema extensions defined on Outlook based entity types (events, messages and personal contacts). We could also improve our error messages to make this more clear too. I'll file some items for this.
Hope this helps,
I am using the function to BuildJsonForm to define a form using a JSON schema. I generate the JObject with some parameters the bot asks the user during runtime.
An example of the JObject/JSON I send to the function BuildJsonForm is this one:
`
{
"References": [
"Microsoft.Bot.Connector.dll",
"System.dll",
"mscorlib.dll",
"System.Net.Http.dll"
],
"Imports": [
"Microsoft.Bot.Connector.ThumbnailCard",
"Microsoft.Bot.Connector.StateClient",
"System.Net.Mail",
"System",
"System.Text.RegularExpressions",
"System.Net.Http",
"System.Net",
"System.Text"
],
"type": "object",
"required": [
"username",
"password"
],
"Templates": {
"NotUnderstood": {
"Patterns": [
"I do not understand, Please rephrase that"
]
},
"EnumSelectOne": {
"Patterns": [
"Choose one please"
],
"ChoiceStyle": "Auto"
}
},
"properties": {
"username": {
"Prompt": {
"Patterns": [
"Tell me the {&}, please",
"I need you to especify a {&}, please"
]
},
"type": [
"string",
"null"
],
"Templates": {
"NotUnderstood": {
"Patterns": [
"That is not a valid input"
]
}
}
},
"password": {
"Prompt": {
"Patterns": [
"Tell me the {&}, please",
"I need you to especify a {&}, please"
]
},
"type": [
"string",
"null"
],
"Templates": {
"NotUnderstood": {
"Patterns": [
"That is not a valid input"
]
}
}
}
},
"OnCompletion": "await context.PostAsync(\"Thank you!\"); string files = \"\"; context.PrivateConversationData.TryGetValue<string>(\"Files\", out files); [more code...]"
}
`
I need to send to the database the user's answers to the generated JObject/JSON form's questions, but so far, I haven't found a way to do that.
I also tried accessing the BotData with this line context.PrivateConversationData.TryGetValue<string>("Files", out files);, so I could send the user's answers to the database directly from the "OnCompletion" section of the JSON, but still I can't seem to access to the botdata or context on the OnCompletion section.
Is there any other way I can successfully retrieve the user's responses to the JObject/JSON generated form after the user answers the last question in the form?
It seemed that what was causing the trouble in my project were sending this parameters to the function:
GeneratedForm.BuildJsonForm(channel, user, convers);
since I edited the function without those parameters and I stopped getting the exception specified in the question. I will look for the reason these parameters were causing problems but the solution I found in this case was to define the funtction this way:
GeneratedForm.BuildJsonForm();
I am using Andy Crum's EmberDataModelMaker.
Having punched in the following two classes
// app/models/server-item.js
export default DS.Model.extend({
hostName: DS.attr('string'),
syncServers: DS.hasMany('string'),
subscribers: DS.hasMany('string'),
mailHost: DS.attr('string'),
mailHostLogin: DS.hasMany('credentials')
});
// app/models/credentials.js
export default DS.Model.extend({
user: DS.attr('string'),
password: DS.attr('string'),
server: DS.belongsTo('serverItem')
});
It's showing the following three different expected JSON formats (a very nice feature btw.):
DS.RESTAdapter
"serverItems": [
{
"id": 1,
"hostName": "foo",
"syncServers": [
<stringids>
],
"subscribers": [
<stringids>
],
"mailHost": "foo",
"mailHostLogin": [
<Credentialsids>
]
}
],
"credentials": [
{
"id": 1,
"user": "foo",
"password": "foo",
"server": <ServerItemid>
}
]
DS.ActiveModelAdapter
"serverItems": [
{
"id": 1,
"host_name": "foo",
"sync_server_ids": [
<stringids>
],
"subscriber_ids": [
<stringids>
],
"mail_host": "foo",
"mail_host_login_ids": [
<Credentialsids>
]
}
],
"credentials": [
{
"id": 1,
"user": "foo",
"password": "foo",
"server_id": <ServerItemid>
}
]
DS.JSONAPIAdapter
{
"data": {
"type": "server-items",
"id": "1",
"attributes": {
"HostName": "foo",
"MailHost": "foo",
},
"relationships": {
"SyncServers": {
"data": {
"type": "SyncServers",
"id": <SyncServersid>
}
},
"Subscribers": {
"data": {
"type": "Subscribers",
"id": <Subscribersid>
}
},
"MailHostLogin": {
"data": {
"type": "MailHostLogin",
"id": <MailHostLoginid>
}
}
},
"included": [
{
<sideloadedrelationships>
]
}
}
}
{
"data": {
"type": "credentials",
"id": "1",
"attributes": {
"User": "foo",
"Password": "foo",
},
"relationships": {
"Server": {
"data": {
"type": "Server",
"id": <Serverid>
}
}
},
"included": [
{
<sideloadedrelationships>
]
}
}
}
I am going to implement (or rather change) some WebServices on the Server side (using C#, ASP.NET Web API). Currently, the WebService already creates a result that is pretty similar to the format expected with DS.RESTAdapter - obviously, it would be ideal if I could use it without compromising the Data Integrity - can I?
If yes, would it empower Ember Data to send all the requests necessary to maintain the data consistency on the server? Meaning, would the client send a DELETE request to the server not only for the ServerItem but also for the Credentials item that is referenced via the mailHostLogin property when the user wants to delete a ServerItem?
If not: are both of the other two adapters fulfilling the above mentioned consistency requirement? Which of the other two should I implement - any experiences/recommendations out there?
You should choose whichever Adapter closest fits your API data structure as a basis(sounds like DS.RESTAdapter in this case). You can extend the adapters and serializers that are a closest fit to make any necessary adjustments(this can be done both application wide or on a per model basis).
However, I don't think that the Ember Data model relationships(i.e. belongsTo and hasMany) are binding in such a way that will automatically result in the "data consistency" you are looking for. If your application requirements are to delete all associated Credentials records when a ServerItem is deleted, I would recommend doing that server side when handling the DELETE ServerItem API request. That would result in better performance(1 HTTP call instead of 2 or N depending if credentials can be deleted in bulk) and be much less error prone due to potential network or other failure of calls to delete Credentials after a ServerItem is deleted.
After a successful ServerItem delete, you could loop through it's credentials and unload the records from the client side store to keep it in sync with the new state on the server. Something like:
serverItemCredentials.forEach(function(id) {
if (this.store.recordIsLoaded('credential', id)) {
this.store.unloadRecord(this.store.peekRecord('credential', id));
}
});