Unable to access AWS using a Facebook AssumeRoleWithWebIdentity credentials - c#

Short version
Logged in as a Facebook user, I use my oAuth token to assume an IAM role on AWS. It returns what looks to be valid credentials, e.g. there is an AccessKeyId, SecretAccessKey that are similar length to our master keys.
When I try to use these credentials to access a DynamoDB table, I get one of two exceptions:
"The remote server returned an error: (400) Bad Request."; or
"The security token included in the request is invalid.".
I'm using the AWS C# SDK version 1.5.25.0
Long version
As I said above, I'm trying to access a DynamoDB table on AWS using credentials supplied by AmazonSecurityTokenServiceClient authorized by Facebook Identity as described in this AWS guide.
The policy for the IAM role that I've created is:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Sid": "Stmt1372350145000",
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}
How I get the credentials:
The user logs in with Facebook using oAuth.
Using the access token, I assume the IAM role using a AmazonSecurityTokenServiceClient.AssumeRoleWithWebIdentity with a request.
This returns what looks like to be valid credentials, e.g. a AccessKeyId, SecretAccessKey that are similar length to our master keys.
using (var tokenServiceClient = new AmazonSecurityTokenServiceClient(RegionEndpoint.USEast1))
{
var request = new AssumeRoleWithWebIdentityRequest
{
DurationSeconds = (int)TimeSpan.FromHours(1).TotalSeconds,
ProviderId = "graph.facebook.com",
RoleArn = "arn:aws:iam::193557284355:role/Facebook-OAuth",
RoleSessionName = result.id,
WebIdentityToken = FBClient.AccessToken
};
var response = tokenServiceClient.AssumeRoleWithWebIdentity(request);
AWSAssumedRoleUser = response.AssumeRoleWithWebIdentityResult.AssumedRoleUser;
AWSCredentials = response.AssumeRoleWithWebIdentityResult.Credentials;
}
How I use these credentials:
Using the returned credentials, I then try to access a AWS DynamoDB resource.
using (var client = new AmazonDynamoDBClient(AWSCredentials.AccessKeyId, AWSCredentials.SecretAccessKey, AWSCredentials.SessionToken, RegionEndpoint.USEast1))
{
var context = new DynamoDBContext(client);
var data = context.Scan<SomeData>();
}
This returns "The remote server returned an error: (400) Bad Request." when trying to Scan the table.
This is where the variation in the exception message is; if I omit the AWSCredentials.SessionToken from the above AmazonDynamoDBClient
using (var client = new AmazonDynamoDBClient(AWSCredentials.AccessKeyId, AWSCredentials.SecretAccessKey, RegionEndpoint.USEast1))
{
var context = new DynamoDBContext(client);
var data = context.Scan<SomeData>();
}
This returns "The security token included in the request is invalid." when trying to Scan the table.
Question
At this point I cannot tell what is wrong, are the credentials invalid or that I'm not passing everything through that is needed to AWS.
Can anyone offer any insight to what is wrong or how I could debug this further?

I cross-posted my question to the AWS forums and received an answer from an Amazon engineer.
https://forums.aws.amazon.com/message.jspa?messageID=465057
DynamoDBContext object invokes DescribeTable on the target table (and caches this data, so for optimal performance you would want to keep the context object around for as long as possible, so this call is only done once per target table). Modify your policy as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem",
"dynamodb:DescribeTable"
],
"Sid": "Stmt1372350145000",
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}

Related

Verify Google pub/sub android payment notification server side C# / ASP.NET MVC

After 3 days I am finished configurations pub/sub push notification from my android app, now my backend server catch every subscription notification made from android app, but now I'm stuck in this stage, all I need is how read full subscription details like(Who make this payment, expire date, ...etc)
I don't know how to do it and what necessary steps to make it happen.
this is what notification look like from my backend server:
{
"message" :
{
"attributes":{ "key": null },
"data": "JSON_CODE",
"messageId": "6542662753109422",
"message_id": "6546652753109422",
"publishTime": "2023-01-01T15:53:42.962Z",
"publish_time": "2023-01-01T15:53:42.962Z"
},
"subscription": "projects/{api_id}/subscriptions/{service_name}-sub"
}
message.data (JSON_CODE) decoded into this:
{
"version": "1.0",
"packageName": "com.expamle.android",
"eventTimeMillis": "1672588422635",
"subscriptionNotification":
{
"version": "1.0",
"notificationType": 4,
"purchaseToken": "lkgkfeofbmfnnalianjdppej.AO-J1OxNcztkkzntpvQk4nttaBiqHJ5WMD58tb_KxCdsyPooE_QPvqXdtnoEpqD0t96j5V4lxol3_FfpuRNDvBeRTYKo_ixJtw",
"subscriptionId": "12_month_plan"
}
}
I have a keys.json file.
And I made all permission required in my pub/sub service accounts.
How to read the full subscription details?
I solved it, to any new coming users this is how to solve it .
first I've used simple .NET library "Google.Apis.Auth.OAuth2" to get access token to any query request.
by this simple code I can get token using key.json i've downloaded from my google cloud console from "**https://console.cloud.google.com/iam-admin/serviceaccounts**" and by manage keys you can generate json secret key.
Auth:
string keyFile = HttpContext.Server.MapPath("~/bin/key.json");
var credential = GoogleCredential.FromFile(keyFile).CreateScoped(new[] { "https://www.googleapis.com/auth/androidpublisher" });
string token = await credential.UnderlyingCredential.GetAccessTokenForRequestAsync();
}
Now you can request google query GET url to get full purchased subscription info .
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{PACKAGE_NAME}/purchases/subscriptionsv2/tokens/{purchaseTokenComesWithMessage.data}
any requests must be included with Authorization Bearer accessToken we'ave generated from Auth. section above.
the result:
{
"kind": "androidpublisher#subscriptionPurchaseV2",
"startTime": "2023-01-03T14:56:24.940Z",
"regionCode": "US",
"subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
"latestOrderId": "GPA.3394-8372-7793-03673",
"testPurchase": {},
"acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
"externalAccountIdentifiers": {
"obfuscatedExternalAccountId": "92d8f330-8d2a-45ab-b6a1-6720b3d15999"
},
"lineItems": [
{
"productId": "12_month_plan",
"expiryTime": "2023-01-03T15:28:21.928Z",
"autoRenewingPlan": {
"autoRenewEnabled": true
},
"offerDetails": {
"basePlanId": "360day",
"offerTags": [
"tools"
]
}
}
] }
Thanks

Access forbidden when trying to create segment from an existing list (Sendgrid v3 API C#)

According to the V3 Sendgrid documentation, I can create segment (on a contact list) using API:
https://docs.sendgrid.com/api-reference/contacts-api-segments/create-a-segment#teconsent
My code is as follows:
public static async void addSegment(SendGridClient client, string list_Id)
{
var data = #"{
""name"": ""location1"",
""list_id"": ""[MY_LIST_ID]"",
""conditions"": [
{
""field"": ""Location"",
""value"": ""location_1"",
""operator"": ""eq"",
""and_or"": """"
},
],
}";
var response = await client.RequestAsync(
method: SendGridClient.Method.POST,
urlPath: "contactdb/segments",
requestBody: data
);
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Body.ReadAsStringAsync().Result);
Console.WriteLine(response.Headers.ToString());
}
However, I got the following error message:
Forbidden
{"errors":[{"field":null,"message":"access forbidden"}]}
What am I doing incorrectly?
Twilio SendGrid developer evangelist here.
SendGrid API keys can be scoped to only permit certain actions against the API. My guess here is that the API key you are using does not have permission to create a segment on the contact list.
You could either use an API key with full access or ensure the key you are using has access to (I think) the marketing APIs.

Cannot get AWS Lambda to PutObject to S3 in same account no matter what

I am trying to write a lambda to run FFMPEG in an AWS lambda. I have done this before at another workplace so I know that it is possible.
The log shows that I make a Temporary URL to read the file in, it processes with FFMPEG, I pipe the output to a byte[] which is showing data in it, and then I try to do an S3 PutObjectRequest, which always fails with this message:
The request signature we calculated does not match the signature you provided. Check your key and signing method.
The S3 client is the same credentials that I use automated all the time to upload files to S3 from different servers at different locations of our company. I have tried a couple different IAMs to no effect.
I am not trying to do any sort of signature whatsoever. I am simply doing this:
var putRequest = new PutObjectRequest
{
BucketName = m.Groups["bucket"].Value,
Key = m.Groups["key"].Value,
InputStream = new MemoryStream(Encoding.UTF8.GetBytes(data ?? "")),
CannedACL = S3CannedACL.PublicRead,
ContentType = MimeTypes.GetMimeType(Path.GetExtension(m.Groups["key"].Value)),
DisablePayloadSigning = true,
};
putRequest.Headers.ContentLength = data.Length;
_context.Logger.LogLine($"Saving file to bucket '{putRequest.BucketName}' and key '{putRequest.Key}' and content type '{putRequest.ContentType}' and content length {putRequest.Headers.ContentLength}");
try
{
await _s3Client.PutObjectAsync(putRequest);
}
catch (AmazonS3Exception s3x)
{
_context.Logger.LogLine($"S3 Exception: {s3x.Message}");
}
I have checked bucket and key and they are correct. Data.length is greater than 0. Content type is "audio/mpeg", which is correct for .mp3. The data is there to be written.
My lambda is running under AWSLambda_Full_Access with the following additional rights granted:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:ListStorageLensConfigurations",
"s3:ListAccessPointsForObjectLambda",
"s3:GetAccessPoint",
"s3:PutAccountPublicAccessBlock",
"s3:GetAccountPublicAccessBlock",
"s3:ListAllMyBuckets",
"s3:*",
"s3:ListAccessPoints",
"s3:ListJobs",
"s3:PutStorageLensConfiguration",
"s3:ListMultiRegionAccessPoints",
"s3:CreateJob"
],
"Resource": "*"
}
]
}
Does anyone have any ideas what else I could be missing? I have been stuck on this one problem for over 3 days now and have tried everything I can think of, so it must be something I'm not thinking of.
Thanks.

ID token has incorrect audience (aud) claim

I'm trying to Verify an Id Token in C#
I'm Creating the app like this:
AppOptions appOptions = new AppOptions()
{
Credential = GoogleCredential.FromFile(#"path/to/Credential.json"),
ServiceAccountId = "serviceAccId",
ProjectId = "ProjectId",
};
var MyApp = FirebaseApp.Create(appOptions);
The error message i get is: ID token has incorrect audience (aud) claim.
Any Ideas on what it could be? Thanks!
I added a few things to the code... the problem i get is in the last step, when i try to signIn with custom token.
It gives me an error stating that the reason was a MissingIdentifier.
using (var customToken = FirebaseAdmin.Auth.FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(authentication.FirebaseUser.LocalId))
{
string token = customToken.Result;
using (FirebaseAuthProvider auth = new FirebaseAuthProvider(new FirebaseConfig(FireBaseAppKey)))
{
using (test = auth.SignInWithCustomTokenAsync(token))
{
test.Wait();
}
}
customToken.Wait();
}
This is the message i get:
Exception occured while authenticating.
Url: https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key={0}
Request Data:
{
"token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJVaWQiOiIyM2E1ZGM0Ny03NDNhLTQzNDUtODc5Mi1lMDY5NjhkNDZjNGIiLCJpc3MiOiJmaXJlYmFzZS1hZG1pbnNkay0xb2ZxNEBhdXRodGVzdHByb2plY3QtYmVlMDkuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzdWIiOiJmaXJlYmFzZS1hZG1pbnNkay0xb2ZxNEBhdXRodGVzdHByb2plY3QtYmVlMDkuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJhdWQiOiJodHRwczovL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbS9nb29nbGUuaWRlbnRpdHkuaWRlbnRpdHl0b29sa2l0LnYxLklkZW50aXR5VG9vbGtpdCIsImV4cCI6MTU4NDU1NTAzNiwiaWF0IjoxNTg0NTUxNDM2fQ.nwvRalOpMs9LYIAFoFZ53Yu72kar9MNpO8gHBGZaMQcdx0ms7OIs0cYEsXUDYy0A_rNfOK03pIWc1y_w2rtIbl_Rg7oHY2u8YublHGe
-n6w9PjQpkONU3YEWHW9qnewhYPFqiLw94j8qEM9V3Bc0FCtspyv8i7Ra9-r2Gz9p88kvUHcIV8_qF9dN_4kNVNiVVHOIhFDQgDOnwUSobmp6aMVnsB9xRwv2_oiWc19s4HNXcNif12d7HHdeRauWVRoTYYvMjrgJTRUsGcB2YFZR8QhH7_0Fmn8bfbiJWP2maTXayL4sY2sIaEyJZDIaBDHkU8l_j_1KxBR7_FTv2Q5_DA\",
"returnSecureToken":true
}
Response: {
"error": {
"code": 400,
"message": "MISSING_IDENTIFIER",
"errors": [
{"message": "MISSING_IDENTIFIER\",
"domain": "global",
"reason": "invalid"
}
]
}
}
Reason: MissingIdentifier"}
This typically means that the ID token is for a different project than what you have the credentials file for. I recommend downloading a fresh credentials file from the Firebase/Cloud console for the project, and trying again.

AWS S3 bucket Temporary Credentials download file .Net

I have a bucket on Amazon S3 and I have created IAM user Now I want to download private bucket file using temporary credential.
This is my bucket policy
{
"Id": "Policy1509026195925",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1509026179419",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::test-folder/*",
"Principal": {
"AWS": [
"arn:aws:iam::461567291450:user/john"
]
}
}
]
}
this is my c# .Net code
ServicePointManager.Expect100Continue = false;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
try
{
// In real applications, the following code is part of your trusted code. It has
// your security credentials you use to obtain temporary security credentials.
AmazonSecurityTokenServiceConfig config = new AmazonSecurityTokenServiceConfig();
AmazonSecurityTokenServiceClient stsClient =
new AmazonSecurityTokenServiceClient(config);
GetFederationTokenRequest federationTokenRequest =
new GetFederationTokenRequest();
federationTokenRequest.Name = "testuser";
// federationTokenRequest.Policy = "Policy1509026195925";
federationTokenRequest.DurationSeconds = 7200;
GetFederationTokenResponse federationTokenResponse = stsClient.GetFederationToken(federationTokenRequest);
//FederatedUser federationTokenResult = federationTokenResponse.;
Credentials credentials = federationTokenResponse.Credentials;
SessionAWSCredentials sessionCredentials =
new SessionAWSCredentials(credentials.AccessKeyId,
credentials.SecretAccessKey,
credentials.SessionToken);
// The following will be part of your less trusted code. You provide temporary security
// credentials so it can send authenticated requests to Amazon S3.
// Create Amazon S3 client by passing in the basicSessionCredentials object.
AmazonS3Client s3Client = new AmazonS3Client(sessionCredentials, Amazon.RegionEndpoint.USEast1);
// Test. For example, send list object keys in a bucket.
ListObjectsRequest listObjectRequest = new ListObjectsRequest();
listObjectRequest.BucketName = bucketName;
ListObjectsResponse response = s3Client.ListObjects(listObjectRequest);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Every time when I run the code I got Access denied message. Why? How to download the bucket file using Temporary credential?
You can try something like :
assumeRoleResult = AssumeRole(role-arn);
tempCredentials = new SessionAWSCredentials(
assumeRoleResult.AccessKeyId,
assumeRoleResult.SecretAccessKey,
assumeRoleResult.SessionToken);
s3Request = CreateAmazonS3Client(tempCredentials);
You need to to call AssumeRole to get temporary security credentials, and then use those credentials to make a call to Amazon S3, see Switching to an IAM Role (API).
Refer : Using Temporary Security Credentials with the AWS SDKs

Categories

Resources